uikit-react-public 0.50.5 → 0.50.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +5 -3
- package/dist/components/ToggleGroup/ToggleGroup.stories.d.ts +7 -2
- package/dist/components/ToggleGroup/ToggleGroupContext.d.ts +2 -0
- package/dist/components/ToggleGroup/index.d.ts +1 -2
- package/dist/components/ToggleGroup/subcomponents/ToggleGroupItem.d.ts +13 -0
- package/dist/components/ToggleGroup/subcomponents/{Item.stories.d.ts → ToggleGroupItem.stories.d.ts} +2 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/index.js +5138 -5050
- package/lib/components/Accordion/Accordion.Heading.tsx +1 -1
- package/lib/components/Accordion/Accordion.Panel.tsx +1 -1
- package/lib/components/Accordion/__tests__/Accordion.test.tsx +21 -0
- package/lib/components/Accordion/__tests__/__snapshots__/Accordion.test.tsx.snap +2 -2
- package/lib/components/Badge/Badge.tsx +3 -1
- package/lib/components/Badge/__tests__/Badge.test.tsx +10 -2
- package/lib/components/Badge/__tests__/__snapshots__/Badge.test.tsx.snap +9 -9
- package/lib/components/Calendar/__tests__/__snapshots__/Calendar.test.tsx.snap +4 -4
- package/lib/components/Callout/Callout.tsx +1 -1
- package/lib/components/Datepicker/__tests__/__snapshots__/Datepicker.test.tsx.snap +6 -6
- package/lib/components/Datepicker/subcomponents/DatepickerInput.tsx +1 -0
- package/lib/components/Datepicker/subcomponents/VisibleField.tsx +2 -1
- package/lib/components/NativeDatepicker/NativeDatepicker.tsx +1 -0
- package/lib/components/Select/__tests__/__snapshots__/Select.test.tsx.snap +1 -1
- package/lib/components/Select/subcomponents/CustomSelect.tsx +1 -0
- package/lib/components/Select/subcomponents/NativeSelect.tsx +1 -0
- package/lib/components/ToggleGroup/ToggleGroup.stories.tsx +3 -0
- package/lib/components/ToggleGroup/ToggleGroup.tsx +51 -10
- package/lib/components/ToggleGroup/ToggleGroupContext.tsx +2 -0
- package/lib/components/ToggleGroup/__tests__/ToggleGroup.test.tsx +105 -6
- package/lib/components/ToggleGroup/index.ts +1 -2
- package/lib/components/ToggleGroup/subcomponents/{Item.stories.tsx → ToggleGroupItem.stories.tsx} +6 -4
- package/lib/components/ToggleGroup/subcomponents/{Item.tsx → ToggleGroupItem.tsx} +126 -52
- package/lib/components/ToggleGroup/subcomponents/__tests__/{Item.test.tsx → ToggleGroupItem.test.tsx} +50 -6
- package/lib/components/index.ts +1 -1
- package/package.json +1 -1
- package/dist/components/ToggleGroup/subcomponents/Item.d.ts +0 -11
- /package/dist/components/ToggleGroup/subcomponents/__tests__/{Item.test.d.ts → ToggleGroupItem.test.d.ts} +0 -0
|
@@ -38,7 +38,7 @@ const AccordionHeading: React.FC<AccordionHeadingProps> = ({
|
|
|
38
38
|
position: relative;
|
|
39
39
|
justify-content: space-between;
|
|
40
40
|
align-items: center;
|
|
41
|
-
padding: ${theme.padding.p16};
|
|
41
|
+
padding: ${theme.padding.p16} ${theme.padding.p8};
|
|
42
42
|
background-color: ${theme.colour.fill.inverse};
|
|
43
43
|
cursor: pointer;
|
|
44
44
|
transition: background-color 0.15s ease;
|
|
@@ -29,7 +29,7 @@ const AccordionPanel: React.FC<AccordionPanelProps> = ({
|
|
|
29
29
|
max-width: 100%;
|
|
30
30
|
min-width: 0;
|
|
31
31
|
flex-shrink: 1;
|
|
32
|
-
padding: ${theme.padding.
|
|
32
|
+
padding: ${theme.padding.p8} ${theme.padding.p8} ${theme.padding.p24};
|
|
33
33
|
box-sizing: border-box;
|
|
34
34
|
overflow: hidden;
|
|
35
35
|
overflow-wrap: break-word;
|
|
@@ -40,6 +40,27 @@ describe('Accordion', () => {
|
|
|
40
40
|
|
|
41
41
|
// Interaction tests
|
|
42
42
|
|
|
43
|
+
test('uses the expected heading and panel padding', () => {
|
|
44
|
+
render(
|
|
45
|
+
<ThemeContextProvider>
|
|
46
|
+
<Accordion>
|
|
47
|
+
<Accordion.Heading>Heading</Accordion.Heading>
|
|
48
|
+
<Accordion.Panel>Panel Content</Accordion.Panel>
|
|
49
|
+
</Accordion>
|
|
50
|
+
</ThemeContextProvider>
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const heading = screen.getByTestId('ucl-uikit-accordion__heading');
|
|
54
|
+
expect(getComputedStyle(heading).padding).toBe('16px 8px');
|
|
55
|
+
|
|
56
|
+
fireEvent.click(heading);
|
|
57
|
+
const panel = screen.getByTestId('ucl-uikit-accordion__panel');
|
|
58
|
+
expect(getComputedStyle(panel).paddingTop).toBe('8px');
|
|
59
|
+
expect(getComputedStyle(panel).paddingRight).toBe('8px');
|
|
60
|
+
expect(getComputedStyle(panel).paddingBottom).toBe('24px');
|
|
61
|
+
expect(getComputedStyle(panel).paddingLeft).toBe('8px');
|
|
62
|
+
});
|
|
63
|
+
|
|
43
64
|
test('should open and close the accordion', () => {
|
|
44
65
|
render(
|
|
45
66
|
<ThemeContextProvider>
|
|
@@ -8,7 +8,7 @@ exports[`Accordion > snapshot: no props 1`] = `
|
|
|
8
8
|
>
|
|
9
9
|
<h6
|
|
10
10
|
aria-expanded="false"
|
|
11
|
-
class="ucl-uikit-heading ucl-uikit-accordion__heading css-
|
|
11
|
+
class="ucl-uikit-heading ucl-uikit-accordion__heading css-3x70cw"
|
|
12
12
|
data-testid="ucl-uikit-accordion__heading"
|
|
13
13
|
role="button"
|
|
14
14
|
tabindex="0"
|
|
@@ -44,7 +44,7 @@ exports[`Accordion > snapshot: testId prop 1`] = `
|
|
|
44
44
|
>
|
|
45
45
|
<h6
|
|
46
46
|
aria-expanded="false"
|
|
47
|
-
class="ucl-uikit-heading ucl-uikit-accordion__heading css-
|
|
47
|
+
class="ucl-uikit-heading ucl-uikit-accordion__heading css-3x70cw"
|
|
48
48
|
data-testid="ucl-uikit-accordion__heading"
|
|
49
49
|
role="button"
|
|
50
50
|
tabindex="0"
|
|
@@ -91,8 +91,9 @@ export const getBadgeVariantColours = (
|
|
|
91
91
|
color: theme.colour.text.inverse,
|
|
92
92
|
backgroundColor: theme.colour.fill.warning,
|
|
93
93
|
},
|
|
94
|
+
// TODO: replace primitiveColour use here with colour.text.warningOnBgFill when token is updated to matching hex
|
|
94
95
|
'warning-subtle': {
|
|
95
|
-
color: theme.
|
|
96
|
+
color: theme.primitiveColour.orange['13'].$value.hex,
|
|
96
97
|
backgroundColor: theme.colour.fill.warningSubtle,
|
|
97
98
|
},
|
|
98
99
|
disabled: {
|
|
@@ -145,6 +146,7 @@ const Badge = ({
|
|
|
145
146
|
padding: 0 ${theme.padding.p8};
|
|
146
147
|
|
|
147
148
|
color: ${color};
|
|
149
|
+
font-weight: ${theme.typography.body.smSemibold.fontWeight};
|
|
148
150
|
background-color: ${backgroundColor};
|
|
149
151
|
border: ${border ?? 'none'};
|
|
150
152
|
|
|
@@ -91,6 +91,14 @@ describe('Badge', () => {
|
|
|
91
91
|
expect(getByText('Hello')).toBeTruthy();
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
+
test('uses semibold text', () => {
|
|
95
|
+
const { getByTestId } = wrap(<Badge>Text</Badge>);
|
|
96
|
+
|
|
97
|
+
expect(getComputedStyle(getByTestId('ucl-uikit-badge')).fontWeight).toBe(
|
|
98
|
+
String(lightTheme.typography.body.smSemibold.fontWeight)
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
94
102
|
test('applies custom testId', () => {
|
|
95
103
|
const { getByTestId } = wrap(<Badge testId='my-badge'>Text</Badge>);
|
|
96
104
|
expect(getByTestId('my-badge')).toBeTruthy();
|
|
@@ -175,7 +183,7 @@ describe('Badge', () => {
|
|
|
175
183
|
backgroundColor: darkTheme.colour.fill.warning,
|
|
176
184
|
});
|
|
177
185
|
expect(colours['warning-subtle']).toMatchObject({
|
|
178
|
-
color: darkTheme.
|
|
186
|
+
color: darkTheme.primitiveColour.orange['13'].$value.hex,
|
|
179
187
|
backgroundColor: darkTheme.colour.fill.warningSubtle,
|
|
180
188
|
});
|
|
181
189
|
});
|
|
@@ -217,7 +225,7 @@ describe('Badge', () => {
|
|
|
217
225
|
backgroundColor: lightTheme.colour.fill.warning,
|
|
218
226
|
});
|
|
219
227
|
expect(colours['warning-subtle']).toMatchObject({
|
|
220
|
-
color:
|
|
228
|
+
color: '#994D29',
|
|
221
229
|
backgroundColor: lightTheme.colour.fill.warningSubtle,
|
|
222
230
|
});
|
|
223
231
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`Badge > snapshot: default 1`] = `
|
|
4
4
|
<span
|
|
5
|
-
class="ucl-uikit-text ucl-uikit-badge css-
|
|
5
|
+
class="ucl-uikit-text ucl-uikit-badge css-193xmhy"
|
|
6
6
|
data-testid="ucl-uikit-badge"
|
|
7
7
|
>
|
|
8
8
|
Default
|
|
@@ -11,7 +11,7 @@ exports[`Badge > snapshot: default 1`] = `
|
|
|
11
11
|
|
|
12
12
|
exports[`Badge > snapshot: size=large 1`] = `
|
|
13
13
|
<span
|
|
14
|
-
class="ucl-uikit-text ucl-uikit-badge css-
|
|
14
|
+
class="ucl-uikit-text ucl-uikit-badge css-xkp5fs"
|
|
15
15
|
data-testid="ucl-uikit-badge"
|
|
16
16
|
>
|
|
17
17
|
Large
|
|
@@ -20,7 +20,7 @@ exports[`Badge > snapshot: size=large 1`] = `
|
|
|
20
20
|
|
|
21
21
|
exports[`Badge > snapshot: statusIndicator 1`] = `
|
|
22
22
|
<span
|
|
23
|
-
class="ucl-uikit-text ucl-uikit-badge css-
|
|
23
|
+
class="ucl-uikit-text ucl-uikit-badge css-193xmhy"
|
|
24
24
|
data-testid="ucl-uikit-badge"
|
|
25
25
|
>
|
|
26
26
|
<span
|
|
@@ -33,7 +33,7 @@ exports[`Badge > snapshot: statusIndicator 1`] = `
|
|
|
33
33
|
|
|
34
34
|
exports[`Badge > snapshot: variant=critical with icon 1`] = `
|
|
35
35
|
<span
|
|
36
|
-
class="ucl-uikit-text ucl-uikit-badge css-
|
|
36
|
+
class="ucl-uikit-text ucl-uikit-badge css-1ussa90"
|
|
37
37
|
data-testid="ucl-uikit-badge"
|
|
38
38
|
>
|
|
39
39
|
<svg
|
|
@@ -66,7 +66,7 @@ exports[`Badge > snapshot: variant=critical with icon 1`] = `
|
|
|
66
66
|
|
|
67
67
|
exports[`Badge > snapshot: variant=disabled 1`] = `
|
|
68
68
|
<span
|
|
69
|
-
class="ucl-uikit-text ucl-uikit-badge css-
|
|
69
|
+
class="ucl-uikit-text ucl-uikit-badge css-1lag7jx"
|
|
70
70
|
data-testid="ucl-uikit-badge"
|
|
71
71
|
>
|
|
72
72
|
Disabled
|
|
@@ -75,7 +75,7 @@ exports[`Badge > snapshot: variant=disabled 1`] = `
|
|
|
75
75
|
|
|
76
76
|
exports[`Badge > snapshot: variant=info with icon 1`] = `
|
|
77
77
|
<span
|
|
78
|
-
class="ucl-uikit-text ucl-uikit-badge css-
|
|
78
|
+
class="ucl-uikit-text ucl-uikit-badge css-pmqt4o"
|
|
79
79
|
data-testid="ucl-uikit-badge"
|
|
80
80
|
>
|
|
81
81
|
<svg
|
|
@@ -108,7 +108,7 @@ exports[`Badge > snapshot: variant=info with icon 1`] = `
|
|
|
108
108
|
|
|
109
109
|
exports[`Badge > snapshot: variant=info-subtle 1`] = `
|
|
110
110
|
<span
|
|
111
|
-
class="ucl-uikit-text ucl-uikit-badge css-
|
|
111
|
+
class="ucl-uikit-text ucl-uikit-badge css-1ikogho"
|
|
112
112
|
data-testid="ucl-uikit-badge"
|
|
113
113
|
>
|
|
114
114
|
Info subtle
|
|
@@ -117,7 +117,7 @@ exports[`Badge > snapshot: variant=info-subtle 1`] = `
|
|
|
117
117
|
|
|
118
118
|
exports[`Badge > snapshot: variant=success with icon 1`] = `
|
|
119
119
|
<span
|
|
120
|
-
class="ucl-uikit-text ucl-uikit-badge css-
|
|
120
|
+
class="ucl-uikit-text ucl-uikit-badge css-plwfy3"
|
|
121
121
|
data-testid="ucl-uikit-badge"
|
|
122
122
|
>
|
|
123
123
|
<svg
|
|
@@ -148,7 +148,7 @@ exports[`Badge > snapshot: variant=success with icon 1`] = `
|
|
|
148
148
|
|
|
149
149
|
exports[`Badge > snapshot: variant=warning with icon 1`] = `
|
|
150
150
|
<span
|
|
151
|
-
class="ucl-uikit-text ucl-uikit-badge css-
|
|
151
|
+
class="ucl-uikit-text ucl-uikit-badge css-159h60j"
|
|
152
152
|
data-testid="ucl-uikit-badge"
|
|
153
153
|
>
|
|
154
154
|
<svg
|
|
@@ -41,7 +41,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
|
|
|
41
41
|
aria-expanded="false"
|
|
42
42
|
aria-haspopup="listbox"
|
|
43
43
|
aria-label="Month"
|
|
44
|
-
class="ucl-uikit-select css-
|
|
44
|
+
class="ucl-uikit-select css-1mgirop"
|
|
45
45
|
data-testid="ucl-uikit-select"
|
|
46
46
|
role="combobox"
|
|
47
47
|
tabindex="0"
|
|
@@ -88,7 +88,7 @@ exports[`Calendar > Snapshot: no date provided 1`] = `
|
|
|
88
88
|
aria-expanded="false"
|
|
89
89
|
aria-haspopup="listbox"
|
|
90
90
|
aria-label="Year"
|
|
91
|
-
class="ucl-uikit-select css-
|
|
91
|
+
class="ucl-uikit-select css-1mgirop"
|
|
92
92
|
data-testid="ucl-uikit-select"
|
|
93
93
|
role="combobox"
|
|
94
94
|
tabindex="0"
|
|
@@ -921,7 +921,7 @@ exports[`Calendar > Snapshot: with date provided 1`] = `
|
|
|
921
921
|
aria-expanded="false"
|
|
922
922
|
aria-haspopup="listbox"
|
|
923
923
|
aria-label="Month"
|
|
924
|
-
class="ucl-uikit-select css-
|
|
924
|
+
class="ucl-uikit-select css-1mgirop"
|
|
925
925
|
data-testid="ucl-uikit-select"
|
|
926
926
|
role="combobox"
|
|
927
927
|
tabindex="0"
|
|
@@ -968,7 +968,7 @@ exports[`Calendar > Snapshot: with date provided 1`] = `
|
|
|
968
968
|
aria-expanded="false"
|
|
969
969
|
aria-haspopup="listbox"
|
|
970
970
|
aria-label="Year"
|
|
971
|
-
class="ucl-uikit-select css-
|
|
971
|
+
class="ucl-uikit-select css-1mgirop"
|
|
972
972
|
data-testid="ucl-uikit-select"
|
|
973
973
|
role="combobox"
|
|
974
974
|
tabindex="0"
|
|
@@ -6,11 +6,11 @@ exports[`Datepicker > Snapshot: no date provided 1`] = `
|
|
|
6
6
|
data-testid="ucl-uikit-datepicker"
|
|
7
7
|
>
|
|
8
8
|
<div
|
|
9
|
-
class="ucl-uikit-datepicker__visible-field css-
|
|
9
|
+
class="ucl-uikit-datepicker__visible-field css-51hkje"
|
|
10
10
|
data-testid="ucl-uikit-datepicker__visible-field"
|
|
11
11
|
>
|
|
12
12
|
<input
|
|
13
|
-
class="ucl-uikit-datepicker__input css-
|
|
13
|
+
class="ucl-uikit-datepicker__input css-gjp4ve"
|
|
14
14
|
data-testid="ucl-uikit-datepicker__input"
|
|
15
15
|
inputmode="numeric"
|
|
16
16
|
placeholder="DD/MM/YYYY"
|
|
@@ -25,7 +25,7 @@ exports[`Datepicker > Snapshot: no date provided 1`] = `
|
|
|
25
25
|
type="button"
|
|
26
26
|
>
|
|
27
27
|
<svg
|
|
28
|
-
class="ucl-uikit-icon css-
|
|
28
|
+
class="ucl-uikit-icon css-7p0vcp"
|
|
29
29
|
data-testid="ucl-uikit-icon"
|
|
30
30
|
fill="none"
|
|
31
31
|
focusable="false"
|
|
@@ -61,11 +61,11 @@ exports[`Datepicker > Snapshot: with date provided 1`] = `
|
|
|
61
61
|
data-testid="ucl-uikit-datepicker"
|
|
62
62
|
>
|
|
63
63
|
<div
|
|
64
|
-
class="ucl-uikit-datepicker__visible-field css-
|
|
64
|
+
class="ucl-uikit-datepicker__visible-field css-51hkje"
|
|
65
65
|
data-testid="ucl-uikit-datepicker__visible-field"
|
|
66
66
|
>
|
|
67
67
|
<input
|
|
68
|
-
class="ucl-uikit-datepicker__input css-
|
|
68
|
+
class="ucl-uikit-datepicker__input css-gjp4ve"
|
|
69
69
|
data-testid="ucl-uikit-datepicker__input"
|
|
70
70
|
inputmode="numeric"
|
|
71
71
|
placeholder="DD/MM/YYYY"
|
|
@@ -80,7 +80,7 @@ exports[`Datepicker > Snapshot: with date provided 1`] = `
|
|
|
80
80
|
type="button"
|
|
81
81
|
>
|
|
82
82
|
<svg
|
|
83
|
-
class="ucl-uikit-icon css-
|
|
83
|
+
class="ucl-uikit-icon css-7p0vcp"
|
|
84
84
|
data-testid="ucl-uikit-icon"
|
|
85
85
|
fill="none"
|
|
86
86
|
focusable="false"
|
|
@@ -45,6 +45,7 @@ const DatepickerInput = ({
|
|
|
45
45
|
height: 100%;
|
|
46
46
|
padding: 0 0 0 16px;
|
|
47
47
|
border: none;
|
|
48
|
+
border-radius: ${theme.radius.r4} 0 0 ${theme.radius.r4};
|
|
48
49
|
color: ${theme.colour.text.default};
|
|
49
50
|
background-color: ${theme.colour.fill.inverse};
|
|
50
51
|
font-family: ${md.fontFamily};
|
|
@@ -44,6 +44,7 @@ const VisibleField = ({
|
|
|
44
44
|
height: 100%;
|
|
45
45
|
box-sizing: border-box;
|
|
46
46
|
border: 1px solid ${theme.colour.speciality.inputDefault};
|
|
47
|
+
border-radius: ${theme.radius.r4};
|
|
47
48
|
background-color: ${theme.colour.fill.inverse};
|
|
48
49
|
|
|
49
50
|
&:focus-within {
|
|
@@ -88,7 +89,7 @@ const VisibleField = ({
|
|
|
88
89
|
// TODO: This ought to be fixed in the <Icon> component itself.
|
|
89
90
|
const iconStyle = css`
|
|
90
91
|
min-width: 24px;
|
|
91
|
-
color: ${disabled ? theme.colour.icon.disabled : theme.colour.icon.
|
|
92
|
+
color: ${disabled ? theme.colour.icon.disabled : theme.colour.icon.secondary};
|
|
92
93
|
`;
|
|
93
94
|
|
|
94
95
|
// Determine which icon to show
|
|
@@ -25,6 +25,7 @@ const NativeDatepicker = ({
|
|
|
25
25
|
box-sizing: border-box;
|
|
26
26
|
padding: 0 16px;
|
|
27
27
|
border: 1px solid ${theme.colour.speciality.inputDefault};
|
|
28
|
+
border-radius: ${theme.radius.r4};
|
|
28
29
|
color: ${theme.colour.text.default};
|
|
29
30
|
font-family: ${md.fontFamily};
|
|
30
31
|
font-feature-settings: ${md.fontSettings};
|
|
@@ -604,6 +604,7 @@ const CustomSelect = <T extends string | number>({
|
|
|
604
604
|
font-weight: ${md.fontWeight};
|
|
605
605
|
line-height: ${md.lineHeight}%;
|
|
606
606
|
border: ${theme.border.b1} solid ${theme.colour.speciality.inputDefault};
|
|
607
|
+
border-radius: ${theme.radius.r4};
|
|
607
608
|
cursor: pointer;
|
|
608
609
|
user-select: none;
|
|
609
610
|
|
|
@@ -44,6 +44,7 @@ const NativeSelect = ({
|
|
|
44
44
|
line-height: ${md.lineHeight}%;
|
|
45
45
|
background-color: ${theme.colour.fill.inverse};
|
|
46
46
|
border: ${theme.border.b1} solid ${theme.colour.border.secondary};
|
|
47
|
+
border-radius: ${theme.radius.r4};
|
|
47
48
|
color: ${theme.colour.text.default};
|
|
48
49
|
appearance: none;
|
|
49
50
|
-webkit-appearance: none;
|
|
@@ -7,18 +7,23 @@ import {
|
|
|
7
7
|
useState,
|
|
8
8
|
} from 'react';
|
|
9
9
|
|
|
10
|
-
import { css } from '@emotion/css';
|
|
10
|
+
import { css, cx } from '@emotion/css';
|
|
11
11
|
import useTheme from '../../theme/useTheme';
|
|
12
12
|
import useMediaQuery from '../../hooks/useMediaQuery';
|
|
13
13
|
import Select, { NonClearableSelectProps } from '../Select';
|
|
14
14
|
import ToggleGroupContext from './ToggleGroupContext';
|
|
15
|
-
import
|
|
15
|
+
import ToggleGroupItem, {
|
|
16
|
+
ToggleGroupItemProps,
|
|
17
|
+
} from './subcomponents/ToggleGroupItem';
|
|
18
|
+
|
|
19
|
+
export const NAME = 'ucl-uikit-toggle-group';
|
|
16
20
|
|
|
17
21
|
export interface ToggleGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
18
22
|
children: React.ReactNode;
|
|
19
23
|
value?: string;
|
|
20
24
|
defaultValue?: string;
|
|
21
25
|
onValueChange?: (value: string) => void;
|
|
26
|
+
testId?: string;
|
|
22
27
|
selectProps?: Omit<
|
|
23
28
|
NonClearableSelectProps<string>,
|
|
24
29
|
'options' | 'value' | 'onValueChange'
|
|
@@ -27,7 +32,14 @@ export interface ToggleGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
27
32
|
|
|
28
33
|
const MOBILE_SELECT_ITEM_THRESHOLD = 2;
|
|
29
34
|
|
|
30
|
-
const NAVIGATION_KEYS = [
|
|
35
|
+
const NAVIGATION_KEYS = [
|
|
36
|
+
'ArrowRight',
|
|
37
|
+
'ArrowDown',
|
|
38
|
+
'ArrowLeft',
|
|
39
|
+
'ArrowUp',
|
|
40
|
+
'Home',
|
|
41
|
+
'End',
|
|
42
|
+
];
|
|
31
43
|
|
|
32
44
|
const getEnabledItems = (container: HTMLElement) =>
|
|
33
45
|
Array.from(
|
|
@@ -38,13 +50,13 @@ const getEnabledItems = (container: HTMLElement) =>
|
|
|
38
50
|
|
|
39
51
|
const getItemsFromChildren = (
|
|
40
52
|
children: React.ReactNode
|
|
41
|
-
): React.ReactElement<
|
|
53
|
+
): React.ReactElement<ToggleGroupItemProps>[] =>
|
|
42
54
|
Children.toArray(children).flatMap((child) => {
|
|
43
55
|
if (!isValidElement<{ children?: React.ReactNode }>(child)) {
|
|
44
56
|
return [];
|
|
45
57
|
}
|
|
46
|
-
if (child.type ===
|
|
47
|
-
return [child as React.ReactElement<
|
|
58
|
+
if (child.type === ToggleGroupItem) {
|
|
59
|
+
return [child as React.ReactElement<ToggleGroupItemProps>];
|
|
48
60
|
}
|
|
49
61
|
return getItemsFromChildren(child.props.children);
|
|
50
62
|
});
|
|
@@ -55,6 +67,10 @@ const ToggleGroup = ({
|
|
|
55
67
|
defaultValue,
|
|
56
68
|
onValueChange,
|
|
57
69
|
selectProps,
|
|
70
|
+
className,
|
|
71
|
+
onKeyDown,
|
|
72
|
+
testId = NAME,
|
|
73
|
+
...htmlAttributes
|
|
58
74
|
}: ToggleGroupProps) => {
|
|
59
75
|
const [theme] = useTheme();
|
|
60
76
|
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
@@ -63,6 +79,14 @@ const ToggleGroup = ({
|
|
|
63
79
|
const isMobile = !useMediaQuery(`(min-width: ${theme.breakpoints.tablet}px)`);
|
|
64
80
|
const items = getItemsFromChildren(children);
|
|
65
81
|
const name = useId();
|
|
82
|
+
const hasSublabel = items.some((item) => item.props.sublabel);
|
|
83
|
+
const firstEnabledValue = items.find((item) => !item.props.disabled)?.props
|
|
84
|
+
.value;
|
|
85
|
+
const tabbableValue = items.some(
|
|
86
|
+
(item) => item.props.value === selectedValue && !item.props.disabled
|
|
87
|
+
)
|
|
88
|
+
? selectedValue
|
|
89
|
+
: firstEnabledValue;
|
|
66
90
|
|
|
67
91
|
const setValue = (nextValue: string) => {
|
|
68
92
|
if (!isControlled) {
|
|
@@ -73,6 +97,12 @@ const ToggleGroup = ({
|
|
|
73
97
|
};
|
|
74
98
|
|
|
75
99
|
const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
|
|
100
|
+
onKeyDown?.(event);
|
|
101
|
+
|
|
102
|
+
if (event.defaultPrevented) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
76
106
|
if (!NAVIGATION_KEYS.includes(event.key)) {
|
|
77
107
|
return;
|
|
78
108
|
}
|
|
@@ -91,8 +121,10 @@ const ToggleGroup = ({
|
|
|
91
121
|
const nextIndex =
|
|
92
122
|
{
|
|
93
123
|
ArrowRight: (currentIndex + 1) % enabledItems.length,
|
|
124
|
+
ArrowDown: (currentIndex + 1) % enabledItems.length,
|
|
94
125
|
ArrowLeft:
|
|
95
126
|
(currentIndex - 1 + enabledItems.length) % enabledItems.length,
|
|
127
|
+
ArrowUp: (currentIndex - 1 + enabledItems.length) % enabledItems.length,
|
|
96
128
|
Home: 0,
|
|
97
129
|
End: enabledItems.length - 1,
|
|
98
130
|
}[event.key] ?? currentIndex;
|
|
@@ -104,7 +136,6 @@ const ToggleGroup = ({
|
|
|
104
136
|
|
|
105
137
|
const toggleGroupStyle = css`
|
|
106
138
|
display: flex;
|
|
107
|
-
gap: -1px;
|
|
108
139
|
padding: ${theme.padding.p4};
|
|
109
140
|
background-color: ${theme.colour.fill.subtle};
|
|
110
141
|
border-radius: ${theme.radius.r4};
|
|
@@ -114,6 +145,8 @@ const ToggleGroup = ({
|
|
|
114
145
|
return (
|
|
115
146
|
<Select
|
|
116
147
|
{...selectProps}
|
|
148
|
+
className={cx(NAME, selectProps?.className, className)}
|
|
149
|
+
testId={testId}
|
|
117
150
|
options={items.map((item) => ({
|
|
118
151
|
label: item.props.label,
|
|
119
152
|
value: item.props.value,
|
|
@@ -126,10 +159,18 @@ const ToggleGroup = ({
|
|
|
126
159
|
|
|
127
160
|
return (
|
|
128
161
|
<ToggleGroupContext.Provider
|
|
129
|
-
value={{
|
|
162
|
+
value={{
|
|
163
|
+
value: selectedValue,
|
|
164
|
+
setValue,
|
|
165
|
+
name,
|
|
166
|
+
tabbableValue,
|
|
167
|
+
hasSublabel,
|
|
168
|
+
}}
|
|
130
169
|
>
|
|
131
170
|
<div
|
|
132
|
-
|
|
171
|
+
{...htmlAttributes}
|
|
172
|
+
className={cx(NAME, toggleGroupStyle, className)}
|
|
173
|
+
data-testid={testId}
|
|
133
174
|
role='radiogroup'
|
|
134
175
|
onKeyDown={handleKeyDown}
|
|
135
176
|
>
|
|
@@ -139,6 +180,6 @@ const ToggleGroup = ({
|
|
|
139
180
|
);
|
|
140
181
|
};
|
|
141
182
|
|
|
142
|
-
ToggleGroup.Item =
|
|
183
|
+
ToggleGroup.Item = ToggleGroupItem;
|
|
143
184
|
|
|
144
185
|
export default ToggleGroup;
|
|
@@ -4,6 +4,8 @@ export interface ToggleGroupContextType {
|
|
|
4
4
|
value: string | undefined;
|
|
5
5
|
setValue: (value: string) => void;
|
|
6
6
|
name: string;
|
|
7
|
+
tabbableValue: string | undefined;
|
|
8
|
+
hasSublabel: boolean;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
const ToggleGroupContext = createContext<ToggleGroupContextType | undefined>(
|