diff --git a/src/@types/react.d.ts b/src/@types/react.d.ts new file mode 100644 index 00000000000..f1f57c5400a --- /dev/null +++ b/src/@types/react.d.ts @@ -0,0 +1,24 @@ +/* +Copyright 2023 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { PropsWithChildren } from "react"; + +declare module "react" { + // Fix forwardRef types for Generic components - https://stackoverflow.com/a/58473012 + function forwardRef( + render: (props: PropsWithChildren

, ref: React.ForwardedRef) => React.ReactElement | null, + ): (props: P & React.RefAttributes) => React.ReactElement | null; +} diff --git a/src/accessibility/context_menu/ContextMenuButton.tsx b/src/accessibility/context_menu/ContextMenuButton.tsx index 090b42333ff..396af5748db 100644 --- a/src/accessibility/context_menu/ContextMenuButton.tsx +++ b/src/accessibility/context_menu/ContextMenuButton.tsx @@ -16,25 +16,25 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; +import React, { ComponentProps } from "react"; import AccessibleButton from "../../components/views/elements/AccessibleButton"; -interface IProps extends React.ComponentProps { +type Props = ComponentProps> & { label?: string; - // whether or not the context menu is currently open + // whether the context menu is currently open isExpanded: boolean; -} +}; // Semantic component for representing the AccessibleButton which launches a -export const ContextMenuButton: React.FC = ({ +export const ContextMenuButton = ({ label, isExpanded, children, onClick, onContextMenu, ...props -}) => { +}: Props): JSX.Element => { return ( { - // whether or not the context menu is currently open +type Props = ComponentProps> & { + // whether the context menu is currently open isExpanded: boolean; -} +}; // Semantic component for representing the AccessibleButton which launches a -export const ContextMenuTooltipButton: React.FC = ({ +export const ContextMenuTooltipButton = ({ isExpanded, children, onClick, onContextMenu, ...props -}) => { +}: Props): JSX.Element => { return ( , "inputRef" | "tabIndex"> { +type Props = Omit< + ComponentProps>, + "inputRef" | "tabIndex" +> & { inputRef?: Ref; focusOnMouseOver?: boolean; -} +}; // Wrapper to allow use of useRovingTabIndex for simple AccessibleButtons outside of React Functional Components. -export const RovingAccessibleButton: React.FC = ({ +export const RovingAccessibleButton = ({ inputRef, onFocus, onMouseOver, focusOnMouseOver, ...props -}) => { +}: Props): JSX.Element => { const [onFocusInternal, isActive, ref] = useRovingTabIndex(inputRef); return ( ; -interface IProps extends Omit { +type Props = Omit< + ComponentProps>, + "tabIndex" +> & { inputRef?: Ref; -} +}; // Wrapper to allow use of useRovingTabIndex for simple AccessibleTooltipButtons outside of React Functional Components. -export const RovingAccessibleTooltipButton: React.FC = ({ inputRef, onFocus, ...props }) => { +export const RovingAccessibleTooltipButton = ({ + inputRef, + onFocus, + ...props +}: Props): JSX.Element => { const [onFocusInternal, isActive, ref] = useRovingTabIndex(inputRef); return ( , "title" | "onClick" | "disabled"> { +type Props = Omit, "title" | "onClick" | "disabled" | "element"> & { // Playback instance to manipulate. Cannot change during the component lifecycle. playback: Playback; // The playback phase to render. Able to change during the component lifecycle. playbackPhase: PlaybackState; -} +}; /** * Displays a play/pause button (activating the play/pause function of the recorder) * to be displayed in reference to a recording. */ -export default class PlayPauseButton extends React.PureComponent { - public constructor(props: IProps) { +export default class PlayPauseButton extends React.PureComponent { + public constructor(props: Props) { super(props); } diff --git a/src/components/views/elements/AccessibleButton.tsx b/src/components/views/elements/AccessibleButton.tsx index e5b3688f49d..fc54e8517a4 100644 --- a/src/components/views/elements/AccessibleButton.tsx +++ b/src/components/views/elements/AccessibleButton.tsx @@ -89,7 +89,10 @@ type Props = DynamicHtmlElementProps & onClick: ((e: ButtonEvent) => void | Promise) | null; }; -export interface IAccessibleButtonProps extends React.InputHTMLAttributes { +/** + * Type of the props passed to the element that is rendered by AccessibleButton. + */ +interface RenderedElementProps extends React.InputHTMLAttributes { ref?: React.Ref; } @@ -114,7 +117,7 @@ export default function AccessibleButton( triggerOnMouseDown, ...restProps }: Props): JSX.Element { - const newProps: IAccessibleButtonProps = restProps; + const newProps: RenderedElementProps = restProps; if (disabled) { newProps["aria-disabled"] = true; newProps["disabled"] = true; diff --git a/src/components/views/elements/AccessibleTooltipButton.tsx b/src/components/views/elements/AccessibleTooltipButton.tsx index 8be307f0412..c561b1b8b58 100644 --- a/src/components/views/elements/AccessibleTooltipButton.tsx +++ b/src/components/views/elements/AccessibleTooltipButton.tsx @@ -25,7 +25,7 @@ import Tooltip, { Alignment } from "./Tooltip"; * * Extends that of {@link AccessibleButton}. */ -interface Props extends React.ComponentProps { +type Props = React.ComponentProps> & { /** * Title to show in the tooltip and use as aria-label */ @@ -58,9 +58,9 @@ interface Props extends React.ComponentProps { * Function to call when the tooltip goes from shown to hidden. */ onHideTooltip?(ev: SyntheticEvent): void; -} +}; -function AccessibleTooltipButton({ +function AccessibleTooltipButton({ title, tooltip, children, @@ -69,7 +69,7 @@ function AccessibleTooltipButton({ onHideTooltip, tooltipClassName, ...props -}: Props): JSX.Element { +}: Props): JSX.Element { const [hover, setHover] = useState(false); useEffect(() => { diff --git a/src/components/views/elements/LearnMore.tsx b/src/components/views/elements/LearnMore.tsx index 03f377da763..efce35bfe34 100644 --- a/src/components/views/elements/LearnMore.tsx +++ b/src/components/views/elements/LearnMore.tsx @@ -14,19 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; +import React, { ComponentProps } from "react"; import { _t } from "../../../languageHandler"; import Modal from "../../../Modal"; import InfoDialog from "../dialogs/InfoDialog"; -import AccessibleButton, { IAccessibleButtonProps } from "./AccessibleButton"; +import AccessibleButton from "./AccessibleButton"; -export interface LearnMoreProps extends IAccessibleButtonProps { +type Props = Omit, "kind" | "onClick" | "className"> & { title: string; description: string | React.ReactNode; -} +}; -const LearnMore: React.FC = ({ title, description, ...rest }) => { +const LearnMore: React.FC = ({ title, description, ...rest }) => { const onClick = (): void => { Modal.createDialog(InfoDialog, { title, diff --git a/src/components/views/messages/CallEvent.tsx b/src/components/views/messages/CallEvent.tsx index bfe959c0058..5718c7a4126 100644 --- a/src/components/views/messages/CallEvent.tsx +++ b/src/components/views/messages/CallEvent.tsx @@ -35,7 +35,6 @@ import FacePile from "../elements/FacePile"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { CallDuration, SessionDuration } from "../voip/CallDuration"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -import { ContinueKind } from "../auth/InteractiveAuthEntryComponents"; const MAX_FACES = 8; @@ -127,7 +126,7 @@ const ActiveLoadedCallEvent = forwardRef(({ mxE ); const [buttonText, buttonKind, onButtonClick] = useMemo< - [string, ContinueKind, null | ((ev: ButtonEvent) => void)] + [string, AccessibleButtonKind, null | ((ev: ButtonEvent) => void)] >(() => { switch (connectionState) { case ConnectionState.Disconnected: diff --git a/src/components/views/rooms/ExtraTile.tsx b/src/components/views/rooms/ExtraTile.tsx index 83f7b179ea3..157bfc4d562 100644 --- a/src/components/views/rooms/ExtraTile.tsx +++ b/src/components/views/rooms/ExtraTile.tsx @@ -73,11 +73,7 @@ export default function ExtraTile({ ); if (isMinimized) nameContainer = null; - let Button = RovingAccessibleButton; - if (isMinimized) { - Button = RovingAccessibleTooltipButton; - } - + const Button = isMinimized ? RovingAccessibleTooltipButton : RovingAccessibleButton; return (