@splunk/react-ui 5.7.1 → 5.8.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/Accordion.js +6 -6
- package/Box.js +83 -34
- package/CHANGELOG.md +29 -0
- package/CollapsiblePanel.js +11 -11
- package/ComboBox.js +31 -27
- package/ControlGroup.js +92 -91
- package/DefinitionList.js +9 -9
- package/Drawer.d.ts +2 -0
- package/Drawer.js +679 -0
- package/DualListbox.js +1 -1
- package/JSONTree.js +73 -72
- package/Link.js +2 -2
- package/MIGRATION.md +10 -0
- package/Menu.js +338 -240
- package/Modal.js +127 -109
- package/Multiselect.js +437 -351
- package/Paginator.js +14 -12
- package/Popover.js +4 -1
- package/README.md +11 -0
- package/RadioBar.js +1 -1
- package/Search.js +103 -88
- package/Select.js +42 -40
- package/SelectBase.js +374 -328
- package/SidePanel.js +346 -167
- package/SlidingPanels.js +11 -11
- package/StepBar.js +7 -7
- package/Switch.js +5 -5
- package/Text.js +24 -24
- package/TextArea.js +7 -7
- package/TransitionOpen.js +188 -169
- package/docs-llm/Accordion.md +267 -0
- package/docs-llm/Anchor Menu.md +115 -0
- package/docs-llm/Anchor.md +54 -0
- package/docs-llm/AnimationToggle.md +254 -0
- package/docs-llm/Avatar.md +298 -0
- package/docs-llm/Badge.md +212 -0
- package/docs-llm/Breadcrumbs.md +306 -0
- package/docs-llm/Button Group.md +53 -0
- package/docs-llm/Button.md +361 -0
- package/docs-llm/Card Layout.md +286 -0
- package/docs-llm/Card.md +619 -0
- package/docs-llm/Checkbox.md +218 -0
- package/docs-llm/Chip.md +291 -0
- package/docs-llm/Clickable.md +160 -0
- package/docs-llm/Code.md +292 -0
- package/docs-llm/Collapsible Panel.md +744 -0
- package/docs-llm/Color.md +253 -0
- package/docs-llm/Column Layout.md +391 -0
- package/docs-llm/Combo Box.md +540 -0
- package/docs-llm/Control Group.md +594 -0
- package/docs-llm/Date.md +270 -0
- package/docs-llm/Definition List.md +278 -0
- package/docs-llm/Divider.md +216 -0
- package/docs-llm/Drawer.md +414 -0
- package/docs-llm/Dropdown.md +472 -0
- package/docs-llm/Dual Listbox.md +325 -0
- package/docs-llm/File.md +653 -0
- package/docs-llm/Form Rows.md +374 -0
- package/docs-llm/Heading.md +179 -0
- package/docs-llm/Image.md +109 -0
- package/docs-llm/JSON Tree.md +260 -0
- package/docs-llm/Layer.md +74 -0
- package/docs-llm/Layout.md +50 -0
- package/docs-llm/Link.md +318 -0
- package/docs-llm/List.md +189 -0
- package/docs-llm/Markdown.md +179 -0
- package/docs-llm/Menu.md +735 -0
- package/docs-llm/Message Bar.md +236 -0
- package/docs-llm/Message.md +248 -0
- package/docs-llm/Modal.md +443 -0
- package/docs-llm/Monogram.md +159 -0
- package/docs-llm/Multiselect.md +937 -0
- package/docs-llm/Number.md +298 -0
- package/docs-llm/Paginator.md +395 -0
- package/docs-llm/Paragraph.md +148 -0
- package/docs-llm/Phone Number.md +254 -0
- package/docs-llm/Popover.md +166 -0
- package/docs-llm/Progress.md +141 -0
- package/docs-llm/Radio Bar.md +303 -0
- package/docs-llm/Radio List.md +350 -0
- package/docs-llm/Resize.md +362 -0
- package/docs-llm/Screen Reader Content.md +73 -0
- package/docs-llm/Scroll Container Context.md +155 -0
- package/docs-llm/Scroll.md +152 -0
- package/docs-llm/Search.md +381 -0
- package/docs-llm/Select.md +985 -0
- package/docs-llm/Side Panel.md +777 -0
- package/docs-llm/Slider.md +339 -0
- package/docs-llm/Sliding Panels.md +340 -0
- package/docs-llm/Split Button.md +295 -0
- package/docs-llm/Static Content.md +90 -0
- package/docs-llm/Step Bar.md +292 -0
- package/docs-llm/Switch.md +268 -0
- package/docs-llm/Tab Bar.md +439 -0
- package/docs-llm/Tab Layout.md +398 -0
- package/docs-llm/Table.md +2642 -0
- package/docs-llm/Text Area.md +253 -0
- package/docs-llm/Text.md +339 -0
- package/docs-llm/Tooltip.md +325 -0
- package/docs-llm/Transition Open.md +406 -0
- package/docs-llm/Tree.md +586 -0
- package/docs-llm/Typography.md +125 -0
- package/docs-llm/Wait Spinner.md +121 -0
- package/docs-llm/llms.txt +97 -0
- package/package.json +6 -5
- package/types/src/Box/Box.d.ts +2 -10
- package/types/src/Drawer/Body.d.ts +17 -0
- package/types/src/Drawer/Drawer.d.ts +114 -0
- package/types/src/Drawer/DrawerContext.d.ts +11 -0
- package/types/src/Drawer/Footer.d.ts +25 -0
- package/types/src/Drawer/Header.d.ts +41 -0
- package/types/src/Drawer/docs/examples/Basic.d.ts +6 -0
- package/types/src/Drawer/docs/examples/ContainerPosition.d.ts +7 -0
- package/types/src/Drawer/docs/examples/InitialFocus.d.ts +9 -0
- package/types/src/Drawer/docs/examples/InlinePosition.d.ts +7 -0
- package/types/src/Drawer/docs/examples/PagePosition.d.ts +7 -0
- package/types/src/Drawer/index.d.ts +2 -0
- package/types/src/JSONTree/JSONTree.d.ts +12 -5
- package/types/src/JSONTree/renderTreeItems.d.ts +2 -1
- package/types/src/Menu/Item.d.ts +2 -1
- package/types/src/Menu/docs/examples/SelectableCheckbox.d.ts +7 -0
- package/types/src/Modal/Modal.d.ts +1 -2
- package/types/src/Select/Option.d.ts +6 -3
- package/types/src/Select/Select.d.ts +8 -5
- package/types/src/Select/docs/examples/Dimmed.d.ts +7 -0
- package/types/src/SelectBase/OptionBase.d.ts +6 -3
- package/types/src/SelectBase/SelectBase.d.ts +8 -3
- package/types/src/SidePanel/SidePanel.d.ts +43 -2
- package/types/src/SidePanel/docs/examples/DockLayout.d.ts +17 -0
- package/types/src/SidePanel/docs/examples/InitialFocus.d.ts +9 -0
- package/types/src/TransitionOpen/TransitionOpen.d.ts +29 -4
- package/types/src/useKeyPress/index.d.ts +9 -2
- package/types/src/useOnClickOutside/index.d.ts +2 -0
- package/types/src/useOnClickOutside/useOnClickOutside.d.ts +4 -0
- package/useKeyPress.js +23 -18
- package/useOnClickOutside.d.ts +2 -0
- package/useOnClickOutside.js +79 -0
- package/types/src/RadioList/docs/examples/Row.d.ts +0 -6
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# Radio List
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
> Image: Illustration of a Radio List component.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## When to use this component
|
|
10
|
+
- To select a single option from a set of two or more that are mutually exclusive.
|
|
11
|
+
- Exposing all available options would benefits the user.
|
|
12
|
+
|
|
13
|
+
## When to use another component
|
|
14
|
+
- The options a user has are opposing states (e.g. on/off, before/after). Use a Switch instead.
|
|
15
|
+
- More than one option can be selected; use a Checkbox or Multiselect component.
|
|
16
|
+
- Visual indicators (like icons for Radio Bar) help the user find an option faster.
|
|
17
|
+
- Options can be collapsed; use Select or Combo Box to conserve space.
|
|
18
|
+
|
|
19
|
+
```mermaid
|
|
20
|
+
graph TD
|
|
21
|
+
accDescr: Decision tree that guides on when to use the RadioList component or something else
|
|
22
|
+
A(Are there fewer than 8 options?) -- Yes --- B("Do the options have long labels or you don't need to conserve vertical space?")
|
|
23
|
+
B -- Yes --- C(Radio List)
|
|
24
|
+
B -- No --- D(Radio Bar)
|
|
25
|
+
A -- No --- E(Select or Combo Box)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Check out
|
|
29
|
+
- [Switch][1]
|
|
30
|
+
- [Multiselect][2]
|
|
31
|
+
- [Select][3]
|
|
32
|
+
- [Radio Bar][4]
|
|
33
|
+
- [Combo Box][5]
|
|
34
|
+
|
|
35
|
+
## Behaviors
|
|
36
|
+
|
|
37
|
+
### Customization
|
|
38
|
+
Child elements, like a text input, can be included if necessary.
|
|
39
|
+
|
|
40
|
+
> Image: Image of a Radio List with the label,
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### Always include a label
|
|
46
|
+
> Image: Examples of a Radio List with the three options,
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### Make options distinct
|
|
50
|
+
Users should be able to easily differentiate between options.
|
|
51
|
+
> Image: Examples of mutual exclusivity: The first example with the heart eyes emoji shows a Radio List with the options,
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
### List options in a logical order
|
|
55
|
+
Order your list of options in a way that will make the most sense. Possible orders include:
|
|
56
|
+
- Most likely to least likely to be selected
|
|
57
|
+
- Simplest to most complex operation
|
|
58
|
+
- Least to most risk
|
|
59
|
+
|
|
60
|
+
> Image: Examples of a Radio List with label
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
### Default option
|
|
64
|
+
An option must be selected at all times. If you need an unselected state, add a "None" option.
|
|
65
|
+
|
|
66
|
+
> Image: Examples of a Radio List with label
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## Content
|
|
71
|
+
|
|
72
|
+
### Avoid punctuation and articles (“the”, “an”, “a”)
|
|
73
|
+
Be descriptive, not instructional. If the selection needs more explanation, use help text.
|
|
74
|
+
|
|
75
|
+
> Image: Examples of label punctuation: The first example with the heart eyes emoji shows a Radio List with the label,
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
### Keep descriptions concise
|
|
79
|
+
Descriptions should be text only and short enough that bullet points aren't needed. If more detail is needed, move the description outside of the radio list.
|
|
80
|
+
|
|
81
|
+
> Image: Examples of description length: The first example with the heart eyes emoji shows a Radio List with label
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
[1]: ./Switch
|
|
85
|
+
[2]: ./Multiselect
|
|
86
|
+
[3]: ./Select
|
|
87
|
+
[4]: ./RadioBar
|
|
88
|
+
[5]: ./ComboBox
|
|
89
|
+
|
|
90
|
+
## Examples
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
### Controlled
|
|
94
|
+
|
|
95
|
+
Radio List requires a value prop and an onChange callback to update the value prop for most use cases.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import React, { useState } from 'react';
|
|
99
|
+
|
|
100
|
+
import RadioList, { RadioListChangeHandler, RadioListValueTypes } from '@splunk/react-ui/RadioList';
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
function Basic() {
|
|
104
|
+
const [value, setValue] = useState<RadioListValueTypes>(2);
|
|
105
|
+
|
|
106
|
+
const handleChange: RadioListChangeHandler = (e, { value: radioValue }) => {
|
|
107
|
+
setValue(radioValue);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<RadioList value={value} onChange={handleChange}>
|
|
112
|
+
<RadioList.Option value={1}>One</RadioList.Option>
|
|
113
|
+
<RadioList.Option value={2}>Two</RadioList.Option>
|
|
114
|
+
<RadioList.Option value={3}>Three three three</RadioList.Option>
|
|
115
|
+
<RadioList.Option disabled value={4}>
|
|
116
|
+
Four
|
|
117
|
+
</RadioList.Option>
|
|
118
|
+
</RadioList>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export default Basic;
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
### Uncontrolled
|
|
128
|
+
|
|
129
|
+
Alternately, Radio List can be uncontrolled and optionally provided a defaultValue. The onChange callback still fires. The value prop cannot be set or updated externally.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import React from 'react';
|
|
133
|
+
|
|
134
|
+
import RadioList from '@splunk/react-ui/RadioList';
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
function Uncontrolled() {
|
|
138
|
+
return (
|
|
139
|
+
<RadioList defaultValue={2}>
|
|
140
|
+
<RadioList.Option value={1}>One</RadioList.Option>
|
|
141
|
+
<RadioList.Option value={2}>Two</RadioList.Option>
|
|
142
|
+
<RadioList.Option value={3}>Three three three</RadioList.Option>
|
|
143
|
+
<RadioList.Option value={4}>Four</RadioList.Option>
|
|
144
|
+
</RadioList>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export default Uncontrolled;
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
### Disabled
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import React, { useState } from 'react';
|
|
157
|
+
|
|
158
|
+
import RadioList, { RadioListChangeHandler, RadioListValueTypes } from '@splunk/react-ui/RadioList';
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
function Disabled() {
|
|
162
|
+
const [value, setValue] = useState<RadioListValueTypes>(2);
|
|
163
|
+
|
|
164
|
+
const handleChange: RadioListChangeHandler = (e, { value: radioValue }) => {
|
|
165
|
+
setValue(radioValue);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<RadioList value={value} disabled onChange={handleChange}>
|
|
170
|
+
<RadioList.Option value={1}>One</RadioList.Option>
|
|
171
|
+
<RadioList.Option value={2}>Two</RadioList.Option>
|
|
172
|
+
<RadioList.Option value={3}>Three three three</RadioList.Option>
|
|
173
|
+
<RadioList.Option disabled value={4}>
|
|
174
|
+
Four
|
|
175
|
+
</RadioList.Option>
|
|
176
|
+
</RadioList>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export default Disabled;
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
### Error
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import React, { useState } from 'react';
|
|
189
|
+
|
|
190
|
+
import RadioList, { RadioListChangeHandler, RadioListValueTypes } from '@splunk/react-ui/RadioList';
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
function RadioListError() {
|
|
194
|
+
const [value, setValue] = useState<RadioListValueTypes>(2);
|
|
195
|
+
|
|
196
|
+
const handleChange: RadioListChangeHandler = (e, { value: radioValue }) => {
|
|
197
|
+
setValue(radioValue);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<RadioList value={value} onChange={handleChange} error>
|
|
202
|
+
<RadioList.Option value={1}>One</RadioList.Option>
|
|
203
|
+
<RadioList.Option value={2}>Two</RadioList.Option>
|
|
204
|
+
<RadioList.Option value={3}>Three three three</RadioList.Option>
|
|
205
|
+
<RadioList.Option value={4}>Four</RadioList.Option>
|
|
206
|
+
</RadioList>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export default RadioListError;
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
### Description
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import React from 'react';
|
|
219
|
+
|
|
220
|
+
import RadioList from '@splunk/react-ui/RadioList';
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
function Description() {
|
|
224
|
+
return (
|
|
225
|
+
<RadioList defaultValue={2}>
|
|
226
|
+
<RadioList.Option value={1} description="This is the first option.">
|
|
227
|
+
One
|
|
228
|
+
</RadioList.Option>
|
|
229
|
+
<RadioList.Option value={2} description="This is the second option.">
|
|
230
|
+
Two
|
|
231
|
+
</RadioList.Option>
|
|
232
|
+
<RadioList.Option value={3} description="This is the third option.">
|
|
233
|
+
Three three three
|
|
234
|
+
</RadioList.Option>
|
|
235
|
+
<RadioList.Option value={4} description="This is the fourth option.">
|
|
236
|
+
Four
|
|
237
|
+
</RadioList.Option>
|
|
238
|
+
</RadioList>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export default Description;
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
## API
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
### RadioList API
|
|
252
|
+
|
|
253
|
+
#### Props
|
|
254
|
+
|
|
255
|
+
| Name | Type | Required | Default | Description |
|
|
256
|
+
|------|------|------|------|------|
|
|
257
|
+
| children | React.ReactNode | no | | `children` should be `RadioList.Option`s. |
|
|
258
|
+
| defaultValue | number \| string \| boolean \| Record<string, unknown> \| symbol | no | | Set this property instead of value to make value uncontrolled. |
|
|
259
|
+
| direction | 'column' \| 'row' | no | | **DEPRECATED**: This prop is deprecated and will be removed in the next major version. Changes the layout of the RadioList. |
|
|
260
|
+
| disabled | boolean | no | false | |
|
|
261
|
+
| elementRef | React.Ref<HTMLDivElement> | no | | A React ref which is set to the DOM element when the component mounts and null when it unmounts. |
|
|
262
|
+
| error | boolean | no | false | Highlight the field as having an error. The buttons and labels will turn red. |
|
|
263
|
+
| name | string | no | | The name is returned with onChange events, which can be used to identify the control when multiple controls share an onChange callback. A randomly generated name is used if one is not provided. |
|
|
264
|
+
| onChange | RadioListChangeHandler | no | | A callback to receive the change events. If value is set, this callback is required. This must set the value prop to retain the change. |
|
|
265
|
+
| value | number \| string \| boolean \| Record<string, unknown> \| symbol | no | | The current selected value. Setting this value makes the property controlled. A callback is required. |
|
|
266
|
+
|
|
267
|
+
#### Types
|
|
268
|
+
|
|
269
|
+
| Name | Type | Description |
|
|
270
|
+
|------|------|------|
|
|
271
|
+
| RadioListChangeHandler | ( event: React.ChangeEvent<HTMLInputElement>, data: { name?: string; value: RadioListValueTypes } ) => void | |
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
### RadioList.Option API
|
|
276
|
+
|
|
277
|
+
#### Props
|
|
278
|
+
|
|
279
|
+
| Name | Type | Required | Default | Description |
|
|
280
|
+
|------|------|------|------|------|
|
|
281
|
+
| children | React.ReactNode | no | | |
|
|
282
|
+
| description | string | no | | Additional information to explain the option. |
|
|
283
|
+
| disabled | boolean | no | false | |
|
|
284
|
+
| error | boolean | no | false | |
|
|
285
|
+
| id | string | no | | |
|
|
286
|
+
| onChange | RadioListChangeHandler | no | | |
|
|
287
|
+
| value | RadioListValueTypes | yes | | The selectable value. If this matches the ControlRadioList value, the item is selected. |
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
## Accessibility
|
|
294
|
+
|
|
295
|
+
## Visual Design
|
|
296
|
+
|
|
297
|
+
- Color contrast ratio **MUST** be:
|
|
298
|
+
- >=4.5:1 for...[SC 1.4.3][1]
|
|
299
|
+
- Label text to page-background (all states)
|
|
300
|
+
- >=3:1 for...[SC 1.4.11][2]
|
|
301
|
+
- Circle to toggle-background-color (selected)
|
|
302
|
+
- Toggle-background-color to page-background (selected)
|
|
303
|
+
- Border to page-background (unselected)
|
|
304
|
+
- Focus State: if the focus ring has a radius of [SC 1.4.11][2]
|
|
305
|
+
- < 3px: >=4.5.1 between button <> focus <> background
|
|
306
|
+
- > 3px: >=3.1 between button <> focus <> background
|
|
307
|
+
|
|
308
|
+
## States
|
|
309
|
+
|
|
310
|
+
- Color contrast rules do not apply to disabled radio buttons
|
|
311
|
+
|
|
312
|
+
## Interaction Model
|
|
313
|
+
|
|
314
|
+
### Focus management
|
|
315
|
+
- For radio groups not in a toolbar (most cases), keyboard navigation **MUST** have [SC 2.1][3]
|
|
316
|
+
- <kbd>Tab</kbd> and <kbd>Shift</kbd>+<kbd>Tab</kbd> to move focus into and out of the radio group.
|
|
317
|
+
When focus moves into a radio group :
|
|
318
|
+
|
|
319
|
+
- If a radio button is checked, focus is set on the checked button.
|
|
320
|
+
- If none of the radio buttons are checked, focus is set on the first radio button in the group.
|
|
321
|
+
- <kbd>Space</kbd> to check the focused radio button if it is not already checked.
|
|
322
|
+
- <kbd>Right/Down Arrow</kbd> to move focus to the next radio button in the group, uncheck the
|
|
323
|
+
previously focused button, and check the newly focused button. If focus is on the last button,
|
|
324
|
+
focus moves to the first button.
|
|
325
|
+
- <kbd>Left/Up Arrow</kbd> to move focus to the previous radio button in the group, uncheck the
|
|
326
|
+
previously focused button, and check the newly focused button. If focus is on the first button,
|
|
327
|
+
focus moves to the last button.
|
|
328
|
+
- For Radio Group inside a toolbar, consult [WAI-ARIA][4]
|
|
329
|
+
|
|
330
|
+
## Implementation
|
|
331
|
+
|
|
332
|
+
- Every radio button **MUST** have...[SC 4.1.2][5]
|
|
333
|
+
- label (name)--visible label referenced by `aria-labelledby`, or a label specified with aria-label
|
|
334
|
+
- `"radio"` role
|
|
335
|
+
- `"checked"` or `"unchecked"` (value)
|
|
336
|
+
- `aria-checked` set to either `"true"` (checked) or `"false"` (unchecked)
|
|
337
|
+
- A group of radio buttons **MUST** ...
|
|
338
|
+
- be contained in or owned by an element with the role radiogroup.
|
|
339
|
+
- have a visible label referenced by `aria-labelledby` or has a label specified with aria-label
|
|
340
|
+
- If elements providing additonal information about either the radio group or each radio button are present, those elements **MUST** be labeled using one of the following:
|
|
341
|
+
- the `aria-describedby` property
|
|
342
|
+
- radiogroup element
|
|
343
|
+
- radio element
|
|
344
|
+
|
|
345
|
+
[1]: https://www.w3.org/TR/WCAG21/#contrast-minimum
|
|
346
|
+
[2]: https://www.w3.org/TR/WCAG21/#non-text-contrast
|
|
347
|
+
[3]: https://www.w3.org/TR/WCAG21/#keyboard-accessible
|
|
348
|
+
[4]: https://www.w3.org/TR/wai-aria-practices-1.1/#for-radio-group-contained-in-a-toolbar
|
|
349
|
+
[5]: https://www.w3.org/TR/WCAG21/#name-role-value
|
|
350
|
+
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
# Resize
|
|
2
|
+
|
|
3
|
+
## Examples
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Basic
|
|
7
|
+
|
|
8
|
+
The onRequestResize handler must handle any desired constraints on size.
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
import React, { useState } from 'react';
|
|
12
|
+
|
|
13
|
+
import Resize, { ResizeRequestResizeHandler } from '@splunk/react-ui/Resize';
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
function Basic() {
|
|
17
|
+
const [state, setState] = useState({
|
|
18
|
+
height: 200,
|
|
19
|
+
width: 400,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const onRequestResize: ResizeRequestResizeHandler = (e, { height, width }) => {
|
|
23
|
+
const constrainedHeight = Math.min(Math.max(height, 100), 400);
|
|
24
|
+
const constrainedWidth = Math.min(Math.max(width, 300), 600);
|
|
25
|
+
setState({ height: constrainedHeight, width: constrainedWidth });
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Resize
|
|
30
|
+
resizeHandles={['se']}
|
|
31
|
+
onRequestResize={onRequestResize}
|
|
32
|
+
style={{
|
|
33
|
+
height: state.height,
|
|
34
|
+
width: state.width,
|
|
35
|
+
padding: 20,
|
|
36
|
+
border: '1px solid #ccc',
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
I am content.
|
|
40
|
+
</Resize>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default Basic;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### Appearance
|
|
50
|
+
|
|
51
|
+
Resize handles can be placed on any edge or corner. Note that margin cannot be overridden when using the "border" appearance.
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import React, { useState } from 'react';
|
|
55
|
+
|
|
56
|
+
import Multiselect, { MultiselectChangeHandler } from '@splunk/react-ui/Multiselect';
|
|
57
|
+
import RadioBar, { RadioBarChangeHandler } from '@splunk/react-ui/RadioBar';
|
|
58
|
+
import Resize, { ResizeDirection, ResizeRequestResizeHandler } from '@splunk/react-ui/Resize';
|
|
59
|
+
import { useSplunkTheme } from '@splunk/themes';
|
|
60
|
+
|
|
61
|
+
interface State {
|
|
62
|
+
appearance: 'border' | 'overlay' | 'separator';
|
|
63
|
+
height: number;
|
|
64
|
+
resizeHandles: ResizeDirection[];
|
|
65
|
+
showHandles: 'always' | 'on-hover';
|
|
66
|
+
width: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
function Appearance() {
|
|
71
|
+
const [state, setState] = useState<State>({
|
|
72
|
+
height: 200,
|
|
73
|
+
width: 200,
|
|
74
|
+
appearance: 'border',
|
|
75
|
+
showHandles: 'always',
|
|
76
|
+
resizeHandles: ['nw', 'n', 'ne', 'w', 'e', 'sw', 's', 'se'],
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const onRequestResize: ResizeRequestResizeHandler = (e, { height, width }) => {
|
|
80
|
+
setState({ ...state, height, width });
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const onChangeAppearance: RadioBarChangeHandler = (e, { value }) => {
|
|
84
|
+
setState({ ...state, appearance: value });
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const onChangeShowHandles: RadioBarChangeHandler = (e, { value }) => {
|
|
88
|
+
setState({ ...state, showHandles: value });
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const onChangeHandles: MultiselectChangeHandler = (e, { values }) => {
|
|
92
|
+
setState({ ...state, resizeHandles: values as ResizeDirection[] });
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const { spacingSmall, spacingXLarge } = useSplunkTheme();
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<div>
|
|
99
|
+
<div
|
|
100
|
+
style={{
|
|
101
|
+
marginBottom: spacingXLarge,
|
|
102
|
+
display: 'flex',
|
|
103
|
+
gap: spacingSmall,
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
<RadioBar onChange={onChangeAppearance} value={state.appearance}>
|
|
107
|
+
<RadioBar.Option value="overlay" label="overlay" />
|
|
108
|
+
<RadioBar.Option value="border" label="border" />
|
|
109
|
+
<RadioBar.Option value="separator" label="separator" />
|
|
110
|
+
</RadioBar>
|
|
111
|
+
<RadioBar onChange={onChangeShowHandles} value={state.showHandles}>
|
|
112
|
+
<RadioBar.Option value="always" label="always" />
|
|
113
|
+
<RadioBar.Option value="on-hover" label="on-hover" />
|
|
114
|
+
</RadioBar>
|
|
115
|
+
<Multiselect onChange={onChangeHandles} values={state.resizeHandles}>
|
|
116
|
+
<Multiselect.Option value="n" label="n" />
|
|
117
|
+
<Multiselect.Option value="ne" label="ne" />
|
|
118
|
+
<Multiselect.Option value="e" label="e" />
|
|
119
|
+
<Multiselect.Option value="se" label="se" />
|
|
120
|
+
<Multiselect.Option value="s" label="s" />
|
|
121
|
+
<Multiselect.Option value="sw" label="sw" />
|
|
122
|
+
<Multiselect.Option value="w" label="w" />
|
|
123
|
+
<Multiselect.Option value="nw" label="nw" />
|
|
124
|
+
</Multiselect>
|
|
125
|
+
</div>
|
|
126
|
+
<div
|
|
127
|
+
style={{
|
|
128
|
+
border: '1px solid #d6d6d6',
|
|
129
|
+
display: 'inline-block',
|
|
130
|
+
}}
|
|
131
|
+
>
|
|
132
|
+
<Resize
|
|
133
|
+
resizeHandles={state.resizeHandles}
|
|
134
|
+
onRequestResize={onRequestResize}
|
|
135
|
+
appearance={state.appearance}
|
|
136
|
+
showHandles={state.showHandles}
|
|
137
|
+
style={{
|
|
138
|
+
height: state.height,
|
|
139
|
+
width: state.width,
|
|
140
|
+
}}
|
|
141
|
+
>
|
|
142
|
+
<div
|
|
143
|
+
style={{
|
|
144
|
+
left: '50%',
|
|
145
|
+
top: '50%',
|
|
146
|
+
transform: 'translate(-50%, -50%)',
|
|
147
|
+
position: 'absolute',
|
|
148
|
+
textAlign: 'center',
|
|
149
|
+
}}
|
|
150
|
+
>
|
|
151
|
+
I am content.
|
|
152
|
+
</div>
|
|
153
|
+
</Resize>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export default Appearance;
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
### Sizing outer
|
|
165
|
+
|
|
166
|
+
Resize does not dictate how it is sized. In this example, styles are placed on an outer container.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import React, { useState } from 'react';
|
|
170
|
+
|
|
171
|
+
import Resize, { ResizeRequestResizeHandler } from '@splunk/react-ui/Resize';
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
function SizingOuter() {
|
|
175
|
+
const [state, setState] = useState({
|
|
176
|
+
height: 200,
|
|
177
|
+
width: 200,
|
|
178
|
+
});
|
|
179
|
+
const onRequestResize: ResizeRequestResizeHandler = (e, { height, width }) => {
|
|
180
|
+
setState({ height, width });
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<div // Width and height on outer container
|
|
185
|
+
style={{
|
|
186
|
+
height: state.height,
|
|
187
|
+
width: state.width,
|
|
188
|
+
border: '1px solid #ccc',
|
|
189
|
+
backgroundColor: 'rgba(128, 128, 128, 0.2)',
|
|
190
|
+
position: 'relative',
|
|
191
|
+
}}
|
|
192
|
+
>
|
|
193
|
+
<Resize
|
|
194
|
+
resizeHandles={['se']}
|
|
195
|
+
onRequestResize={onRequestResize}
|
|
196
|
+
style={{
|
|
197
|
+
position: 'absolute',
|
|
198
|
+
top: 0,
|
|
199
|
+
right: 0,
|
|
200
|
+
bottom: 0,
|
|
201
|
+
left: 0,
|
|
202
|
+
padding: 20,
|
|
203
|
+
}}
|
|
204
|
+
>
|
|
205
|
+
Width and height on outer container
|
|
206
|
+
</Resize>
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export default SizingOuter;
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
### Sizing inner
|
|
217
|
+
|
|
218
|
+
In this example, styles are placed on the inner content.
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import React, { useState } from 'react';
|
|
222
|
+
|
|
223
|
+
import Resize, { ResizeRequestResizeHandler } from '@splunk/react-ui/Resize';
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
function SizingInner() {
|
|
227
|
+
const [state, setState] = useState({
|
|
228
|
+
height: 200,
|
|
229
|
+
width: 200,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const onRequestResize: ResizeRequestResizeHandler = (e, { height, width }) => {
|
|
233
|
+
setState({ height: height - 2, width: width - 2 }); // border adjustment
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
return (
|
|
237
|
+
<Resize // Width and height on inner container
|
|
238
|
+
resizeHandles={['se']}
|
|
239
|
+
onRequestResize={onRequestResize}
|
|
240
|
+
style={{
|
|
241
|
+
border: '1px solid #ccc',
|
|
242
|
+
display: 'inline-block',
|
|
243
|
+
}}
|
|
244
|
+
>
|
|
245
|
+
<div
|
|
246
|
+
style={{
|
|
247
|
+
width: state.width,
|
|
248
|
+
height: state.height,
|
|
249
|
+
backgroundColor: 'rgba(128, 128, 128, 0.2)',
|
|
250
|
+
padding: 20,
|
|
251
|
+
boxSizing: 'border-box',
|
|
252
|
+
}}
|
|
253
|
+
>
|
|
254
|
+
Width and height on inner container
|
|
255
|
+
</div>
|
|
256
|
+
</Resize>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export default SizingInner;
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
### Percentage
|
|
266
|
+
|
|
267
|
+
Sizes don't need to be defined in pixels or with height and width styles. Here, flex-basis is calculated as a percentage.
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
import React, { useRef, useState } from 'react';
|
|
271
|
+
|
|
272
|
+
import Resize, { ResizeRequestResizeHandler } from '@splunk/react-ui/Resize';
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
function Percentage() {
|
|
276
|
+
const el = useRef<HTMLDivElement | null>(null);
|
|
277
|
+
|
|
278
|
+
const [percentage, setPercentage] = useState(50);
|
|
279
|
+
|
|
280
|
+
const onRequestResize: ResizeRequestResizeHandler = (e, { width }) => {
|
|
281
|
+
if (el.current) {
|
|
282
|
+
const calculatedPercentage = Math.max((width / el.current.clientWidth) * 100);
|
|
283
|
+
const percentageValue = Math.min(Math.max(calculatedPercentage, 10), 90);
|
|
284
|
+
|
|
285
|
+
setPercentage(percentageValue);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
<div
|
|
291
|
+
ref={el}
|
|
292
|
+
style={{
|
|
293
|
+
minHeight: 100,
|
|
294
|
+
display: 'flex',
|
|
295
|
+
}}
|
|
296
|
+
>
|
|
297
|
+
<Resize
|
|
298
|
+
resizeHandles={['e']}
|
|
299
|
+
onRequestResize={onRequestResize}
|
|
300
|
+
appearance="separator"
|
|
301
|
+
style={{
|
|
302
|
+
flexBasis: `${percentage}%`,
|
|
303
|
+
backgroundColor: 'rgba(128, 128, 128, 0.2)',
|
|
304
|
+
}}
|
|
305
|
+
>
|
|
306
|
+
<div
|
|
307
|
+
style={{
|
|
308
|
+
padding: 20,
|
|
309
|
+
}}
|
|
310
|
+
>
|
|
311
|
+
Left side
|
|
312
|
+
</div>
|
|
313
|
+
</Resize>
|
|
314
|
+
<div
|
|
315
|
+
style={{
|
|
316
|
+
flexGrow: 1,
|
|
317
|
+
backgroundColor: 'rgba(128, 200, 128, 0.2)',
|
|
318
|
+
padding: 20,
|
|
319
|
+
}}
|
|
320
|
+
>
|
|
321
|
+
Right side
|
|
322
|
+
</div>
|
|
323
|
+
</div>
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export default Percentage;
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
## API
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
### Resize API
|
|
337
|
+
|
|
338
|
+
Resize is a utility container with drag handles for resizing.
|
|
339
|
+
|
|
340
|
+
#### Props
|
|
341
|
+
|
|
342
|
+
| Name | Type | Required | Default | Description |
|
|
343
|
+
|------|------|------|------|------|
|
|
344
|
+
| appearance | 'border' \| 'overlay' \| 'separator' | no | 'overlay' | The appearance of the resize handles. Note: When appearance is 'separator', active full length borders will only appear for 'n', 's', 'e', or 'w' `resizeHandles`. |
|
|
345
|
+
| children | React.ReactNode | no | | |
|
|
346
|
+
| elementRef | React.Ref<HTMLDivElement> | no | | A React ref which is set to the DOM element when the component mounts and null when it unmounts. |
|
|
347
|
+
| keyIncrement | number | no | 10 | When focused on a resize handle, the arrow keys will adjust the height or width by this amount with each press. |
|
|
348
|
+
| onRequestResize | ResizeRequestResizeHandler | yes | | A callback which is passed the event and an object with the requested height and width. |
|
|
349
|
+
| resizeHandles | ResizeDirection[] | yes | | An array of resize handles placements. |
|
|
350
|
+
| showHandles | 'always' \| 'on-hover' | no | 'always' | The appearance of the resize handles. |
|
|
351
|
+
|
|
352
|
+
#### Types
|
|
353
|
+
|
|
354
|
+
| Name | Type | Description |
|
|
355
|
+
|------|------|------|
|
|
356
|
+
| ResizeDirection | 'nw' \| 'n' \| 'ne' \| 'w' \| 'e' \| 'sw' \| 's' \| 'se' | |
|
|
357
|
+
| ResizeRequestResizeHandler | ( event: MouseEvent \| React.KeyboardEvent<HTMLButtonElement>, data: { height: number; width: number } ) => void | |
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|