diff --git a/.changeset/slow-news-love.md b/.changeset/slow-news-love.md new file mode 100644 index 00000000000..b133d700fed --- /dev/null +++ b/.changeset/slow-news-love.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +fix(ButtonGroup): add toolbar interactions for role toolbar diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-colorblind-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-colorblind-linux.png new file mode 100644 index 00000000000..6153d33044c Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-dimmed-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-dimmed-linux.png new file mode 100644 index 00000000000..ec8b719dd01 Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-high-contrast-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-high-contrast-linux.png new file mode 100644 index 00000000000..1a1ce14f0f0 Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-linux.png new file mode 100644 index 00000000000..6153d33044c Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-linux.png differ diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-tritanopia-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-tritanopia-linux.png new file mode 100644 index 00000000000..6153d33044c Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-colorblind-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-colorblind-linux.png new file mode 100644 index 00000000000..a4ac8d7c369 Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-high-contrast-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-high-contrast-linux.png new file mode 100644 index 00000000000..57feb9d6d99 Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-linux.png new file mode 100644 index 00000000000..a4ac8d7c369 Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-linux.png differ diff --git a/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-tritanopia-linux.png b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-tritanopia-linux.png new file mode 100644 index 00000000000..a4ac8d7c369 Binary files /dev/null and b/.playwright/snapshots/components/ButtonGroup.test.ts-snapshots/ButtonGroup-As-Toolbar-light-tritanopia-linux.png differ diff --git a/e2e/components/ButtonGroup.test.ts b/e2e/components/ButtonGroup.test.ts index c3ca9822ff7..1a9eab686b9 100644 --- a/e2e/components/ButtonGroup.test.ts +++ b/e2e/components/ButtonGroup.test.ts @@ -86,4 +86,32 @@ test.describe('ButtonGroup', () => { }) } }) + + test.describe('As Toolbar', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-buttongroup-features--as-toolbar', + globals: { + colorScheme: theme, + }, + }) + + // Default state + expect(await page.screenshot()).toMatchSnapshot(`ButtonGroup.As Toolbar.${theme}.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-buttongroup-features--as-toolbar', + globals: { + colorScheme: theme, + }, + }) + await expect(page).toHaveNoViolations() + }) + }) + } + }) }) diff --git a/packages/react/src/ButtonGroup/ButtonGroup.features.stories.tsx b/packages/react/src/ButtonGroup/ButtonGroup.features.stories.tsx index 091fe5c292c..211e09ad17e 100644 --- a/packages/react/src/ButtonGroup/ButtonGroup.features.stories.tsx +++ b/packages/react/src/ButtonGroup/ButtonGroup.features.stories.tsx @@ -73,3 +73,11 @@ export const DropdownSplit = () => { ) } + +export const AsToolbar = () => ( + + + + + +) diff --git a/packages/react/src/ButtonGroup/ButtonGroup.test.tsx b/packages/react/src/ButtonGroup/ButtonGroup.test.tsx new file mode 100644 index 00000000000..67b3b0b3b6f --- /dev/null +++ b/packages/react/src/ButtonGroup/ButtonGroup.test.tsx @@ -0,0 +1,58 @@ +import {Button} from '../Button' +import {render, screen} from '@testing-library/react' +import axe from 'axe-core' +import {FeatureFlags} from '../FeatureFlags' +import {behavesAsComponent} from '../utils/testing' +import type {ButtonGroupProps} from './ButtonGroup' +import ButtonGroup from './ButtonGroup' +import React from 'react' + +const TestButtonGroup = (props: ButtonGroupProps) => ( + + + + + +) + +describe('ButtonGroup', () => { + behavesAsComponent({ + Component: TestButtonGroup, + options: {skipSx: true, skipAs: true}, + }) + + it('should support `className` on the outermost element', () => { + const Element = () => + const FeatureFlagElement = () => { + return ( + + + + ) + } + expect(render().container.firstChild).toHaveClass('test-class-name') + expect(render().container.firstChild).toHaveClass('test-class-name') + }) + + it('renders a
', () => { + const container = render() + expect(container.getByTestId('button-group').tagName).toBe('DIV') + }) + + it('should have no axe violations', async () => { + const {container} = render() + const results = await axe.run(container) + expect(results).toHaveNoViolations() + }) + + it('should respect role prop', () => { + render() + expect(screen.getByRole('toolbar')).toBeInTheDocument() + }) +}) diff --git a/packages/react/src/ButtonGroup/ButtonGroup.tsx b/packages/react/src/ButtonGroup/ButtonGroup.tsx index 74f9ff32e15..a65a813af19 100644 --- a/packages/react/src/ButtonGroup/ButtonGroup.tsx +++ b/packages/react/src/ButtonGroup/ButtonGroup.tsx @@ -7,6 +7,9 @@ import classes from './ButtonGroup.module.css' import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent' import {clsx} from 'clsx' import {useFeatureFlag} from '../FeatureFlags' +import {FocusKeys, useFocusZone} from '../hooks/useFocusZone' +import {useProvidedRefOrCreate} from '../hooks' +import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../utils/polymorphic' const StyledButtonGroup = toggleStyledComponent( 'primer_react_css_modules_staff', @@ -74,23 +77,34 @@ const StyledButtonGroup = toggleStyledComponent( ) export type ButtonGroupProps = ComponentProps + const ButtonGroup = React.forwardRef(function ButtonGroup( - {children, className, ...rest}, + {children, className, role, ...rest}, forwardRef, ) { const enabled = useFeatureFlag('primer_react_css_modules_staff') + const buttonRef = useProvidedRefOrCreate(forwardRef as React.RefObject) + + useFocusZone({ + containerRef: buttonRef, + disabled: role !== 'toolbar', + bindKeys: FocusKeys.ArrowHorizontal, + focusOutBehavior: 'wrap', + }) + return ( {children} ) -}) +}) as PolymorphicForwardRefComponent<'div', ButtonGroupProps> ButtonGroup.displayName = 'ButtonGroup'