From 6ebac45f18354baf40e6615b47cd54bc83bb7f03 Mon Sep 17 00:00:00 2001 From: Pavithra Kodmad Date: Wed, 24 Sep 2025 23:08:04 +1000 Subject: [PATCH 01/49] Adapt Button to styled-react and remove sx --- .../src/components/ActionMenu.tsx | 33 +++++++ .../styled-react/src/components/Button.tsx | 92 +++++++++++++++++++ .../src/components/IconButton.tsx | 19 ++++ .../src/components/PageHeader.tsx | 6 +- packages/styled-react/src/index.tsx | 6 +- packages/styled-react/src/sx.ts | 3 + 6 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 packages/styled-react/src/components/ActionMenu.tsx create mode 100644 packages/styled-react/src/components/Button.tsx create mode 100644 packages/styled-react/src/components/IconButton.tsx diff --git a/packages/styled-react/src/components/ActionMenu.tsx b/packages/styled-react/src/components/ActionMenu.tsx new file mode 100644 index 00000000000..df6332dbaa5 --- /dev/null +++ b/packages/styled-react/src/components/ActionMenu.tsx @@ -0,0 +1,33 @@ +import {ActionMenu as PrimerActionMenu} from '@primer/react' +import type {ComponentProps} from 'react' +import {forwardRef} from 'react' +import {Box} from './Box' +import type {SxProp} from '../sx' + +// Derive prop types from the underlying Primer components and augment with SxProp +export type ActionMenuProps = ComponentProps & SxProp +export type ActionMenuButtonProps = ComponentProps & SxProp + +const ActionMenuButton = forwardRef(function ActionMenuButton(props, ref) { + return +}) + +const ActionMenuImpl = (props: ActionMenuProps) => { + return +} + +type ActionMenuComposite = ((props: ActionMenuProps) => JSX.Element) & { + Button: typeof ActionMenuButton + Anchor: typeof PrimerActionMenu.Anchor + Overlay: typeof PrimerActionMenu.Overlay + Divider: typeof PrimerActionMenu.Divider +} + +export const ActionMenu: ActionMenuComposite = Object.assign(ActionMenuImpl, { + Button: ActionMenuButton, + Anchor: PrimerActionMenu.Anchor, + Overlay: PrimerActionMenu.Overlay, + Divider: PrimerActionMenu.Divider, +}) + +export {ActionMenuButton} diff --git a/packages/styled-react/src/components/Button.tsx b/packages/styled-react/src/components/Button.tsx new file mode 100644 index 00000000000..3e40f9cfe65 --- /dev/null +++ b/packages/styled-react/src/components/Button.tsx @@ -0,0 +1,92 @@ +import {Button as PrimerButton, type ButtonProps as PrimerButtonProps} from '@primer/react' +import type {SxProp, CSSCustomProperties} from '../sx' +import type {BetterSystemStyleObject} from '../styled-props' +import {Box} from './Box' + +type ButtonComponentProps = PrimerButtonProps & SxProp +const ButtonComponent = ({sx, ...rest}: ButtonComponentProps) => { + const {block, size = 'medium', leadingVisual, trailingVisual, trailingAction} = rest + let sxStyles: {[key: string]: BetterSystemStyleObject} = {} + const style: CSSCustomProperties = {} + + if (sx !== null && Object.keys(sx || {}).length > 0) { + sxStyles = generateCustomSxProp( + {block, size, leadingVisual, trailingVisual, trailingAction}, + sx as BetterSystemStyleObject, + ) + + // @ts-ignore sx can have color attribute + const {color} = sx + if (color) style['--button-color'] = color + } + + // @ts-expect-error type mismatch between Box usage here and PrimerButton + return +} + +// This function is used to generate a custom cssSelector for the sxProp + +// The usual sx prop can like this: +// sx={{ +// [`@media (max-width: 768px)`]: { +// '& > ul': { +// backgroundColor: 'deeppink', +// }, +// '&:hover': { +// backgroundColor: 'yellow', +// }, +// }, +// '&:hover': { +// backgroundColor: 'yellow', +// }, +// '&': { +// width : 320px +// } +// }} +//* +/* What we want for Button styles is this: +sx={{ +// [`@media (max-width: 768px)`]: { +// '&[data-attribute="something"] > ul': { +// backgroundColor: 'deeppink', +// }, +// '&[data-attribute="something"]:hover': { +// backgroundColor: 'yellow', +// }, +// }, +// '&[data-attribute="something"]:hover': { +// backgroundColor: 'yellow', +// }, +// '&[data-attribute="something"]': { +// width : 320px +// } +// }} + +// We need to make sure we append the customCSSSelector to the original class selector. i.e & - > &[data-attribute="Icon"][data-size="small"] +*/ +export function generateCustomSxProp( + props: Partial>, + providedSx: BetterSystemStyleObject, +) { + // Possible data attributes: data-size, data-block, data-no-visuals + const size = `[data-size="${props.size}"]` + const block = props.block ? `[data-block="block"]` : '' + const noVisuals = props.leadingVisual || props.trailingVisual || props.trailingAction ? '' : '[data-no-visuals]' + + // this is a custom selector. We need to make sure we add the data attributes to the base css class (& -> &[data-attributename="value"]]) + const cssSelector = `&${size}${block}${noVisuals}` // &[data-size="small"][data-block="block"][data-no-visuals] + + const customSxProp: { + [key: string]: BetterSystemStyleObject + } = {} + + if (!providedSx) return customSxProp + else { + customSxProp[cssSelector] = providedSx + return customSxProp + } +} + +ButtonComponent.displayName = 'Button' + +export {ButtonComponent, type ButtonComponentProps} diff --git a/packages/styled-react/src/components/IconButton.tsx b/packages/styled-react/src/components/IconButton.tsx new file mode 100644 index 00000000000..514b4e4d8ac --- /dev/null +++ b/packages/styled-react/src/components/IconButton.tsx @@ -0,0 +1,19 @@ +import { + IconButton as PrimerIconButton, + type IconButtonProps as PrimerIconButtonProps, + sx, + type SxProp, +} from '@primer/react' +import styled from 'styled-components' +import {type ForwardRefComponent} from '../polymorphic' + +type IconButtonProps = PrimerIconButtonProps & SxProp + +const IconButton: ForwardRefComponent<'a' | 'button', IconButtonProps> = styled(PrimerIconButton).withConfig({ + shouldForwardProp: prop => (prop as keyof IconButtonProps) !== 'sx', +})` + ${sx} +` + +export {IconButton} +export type {IconButtonProps} diff --git a/packages/styled-react/src/components/PageHeader.tsx b/packages/styled-react/src/components/PageHeader.tsx index db23410c7c7..e0ee8b3378e 100644 --- a/packages/styled-react/src/components/PageHeader.tsx +++ b/packages/styled-react/src/components/PageHeader.tsx @@ -6,7 +6,7 @@ import { type PageHeaderTitleAreaProps as PrimerPageHeaderTitleAreaProps, } from '@primer/react' import styled from 'styled-components' -import {sx, type SxProp} from '../sx' +import {sx, type SxProp, type CSSCustomProperties} from '../sx' import type {ForwardRefComponent} from '../polymorphic' import {Box} from './Box' import type {PropsWithChildren} from 'react' @@ -39,10 +39,6 @@ function PageHeaderActions({sx, ...rest}: PageHeaderActionsProps) { type PageHeaderTitleProps = PropsWithChildren & SxProp -type CSSCustomProperties = { - [key: `--${string}`]: string | number -} - function PageHeaderTitle({sx, ...rest}: PageHeaderTitleProps) { const style: CSSCustomProperties = {} if (sx) { diff --git a/packages/styled-react/src/index.tsx b/packages/styled-react/src/index.tsx index 8be52072298..eb57200e365 100644 --- a/packages/styled-react/src/index.tsx +++ b/packages/styled-react/src/index.tsx @@ -1,17 +1,14 @@ export {ActionList} from '@primer/react' -export {ActionMenu} from '@primer/react' export {Autocomplete} from '@primer/react' export {Avatar} from '@primer/react' export {Breadcrumbs} from '@primer/react' export {Box, type BoxProps} from './components/Box' -export {Button} from '@primer/react' export {CheckboxGroup} from '@primer/react' export {CircleBadge} from '@primer/react' export {Details} from '@primer/react' export {Dialog} from '@primer/react' export {FormControl} from '@primer/react' export {Heading} from '@primer/react' -export {IconButton} from '@primer/react' export {Label} from '@primer/react' export {Link} from '@primer/react' export {NavList} from '@primer/react' @@ -35,10 +32,13 @@ export {themeGet} from '@primer/react' export {useColorSchemeVar} from '@primer/react' export {useTheme} from '@primer/react' +export {ActionMenu, type ActionMenuProps, type ActionMenuButtonProps} from './components/ActionMenu' +export {ButtonComponent as Button, type ButtonComponentProps as ButtonProps} from './components/Button' export {Checkbox, type CheckboxProps} from './components/Checkbox' export {CounterLabel, type CounterLabelProps} from './components/CounterLabel' export {Flash} from './components/Flash' export {Header, type HeaderProps} from './components/Header' +export {IconButton, type IconButtonProps} from './components/IconButton' export {LinkButton, type LinkButtonProps} from './components/LinkButton' export { PageHeader, diff --git a/packages/styled-react/src/sx.ts b/packages/styled-react/src/sx.ts index e706676100f..6d0ad2d559a 100644 --- a/packages/styled-react/src/sx.ts +++ b/packages/styled-react/src/sx.ts @@ -1 +1,4 @@ export {sx, type SxProp} from '@primer/react' +export type CSSCustomProperties = { + [key: `--${string}`]: string | number +} From 3355375f6110a3b88e68c96e1384e67096661f27 Mon Sep 17 00:00:00 2001 From: Pavithra Kodmad Date: Wed, 24 Sep 2025 23:27:31 +1000 Subject: [PATCH 02/49] Remove sx property from Button --- .changeset/tasty-suns-behave.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/tasty-suns-behave.md diff --git a/.changeset/tasty-suns-behave.md b/.changeset/tasty-suns-behave.md new file mode 100644 index 00000000000..b0b7961fc54 --- /dev/null +++ b/.changeset/tasty-suns-behave.md @@ -0,0 +1,6 @@ + +--- +"@primer/react": major +"@primer/styled-react": patch +--- +Remove sx property from Button From 951d29c8714bb896f54263fbde216dbe523f99a1 Mon Sep 17 00:00:00 2001 From: Pavithra Kodmad Date: Wed, 24 Sep 2025 23:41:38 +1000 Subject: [PATCH 03/49] fix(ActionMenu): remove unused ActionMenuButtonProps export --- packages/styled-react/src/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/styled-react/src/index.tsx b/packages/styled-react/src/index.tsx index eb57200e365..b31218f813e 100644 --- a/packages/styled-react/src/index.tsx +++ b/packages/styled-react/src/index.tsx @@ -32,7 +32,7 @@ export {themeGet} from '@primer/react' export {useColorSchemeVar} from '@primer/react' export {useTheme} from '@primer/react' -export {ActionMenu, type ActionMenuProps, type ActionMenuButtonProps} from './components/ActionMenu' +export {ActionMenu, type ActionMenuProps} from './components/ActionMenu' export {ButtonComponent as Button, type ButtonComponentProps as ButtonProps} from './components/Button' export {Checkbox, type CheckboxProps} from './components/Checkbox' export {CounterLabel, type CounterLabelProps} from './components/CounterLabel' From 84ee2d95fd67664328358979a7489c51dcb03085 Mon Sep 17 00:00:00 2001 From: Pavithra Kodmad Date: Wed, 24 Sep 2025 23:41:58 +1000 Subject: [PATCH 04/49] refactor(ActionMenu): streamline ActionMenuOverlay and improve prop typing --- packages/styled-react/src/components/ActionMenu.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/styled-react/src/components/ActionMenu.tsx b/packages/styled-react/src/components/ActionMenu.tsx index df6332dbaa5..cf1f377c27d 100644 --- a/packages/styled-react/src/components/ActionMenu.tsx +++ b/packages/styled-react/src/components/ActionMenu.tsx @@ -7,27 +7,26 @@ import type {SxProp} from '../sx' // Derive prop types from the underlying Primer components and augment with SxProp export type ActionMenuProps = ComponentProps & SxProp export type ActionMenuButtonProps = ComponentProps & SxProp +export type ActionMenuOverlayProps = ComponentProps & SxProp const ActionMenuButton = forwardRef(function ActionMenuButton(props, ref) { return }) -const ActionMenuImpl = (props: ActionMenuProps) => { - return -} +const ActionMenuImpl = (props: ActionMenuProps) => + +const ActionMenuOverlay = (props: ActionMenuOverlayProps) => type ActionMenuComposite = ((props: ActionMenuProps) => JSX.Element) & { Button: typeof ActionMenuButton Anchor: typeof PrimerActionMenu.Anchor - Overlay: typeof PrimerActionMenu.Overlay + Overlay: typeof ActionMenuOverlay Divider: typeof PrimerActionMenu.Divider } export const ActionMenu: ActionMenuComposite = Object.assign(ActionMenuImpl, { Button: ActionMenuButton, Anchor: PrimerActionMenu.Anchor, - Overlay: PrimerActionMenu.Overlay, + Overlay: ActionMenuOverlay, Divider: PrimerActionMenu.Divider, }) - -export {ActionMenuButton} From 1803ebc6569030f0f7a8591806f8ec7472ad9ab2 Mon Sep 17 00:00:00 2001 From: Pavithra Kodmad Date: Thu, 25 Sep 2025 09:51:12 +1000 Subject: [PATCH 05/49] Remove sx from Button components --- .../react/src/Button/Button.dev.stories.tsx | 53 +-- packages/react/src/Button/Button.tsx | 83 +--- packages/react/src/Button/ButtonBase.tsx | 427 ++++++------------ packages/react/src/Button/IconButton.tsx | 13 - packages/react/src/Button/types.ts | 12 +- .../__tests__/primer-react.browser.test.tsx | 2 +- .../src/components/ActionMenu.tsx | 6 +- 7 files changed, 168 insertions(+), 428 deletions(-) diff --git a/packages/react/src/Button/Button.dev.stories.tsx b/packages/react/src/Button/Button.dev.stories.tsx index 977b86a74f5..29ee5687031 100644 --- a/packages/react/src/Button/Button.dev.stories.tsx +++ b/packages/react/src/Button/Button.dev.stories.tsx @@ -1,5 +1,6 @@ import {SearchIcon, TriangleDownIcon, EyeIcon, IssueClosedIcon, HeartFillIcon} from '@primer/octicons-react' import {Button, IconButton} from '.' +import classes from './Button.dev.stories.module.css' import {default as Text} from '../Text' import {Stack} from '../Stack' @@ -32,63 +33,29 @@ export const InvisibleVariants = () => { ) } -export const TestSxProp = () => { +export const TestClassProp = () => { const count = 4 return (
- - - - - - -
diff --git a/packages/react/src/Button/Button.tsx b/packages/react/src/Button/Button.tsx index fddc8f84aab..72a68b80d3a 100644 --- a/packages/react/src/Button/Button.tsx +++ b/packages/react/src/Button/Button.tsx @@ -2,92 +2,15 @@ import {forwardRef} from 'react' import type {ButtonProps} from './types' import {ButtonBase} from './ButtonBase' import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic' -import {defaultSxProp} from '../utils/defaultSxProp' -import type {BetterSystemStyleObject, CSSCustomProperties} from '../sx' - -const ButtonComponent = forwardRef(({children, sx: sxProp = defaultSxProp, ...props}, forwardedRef): JSX.Element => { - const {block, size = 'medium', leadingVisual, trailingVisual, trailingAction} = props - let sxStyles = sxProp - const style: CSSCustomProperties = {} - - if (sxProp !== null && Object.keys(sxProp).length > 0) { - sxStyles = generateCustomSxProp({block, size, leadingVisual, trailingVisual, trailingAction}, sxProp) - - // @ts-ignore sxProp can have color attribute - const {color} = sxProp - if (color) style['--button-color'] = color - } +const ButtonComponent = forwardRef(({children, ...props}, forwardedRef): JSX.Element => { return ( - + {children} ) }) as PolymorphicForwardRefComponent<'button', ButtonProps> -// This function is used to generate a custom cssSelector for the sxProp - -// The usual sx prop can like this: -// sx={{ -// [`@media (max-width: 768px)`]: { -// '& > ul': { -// backgroundColor: 'deeppink', -// }, -// '&:hover': { -// backgroundColor: 'yellow', -// }, -// }, -// '&:hover': { -// backgroundColor: 'yellow', -// }, -// '&': { -// width : 320px -// } -// }} -//* -/* What we want for Button styles is this: -sx={{ -// [`@media (max-width: 768px)`]: { -// '&[data-attribute="something"] > ul': { -// backgroundColor: 'deeppink', -// }, -// '&[data-attribute="something"]:hover': { -// backgroundColor: 'yellow', -// }, -// }, -// '&[data-attribute="something"]:hover': { -// backgroundColor: 'yellow', -// }, -// '&[data-attribute="something"]': { -// width : 320px -// } -// }} - -// We need to make sure we append the customCSSSelector to the original class selector. i.e & - > &[data-attribute="Icon"][data-size="small"] -*/ -export function generateCustomSxProp( - props: Partial>, - providedSx: BetterSystemStyleObject, -) { - // Possible data attributes: data-size, data-block, data-no-visuals - const size = `[data-size="${props.size}"]` - const block = props.block ? `[data-block="block"]` : '' - const noVisuals = props.leadingVisual || props.trailingVisual || props.trailingAction ? '' : '[data-no-visuals]' - - // this is a custom selector. We need to make sure we add the data attributes to the base css class (& -> &[data-attributename="value"]]) - const cssSelector = `&${size}${block}${noVisuals}` // &[data-size="small"][data-block="block"][data-no-visuals] - - const customSxProp: { - [key: string]: BetterSystemStyleObject - } = {} - - if (!providedSx) return customSxProp - else { - customSxProp[cssSelector] = providedSx - return customSxProp - } -} - ButtonComponent.displayName = 'Button' -export {ButtonComponent} +export {ButtonComponent, type ButtonProps} diff --git a/packages/react/src/Button/ButtonBase.tsx b/packages/react/src/Button/ButtonBase.tsx index e60b9b9460d..62575d8bb8e 100644 --- a/packages/react/src/Button/ButtonBase.tsx +++ b/packages/react/src/Button/ButtonBase.tsx @@ -1,10 +1,7 @@ import React, {forwardRef} from 'react' import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic' -import Box from '../Box' import type {ButtonProps} from './types' -import {getAlignContentSize} from './styles' import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef' -import {defaultSxProp} from '../utils/defaultSxProp' import {VisuallyHidden} from '../VisuallyHidden' import Spinner from '../Spinner' import CounterLabel from '../CounterLabel' @@ -29,295 +26,169 @@ const renderModuleVisual = ( ) -const ButtonBase = forwardRef( - ({children, as: Component = 'button', sx: sxProp = defaultSxProp, ...props}, forwardedRef): JSX.Element => { - const { - leadingVisual: LeadingVisual, - trailingVisual: TrailingVisual, - trailingAction: TrailingAction, - ['aria-describedby']: ariaDescribedBy, - ['aria-labelledby']: ariaLabelledBy, - count, - icon: Icon, - id, - variant = 'default', - size = 'medium', - alignContent = 'center', - block = false, - loading, - loadingAnnouncement = 'Loading', - inactive, - onClick, - labelWrap, - className, - ...rest - } = props +const ButtonBase = forwardRef(({children, as: Component = 'button', ...props}, forwardedRef): JSX.Element => { + const { + leadingVisual: LeadingVisual, + trailingVisual: TrailingVisual, + trailingAction: TrailingAction, + ['aria-describedby']: ariaDescribedBy, + ['aria-labelledby']: ariaLabelledBy, + count, + icon: Icon, + id, + variant = 'default', + size = 'medium', + alignContent = 'center', + block = false, + loading, + loadingAnnouncement = 'Loading', + inactive, + onClick, + labelWrap, + className, + ...rest + } = props - const innerRef = React.useRef(null) - useRefObjectAsForwardedRef(forwardedRef, innerRef) + const innerRef = React.useRef(null) + useRefObjectAsForwardedRef(forwardedRef, innerRef) - const uuid = useId(id) - const loadingAnnouncementID = `${uuid}-loading-announcement` + const uuid = useId(id) + const loadingAnnouncementID = `${uuid}-loading-announcement` - if (__DEV__) { - /** - * The Linter yells because it thinks this conditionally calls an effect, - * but since this is a compile-time flag and not a runtime conditional - * this is safe, and ensures the entire effect is kept out of prod builds - * shaving precious bytes from the output, and avoiding mounting a noop effect - */ - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/rules-of-hooks - React.useEffect(() => { - if ( - innerRef.current && - !(innerRef.current instanceof HTMLButtonElement) && - !((innerRef.current as unknown) instanceof HTMLAnchorElement) && - !((innerRef.current as HTMLElement).tagName === 'SUMMARY') - ) { - // eslint-disable-next-line no-console - console.warn('This component should be an instanceof a semantic button or anchor') - } - }, [innerRef]) - } + if (__DEV__) { + /** + * The Linter yells because it thinks this conditionally calls an effect, + * but since this is a compile-time flag and not a runtime conditional + * this is safe, and ensures the entire effect is kept out of prod builds + * shaving precious bytes from the output, and avoiding mounting a noop effect + */ + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/rules-of-hooks + React.useEffect(() => { + if ( + innerRef.current && + !(innerRef.current instanceof HTMLButtonElement) && + !((innerRef.current as unknown) instanceof HTMLAnchorElement) && + !((innerRef.current as HTMLElement).tagName === 'SUMMARY') + ) { + // eslint-disable-next-line no-console + console.warn('This component should be an instanceof a semantic button or anchor') + } + }, [innerRef]) + } - if (sxProp !== defaultSxProp) { - return ( - - Boolean(descriptionID)) - .join(' ')} - // aria-labelledby is needed because the accessible name becomes unset when the button is in a loading state. - // We only set it when the button is in a loading state because it will supersede the aria-label when the screen - // reader announces the button name. - aria-labelledby={ - loading ? [`${uuid}-label`, ariaLabelledBy].filter(labelID => Boolean(labelID)).join(' ') : ariaLabelledBy - } - id={id} - onClick={loading ? undefined : onClick} - > - {Icon ? ( - loading ? ( - - ) : isElement(Icon) ? ( - Icon - ) : ( - - ) - ) : ( - <> - - { - /* If there are no leading/trailing visuals/actions to replace with a loading spinner, - render a loading spiner in place of the button content. */ - loading && - !LeadingVisual && - !TrailingVisual && - !TrailingAction && - count === undefined && - renderModuleVisual(Spinner, loading, 'loadingSpinner', false) - } - { - /* Render a leading visual unless the button is in a loading state. - Then replace the leading visual with a loading spinner. */ - LeadingVisual && renderModuleVisual(LeadingVisual, Boolean(loading), 'leadingVisual', false) - } - {children && ( - - {children} - - )} - { - /* If there is a count, render a counter label unless there is a trailing visual. - Then render the counter label as a trailing visual. - Replace the counter label or the trailing visual with a loading spinner if: - - the button is in a loading state - - there is no leading visual to replace with a loading spinner - */ - count !== undefined && !TrailingVisual - ? renderModuleVisual( - () => ( - - {count} - - ), - Boolean(loading) && !LeadingVisual, - 'trailingVisual', - true, - ) - : TrailingVisual - ? renderModuleVisual( - TrailingVisual, - Boolean(loading) && !LeadingVisual, - 'trailingVisual', - false, - ) - : null - } - - { - /* If there is a trailing action, render it unless the button is in a loading state - and there is no leading or trailing visual to replace with a loading spinner. */ - TrailingAction && - renderModuleVisual( - TrailingAction, - Boolean(loading) && !LeadingVisual && !TrailingVisual, - 'trailingAction', - false, - ) - } - - )} - - {loading && ( - - {loadingAnnouncement} - - )} - - ) - } - return ( - + Boolean(descriptionID)) + .join(' ')} + // aria-labelledby is needed because the accessible name becomes unset when the button is in a loading state. + // We only set it when the button is in a loading state because it will supersede the aria-label when the screen + // reader announces the button name. + aria-labelledby={ + loading ? [`${uuid}-label`, ariaLabelledBy].filter(labelID => Boolean(labelID)).join(' ') : ariaLabelledBy + } + id={id} + // @ts-ignore temporary disable as we migrate to css modules, until we remove PolymorphicForwardRefComponent + onClick={loading ? undefined : onClick} > - Boolean(descriptionID)) - .join(' ')} - // aria-labelledby is needed because the accessible name becomes unset when the button is in a loading state. - // We only set it when the button is in a loading state because it will supersede the aria-label when the screen - // reader announces the button name. - aria-labelledby={ - loading ? [`${uuid}-label`, ariaLabelledBy].filter(labelID => Boolean(labelID)).join(' ') : ariaLabelledBy - } - id={id} - // @ts-ignore temporary disable as we migrate to css modules, until we remove PolymorphicForwardRefComponent - onClick={loading ? undefined : onClick} - > - {Icon ? ( - loading ? ( - - ) : isElement(Icon) ? ( - Icon - ) : ( - - ) + {Icon ? ( + loading ? ( + + ) : isElement(Icon) ? ( + Icon ) : ( - <> - - { - /* If there are no leading/trailing visuals/actions to replace with a loading spinner, + + ) + ) : ( + <> + + { + /* If there are no leading/trailing visuals/actions to replace with a loading spinner, render a loading spiner in place of the button content. */ - loading && - !LeadingVisual && - !TrailingVisual && - !TrailingAction && - count === undefined && - renderModuleVisual(Spinner, loading, 'loadingSpinner', false) - } - { - /* Render a leading visual unless the button is in a loading state. + loading && + !LeadingVisual && + !TrailingVisual && + !TrailingAction && + count === undefined && + renderModuleVisual(Spinner, loading, 'loadingSpinner', false) + } + { + /* Render a leading visual unless the button is in a loading state. Then replace the leading visual with a loading spinner. */ - LeadingVisual && renderModuleVisual(LeadingVisual, Boolean(loading), 'leadingVisual', false) - } - {children && ( - - {children} - - )} - { - /* If there is a count, render a counter label unless there is a trailing visual. + LeadingVisual && renderModuleVisual(LeadingVisual, Boolean(loading), 'leadingVisual', false) + } + {children && ( + + {children} + + )} + { + /* If there is a count, render a counter label unless there is a trailing visual. Then render the counter label as a trailing visual. Replace the counter label or the trailing visual with a loading spinner if: - the button is in a loading state - there is no leading visual to replace with a loading spinner */ - count !== undefined && !TrailingVisual - ? renderModuleVisual( - () => ( - - {count} - - ), - Boolean(loading) && !LeadingVisual, - 'trailingVisual', - true, - ) - : TrailingVisual - ? renderModuleVisual(TrailingVisual, Boolean(loading) && !LeadingVisual, 'trailingVisual', false) - : null - } - - { - /* If there is a trailing action, render it unless the button is in a loading state - and there is no leading or trailing visual to replace with a loading spinner. */ - TrailingAction && - renderModuleVisual( - TrailingAction, - Boolean(loading) && !LeadingVisual && !TrailingVisual, - 'trailingAction', - false, - ) + count !== undefined && !TrailingVisual + ? renderModuleVisual( + () => ( + + {count} + + ), + Boolean(loading) && !LeadingVisual, + 'trailingVisual', + true, + ) + : TrailingVisual + ? renderModuleVisual(TrailingVisual, Boolean(loading) && !LeadingVisual, 'trailingVisual', false) + : null } - - )} - - {loading && ( - - {loadingAnnouncement} - + + { + /* If there is a trailing action, render it unless the button is in a loading state + and there is no leading or trailing visual to replace with a loading spinner. */ + TrailingAction && + renderModuleVisual( + TrailingAction, + Boolean(loading) && !LeadingVisual && !TrailingVisual, + 'trailingAction', + false, + ) + } + )} - - ) - }, -) as PolymorphicForwardRefComponent<'button' | 'a', ButtonProps> + + {loading && ( + + {loadingAnnouncement} + + )} + + ) +}) as PolymorphicForwardRefComponent<'button' | 'a', ButtonProps> export {ButtonBase} diff --git a/packages/react/src/Button/IconButton.tsx b/packages/react/src/Button/IconButton.tsx index 4b86ea1bd48..7c439047429 100644 --- a/packages/react/src/Button/IconButton.tsx +++ b/packages/react/src/Button/IconButton.tsx @@ -2,8 +2,6 @@ import React, {forwardRef} from 'react' import type {IconButtonProps} from './types' import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic' import {ButtonBase} from './ButtonBase' -import {defaultSxProp} from '../utils/defaultSxProp' -import {generateCustomSxProp} from './Button' import {TooltipContext, Tooltip} from '../TooltipV2/Tooltip' import {TooltipContext as TooltipContextV1} from '../Tooltip/Tooltip' import classes from './ButtonBase.module.css' @@ -12,7 +10,6 @@ import {clsx} from 'clsx' const IconButton = forwardRef( ( { - sx: sxProp = defaultSxProp, icon: Icon, 'aria-label': ariaLabel, description, @@ -27,14 +24,6 @@ const IconButton = forwardRef( }, forwardedRef, ): JSX.Element => { - let sxStyles = sxProp - // grap the button props that have associated data attributes in the styles - const {size = 'medium'} = props - - if (sxProp !== null && Object.keys(sxProp).length > 0) { - sxStyles = generateCustomSxProp({size}, sxProp) - } - // If the icon button is already wrapped in a tooltip, do not add one. const {tooltipId} = React.useContext(TooltipContext) // Tooltip v2 const {tooltipId: tooltipIdV1} = React.useContext(TooltipContextV1) // Tooltip v1 @@ -49,7 +38,6 @@ const IconButton = forwardRef( icon={Icon} className={clsx(className, classes.IconButton)} data-component="IconButton" - sx={sxStyles} type="button" aria-label={ariaLabel} disabled={disabled} @@ -72,7 +60,6 @@ const IconButton = forwardRef( icon={Icon} className={clsx(className, classes.IconButton)} data-component="IconButton" - sx={sxStyles} type="button" aria-keyshortcuts={keyshortcuts ?? undefined} // If description is provided, we will use the tooltip to describe the button, so we need to keep the aria-label to label the button. diff --git a/packages/react/src/Button/types.ts b/packages/react/src/Button/types.ts index cc9c183bacb..1394f10962a 100644 --- a/packages/react/src/Button/types.ts +++ b/packages/react/src/Button/types.ts @@ -1,16 +1,7 @@ import type React from 'react' -import styled from 'styled-components' -import type {SxProp} from '../sx' -import sx from '../sx' -import getGlobalFocusStyles from '../internal/utils/getGlobalFocusStyles' import type {TooltipDirection} from '../TooltipV2' import type {IconProps} from '@primer/octicons-react' -export const StyledButton = styled.button` - ${getGlobalFocusStyles('-2px')}; - ${sx}; -` - export type VariantType = 'default' | 'primary' | 'invisible' | 'danger' | 'link' export type Size = 'small' | 'medium' | 'large' @@ -56,8 +47,7 @@ export type ButtonBaseProps = { * Whether the button label should wrap to multiple lines if it is longer than the button width */ labelWrap?: boolean -} & SxProp & - React.ButtonHTMLAttributes +} & React.ButtonHTMLAttributes export type ButtonProps = { /** diff --git a/packages/styled-react/src/__tests__/primer-react.browser.test.tsx b/packages/styled-react/src/__tests__/primer-react.browser.test.tsx index 89eeeb65764..523717957c7 100644 --- a/packages/styled-react/src/__tests__/primer-react.browser.test.tsx +++ b/packages/styled-react/src/__tests__/primer-react.browser.test.tsx @@ -63,7 +63,7 @@ describe('@primer/react', () => { test - test + test overlay , diff --git a/packages/styled-react/src/components/ActionMenu.tsx b/packages/styled-react/src/components/ActionMenu.tsx index cf1f377c27d..9ec8d59e4f7 100644 --- a/packages/styled-react/src/components/ActionMenu.tsx +++ b/packages/styled-react/src/components/ActionMenu.tsx @@ -9,13 +9,15 @@ export type ActionMenuProps = ComponentProps & SxProp export type ActionMenuButtonProps = ComponentProps & SxProp export type ActionMenuOverlayProps = ComponentProps & SxProp -const ActionMenuButton = forwardRef(function ActionMenuButton(props, ref) { +const ActionMenuButton = forwardRef((props, ref) => { return }) const ActionMenuImpl = (props: ActionMenuProps) => -const ActionMenuOverlay = (props: ActionMenuOverlayProps) => +const ActionMenuOverlay = (props: ActionMenuOverlayProps) => { + return +} type ActionMenuComposite = ((props: ActionMenuProps) => JSX.Element) & { Button: typeof ActionMenuButton From ee422b9e8b2ee9474fb84eaf25260bef55e7b13c Mon Sep 17 00:00:00 2001 From: Pavithra Kodmad Date: Thu, 25 Sep 2025 10:14:26 +1000 Subject: [PATCH 06/49] Move button styles in UnderlineNav --- .../src/UnderlineNav/UnderlineNav.module.css | 16 ++++++++++++++++ packages/react/src/UnderlineNav/UnderlineNav.tsx | 4 ++-- packages/react/src/UnderlineNav/styles.ts | 14 -------------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/react/src/UnderlineNav/UnderlineNav.module.css b/packages/react/src/UnderlineNav/UnderlineNav.module.css index b016174571a..6e9aa5ea1c7 100644 --- a/packages/react/src/UnderlineNav/UnderlineNav.module.css +++ b/packages/react/src/UnderlineNav/UnderlineNav.module.css @@ -3,3 +3,19 @@ align-items: center; justify-content: space-between; } + +/* More button styles migrated from styles.ts (was moreBtnStyles) */ +.MoreButton { + margin: 0; /* reset Safari extra margin */ + border: 0; + background: transparent; + font-weight: normal; + box-shadow: none; + padding-top: var(--base-size-4, 4px); + padding-bottom: var(--base-size-4, 4px); + padding-left: var(--base-size-8, 8px); + padding-right: var(--base-size-8, 8px); + & > span[data-component='trailingVisual'] { + margin-left: 0; + } +} diff --git a/packages/react/src/UnderlineNav/UnderlineNav.tsx b/packages/react/src/UnderlineNav/UnderlineNav.tsx index 989395eca2c..57614e7184b 100644 --- a/packages/react/src/UnderlineNav/UnderlineNav.tsx +++ b/packages/react/src/UnderlineNav/UnderlineNav.tsx @@ -6,7 +6,7 @@ import {useResizeObserver} from '../hooks/useResizeObserver' import {useTheme} from '../ThemeProvider' import type {ChildWidthArray, ResponsiveProps, ChildSize} from './types' import VisuallyHidden from '../_VisuallyHidden' -import {moreBtnStyles, getDividerStyle, menuStyles, menuItemStyles, baseMenuStyles, baseMenuMinWidth} from './styles' +import {getDividerStyle, menuStyles, menuItemStyles, baseMenuStyles, baseMenuMinWidth} from './styles' import {UnderlineItemList, UnderlineWrapper, LoadingCounter, GAP} from '../internal/components/UnderlineTabbedInterface' import styled from 'styled-components' import {Button} from '../Button' @@ -314,7 +314,7 @@ export const UnderlineNav = forwardRef( {!onlyMenuVisible &&
} - - - - - - - - ) -} - export const DisabledButtonVariants = () => { return ( From 86e24cb70af35e4b33301f5c0371e21f2c087b91 Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 11:52:00 -0400 Subject: [PATCH 17/49] remove unused file --- packages/react/src/Button/styles.ts | 423 ---------------------------- 1 file changed, 423 deletions(-) delete mode 100644 packages/react/src/Button/styles.ts diff --git a/packages/react/src/Button/styles.ts b/packages/react/src/Button/styles.ts deleted file mode 100644 index dafe8a8050a..00000000000 --- a/packages/react/src/Button/styles.ts +++ /dev/null @@ -1,423 +0,0 @@ -import type {VariantType, AlignContent} from './types' -import type {Theme} from '../ThemeProvider' - -export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme) => { - const style = { - default: { - color: 'btn.text', - backgroundColor: 'btn.bg', - boxShadow: `${theme?.shadows.btn.shadow}, ${theme?.shadows.btn.insetShadow}`, - '&:hover:not([disabled]):not([data-inactive])': { - backgroundColor: 'btn.hoverBg', - borderColor: `var(--button-default-borderColor-hover, ${theme?.colors.btn.hoverBorder})`, - }, - '&:active:not([disabled]):not([data-inactive])': { - backgroundColor: 'btn.activeBg', - borderColor: `var(--button-default-borderColor-active, ${theme?.colors.btn.activeBorder})`, - }, - '&:disabled': { - color: 'primer.fg.disabled', - borderColor: `var(--button-default-borderColor-disabled, ${theme?.colors.btn.border})`, - backgroundColor: `var(--button-default-bgColor-disabled, ${theme?.colors.input.disabledBg})`, - '[data-component=ButtonCounter]': { - color: 'inherit', - }, - }, - '&[aria-expanded=true]': { - backgroundColor: 'btn.activeBg', - borderColor: `var(--button-default-borderColor-active, ${theme?.colors.btn.activeBorder})`, - }, - '[data-component="leadingVisual"], [data-component="trailingVisual"], [data-component="trailingAction"]': { - color: `var(--button-color, ${theme?.colors.fg.muted})`, - }, - '[data-component=ButtonCounter]': { - backgroundColor: 'btn.counterBg', - }, - '&[data-component="IconButton"][data-no-visuals]:not(:disabled)': { - color: 'fg.muted', - }, - }, - primary: { - color: 'btn.primary.text', - backgroundColor: 'btn.primary.bg', - borderColor: 'btn.primary.border', - boxShadow: `${theme?.shadows.btn.primary.shadow}`, - '&:hover:not([disabled]):not([data-inactive])': { - color: 'btn.primary.hoverText', - backgroundColor: 'btn.primary.hoverBg', - }, - '&:focus:not([disabled])': { - boxShadow: 'inset 0 0 0 3px', - }, - '&:focus-visible:not([disabled])': { - boxShadow: 'inset 0 0 0 3px', - }, - '&:active:not([disabled]):not([data-inactive])': { - backgroundColor: 'btn.primary.selectedBg', - boxShadow: `${theme?.shadows.btn.primary.selectedShadow}`, - }, - '&:disabled': { - color: 'btn.primary.disabledText', - backgroundColor: 'btn.primary.disabledBg', - borderColor: 'btn.primary.disabledBorder', - '[data-component=ButtonCounter]': { - color: 'inherit', - }, - }, - '[data-component=ButtonCounter]': { - backgroundColor: 'btn.primary.counterBg', - color: 'btn.primary.text', - }, - '&[aria-expanded=true]': { - backgroundColor: 'btn.primary.selectedBg', - boxShadow: `${theme?.shadows.btn.primary.selectedShadow}`, - }, - }, - danger: { - color: 'btn.danger.text', - backgroundColor: 'btn.bg', - boxShadow: `${theme?.shadows.btn.shadow}`, - '&:hover:not([disabled]):not([data-inactive])': { - color: 'btn.danger.hoverText', - backgroundColor: 'btn.danger.hoverBg', - borderColor: 'btn.danger.hoverBorder', - boxShadow: `${theme?.shadows.btn.danger.hoverShadow}`, - '[data-component=ButtonCounter]': { - backgroundColor: 'btn.danger.hoverCounterBg', - color: 'btn.danger.hoverCounterFg', - }, - }, - '&:active:not([disabled]):not([data-inactive])': { - color: 'btn.danger.selectedText', - backgroundColor: 'btn.danger.selectedBg', - boxShadow: `${theme?.shadows.btn.danger.selectedShadow}`, - borderColor: 'btn.danger.selectedBorder', - }, - '&:disabled': { - color: 'btn.danger.disabledText', - backgroundColor: 'btn.danger.disabledBg', - borderColor: `var(--button-default-borderColor-disabled, ${theme?.colors.btn.border})`, - '[data-component=ButtonCounter]': { - color: 'btn.danger.disabledCounterFg', - backgroundColor: 'btn.danger.disabledCounterBg', - }, - }, - '[data-component=ButtonCounter]': { - color: 'btn.danger.counterFg', - backgroundColor: 'btn.danger.counterBg', - }, - '&[aria-expanded=true]': { - color: 'btn.danger.selectedText', - backgroundColor: 'btn.danger.selectedBg', - boxShadow: `${theme?.shadows.btn.danger.selectedShadow}`, - borderColor: 'btn.danger.selectedBorder', - }, - }, - invisible: { - color: `var(--button-invisible-fgColor-rest, ${theme?.colors.btn.text})`, - backgroundColor: 'transparent', - borderColor: 'transparent', - boxShadow: 'none', - '&:hover:not([disabled])': { - backgroundColor: 'actionListItem.default.hoverBg', - }, - '&:active:not([disabled])': { - backgroundColor: 'actionListItem.default.activeBg', - }, - '&:disabled': { - color: 'primer.fg.disabled', - backgroundColor: `var(--button-invisible-bgColor-disabled, transparent)`, - '[data-component=ButtonCounter], [data-component="leadingVisual"], [data-component="trailingAction"]': { - color: 'inherit', - }, - }, - '&[aria-expanded=true]': { - backgroundColor: 'actionListItem.default.selectedBg', - }, - '&[data-component="IconButton"][data-no-visuals]': { - color: `var(--button-invisible-iconColor-rest, ${theme?.colors.fg.muted})`, - }, - '[data-component="trailingAction"]': { - color: `var(--button-invisible-iconColor-rest, ${theme?.colors.fg.muted})`, - }, - '[data-component="leadingVisual"]': { - color: `var(--button-invisible-iconColor-rest, ${theme?.colors.fg.muted})`, - }, - '[data-component="trailingVisual"]': { - color: `var(--button-invisible-iconColor-rest, ${theme?.colors.fg.muted})`, - }, - '&[data-no-visuals]': { - color: `var(--button-invisible-fgColor-rest, ${theme?.colors.btn.text})`, - }, - '&:has([data-component="ButtonCounter"])': { - color: `var(--button-invisible-fgColor-rest, ${theme?.colors.btn.text})`, - }, - '&:disabled[data-no-visuals]': { - color: 'primer.fg.disabled', - '[data-component=ButtonCounter]': { - color: 'inherit', - }, - }, - }, - outline: { - color: 'btn.outline.text', - boxShadow: `${theme?.shadows.btn.shadow}`, - borderColor: `var(--button-default-borderColor-rest, ${theme?.colors.btn.border})`, - backgroundColor: 'btn.bg', - - '&:hover:not([disabled]):not([data-inactive])': { - color: 'btn.outline.hoverText', - backgroundColor: 'btn.outline.hoverBg', - borderColor: `${theme?.colors.btn.outline.hoverBorder}`, - boxShadow: `${theme?.shadows.btn.outline.hoverShadow}`, - '[data-component=ButtonCounter]': { - backgroundColor: 'btn.outline.hoverCounterBg', - color: 'btn.outline.hoverCounterFg', - }, - }, - '&:active:not([disabled]):not([data-inactive])': { - color: 'btn.outline.selectedText', - backgroundColor: 'btn.outline.selectedBg', - boxShadow: `${theme?.shadows.btn.outline.selectedShadow}`, - borderColor: `${theme?.colors.btn.outline.selectedBorder}`, - }, - - '&:disabled': { - color: 'btn.outline.disabledText', - backgroundColor: 'btn.outline.disabledBg', - borderColor: 'btn.border', - '[data-component=ButtonCounter]': { - backgroundColor: 'btn.outline.disabledCounterBg', - color: 'btn.outline.disabledCounterFg', - }, - }, - '[data-component=ButtonCounter]': { - backgroundColor: 'btn.outline.counterBg', - color: 'btn.outline.counterFg', - }, - '&[aria-expanded=true]': { - color: 'btn.outline.selectedText', - backgroundColor: 'btn.outline.selectedBg', - boxShadow: `${theme?.shadows.btn.outline.selectedShadow}`, - borderColor: `var(--button-default-borderColor-active, ${theme?.colors.btn.outline.selectedBorder})`, - }, - }, - link: { - color: 'var(--fgColor-link)', - display: 'inline-block', - fontSize: 'inherit', - border: 'none', - height: 'unset', - padding: '0', - minWidth: 'fit-content', - backgroundColor: 'transparent', - - '&:hover:not([disabled]):not([data-inactive])': { - textDecoration: 'underline', - }, - - '&:focus-visible:not([disabled])': { - outlineOffset: '2px', - }, - - '&:disabled': { - color: 'primer.fg.disabled', - '[data-component=ButtonCounter], [data-component="leadingVisual"], [data-component="trailingAction"]': { - color: 'inherit', - }, - }, - - '[data-component="text"]': { - whiteSpace: 'unset', - }, - }, - } - - return style[variant] -} - -export const getBaseStyles = (theme?: Theme) => ({ - borderRadius: '2', - border: '1px solid', - borderColor: `var(--button-default-borderColor-rest, ${theme?.colors.btn.border})`, - fontFamily: 'inherit', - fontWeight: 'semibold', - fontSize: '1', - cursor: 'pointer', - appearance: 'none', - userSelect: 'none', - textDecoration: 'none', - textAlign: 'center', - display: 'flex', - alignItems: 'center', - justifyContent: 'space-between', - height: '32px', - padding: '0 12px', - gap: '8px', - minWidth: 'max-content', - transition: '80ms cubic-bezier(0.65, 0, 0.35, 1)', - transitionProperty: 'color, fill, background-color, border-color', - '&[href]': { - display: 'inline-flex', - '&:hover': { - textDecoration: 'none', - }, - }, - '&:hover': { - transitionDuration: '80ms', - }, - '&:active': { - transition: 'none', - }, - '&[data-inactive]': { - cursor: 'auto', - }, - '&:disabled': { - cursor: 'not-allowed', - boxShadow: 'none', - }, - '@media (forced-colors: active)': { - '&:focus': { - // Support for Windows high contrast https://sarahmhigley.com/writing/whcm-quick-tips - outline: 'solid 1px transparent', - }, - }, - '[data-component=ButtonCounter]': { - fontSize: '0', - }, - '&[data-component=IconButton]': { - display: 'inline-grid', - padding: 'unset', - placeContent: 'center', - width: '32px', - minWidth: 'unset', - }, - '&[data-size="small"]': { - padding: '0 8px', - height: '28px', - gap: '4px', - fontSize: '0', - - '[data-component="text"]': { - lineHeight: '1.6666667', - }, - - '[data-component=ButtonCounter]': { - fontSize: '0', - }, - - '[data-component="buttonContent"] > :not(:last-child)': { - mr: '4px', - }, - - '&[data-component=IconButton]': { - width: '28px', - padding: 'unset', - }, - }, - '&[data-size="large"]': { - padding: '0 16px', - height: '40px', - gap: '8px', - - '[data-component="buttonContent"] > :not(:last-child)': { - mr: '8px', - }, - - '&[data-component=IconButton]': { - width: '40px', - padding: 'unset', - }, - }, -}) - -export const getButtonStyles = (theme?: Theme) => { - const styles = { - ...getBaseStyles(theme), - '&[data-block="block"]': { - width: '100%', - }, - '&[data-label-wrap="true"]': { - minWidth: 'fit-content', - height: 'unset', - minHeight: 'var(--control-medium-size, 2rem)', - - '[data-component="buttonContent"]': { - flex: '1 1 auto', - alignSelf: 'stretch', - paddingBlock: 'calc(var(--control-medium-paddingBlock, 0.375rem) - 2px)', - }, - - '[data-component="text"]': { - whiteSpace: 'unset', - wordBreak: 'break-word', - }, - - '&[data-size="small"]': { - height: 'unset', - minHeight: 'var(--control-small-size, 1.75rem)', - - '[data-component="buttonContent"]': { - paddingBlock: 'calc(var(--control-small-paddingBlock, 0.25rem) - 2px)', - }, - }, - - '&[data-size="large"]': { - height: 'unset', - minHeight: 'var(--control-large-size, 2.5rem)', - paddingInline: 'var(--control-large-paddingInline-spacious, 1rem)', - - '[data-component="buttonContent"]': { - paddingBlock: 'calc(var(--control-large-paddingBlock, 0.625rem) - 2px)', - }, - }, - }, - '&[data-inactive]:not([disabled])': { - backgroundColor: `var(--button-inactive-bgColor, ${theme?.colors.btn.inactive.bg})`, - borderColor: `var(--button-inactive-bgColor, ${theme?.colors.btn.inactive.bg})`, - color: `var(--button-inactive-fgColor, ${theme?.colors.btn.inactive.text})`, - }, - '&[data-inactive]:not([disabled]):focus-visible': { - boxShadow: 'none', - }, - '[data-component="leadingVisual"]': { - gridArea: 'leadingVisual', - }, - '[data-component="text"]': { - gridArea: 'text', - lineHeight: '1.4285714', - whiteSpace: 'nowrap', - }, - '[data-component="trailingVisual"]': { - gridArea: 'trailingVisual', - }, - '[data-component="trailingAction"]': { - marginRight: '-4px', - }, - '[data-component="buttonContent"]': { - flex: '1 0 auto', - display: 'grid', - gridTemplateAreas: '"leadingVisual text trailingVisual"', - gridTemplateColumns: 'min-content minmax(0, auto) min-content', - alignItems: 'center', - alignContent: 'center', - }, - '[data-component="buttonContent"] > :not(:last-child)': { - mr: '8px', - }, - '[data-component="loadingSpinner"]': { - gridArea: 'text', - marginRight: '0px !important', - placeSelf: 'center', - color: 'fg.muted', - }, - '[data-component="loadingSpinner"] + [data-component="text"]': { - visibility: 'hidden', - }, - } - return styles -} - -export const getAlignContentSize = (alignContent: AlignContent = 'center') => ({ - justifyContent: alignContent === 'center' ? 'center' : 'flex-start', -}) From 38064ab3f4d383a2d1bc6a319b207ff7b4745f2d Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 11:59:02 -0400 Subject: [PATCH 18/49] revert test changes --- .../src/__tests__/primer-react.browser.test.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/styled-react/src/__tests__/primer-react.browser.test.tsx b/packages/styled-react/src/__tests__/primer-react.browser.test.tsx index 087921a0010..7c179eb7ee7 100644 --- a/packages/styled-react/src/__tests__/primer-react.browser.test.tsx +++ b/packages/styled-react/src/__tests__/primer-react.browser.test.tsx @@ -56,19 +56,18 @@ describe('@primer/react', () => { expect(window.getComputedStyle(container.firstElementChild!).backgroundColor).toBe('rgb(255, 0, 0)') }) - test.skip('ActionMenu.Overlay supports `sx` prop', async () => { + test('ActionMenu.Overlay supports `sx` prop', async () => { const user = userEvent.setup() - const menu = ( + render( test - test overlay + test - + , ) - render(menu) await user.click(screen.getByText('test')) From 00714787e8d40eec979565142eab60bc5c814bd1 Mon Sep 17 00:00:00 2001 From: Marie Lucca <40550942+francinelucca@users.noreply.github.com> Date: Tue, 30 Sep 2025 12:11:20 -0400 Subject: [PATCH 19/49] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/styled-react/src/components/Button.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/styled-react/src/components/Button.tsx b/packages/styled-react/src/components/Button.tsx index 3e40f9cfe65..13da50c0006 100644 --- a/packages/styled-react/src/components/Button.tsx +++ b/packages/styled-react/src/components/Button.tsx @@ -15,8 +15,7 @@ const ButtonComponent = ({sx, ...rest}: ButtonComponentProps) => { sx as BetterSystemStyleObject, ) - // @ts-ignore sx can have color attribute - const {color} = sx + const {color} = sx as {color?: string} if (color) style['--button-color'] = color } From 60d2f6f4019c91db87734e4cb187caeb594f4951 Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 12:27:24 -0400 Subject: [PATCH 20/49] use forwardedAs --- .../styled-react/src/components/Button.tsx | 14 +++++++---- .../src/components/IconButton.tsx | 23 ++++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/packages/styled-react/src/components/Button.tsx b/packages/styled-react/src/components/Button.tsx index 3e40f9cfe65..6414b57c544 100644 --- a/packages/styled-react/src/components/Button.tsx +++ b/packages/styled-react/src/components/Button.tsx @@ -2,9 +2,12 @@ import {Button as PrimerButton, type ButtonProps as PrimerButtonProps} from '@pr import type {SxProp, CSSCustomProperties} from '../sx' import type {BetterSystemStyleObject} from '../styled-props' import {Box} from './Box' +import {forwardRef} from 'react' +import type {ForwardRefComponent} from '../polymorphic' type ButtonComponentProps = PrimerButtonProps & SxProp -const ButtonComponent = ({sx, ...rest}: ButtonComponentProps) => { + +const StyledButtonComponent = forwardRef(({sx, ...rest}: ButtonComponentProps, ref) => { const {block, size = 'medium', leadingVisual, trailingVisual, trailingAction} = rest let sxStyles: {[key: string]: BetterSystemStyleObject} = {} const style: CSSCustomProperties = {} @@ -20,9 +23,12 @@ const ButtonComponent = ({sx, ...rest}: ButtonComponentProps) => { if (color) style['--button-color'] = color } - // @ts-expect-error type mismatch between Box usage here and PrimerButton - return -} + return +}) + +const ButtonComponent = forwardRef(({as, ...props}: ButtonComponentProps, ref) => ( + +)) as ForwardRefComponent<'button', ButtonComponentProps> // This function is used to generate a custom cssSelector for the sxProp diff --git a/packages/styled-react/src/components/IconButton.tsx b/packages/styled-react/src/components/IconButton.tsx index 514b4e4d8ac..cdce7c5df3a 100644 --- a/packages/styled-react/src/components/IconButton.tsx +++ b/packages/styled-react/src/components/IconButton.tsx @@ -4,16 +4,27 @@ import { sx, type SxProp, } from '@primer/react' -import styled from 'styled-components' import {type ForwardRefComponent} from '../polymorphic' +import {Box} from './Box' +import {generateCustomSxProp} from './Button' +import {forwardRef} from 'react' type IconButtonProps = PrimerIconButtonProps & SxProp -const IconButton: ForwardRefComponent<'a' | 'button', IconButtonProps> = styled(PrimerIconButton).withConfig({ - shouldForwardProp: prop => (prop as keyof IconButtonProps) !== 'sx', -})` - ${sx} -` +const StyledIconButton = forwardRef(({sx, ...rest}: PrimerIconButtonProps, ref) => { + let sxStyles = sx + // grap the button props that have associated data attributes in the styles + const {size = 'medium'} = rest + + if (sx !== null && Object.keys(sx).length > 0) { + sxStyles = generateCustomSxProp({size}, sx) + } + return +}) + +const IconButton = (({as, ...props}: IconButtonProps) => ( + +)) as ForwardRefComponent<'a' | 'button', IconButtonProps> export {IconButton} export type {IconButtonProps} From 95cba9dbeebbabfd0b893c665df9826b5adb40a6 Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 12:37:17 -0400 Subject: [PATCH 21/49] use forwardedAs in ActionMenuButton --- packages/styled-react/src/components/ActionMenu.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/styled-react/src/components/ActionMenu.tsx b/packages/styled-react/src/components/ActionMenu.tsx index e3a5224fd2c..6c5f39dc351 100644 --- a/packages/styled-react/src/components/ActionMenu.tsx +++ b/packages/styled-react/src/components/ActionMenu.tsx @@ -2,6 +2,7 @@ import {Box, ActionMenu as PrimerActionMenu, type SxProp} from '@primer/react' import {sx} from '../sx' import styled from 'styled-components' import {forwardRef, type ComponentProps} from 'react' +import type {ForwardRefComponent} from '../polymorphic' type ActionMenuOverlayProps = ComponentProps & SxProp @@ -10,12 +11,17 @@ const ActionMenuOverlay: React.ComponentType = styled(Pr })` ${sx} ` + export type ActionMenuButtonProps = ComponentProps & SxProp -const ActionMenuButton = forwardRef((props, ref) => { +const StyledActionMenuButton = forwardRef((props, ref) => { return }) +const ActionMenuButton = forwardRef(({as, ...props}: ActionMenuButtonProps, ref) => ( + +)) as ForwardRefComponent<'button', ActionMenuButtonProps> + export const ActionMenu: typeof PrimerActionMenu & { Button: typeof PrimerActionMenu.Button Anchor: typeof PrimerActionMenu.Anchor From 5a6b9201e8bf9356038f9448df2a6da1e4c15a14 Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 12:59:42 -0400 Subject: [PATCH 22/49] revert some changes --- .../react/src/TextInput/TextInput.docs.json | 5 ++++ .../styled-react/src/components/TextInput.tsx | 25 ------------------- 2 files changed, 5 insertions(+), 25 deletions(-) delete mode 100644 packages/styled-react/src/components/TextInput.tsx diff --git a/packages/react/src/TextInput/TextInput.docs.json b/packages/react/src/TextInput/TextInput.docs.json index 257779a53ff..66de3f3ac0a 100644 --- a/packages/react/src/TextInput/TextInput.docs.json +++ b/packages/react/src/TextInput/TextInput.docs.json @@ -215,6 +215,11 @@ "name": "as", "type": "React.ElementType", "defaultValue": "\"button\"" + }, + { + "name": "sx", + "type": "SystemStyleObject", + "deprecated": true } ], "passthrough": { diff --git a/packages/styled-react/src/components/TextInput.tsx b/packages/styled-react/src/components/TextInput.tsx deleted file mode 100644 index e7a7756a7b2..00000000000 --- a/packages/styled-react/src/components/TextInput.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import {TextInput as PrimerTextInput} from '@primer/react' -import type {ComponentProps} from 'react' -import {forwardRef} from 'react' -import {Box} from './Box' -import type {SxProp} from '../sx' - -export type TextInputProps = ComponentProps & SxProp -export type TextInputActionProps = ComponentProps & SxProp - -const TextInputImpl = (props: TextInputProps) => - -const TextInputAction = forwardRef((props, ref) => { - return -}) - -type TextInputComposite = ((props: TextInputProps) => JSX.Element) & { - Action: typeof TextInputAction -} - -export const TextInput: TextInputComposite = Object.assign(TextInputImpl, { - Action: TextInputAction, -}) - -TextInputAction.displayName = 'TextInputAction' -TextInputImpl.displayName = 'TextInput' From bc5c7b9c6ce0a920277be3d6206729ce33d2fe2e Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 13:17:54 -0400 Subject: [PATCH 23/49] lint fixes --- packages/react/src/Button/Button.dev.stories.tsx | 4 +--- packages/styled-react/src/components/Button.tsx | 4 ++-- .../styled-react/src/components/IconButton.tsx | 15 +++++---------- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/react/src/Button/Button.dev.stories.tsx b/packages/react/src/Button/Button.dev.stories.tsx index 42aa39a1ee0..4df2b81c135 100644 --- a/packages/react/src/Button/Button.dev.stories.tsx +++ b/packages/react/src/Button/Button.dev.stories.tsx @@ -1,7 +1,5 @@ -import {SearchIcon, TriangleDownIcon, EyeIcon, IssueClosedIcon, HeartFillIcon} from '@primer/octicons-react' +import {SearchIcon, TriangleDownIcon, EyeIcon, HeartFillIcon} from '@primer/octicons-react' import {Button, IconButton} from '.' -import classes from './Button.dev.stories.module.css' -import {default as Text} from '../Text' import {Stack} from '../Stack' export default { diff --git a/packages/styled-react/src/components/Button.tsx b/packages/styled-react/src/components/Button.tsx index c772fdcbc1f..c3ebe480a11 100644 --- a/packages/styled-react/src/components/Button.tsx +++ b/packages/styled-react/src/components/Button.tsx @@ -5,7 +5,7 @@ import {Box} from './Box' import {forwardRef} from 'react' import type {ForwardRefComponent} from '../polymorphic' -type ButtonComponentProps = PrimerButtonProps & SxProp +type ButtonComponentProps = PrimerButtonProps & SxProp & {as?: React.ElementType} const StyledButtonComponent = forwardRef(({sx, ...rest}: ButtonComponentProps, ref) => { const {block, size = 'medium', leadingVisual, trailingVisual, trailingAction} = rest @@ -26,7 +26,7 @@ const StyledButtonComponent = forwardRef(({sx, ...rest}: ButtonComponentProps, r }) const ButtonComponent = forwardRef(({as, ...props}: ButtonComponentProps, ref) => ( - + )) as ForwardRefComponent<'button', ButtonComponentProps> // This function is used to generate a custom cssSelector for the sxProp diff --git a/packages/styled-react/src/components/IconButton.tsx b/packages/styled-react/src/components/IconButton.tsx index cdce7c5df3a..f0691ecaa4d 100644 --- a/packages/styled-react/src/components/IconButton.tsx +++ b/packages/styled-react/src/components/IconButton.tsx @@ -1,29 +1,24 @@ -import { - IconButton as PrimerIconButton, - type IconButtonProps as PrimerIconButtonProps, - sx, - type SxProp, -} from '@primer/react' +import {IconButton as PrimerIconButton, type IconButtonProps as PrimerIconButtonProps, type SxProp} from '@primer/react' import {type ForwardRefComponent} from '../polymorphic' import {Box} from './Box' import {generateCustomSxProp} from './Button' import {forwardRef} from 'react' -type IconButtonProps = PrimerIconButtonProps & SxProp +type IconButtonProps = PrimerIconButtonProps & SxProp & {as?: React.ElementType} -const StyledIconButton = forwardRef(({sx, ...rest}: PrimerIconButtonProps, ref) => { +const StyledIconButton = forwardRef(({sx, ...rest}: IconButtonProps, ref) => { let sxStyles = sx // grap the button props that have associated data attributes in the styles const {size = 'medium'} = rest - if (sx !== null && Object.keys(sx).length > 0) { + if (sx !== null && sx !== undefined && Object.keys(sx).length > 0) { sxStyles = generateCustomSxProp({size}, sx) } return }) const IconButton = (({as, ...props}: IconButtonProps) => ( - + )) as ForwardRefComponent<'a' | 'button', IconButtonProps> export {IconButton} From 5c005fb511d7fbd6b0e0fa30611169576796307e Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 13:21:42 -0400 Subject: [PATCH 24/49] index fix --- packages/styled-react/src/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/styled-react/src/index.tsx b/packages/styled-react/src/index.tsx index aebf6c76315..6ee64af85a4 100644 --- a/packages/styled-react/src/index.tsx +++ b/packages/styled-react/src/index.tsx @@ -7,7 +7,7 @@ export {ProgressBar} from '@primer/react' export {Select} from '@primer/react' export {Text} from '@primer/react' export {Textarea} from '@primer/react' -export {TextInput, type TextInputProps, type TextInputActionProps} from './components/TextInput' +export {TextInput, type TextInputProps} from '@primer/react' export {Token} from '@primer/react' export {Tooltip} from '@primer/react' export {type TokenProps} from '@primer/react' From 607b3b6a852f93896a1540b91fd49611ff68b9fb Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 13:25:14 -0400 Subject: [PATCH 25/49] remove sx from test --- packages/react/src/Button/__tests__/Button.types.test.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/react/src/Button/__tests__/Button.types.test.tsx b/packages/react/src/Button/__tests__/Button.types.test.tsx index 50cebbc11a7..866d9b3046d 100644 --- a/packages/react/src/Button/__tests__/Button.types.test.tsx +++ b/packages/react/src/Button/__tests__/Button.types.test.tsx @@ -21,9 +21,6 @@ export function ShouldAcceptKnownButtonPropsAndDomProps() { // current target is assignable to HTMLButtonElement buttonEl.current = e.currentTarget }} - sx={{ - m: 1, - }} > Child @@ -59,7 +56,6 @@ export function iconButtonOptionalProps() { <> - ) } From 622b98e78ba6d113ba3bc0ac53f9b3bd9fb5582c Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 13:29:46 -0400 Subject: [PATCH 26/49] revert change --- .../react/src/internal/components/TextInputInnerAction.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/react/src/internal/components/TextInputInnerAction.tsx b/packages/react/src/internal/components/TextInputInnerAction.tsx index 89bd7e1150b..03093d32575 100644 --- a/packages/react/src/internal/components/TextInputInnerAction.tsx +++ b/packages/react/src/internal/components/TextInputInnerAction.tsx @@ -4,6 +4,7 @@ import type {IconProps} from '@primer/octicons-react' import {Button, IconButton} from '../../Button' import {Tooltip} from '../../TooltipV2' import type {ButtonProps} from '../../Button' +import type {SxProp} from '../../sx' import {clsx} from 'clsx' import styles from './TextInputInnerAction.module.css' @@ -25,7 +26,7 @@ type TextInputActionProps = Omit< * Determine's the styles on a button one of 'default' | 'primary' | 'invisible' | 'danger' */ variant?: ButtonProps['variant'] -} +} & SxProp const ConditionalTooltip: React.FC< React.PropsWithChildren<{ @@ -53,13 +54,14 @@ const TextInputAction = forwardRef( tooltipDirection, children, icon, + sx: sxProp, className, variant = 'invisible', ...rest }, forwardedRef, ) => { - const styleProps = {className: clsx(variant === 'invisible' && styles.Invisible, className)} + const styleProps = {className: clsx(variant === 'invisible' && styles.Invisible, className), sx: sxProp || {}} if ((icon && !ariaLabel) || (!children && !ariaLabel)) { // eslint-disable-next-line no-console From a119ec1d4d17a2eb15c521dc6bf60cf709e8a1a6 Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 13:39:16 -0400 Subject: [PATCH 27/49] type fixes --- packages/styled-react/src/components/ActionMenu.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/styled-react/src/components/ActionMenu.tsx b/packages/styled-react/src/components/ActionMenu.tsx index 6c5f39dc351..c75af089c8e 100644 --- a/packages/styled-react/src/components/ActionMenu.tsx +++ b/packages/styled-react/src/components/ActionMenu.tsx @@ -1,4 +1,9 @@ -import {Box, ActionMenu as PrimerActionMenu, type SxProp} from '@primer/react' +import { + Box, + ActionMenu as PrimerActionMenu, + type SxProp, + type ActionMenuButtonProps as PrimerActionMenuButtonProps, +} from '@primer/react' import {sx} from '../sx' import styled from 'styled-components' import {forwardRef, type ComponentProps} from 'react' @@ -12,7 +17,7 @@ const ActionMenuOverlay: React.ComponentType = styled(Pr ${sx} ` -export type ActionMenuButtonProps = ComponentProps & SxProp +export type ActionMenuButtonProps = PrimerActionMenuButtonProps & SxProp const StyledActionMenuButton = forwardRef((props, ref) => { return From 79b26bb6fce9d729980426493b620114aa038d82 Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 13:43:22 -0400 Subject: [PATCH 28/49] type fixes --- packages/styled-react/src/components/ActionMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/styled-react/src/components/ActionMenu.tsx b/packages/styled-react/src/components/ActionMenu.tsx index c75af089c8e..3f4a30eddda 100644 --- a/packages/styled-react/src/components/ActionMenu.tsx +++ b/packages/styled-react/src/components/ActionMenu.tsx @@ -17,7 +17,7 @@ const ActionMenuOverlay: React.ComponentType = styled(Pr ${sx} ` -export type ActionMenuButtonProps = PrimerActionMenuButtonProps & SxProp +export type ActionMenuButtonProps = PrimerActionMenuButtonProps & SxProp & {as?: React.ElementType} const StyledActionMenuButton = forwardRef((props, ref) => { return From 421b9dbe3a00891dfb4b05d65d773a673214fc71 Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Tue, 30 Sep 2025 16:36:06 -0400 Subject: [PATCH 29/49] remove sx from stories --- .../src/Overlay/Overlay.features.stories.tsx | 26 ++++++++++++------- .../src/Spinner/Spinner.examples.stories.tsx | 2 +- .../SelectPanel.examples.stories.module.css | 20 ++++++++++++++ .../SelectPanel.examples.stories.tsx | 21 +++++++-------- .../stories/deprecated/ActionMenu.stories.tsx | 2 +- 5 files changed, 48 insertions(+), 23 deletions(-) diff --git a/packages/react/src/Overlay/Overlay.features.stories.tsx b/packages/react/src/Overlay/Overlay.features.stories.tsx index a8860d992c9..f3629a23427 100644 --- a/packages/react/src/Overlay/Overlay.features.stories.tsx +++ b/packages/react/src/Overlay/Overlay.features.stories.tsx @@ -62,7 +62,7 @@ export const DropdownOverlay = ({anchorSide, open}: Args) => { return ( <> - {isOpen || open ? ( @@ -263,7 +263,7 @@ export const MemexNestedOverlays = ({role, open}: Args) => { - + {duration} @@ -361,7 +361,13 @@ export const NestedOverlays = ({role, open}: Args) => { {state === 'loading' && } diff --git a/packages/react/src/experimental/SelectPanel2/SelectPanel.examples.stories.module.css b/packages/react/src/experimental/SelectPanel2/SelectPanel.examples.stories.module.css index 731d400ca03..360379aba69 100644 --- a/packages/react/src/experimental/SelectPanel2/SelectPanel.examples.stories.module.css +++ b/packages/react/src/experimental/SelectPanel2/SelectPanel.examples.stories.module.css @@ -15,6 +15,26 @@ color: var(--fgColor-muted); } +.WideButton { + width: 200px; +} + +.WideButton:where([data-component="buttonContent"]) { + justify-content: start; +} + +.HiddenSelection:where([data-component="ActionList.Selection"]) { + display: none; +} + +.NormalFontWeight:where([data-component="text"]) { + font-weight: var(--base-text-weight-normal); +} + +.MutedText { + color: var(--fgColor-muted); +} + .FilterButtons { display: flex; margin-top: var(--base-size-4); diff --git a/packages/react/src/experimental/SelectPanel2/SelectPanel.examples.stories.tsx b/packages/react/src/experimental/SelectPanel2/SelectPanel.examples.stories.tsx index b21b6b87d07..e9037b65d59 100644 --- a/packages/react/src/experimental/SelectPanel2/SelectPanel.examples.stories.tsx +++ b/packages/react/src/experimental/SelectPanel2/SelectPanel.examples.stories.tsx @@ -145,11 +145,7 @@ export const WithGroups = () => { onCancel={onCancel} onClearSelection={onClearSelection} > - + Reviewers @@ -570,7 +566,10 @@ export const WithFilterButtons = () => {
@@ -791,7 +790,7 @@ export const NestedSelection = () => { key={repo.name} selected={selectedRepo === `${repo.org}/${repo.name}`} onSelect={() => setSelectedRepo(`${repo.org}/${repo.name}`)} - sx={{'[data-component="ActionList.Selection"]': {display: 'none'}}} + className={classes.HiddenSelection} > @@ -1002,7 +1001,7 @@ export const CreateNewRow = () => { leadingVisual={PlusCircleIcon} block alignContent="start" - sx={{'[data-component=text]': {fontWeight: 'normal'}}} + className={classes.NormalFontWeight} onClick={openCreateLabelDialog} > Create new label "{query}"... diff --git a/packages/react/src/stories/deprecated/ActionMenu.stories.tsx b/packages/react/src/stories/deprecated/ActionMenu.stories.tsx index df60fc88a22..a0928a4543d 100644 --- a/packages/react/src/stories/deprecated/ActionMenu.stories.tsx +++ b/packages/react/src/stories/deprecated/ActionMenu.stories.tsx @@ -230,7 +230,7 @@ export function ComplexListStory(): JSX.Element { ComplexListStory.storyName = 'Complex List' export function CustomTrigger(): JSX.Element { - const customAnchor = (props: ButtonProps) =>