@automattic/vip-design-system 2.8.2 → 2.9.0
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/build/system/Form/RadioBoxGroup.js +100 -8
- package/build/system/Form/RadioBoxGroup.stories.d.ts +8 -0
- package/build/system/Form/RadioBoxGroup.stories.jsx +51 -0
- package/build/system/Form/RadioBoxGroup.test.d.ts +1 -0
- package/build/system/Form/RadioBoxGroup.test.jsx +47 -0
- package/build/system/Tooltip/Tooltip.stories.js +1 -1
- package/package.json +1 -1
- package/src/system/Form/RadioBoxGroup.js +100 -8
- package/src/system/Form/RadioBoxGroup.stories.jsx +51 -0
- package/src/system/Form/RadioBoxGroup.test.jsx +47 -0
- package/src/system/Tooltip/Tooltip.stories.tsx +1 -1
|
@@ -94,16 +94,103 @@ const RadioOption = ( {
|
|
|
94
94
|
);
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
const ChipOption = ( {
|
|
98
|
+
defaultValue,
|
|
99
|
+
option: { id, value, label },
|
|
100
|
+
name,
|
|
101
|
+
disabled,
|
|
102
|
+
onChangeHandler,
|
|
103
|
+
} ) => {
|
|
104
|
+
const checked = `${ defaultValue }` === `${ value }`;
|
|
105
|
+
const forLabel = id || value;
|
|
106
|
+
const ref = React.useRef( null );
|
|
107
|
+
const describedById = `input-radio-box-${ forLabel }-description`;
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<div
|
|
111
|
+
id={ `o${ forLabel }` }
|
|
112
|
+
onClick={ () => {
|
|
113
|
+
ref.current?.click();
|
|
114
|
+
} }
|
|
115
|
+
sx={ {
|
|
116
|
+
display: 'inline-flex',
|
|
117
|
+
position: 'relative',
|
|
118
|
+
background: checked ? 'layer.4' : undefined,
|
|
119
|
+
color: 'text',
|
|
120
|
+
minHeight: '32px',
|
|
121
|
+
boxShadow: checked ? 'low' : undefined,
|
|
122
|
+
'&:hover': {
|
|
123
|
+
background: checked ? 'layer.4' : 'layer.1',
|
|
124
|
+
},
|
|
125
|
+
borderRadius: 1,
|
|
126
|
+
} }
|
|
127
|
+
>
|
|
128
|
+
<input
|
|
129
|
+
ref={ ref }
|
|
130
|
+
type="radio"
|
|
131
|
+
id={ forLabel }
|
|
132
|
+
disabled={ disabled }
|
|
133
|
+
name={ name }
|
|
134
|
+
checked={ checked }
|
|
135
|
+
aria-checked={ checked }
|
|
136
|
+
value={ value }
|
|
137
|
+
onChange={ onChangeHandler }
|
|
138
|
+
aria-labelledby={ describedById }
|
|
139
|
+
sx={ {
|
|
140
|
+
opacity: 0,
|
|
141
|
+
height: 0,
|
|
142
|
+
width: 0,
|
|
143
|
+
position: 'absolute',
|
|
144
|
+
'&:focus-visible + label': theme => theme.outline,
|
|
145
|
+
} }
|
|
146
|
+
/>
|
|
147
|
+
|
|
148
|
+
<label
|
|
149
|
+
id={ describedById }
|
|
150
|
+
htmlFor={ forLabel }
|
|
151
|
+
sx={ {
|
|
152
|
+
height: '100%',
|
|
153
|
+
display: 'flex',
|
|
154
|
+
flexDirection: 'column',
|
|
155
|
+
justifyContent: 'center',
|
|
156
|
+
width: '100%',
|
|
157
|
+
px: 3,
|
|
158
|
+
fontWeight: 400,
|
|
159
|
+
fontSize: 2,
|
|
160
|
+
cursor: 'pointer',
|
|
161
|
+
borderRadius: 1,
|
|
162
|
+
} }
|
|
163
|
+
>
|
|
164
|
+
{ label }
|
|
165
|
+
</label>
|
|
166
|
+
</div>
|
|
167
|
+
);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
ChipOption.propTypes = RadioOption.propTypes = {
|
|
98
171
|
defaultValue: PropTypes.string,
|
|
99
172
|
option: PropTypes.object,
|
|
100
173
|
name: PropTypes.string,
|
|
101
174
|
onChangeHandler: PropTypes.func,
|
|
102
|
-
checked: PropTypes.bool,
|
|
103
175
|
disabled: PropTypes.bool,
|
|
104
176
|
width: PropTypes.string,
|
|
105
177
|
};
|
|
106
178
|
|
|
179
|
+
const groupStyleOverrides = {
|
|
180
|
+
chip: {
|
|
181
|
+
background: 'layer.3',
|
|
182
|
+
p: 1,
|
|
183
|
+
display: 'inline-flex',
|
|
184
|
+
gap: 1,
|
|
185
|
+
borderRadius: 1,
|
|
186
|
+
},
|
|
187
|
+
primary: {
|
|
188
|
+
display: 'inline-block',
|
|
189
|
+
mb: 2,
|
|
190
|
+
p: 0,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
107
194
|
const RadioBoxGroup = React.forwardRef(
|
|
108
195
|
(
|
|
109
196
|
{
|
|
@@ -117,6 +204,7 @@ const RadioBoxGroup = React.forwardRef(
|
|
|
117
204
|
errorMessage,
|
|
118
205
|
hasError,
|
|
119
206
|
required,
|
|
207
|
+
variant = 'primary',
|
|
120
208
|
...props
|
|
121
209
|
},
|
|
122
210
|
forwardRef
|
|
@@ -131,8 +219,13 @@ const RadioBoxGroup = React.forwardRef(
|
|
|
131
219
|
[ onChange ]
|
|
132
220
|
);
|
|
133
221
|
|
|
222
|
+
let Option = RadioOption;
|
|
223
|
+
if ( variant === 'chip' ) {
|
|
224
|
+
Option = ChipOption;
|
|
225
|
+
}
|
|
226
|
+
|
|
134
227
|
const renderedOptions = options.map( option => (
|
|
135
|
-
<
|
|
228
|
+
<Option
|
|
136
229
|
defaultValue={ defaultValue }
|
|
137
230
|
disabled={ disabled }
|
|
138
231
|
key={ option?.id || option?.value }
|
|
@@ -148,11 +241,9 @@ const RadioBoxGroup = React.forwardRef(
|
|
|
148
241
|
<fieldset
|
|
149
242
|
sx={ {
|
|
150
243
|
border: 0,
|
|
151
|
-
|
|
152
|
-
display: 'inline-block',
|
|
153
|
-
mb: 2,
|
|
244
|
+
...groupStyleOverrides[ variant ],
|
|
154
245
|
...( hasError
|
|
155
|
-
? { border: '1px solid', borderColor: 'input.border.error', borderRadius: 2 }
|
|
246
|
+
? { border: '1px solid', borderColor: 'input.border.error', borderRadius: 2, p: 2 }
|
|
156
247
|
: {} ),
|
|
157
248
|
} }
|
|
158
249
|
ref={ forwardRef }
|
|
@@ -171,7 +262,7 @@ const RadioBoxGroup = React.forwardRef(
|
|
|
171
262
|
<div
|
|
172
263
|
sx={ {
|
|
173
264
|
display: 'flex',
|
|
174
|
-
gap: 2,
|
|
265
|
+
gap: variant === 'chip' ? 1 : 2,
|
|
175
266
|
} }
|
|
176
267
|
>
|
|
177
268
|
{ renderedOptions }
|
|
@@ -202,6 +293,7 @@ RadioBoxGroup.propTypes = {
|
|
|
202
293
|
errorMessage: PropTypes.string,
|
|
203
294
|
hasError: PropTypes.bool,
|
|
204
295
|
required: PropTypes.bool,
|
|
296
|
+
variant: PropTypes.oneOf( [ 'primary', 'chip' ] ),
|
|
205
297
|
};
|
|
206
298
|
|
|
207
299
|
export { RadioBoxGroup };
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
declare namespace _default {
|
|
2
2
|
export let title: string;
|
|
3
3
|
export { RadioBoxGroup as component };
|
|
4
|
+
export namespace parameters {
|
|
5
|
+
namespace docs {
|
|
6
|
+
namespace description {
|
|
7
|
+
let component: string;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
4
11
|
}
|
|
5
12
|
export default _default;
|
|
6
13
|
export function Default(): import("react").JSX.Element;
|
|
7
14
|
export function Errors(): import("react").JSX.Element;
|
|
15
|
+
export function ChipVariant(): import("react").JSX.Element;
|
|
8
16
|
import { RadioBoxGroup } from '..';
|
|
@@ -11,6 +11,31 @@ import { RadioBoxGroup } from '..';
|
|
|
11
11
|
export default {
|
|
12
12
|
title: 'RadioBoxGroup',
|
|
13
13
|
component: RadioBoxGroup,
|
|
14
|
+
parameters: {
|
|
15
|
+
docs: {
|
|
16
|
+
description: {
|
|
17
|
+
component: `
|
|
18
|
+
A radio-box-group is a group of radio buttons that are styled as boxes. This component is used
|
|
19
|
+
to allow users to select one option from a list of options.
|
|
20
|
+
|
|
21
|
+
## Guidance
|
|
22
|
+
|
|
23
|
+
### When to use the component
|
|
24
|
+
|
|
25
|
+
- <strong>Select an option in a form.</strong> Use a radio-box-group when you want users to select
|
|
26
|
+
a single option from a list of options.
|
|
27
|
+
- <strong>Use as a toggle-group.</strong> Use a radio-box-group with the chip variant when you want
|
|
28
|
+
to allow users to toggle between different options.
|
|
29
|
+
|
|
30
|
+
-------
|
|
31
|
+
|
|
32
|
+
This documentation is heavily inspired by the [U.S Web Design System (USWDS)](https://designsystem.digital.gov/components/tooltip/#package). We use USWDS as trusted source of truth for accessibility and usability best practices.
|
|
33
|
+
|
|
34
|
+
## Component Properties
|
|
35
|
+
`,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
14
39
|
};
|
|
15
40
|
|
|
16
41
|
const options = [
|
|
@@ -58,3 +83,29 @@ export const Errors = () => {
|
|
|
58
83
|
/>
|
|
59
84
|
);
|
|
60
85
|
};
|
|
86
|
+
|
|
87
|
+
export const ChipVariant = () => {
|
|
88
|
+
const [ value, setValue ] = useState( 'table' );
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<RadioBoxGroup
|
|
92
|
+
defaultValue={ value }
|
|
93
|
+
onChange={ e => setValue( e.target.value ) }
|
|
94
|
+
options={ [
|
|
95
|
+
{
|
|
96
|
+
label: 'Table',
|
|
97
|
+
value: 'table',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
label: 'Grid',
|
|
101
|
+
value: 'grid',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
label: 'Card',
|
|
105
|
+
value: 'card',
|
|
106
|
+
},
|
|
107
|
+
] }
|
|
108
|
+
variant="chip"
|
|
109
|
+
/>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { render, screen } from '@testing-library/react';
|
|
5
|
+
import { axe } from 'jest-axe';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { RadioBoxGroup } from './RadioBoxGroup';
|
|
11
|
+
|
|
12
|
+
const defaultProps = {
|
|
13
|
+
options: [
|
|
14
|
+
{
|
|
15
|
+
label: 'One',
|
|
16
|
+
value: 'one',
|
|
17
|
+
description: 'This is desc 1',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: 'Two',
|
|
21
|
+
value: 'two',
|
|
22
|
+
description: 'This is desc 2',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
label: 'Three',
|
|
26
|
+
value: 'three',
|
|
27
|
+
description: 'This is desc 3',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
onChange: jest.fn(),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
describe( '<RadioBoxGroup />', () => {
|
|
34
|
+
it.each( [ 'primary', 'chip' ] )( 'renders the default variant', async variant => {
|
|
35
|
+
const { container } = render( <RadioBoxGroup { ...defaultProps } variant={ variant } /> );
|
|
36
|
+
|
|
37
|
+
const dom = await screen.findAllByRole( 'radio' );
|
|
38
|
+
|
|
39
|
+
expect( dom ).toHaveLength( 3 );
|
|
40
|
+
expect( dom[ 0 ] ).toHaveAttribute( 'value', 'one' );
|
|
41
|
+
expect( dom[ 1 ] ).toHaveAttribute( 'value', 'two' );
|
|
42
|
+
expect( dom[ 2 ] ).toHaveAttribute( 'value', 'three' );
|
|
43
|
+
|
|
44
|
+
// Check for accessibility issues
|
|
45
|
+
expect( await axe( container ) ).toHaveNoViolations();
|
|
46
|
+
} );
|
|
47
|
+
} );
|
|
@@ -13,7 +13,7 @@ var _default = exports["default"] = {
|
|
|
13
13
|
parameters: {
|
|
14
14
|
docs: {
|
|
15
15
|
description: {
|
|
16
|
-
component: "\nA tooltip is a short descriptive message that appears when a user hovers or focuses on an\nelement. Our tooltip aims to be 100% CSS-only. It uses a global css approach to inject the\ntooltip styles.\n\n##
|
|
16
|
+
component: "\nA tooltip is a short descriptive message that appears when a user hovers or focuses on an\nelement. Our tooltip aims to be 100% CSS-only. It uses a global css approach to inject the\ntooltip styles.\n\n## Known issues\n\n- Storybook uses iframes to render the components. This means that the tooltip box will overlap in the demos, but you can click on each demo page to see the correct render.\n- The current implementation of this component is <strong>NOT</strong> protected from viewport\nclipping (collision). For now, you can pick another <code>vip-tooltip-position</code> if\npossible.\n\n## Guidance\n\n### When to use the tooltip component\n\n- <strong>Helpful, non-critical information.</strong> Use tooltips to strengthen an existing\nmessage.\n- <strong>Enhance confidence.</strong> Use tooltips to increase certainty about an\ninteraction.\n- <strong>Brief descriptions.</strong> Tooltips perform best with succinct helper text.\n- <strong>Lack of space.</strong> Tooltips are useful as a last resort for space-constrained\nUI. Explore other options for keeping content visible without a tooltip.\n\n### When to consider something else\n\n- <strong>Critical information.</strong> Don't hide information necessary for completing\na task behind an tooltip interaction.\n- <strong>Lengthy descriptions.</strong> Tooltips are microcopy, and should be brief.\nDon't use a tooltip if you need a lot of text.\n- <strong>Redundant content.</strong> Don't use a tooltip when its content is repetitive\nor if usability is obvious.\n- <strong>Sufficient space.</strong> If content can fit outside a tooltip, don't use a\ntooltip.\n\n## Using the component\n\n- <strong>Use affordances.</strong> A hidden tooltip is unusable. Use tooltips only on\nelements that appear interactive, like buttons or links.\n- <strong>Avoid collisions.</strong> Be careful not introduce conflicting hover or focus\nevents.\n- <strong>Use consistently.</strong> If using tooltips in one context, use in all similar\ncontexts.\n- <strong>Don't block content.</strong> Use the <code>vip-tooltip-position</code> attribute to\nprevent the tooltip from covering other page elements.\n\n-------\n\nThis documentation is heavily inspired by the [U.S Web Design System (USWDS)](https://designsystem.digital.gov/components/tooltip/#package). We use USWDS as trusted source of truth for accessibility and usability best practices.\n\n## Component Properties\n"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
}
|
package/package.json
CHANGED
|
@@ -94,16 +94,103 @@ const RadioOption = ( {
|
|
|
94
94
|
);
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
const ChipOption = ( {
|
|
98
|
+
defaultValue,
|
|
99
|
+
option: { id, value, label },
|
|
100
|
+
name,
|
|
101
|
+
disabled,
|
|
102
|
+
onChangeHandler,
|
|
103
|
+
} ) => {
|
|
104
|
+
const checked = `${ defaultValue }` === `${ value }`;
|
|
105
|
+
const forLabel = id || value;
|
|
106
|
+
const ref = React.useRef( null );
|
|
107
|
+
const describedById = `input-radio-box-${ forLabel }-description`;
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<div
|
|
111
|
+
id={ `o${ forLabel }` }
|
|
112
|
+
onClick={ () => {
|
|
113
|
+
ref.current?.click();
|
|
114
|
+
} }
|
|
115
|
+
sx={ {
|
|
116
|
+
display: 'inline-flex',
|
|
117
|
+
position: 'relative',
|
|
118
|
+
background: checked ? 'layer.4' : undefined,
|
|
119
|
+
color: 'text',
|
|
120
|
+
minHeight: '32px',
|
|
121
|
+
boxShadow: checked ? 'low' : undefined,
|
|
122
|
+
'&:hover': {
|
|
123
|
+
background: checked ? 'layer.4' : 'layer.1',
|
|
124
|
+
},
|
|
125
|
+
borderRadius: 1,
|
|
126
|
+
} }
|
|
127
|
+
>
|
|
128
|
+
<input
|
|
129
|
+
ref={ ref }
|
|
130
|
+
type="radio"
|
|
131
|
+
id={ forLabel }
|
|
132
|
+
disabled={ disabled }
|
|
133
|
+
name={ name }
|
|
134
|
+
checked={ checked }
|
|
135
|
+
aria-checked={ checked }
|
|
136
|
+
value={ value }
|
|
137
|
+
onChange={ onChangeHandler }
|
|
138
|
+
aria-labelledby={ describedById }
|
|
139
|
+
sx={ {
|
|
140
|
+
opacity: 0,
|
|
141
|
+
height: 0,
|
|
142
|
+
width: 0,
|
|
143
|
+
position: 'absolute',
|
|
144
|
+
'&:focus-visible + label': theme => theme.outline,
|
|
145
|
+
} }
|
|
146
|
+
/>
|
|
147
|
+
|
|
148
|
+
<label
|
|
149
|
+
id={ describedById }
|
|
150
|
+
htmlFor={ forLabel }
|
|
151
|
+
sx={ {
|
|
152
|
+
height: '100%',
|
|
153
|
+
display: 'flex',
|
|
154
|
+
flexDirection: 'column',
|
|
155
|
+
justifyContent: 'center',
|
|
156
|
+
width: '100%',
|
|
157
|
+
px: 3,
|
|
158
|
+
fontWeight: 400,
|
|
159
|
+
fontSize: 2,
|
|
160
|
+
cursor: 'pointer',
|
|
161
|
+
borderRadius: 1,
|
|
162
|
+
} }
|
|
163
|
+
>
|
|
164
|
+
{ label }
|
|
165
|
+
</label>
|
|
166
|
+
</div>
|
|
167
|
+
);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
ChipOption.propTypes = RadioOption.propTypes = {
|
|
98
171
|
defaultValue: PropTypes.string,
|
|
99
172
|
option: PropTypes.object,
|
|
100
173
|
name: PropTypes.string,
|
|
101
174
|
onChangeHandler: PropTypes.func,
|
|
102
|
-
checked: PropTypes.bool,
|
|
103
175
|
disabled: PropTypes.bool,
|
|
104
176
|
width: PropTypes.string,
|
|
105
177
|
};
|
|
106
178
|
|
|
179
|
+
const groupStyleOverrides = {
|
|
180
|
+
chip: {
|
|
181
|
+
background: 'layer.3',
|
|
182
|
+
p: 1,
|
|
183
|
+
display: 'inline-flex',
|
|
184
|
+
gap: 1,
|
|
185
|
+
borderRadius: 1,
|
|
186
|
+
},
|
|
187
|
+
primary: {
|
|
188
|
+
display: 'inline-block',
|
|
189
|
+
mb: 2,
|
|
190
|
+
p: 0,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
107
194
|
const RadioBoxGroup = React.forwardRef(
|
|
108
195
|
(
|
|
109
196
|
{
|
|
@@ -117,6 +204,7 @@ const RadioBoxGroup = React.forwardRef(
|
|
|
117
204
|
errorMessage,
|
|
118
205
|
hasError,
|
|
119
206
|
required,
|
|
207
|
+
variant = 'primary',
|
|
120
208
|
...props
|
|
121
209
|
},
|
|
122
210
|
forwardRef
|
|
@@ -131,8 +219,13 @@ const RadioBoxGroup = React.forwardRef(
|
|
|
131
219
|
[ onChange ]
|
|
132
220
|
);
|
|
133
221
|
|
|
222
|
+
let Option = RadioOption;
|
|
223
|
+
if ( variant === 'chip' ) {
|
|
224
|
+
Option = ChipOption;
|
|
225
|
+
}
|
|
226
|
+
|
|
134
227
|
const renderedOptions = options.map( option => (
|
|
135
|
-
<
|
|
228
|
+
<Option
|
|
136
229
|
defaultValue={ defaultValue }
|
|
137
230
|
disabled={ disabled }
|
|
138
231
|
key={ option?.id || option?.value }
|
|
@@ -148,11 +241,9 @@ const RadioBoxGroup = React.forwardRef(
|
|
|
148
241
|
<fieldset
|
|
149
242
|
sx={ {
|
|
150
243
|
border: 0,
|
|
151
|
-
|
|
152
|
-
display: 'inline-block',
|
|
153
|
-
mb: 2,
|
|
244
|
+
...groupStyleOverrides[ variant ],
|
|
154
245
|
...( hasError
|
|
155
|
-
? { border: '1px solid', borderColor: 'input.border.error', borderRadius: 2 }
|
|
246
|
+
? { border: '1px solid', borderColor: 'input.border.error', borderRadius: 2, p: 2 }
|
|
156
247
|
: {} ),
|
|
157
248
|
} }
|
|
158
249
|
ref={ forwardRef }
|
|
@@ -171,7 +262,7 @@ const RadioBoxGroup = React.forwardRef(
|
|
|
171
262
|
<div
|
|
172
263
|
sx={ {
|
|
173
264
|
display: 'flex',
|
|
174
|
-
gap: 2,
|
|
265
|
+
gap: variant === 'chip' ? 1 : 2,
|
|
175
266
|
} }
|
|
176
267
|
>
|
|
177
268
|
{ renderedOptions }
|
|
@@ -202,6 +293,7 @@ RadioBoxGroup.propTypes = {
|
|
|
202
293
|
errorMessage: PropTypes.string,
|
|
203
294
|
hasError: PropTypes.bool,
|
|
204
295
|
required: PropTypes.bool,
|
|
296
|
+
variant: PropTypes.oneOf( [ 'primary', 'chip' ] ),
|
|
205
297
|
};
|
|
206
298
|
|
|
207
299
|
export { RadioBoxGroup };
|
|
@@ -11,6 +11,31 @@ import { RadioBoxGroup } from '..';
|
|
|
11
11
|
export default {
|
|
12
12
|
title: 'RadioBoxGroup',
|
|
13
13
|
component: RadioBoxGroup,
|
|
14
|
+
parameters: {
|
|
15
|
+
docs: {
|
|
16
|
+
description: {
|
|
17
|
+
component: `
|
|
18
|
+
A radio-box-group is a group of radio buttons that are styled as boxes. This component is used
|
|
19
|
+
to allow users to select one option from a list of options.
|
|
20
|
+
|
|
21
|
+
## Guidance
|
|
22
|
+
|
|
23
|
+
### When to use the component
|
|
24
|
+
|
|
25
|
+
- <strong>Select an option in a form.</strong> Use a radio-box-group when you want users to select
|
|
26
|
+
a single option from a list of options.
|
|
27
|
+
- <strong>Use as a toggle-group.</strong> Use a radio-box-group with the chip variant when you want
|
|
28
|
+
to allow users to toggle between different options.
|
|
29
|
+
|
|
30
|
+
-------
|
|
31
|
+
|
|
32
|
+
This documentation is heavily inspired by the [U.S Web Design System (USWDS)](https://designsystem.digital.gov/components/tooltip/#package). We use USWDS as trusted source of truth for accessibility and usability best practices.
|
|
33
|
+
|
|
34
|
+
## Component Properties
|
|
35
|
+
`,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
14
39
|
};
|
|
15
40
|
|
|
16
41
|
const options = [
|
|
@@ -58,3 +83,29 @@ export const Errors = () => {
|
|
|
58
83
|
/>
|
|
59
84
|
);
|
|
60
85
|
};
|
|
86
|
+
|
|
87
|
+
export const ChipVariant = () => {
|
|
88
|
+
const [ value, setValue ] = useState( 'table' );
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<RadioBoxGroup
|
|
92
|
+
defaultValue={ value }
|
|
93
|
+
onChange={ e => setValue( e.target.value ) }
|
|
94
|
+
options={ [
|
|
95
|
+
{
|
|
96
|
+
label: 'Table',
|
|
97
|
+
value: 'table',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
label: 'Grid',
|
|
101
|
+
value: 'grid',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
label: 'Card',
|
|
105
|
+
value: 'card',
|
|
106
|
+
},
|
|
107
|
+
] }
|
|
108
|
+
variant="chip"
|
|
109
|
+
/>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { render, screen } from '@testing-library/react';
|
|
5
|
+
import { axe } from 'jest-axe';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { RadioBoxGroup } from './RadioBoxGroup';
|
|
11
|
+
|
|
12
|
+
const defaultProps = {
|
|
13
|
+
options: [
|
|
14
|
+
{
|
|
15
|
+
label: 'One',
|
|
16
|
+
value: 'one',
|
|
17
|
+
description: 'This is desc 1',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: 'Two',
|
|
21
|
+
value: 'two',
|
|
22
|
+
description: 'This is desc 2',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
label: 'Three',
|
|
26
|
+
value: 'three',
|
|
27
|
+
description: 'This is desc 3',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
onChange: jest.fn(),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
describe( '<RadioBoxGroup />', () => {
|
|
34
|
+
it.each( [ 'primary', 'chip' ] )( 'renders the default variant', async variant => {
|
|
35
|
+
const { container } = render( <RadioBoxGroup { ...defaultProps } variant={ variant } /> );
|
|
36
|
+
|
|
37
|
+
const dom = await screen.findAllByRole( 'radio' );
|
|
38
|
+
|
|
39
|
+
expect( dom ).toHaveLength( 3 );
|
|
40
|
+
expect( dom[ 0 ] ).toHaveAttribute( 'value', 'one' );
|
|
41
|
+
expect( dom[ 1 ] ).toHaveAttribute( 'value', 'two' );
|
|
42
|
+
expect( dom[ 2 ] ).toHaveAttribute( 'value', 'three' );
|
|
43
|
+
|
|
44
|
+
// Check for accessibility issues
|
|
45
|
+
expect( await axe( container ) ).toHaveNoViolations();
|
|
46
|
+
} );
|
|
47
|
+
} );
|
|
@@ -14,7 +14,7 @@ A tooltip is a short descriptive message that appears when a user hovers or focu
|
|
|
14
14
|
element. Our tooltip aims to be 100% CSS-only. It uses a global css approach to inject the
|
|
15
15
|
tooltip styles.
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Known issues
|
|
18
18
|
|
|
19
19
|
- Storybook uses iframes to render the components. This means that the tooltip box will overlap in the demos, but you can click on each demo page to see the correct render.
|
|
20
20
|
- The current implementation of this component is <strong>NOT</strong> protected from viewport
|