Improve AccessibleButton & related types (#12075)

* Fix wrong type enum usage

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Use improved type definition for forwardRef which enables Generic props

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Improve AccessibleButton & related Props types

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove useless comment

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2023-12-20 14:42:31 +00:00 committed by GitHub
parent e26d3e9b68
commit af31965866
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 109 additions and 79 deletions

View file

@ -14,28 +14,27 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ReactNode } from "react";
import React, { ComponentProps, ReactNode } from "react";
import classNames from "classnames";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { _t } from "../../../languageHandler";
import { Playback, PlaybackState } from "../../../audio/Playback";
// omitted props are handled by render function
interface IProps extends Omit<React.ComponentProps<typeof AccessibleTooltipButton>, "title" | "onClick" | "disabled"> {
type Props = Omit<ComponentProps<typeof AccessibleTooltipButton>, "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<IProps> {
public constructor(props: IProps) {
export default class PlayPauseButton extends React.PureComponent<Props> {
public constructor(props: Props) {
super(props);
}

View file

@ -89,7 +89,10 @@ type Props<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> &
onClick: ((e: ButtonEvent) => void | Promise<void>) | null;
};
export interface IAccessibleButtonProps extends React.InputHTMLAttributes<Element> {
/**
* Type of the props passed to the element that is rendered by AccessibleButton.
*/
interface RenderedElementProps extends React.InputHTMLAttributes<Element> {
ref?: React.Ref<Element>;
}
@ -114,7 +117,7 @@ export default function AccessibleButton<T extends keyof JSX.IntrinsicElements>(
triggerOnMouseDown,
...restProps
}: Props<T>): JSX.Element {
const newProps: IAccessibleButtonProps = restProps;
const newProps: RenderedElementProps = restProps;
if (disabled) {
newProps["aria-disabled"] = true;
newProps["disabled"] = true;

View file

@ -25,7 +25,7 @@ import Tooltip, { Alignment } from "./Tooltip";
*
* Extends that of {@link AccessibleButton}.
*/
interface Props extends React.ComponentProps<typeof AccessibleButton> {
type Props<T extends keyof JSX.IntrinsicElements> = React.ComponentProps<typeof AccessibleButton<T>> & {
/**
* Title to show in the tooltip and use as aria-label
*/
@ -58,9 +58,9 @@ interface Props extends React.ComponentProps<typeof AccessibleButton> {
* Function to call when the tooltip goes from shown to hidden.
*/
onHideTooltip?(ev: SyntheticEvent): void;
}
};
function AccessibleTooltipButton({
function AccessibleTooltipButton<T extends keyof JSX.IntrinsicElements>({
title,
tooltip,
children,
@ -69,7 +69,7 @@ function AccessibleTooltipButton({
onHideTooltip,
tooltipClassName,
...props
}: Props): JSX.Element {
}: Props<T>): JSX.Element {
const [hover, setHover] = useState(false);
useEffect(() => {

View file

@ -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<ComponentProps<typeof AccessibleButton>, "kind" | "onClick" | "className"> & {
title: string;
description: string | React.ReactNode;
}
};
const LearnMore: React.FC<LearnMoreProps> = ({ title, description, ...rest }) => {
const LearnMore: React.FC<Props> = ({ title, description, ...rest }) => {
const onClick = (): void => {
Modal.createDialog(InfoDialog, {
title,

View file

@ -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<any, ActiveLoadedCallEventProps>(({ mxE
);
const [buttonText, buttonKind, onButtonClick] = useMemo<
[string, ContinueKind, null | ((ev: ButtonEvent) => void)]
[string, AccessibleButtonKind, null | ((ev: ButtonEvent) => void)]
>(() => {
switch (connectionState) {
case ConnectionState.Disconnected:

View file

@ -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 (
<Button
className={classes}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ForwardedRef, forwardRef } from "react";
import React, { ForwardedRef, forwardRef, FunctionComponent } from "react";
import { FormattingFunctions, MappedSuggestion } from "@matrix-org/matrix-wysiwyg";
import { logger } from "matrix-js-sdk/src/logger";
@ -120,6 +120,6 @@ const WysiwygAutocomplete = forwardRef(
},
);
WysiwygAutocomplete.displayName = "WysiwygAutocomplete";
(WysiwygAutocomplete as FunctionComponent).displayName = "WysiwygAutocomplete";
export { WysiwygAutocomplete };

View file

@ -15,18 +15,25 @@ limitations under the License.
*/
import classNames from "classnames";
import React from "react";
import React, { ComponentProps } from "react";
import { Icon as CaretIcon } from "../../../../../res/img/feather-customised/dropdown-arrow.svg";
import { _t } from "../../../../languageHandler";
import AccessibleTooltipButton from "../../elements/AccessibleTooltipButton";
interface Props extends React.ComponentProps<typeof AccessibleTooltipButton> {
type Props<T extends keyof JSX.IntrinsicElements> = Omit<
ComponentProps<typeof AccessibleTooltipButton<T>>,
"aria-label" | "title" | "kind" | "className" | "onClick"
> & {
isExpanded: boolean;
onClick: () => void;
}
};
export const DeviceExpandDetailsButton: React.FC<Props> = ({ isExpanded, onClick, ...rest }) => {
export const DeviceExpandDetailsButton = <T extends keyof JSX.IntrinsicElements>({
isExpanded,
onClick,
...rest
}: Props<T>): JSX.Element => {
const label = isExpanded ? _t("settings|sessions|hide_details") : _t("settings|sessions|show_details");
return (
<AccessibleTooltipButton

View file

@ -14,15 +14,15 @@ 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 LearnMore, { LearnMoreProps } from "../../elements/LearnMore";
import LearnMore from "../../elements/LearnMore";
import { DeviceSecurityVariation } from "./types";
interface Props extends Omit<LearnMoreProps, "title" | "description"> {
type Props = Omit<ComponentProps<typeof LearnMore>, "title" | "description"> & {
variation: DeviceSecurityVariation;
}
};
const securityCardContent: Record<
DeviceSecurityVariation,

View file

@ -48,7 +48,10 @@ import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
interface IButtonProps extends Omit<ComponentProps<typeof AccessibleTooltipButton>, "title" | "onClick" | "size"> {
type ButtonProps<T extends keyof JSX.IntrinsicElements> = Omit<
ComponentProps<typeof AccessibleTooltipButton<T>>,
"title" | "onClick" | "size"
> & {
space?: Room;
spaceKey?: SpaceKey;
className?: string;
@ -61,9 +64,9 @@ interface IButtonProps extends Omit<ComponentProps<typeof AccessibleTooltipButto
innerRef?: RefObject<HTMLElement>;
ContextMenuComponent?: ComponentType<ComponentProps<typeof SpaceContextMenu>>;
onClick?(ev?: ButtonEvent): void;
}
};
export const SpaceButton: React.FC<IButtonProps> = ({
export const SpaceButton = <T extends keyof JSX.IntrinsicElements>({
space,
spaceKey: _spaceKey,
className,
@ -77,7 +80,7 @@ export const SpaceButton: React.FC<IButtonProps> = ({
innerRef,
ContextMenuComponent,
...props
}) => {
}: ButtonProps<T>): JSX.Element => {
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLElement>(innerRef);
const [onFocus, isActive] = useRovingTabIndex(handle);
const tabIndex = isActive ? 0 : -1;

View file

@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { createRef, useState } from "react";
import React, { ComponentProps, createRef, useState } from "react";
import classNames from "classnames";
import { MatrixCall } from "matrix-js-sdk/src/webrtc/call";
@ -42,14 +42,13 @@ const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the butt
const CONTROLS_HIDE_DELAY = 2000;
interface IButtonProps extends Omit<React.ComponentProps<typeof AccessibleTooltipButton>, "title"> {
type ButtonProps = Omit<ComponentProps<typeof AccessibleTooltipButton>, "title" | "element"> & {
state: boolean;
className: string;
onLabel?: string;
offLabel?: string;
}
};
const LegacyCallViewToggleButton: React.FC<IButtonProps> = ({
const LegacyCallViewToggleButton: React.FC<ButtonProps> = ({
children,
state: isOn,
className,
@ -74,7 +73,7 @@ const LegacyCallViewToggleButton: React.FC<IButtonProps> = ({
);
};
interface IDropdownButtonProps extends IButtonProps {
interface IDropdownButtonProps extends ButtonProps {
deviceKinds: MediaDeviceKindEnum[];
}