From 6189e6454dad7a3979b94a2bff8887694e030364 Mon Sep 17 00:00:00 2001 From: Emmanuel Pelletier Date: Mon, 5 Aug 2024 17:19:09 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(frontend)=20extract=20Toggle?= =?UTF-8?q?Button=20in=20a=20proper=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor the existing Button component to extract a new ToggleButton component that wraps react aria ToggleButton. This will be used to toggle cam/mic on/off, or any other controls in the control bar. --- .../components/controls/ChatToggle.tsx | 7 +- .../Participants/ParticipantsToggle.tsx | 7 +- src/frontend/src/primitives/Button.tsx | 181 ++---------------- src/frontend/src/primitives/ToggleButton.tsx | 25 +++ .../{Tooltip.tsx => TooltipWrapper.tsx} | 35 +++- src/frontend/src/primitives/buttonRecipe.ts | 125 ++++++++++++ src/frontend/src/primitives/index.ts | 1 + 7 files changed, 198 insertions(+), 183 deletions(-) create mode 100644 src/frontend/src/primitives/ToggleButton.tsx rename src/frontend/src/primitives/{Tooltip.tsx => TooltipWrapper.tsx} (77%) create mode 100644 src/frontend/src/primitives/buttonRecipe.ts diff --git a/src/frontend/src/features/rooms/livekit/components/controls/ChatToggle.tsx b/src/frontend/src/features/rooms/livekit/components/controls/ChatToggle.tsx index 9f260643..3b56a141 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/ChatToggle.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/ChatToggle.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'react-i18next' import { RiChat1Line } from '@remixicon/react' -import { Button } from '@/primitives' +import { ToggleButton } from '@/primitives' import { css } from '@/styled-system/css' import { useLayoutContext } from '@livekit/components-react' import { useSnapshot } from 'valtio' @@ -22,8 +22,7 @@ export const ChatToggle = () => { display: 'inline-block', })} > - + {!!state?.unreadMessages && (
{ display: 'inline-block', })} > - +
& +export type ButtonProps = RecipeVariantProps & RACButtonsProps & - Tooltip & { - toggle?: boolean - isSelected?: boolean - } + TooltipWrapperProps -type LinkButtonProps = RecipeVariantProps & LinkProps & Tooltip +type LinkButtonProps = RecipeVariantProps & + LinkProps & + TooltipWrapperProps type ButtonOrLinkProps = ButtonProps | LinkButtonProps @@ -154,22 +23,11 @@ export const Button = ({ tooltipType = 'instant', ...props }: ButtonOrLinkProps) => { - const [variantProps, componentProps] = button.splitVariantProps(props) + const [variantProps, componentProps] = buttonRecipe.splitVariantProps(props) if ((props as LinkButtonProps).href !== undefined) { return ( - - - ) - } - - if ((props as ButtonProps).toggle) { - return ( - - + ) } @@ -177,26 +35,9 @@ export const Button = ({ return ( ) } - -const TooltipWrapper = ({ - tooltip, - tooltipType, - children, -}: { - children: ReactNode -} & Tooltip) => { - return tooltip ? ( - - {children} - {tooltip} - - ) : ( - children - ) -} diff --git a/src/frontend/src/primitives/ToggleButton.tsx b/src/frontend/src/primitives/ToggleButton.tsx new file mode 100644 index 00000000..288a9335 --- /dev/null +++ b/src/frontend/src/primitives/ToggleButton.tsx @@ -0,0 +1,25 @@ +import { + ToggleButton as RACToggleButton, + ToggleButtonProps, +} from 'react-aria-components' +import { type ButtonRecipeProps, buttonRecipe } from './buttonRecipe' +import { TooltipWrapper, TooltipWrapperProps } from './TooltipWrapper' + +/** + * React aria ToggleButton with our button styles, that can take a tooltip if needed + */ +export const ToggleButton = ({ + tooltip, + tooltipType, + ...props +}: ToggleButtonProps & ButtonRecipeProps & TooltipWrapperProps) => { + const [variantProps, componentProps] = buttonRecipe.splitVariantProps(props) + return ( + + + + ) +} diff --git a/src/frontend/src/primitives/Tooltip.tsx b/src/frontend/src/primitives/TooltipWrapper.tsx similarity index 77% rename from src/frontend/src/primitives/Tooltip.tsx rename to src/frontend/src/primitives/TooltipWrapper.tsx index 2faf6d55..b1818926 100644 --- a/src/frontend/src/primitives/Tooltip.tsx +++ b/src/frontend/src/primitives/TooltipWrapper.tsx @@ -2,16 +2,41 @@ import { type ReactNode } from 'react' import { OverlayArrow, Tooltip as RACTooltip, - TooltipProps, + TooltipTrigger, + type TooltipProps, } from 'react-aria-components' import { styled } from '@/styled-system/jsx' +export type TooltipWrapperProps = { + tooltip?: string + tooltipType?: 'instant' | 'delayed' +} + +/** + * Wrap a component you want to apply a tooltip on (for example a Button) + * + * If no tooltip is given, just returns children + */ +export const TooltipWrapper = ({ + tooltip, + tooltipType, + children, +}: { + children: ReactNode +} & TooltipWrapperProps) => { + return tooltip ? ( + + {children} + {tooltip} + + ) : ( + children + ) +} + /** * Styled react aria Tooltip component. * - * Note that tooltips are directly handled by Buttons via the `tooltip` prop, - * so you should not need to use this component directly. - * * Style taken from example at https://react-spectrum.adobe.com/react-aria/Tooltip.html */ const StyledTooltip = styled(RACTooltip, { @@ -80,7 +105,7 @@ const TooltipArrow = () => { ) } -export const Tooltip = ({ +const Tooltip = ({ children, ...props }: Omit & { children: ReactNode }) => { diff --git a/src/frontend/src/primitives/buttonRecipe.ts b/src/frontend/src/primitives/buttonRecipe.ts new file mode 100644 index 00000000..1a590235 --- /dev/null +++ b/src/frontend/src/primitives/buttonRecipe.ts @@ -0,0 +1,125 @@ +import { type RecipeVariantProps, cva } from '@/styled-system/css' + +export type ButtonRecipe = typeof buttonRecipe + +export type ButtonRecipeProps = RecipeVariantProps + +export const buttonRecipe = cva({ + base: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + transition: 'background 200ms, outline 200ms, border-color 200ms', + cursor: 'pointer', + border: '1px solid transparent', + color: 'colorPalette.text', + backgroundColor: 'colorPalette', + '&[data-hovered]': { + backgroundColor: 'colorPalette.hover', + }, + '&[data-pressed]': { + backgroundColor: 'colorPalette.active', + }, + }, + variants: { + size: { + default: { + borderRadius: 8, + paddingX: '1', + paddingY: '0.625', + '--square-padding': '{spacing.0.625}', + }, + sm: { + borderRadius: 4, + paddingX: '0.5', + paddingY: '0.25', + '--square-padding': '{spacing.0.25}', + }, + xs: { + borderRadius: 4, + '--square-padding': '0', + }, + }, + square: { + true: { + paddingX: 'var(--square-padding)', + paddingY: 'var(--square-padding)', + }, + }, + variant: { + default: { + colorPalette: 'control', + }, + primary: { + colorPalette: 'primary', + }, + // @TODO: better handling of colors… this is a mess + success: { + colorPalette: 'success', + borderColor: 'success.300', + color: 'success.subtle-text', + backgroundColor: 'success.subtle', + '&[data-hovered]': { + backgroundColor: 'success.200', + }, + '&[data-pressed]': { + backgroundColor: 'success.subtle!', + }, + }, + }, + outline: { + true: { + color: 'colorPalette', + backgroundColor: 'transparent!', + borderColor: 'currentcolor!', + '&[data-hovered]': { + backgroundColor: 'colorPalette.subtle!', + }, + '&[data-pressed]': { + backgroundColor: 'colorPalette.subtle!', + }, + }, + }, + invisible: { + true: { + borderColor: 'none!', + backgroundColor: 'none!', + '&[data-hovered]': { + backgroundColor: 'none!', + borderColor: 'colorPalette.active!', + }, + '&[data-pressed]': { + borderColor: 'currentcolor', + }, + }, + }, + fullWidth: { + true: { + width: 'full', + }, + }, + legacyStyle: { + true: { + borderColor: 'gray.400', + '&[data-hovered]': { + borderColor: 'gray.500', + }, + '&[data-pressed]': { + borderColor: 'gray.500', + }, + '&[data-selected]': { + background: '#e5e7eb', + borderColor: 'gray.400', + '&[data-hovered]': { + backgroundColor: 'gray.300', + }, + }, + }, + }, + }, + defaultVariants: { + size: 'default', + variant: 'default', + outline: false, + }, +}) diff --git a/src/frontend/src/primitives/index.ts b/src/frontend/src/primitives/index.ts index d7f9c706..16a0ffc0 100644 --- a/src/frontend/src/primitives/index.ts +++ b/src/frontend/src/primitives/index.ts @@ -24,5 +24,6 @@ export { MenuList } from './MenuList' export { P } from './P' export { Popover } from './Popover' export { Text } from './Text' +export { ToggleButton } from './ToggleButton' export { Ul } from './Ul' export { VerticallyOffCenter } from './VerticallyOffCenter'