Replace remaining React ARIA components with Compound components (#2576)

* Fix issues detected by Knip

Including cleaning up some unused code and dependencies, using a React hook that we unintentionally stopped using, and also adding some previously undeclared dependencies.

* Replace remaining React ARIA components with Compound components

* fix button position

* disable scrollbars to resolve overlapping button

---------

Co-authored-by: Timo <toger5@hotmail.de>
This commit is contained in:
Robin
2024-08-28 08:44:39 -04:00
committed by GitHub
parent 7bca541cb6
commit 0db51d9dfd
62 changed files with 668 additions and 2603 deletions

View File

@@ -1,5 +1,5 @@
/*
Copyright 2022 - 2023 New Vector Ltd
Copyright 2022-2024 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,13 +13,10 @@ 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 { FC, forwardRef } from "react";
import { PressEvent } from "@react-types/shared";
import { ComponentPropsWithoutRef, FC } from "react";
import classNames from "classnames";
import { useButton } from "@react-aria/button";
import { mergeProps, useObjectRef } from "@react-aria/utils";
import { useTranslation } from "react-i18next";
import { Tooltip } from "@vector-im/compound-web";
import { Button as CpdButton, Tooltip } from "@vector-im/compound-web";
import {
MicOnSolidIcon,
MicOffSolidIcon,
@@ -28,120 +25,15 @@ import {
EndCallIcon,
ShareScreenSolidIcon,
SettingsSolidIcon,
ChevronDownIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons";
import styles from "./Button.module.css";
export type ButtonVariant =
| "default"
| "toolbar"
| "toolbarSecondary"
| "icon"
| "secondary"
| "copy"
| "secondaryCopy"
| "iconCopy"
| "secondaryHangup"
| "dropdown"
| "link";
export const variantToClassName = {
default: [styles.button],
toolbar: [styles.toolbarButton],
toolbarSecondary: [styles.toolbarButtonSecondary],
icon: [styles.iconButton],
secondary: [styles.secondary],
copy: [styles.copyButton],
secondaryCopy: [styles.secondaryCopy, styles.copyButton],
iconCopy: [styles.iconCopyButton],
secondaryHangup: [styles.secondaryHangup],
dropdown: [styles.dropdownButton],
link: [styles.linkButton],
};
export type ButtonSize = "lg";
export const sizeToClassName: { lg: string[] } = {
lg: [styles.lg],
};
interface Props {
variant: ButtonVariant;
size: ButtonSize;
on: () => void;
off: () => void;
iconStyle: string;
className: string;
children: Element[];
onPress: (e: PressEvent) => void;
onPressStart: (e: PressEvent) => void;
disabled: boolean;
// TODO: add all props for <Button>
[index: string]: unknown;
interface MicButtonProps extends ComponentPropsWithoutRef<"button"> {
muted: boolean;
}
export const Button = forwardRef<HTMLButtonElement, Props>(
(
{
variant = "default",
size,
on,
off,
iconStyle,
className,
children,
onPress,
onPressStart,
...rest
},
ref,
) => {
const buttonRef = useObjectRef<HTMLButtonElement>(ref);
const { buttonProps } = useButton(
{ onPress, onPressStart, ...rest },
buttonRef,
);
// TODO: react-aria's useButton hook prevents form submission via keyboard
// Remove the hack below after this is merged https://github.com/adobe/react-spectrum/pull/904
let filteredButtonProps = buttonProps;
if (rest.type === "submit" && !rest.onPress) {
const { ...filtered } = buttonProps;
filteredButtonProps = filtered;
}
return (
<button
className={classNames(
variantToClassName[variant],
sizeToClassName[size],
styles[iconStyle],
className,
{
[styles.on]: on,
[styles.off]: off,
},
)}
{...mergeProps(rest, filteredButtonProps)}
ref={buttonRef}
>
<>
{children}
{variant === "dropdown" && <ChevronDownIcon />}
</>
</button>
);
},
);
Button.displayName = "Button";
export const MicButton: FC<{
muted: boolean;
// TODO: add all props for <Button>
[index: string]: unknown;
}> = ({ muted, ...rest }) => {
export const MicButton: FC<MicButtonProps> = ({ muted, ...props }) => {
const { t } = useTranslation();
const Icon = muted ? MicOffSolidIcon : MicOnSolidIcon;
const label = muted
@@ -150,18 +42,21 @@ export const MicButton: FC<{
return (
<Tooltip label={label}>
<Button variant="toolbar" {...rest} on={muted}>
<Icon aria-hidden width={24} height={24} />
</Button>
<CpdButton
iconOnly
Icon={Icon}
kind={muted ? "primary" : "secondary"}
{...props}
/>
</Tooltip>
);
};
export const VideoButton: FC<{
interface VideoButtonProps extends ComponentPropsWithoutRef<"button"> {
muted: boolean;
// TODO: add all props for <Button>
[index: string]: unknown;
}> = ({ muted, ...rest }) => {
}
export const VideoButton: FC<VideoButtonProps> = ({ muted, ...props }) => {
const { t } = useTranslation();
const Icon = muted ? VideoCallOffSolidIcon : VideoCallSolidIcon;
const label = muted
@@ -170,19 +65,24 @@ export const VideoButton: FC<{
return (
<Tooltip label={label}>
<Button variant="toolbar" {...rest} on={muted}>
<Icon aria-hidden width={24} height={24} />
</Button>
<CpdButton
iconOnly
Icon={Icon}
kind={muted ? "primary" : "secondary"}
{...props}
/>
</Tooltip>
);
};
export const ScreenshareButton: FC<{
interface ShareScreenButtonProps extends ComponentPropsWithoutRef<"button"> {
enabled: boolean;
className?: string;
// TODO: add all props for <Button>
[index: string]: unknown;
}> = ({ enabled, className, ...rest }) => {
}
export const ShareScreenButton: FC<ShareScreenButtonProps> = ({
enabled,
...props
}) => {
const { t } = useTranslation();
const label = enabled
? t("stop_screenshare_button_label")
@@ -190,45 +90,48 @@ export const ScreenshareButton: FC<{
return (
<Tooltip label={label}>
<Button variant="toolbar" {...rest} on={enabled}>
<ShareScreenSolidIcon aria-hidden width={24} height={24} />
</Button>
<CpdButton
iconOnly
Icon={ShareScreenSolidIcon}
kind={enabled ? "primary" : "secondary"}
{...props}
/>
</Tooltip>
);
};
export const HangupButton: FC<{
className?: string;
// TODO: add all props for <Button>
[index: string]: unknown;
}> = ({ className, ...rest }) => {
export const EndCallButton: FC<ComponentPropsWithoutRef<"button">> = ({
className,
...props
}) => {
const { t } = useTranslation();
return (
<Tooltip label={t("hangup_button_label")}>
<Button
variant="toolbar"
className={classNames(styles.hangupButton, className)}
{...rest}
>
<EndCallIcon aria-hidden width={24} height={24} />
</Button>
<CpdButton
className={classNames(className, styles.endCall)}
iconOnly
Icon={EndCallIcon}
destructive
{...props}
/>
</Tooltip>
);
};
export const SettingsButton: FC<{
className?: string;
// TODO: add all props for <Button>
[index: string]: unknown;
}> = ({ className, ...rest }) => {
export const SettingsButton: FC<ComponentPropsWithoutRef<"button">> = (
props,
) => {
const { t } = useTranslation();
return (
<Tooltip label={t("common.settings")}>
<Button variant="toolbar" {...rest}>
<SettingsSolidIcon aria-hidden width={24} height={24} />
</Button>
<CpdButton
iconOnly
Icon={SettingsSolidIcon}
kind="secondary"
{...props}
/>
</Tooltip>
);
};