Skip to content

Commit e2adcb0

Browse files
committed
feat: Add children-based API for button group
1 parent 84e9280 commit e2adcb0

File tree

8 files changed

+389
-17
lines changed

8 files changed

+389
-17
lines changed

package-lock.json

Lines changed: 210 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import React from 'react';
5+
6+
import { Box, Button, ButtonDropdown, ButtonGroup, Header } from '~components';
7+
8+
export default function ButtonGroupPage() {
9+
return (
10+
<Box margin={'m'}>
11+
<Header variant="h1">ButtonGroup composition API</Header>
12+
<input data-testid="focus-before" aria-label="Focus helper" />
13+
<br />
14+
15+
<ButtonGroup variant="children" ariaLabel="Actions">
16+
<Button data-itemid="one">Normal button</Button>
17+
<Button data-itemid="two">Another button</Button>
18+
<Button data-itemid="three" variant="icon" iconName="ticket" ariaLabel="Icon button" />
19+
<ButtonDropdown
20+
nativeTriggerAttributes={{ 'data-itemid': 'dropdown' }}
21+
ariaLabel="Icon button dropdown"
22+
items={[
23+
{ id: 'four', text: 'Button dropdown item' },
24+
{ id: 'another', text: 'Item 2' },
25+
]}
26+
variant="icon"
27+
/>
28+
</ButtonGroup>
29+
</Box>
30+
);
31+
}

src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6106,18 +6106,35 @@ use the \`id\` attribute, consider setting it on a parent element instead.",
61066106
* \`text\` (string) - The name of the group rendered as ARIA label for this group.
61076107
* \`items\` ((ButtonGroupProps.IconButton | ButtonGroupProps.MenuDropdown)[]) - The array of items that belong to this group.",
61086108
"name": "items",
6109-
"optional": false,
6109+
"optional": true,
61106110
"type": "ReadonlyArray<ButtonGroupProps.ItemOrGroup>",
61116111
},
61126112
{
6113+
"defaultValue": "'icon'",
61136114
"description": "Determines the general styling of the button dropdown.
61146115
* \`icon\` for icon buttons.",
61156116
"name": "variant",
6116-
"optional": false,
6117+
"optional": true,
61176118
"type": ""icon"",
61186119
},
61196120
],
6120-
"regions": [],
6121+
"regions": [
6122+
{
6123+
"description": "Instead of passing \`items\`, group items can be passed as children. When using this,
6124+
you will need to manage click handlers and state of buttons.
6125+
6126+
Each item should contain a single focusable element which must have a unique \`data-itemid\` attribute.
6127+
6128+
For example:
6129+
- \`<Button data-itemid="button-one">One</Button>\`
6130+
- \`<ButtonDropdown nativeButtonAttributes={{'data-itemid': 'button-two'}} items={...} />\`",
6131+
"isDefault": true,
6132+
"name": "children",
6133+
"systemTags": [
6134+
"core",
6135+
],
6136+
},
6137+
],
61216138
"releaseStatus": "stable",
61226139
}
61236140
`;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { BasePageObject } from '@cloudscape-design/browser-test-tools/page-objects';
4+
import useBrowser from '@cloudscape-design/browser-test-tools/use-browser';
5+
6+
import createWrapper from '../../../lib/components/test-utils/selectors';
7+
8+
const buttonGroup = createWrapper().findButtonGroup();
9+
10+
// First button group elements
11+
const button1 = buttonGroup.findContent().findButton('[data-itemid=one]').toSelector();
12+
const button2 = buttonGroup.findContent().findButton('[data-itemid=two]').toSelector();
13+
const dropdown = buttonGroup.findContent().findButtonDropdown().findNativeButton().toSelector();
14+
15+
const beforeSelector = '[data-testid="focus-before"]';
16+
17+
function setup(testFn: (page: BasePageObject) => Promise<void>) {
18+
return useBrowser(async browser => {
19+
const page = new BasePageObject(browser);
20+
await browser.url('/#/light/button-group/composition');
21+
await testFn(page);
22+
});
23+
}
24+
25+
test(
26+
'navigates between buttons with arrow keys',
27+
setup(async page => {
28+
await page.click(beforeSelector);
29+
30+
await page.keys(['Tab']);
31+
await expect(page.isFocused(button1)).resolves.toBe(true);
32+
33+
await page.keys(['ArrowRight']);
34+
debugger;
35+
await expect(page.isFocused(button2)).resolves.toBe(true);
36+
37+
await page.keys(['ArrowRight', 'ArrowRight']);
38+
await expect(page.isFocused(dropdown)).resolves.toBe(true);
39+
})
40+
);
41+
42+
test(
43+
'maintains focus when moving back to group',
44+
setup(async page => {
45+
await page.click(beforeSelector);
46+
47+
await page.keys(['Tab']);
48+
await expect(page.isFocused(button1)).resolves.toBe(true);
49+
50+
await page.keys(['ArrowRight']);
51+
await expect(page.isFocused(button2)).resolves.toBe(true);
52+
53+
await page.keys(['Shift', 'Tab']);
54+
await expect(page.isFocused(beforeSelector)).resolves.toBe(true);
55+
56+
await page.keys(['Tab']);
57+
await expect(page.isFocused(button2)).resolves.toBe(true);
58+
})
59+
);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import React from 'react';
5+
import { render } from '@testing-library/react';
6+
7+
import Button from '../../../lib/components/button';
8+
import ButtonGroup from '../../../lib/components/button-group';
9+
import createWrapper from '../../../lib/components/test-utils/dom';
10+
11+
describe('ButtonGroup children property', () => {
12+
test('renders children', () => {
13+
const { container } = render(
14+
<ButtonGroup variant="children">
15+
<Button data-testid="child-element">Button one</Button>
16+
<Button data-testid="child-element-two">Another button</Button>
17+
</ButtonGroup>
18+
);
19+
20+
const wrapper = createWrapper(container);
21+
const buttonGroup = wrapper.findButtonGroup()!;
22+
23+
expect(buttonGroup.findContent().findAllButtons()).toHaveLength(2);
24+
25+
const childElement = wrapper.find('[data-testid="child-element"]');
26+
expect(childElement).not.toBeNull();
27+
expect(childElement!.getElement()).toHaveTextContent('Button one');
28+
});
29+
});

0 commit comments

Comments
 (0)