@splunk/react-ui 5.7.0 → 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.
Files changed (138) hide show
  1. package/Accordion.js +6 -6
  2. package/Box.js +83 -34
  3. package/CHANGELOG.md +34 -0
  4. package/CollapsiblePanel.js +11 -11
  5. package/ComboBox.js +31 -27
  6. package/ControlGroup.js +92 -91
  7. package/DefinitionList.js +9 -9
  8. package/Drawer.d.ts +2 -0
  9. package/Drawer.js +679 -0
  10. package/DualListbox.js +1 -1
  11. package/JSONTree.js +73 -72
  12. package/Link.js +2 -2
  13. package/MIGRATION.md +10 -0
  14. package/Menu.js +338 -240
  15. package/Modal.js +127 -109
  16. package/Multiselect.js +437 -351
  17. package/Paginator.js +14 -12
  18. package/Popover.js +4 -1
  19. package/README.md +11 -0
  20. package/RadioBar.js +1 -1
  21. package/Search.js +103 -88
  22. package/Select.js +42 -40
  23. package/SelectBase.js +374 -328
  24. package/SidePanel.js +346 -167
  25. package/SlidingPanels.js +11 -11
  26. package/StepBar.js +7 -7
  27. package/Switch.js +5 -5
  28. package/Text.js +24 -24
  29. package/TextArea.js +7 -7
  30. package/TransitionOpen.js +204 -185
  31. package/docs-llm/Accordion.md +267 -0
  32. package/docs-llm/Anchor Menu.md +115 -0
  33. package/docs-llm/Anchor.md +54 -0
  34. package/docs-llm/AnimationToggle.md +254 -0
  35. package/docs-llm/Avatar.md +298 -0
  36. package/docs-llm/Badge.md +212 -0
  37. package/docs-llm/Breadcrumbs.md +306 -0
  38. package/docs-llm/Button Group.md +53 -0
  39. package/docs-llm/Button.md +361 -0
  40. package/docs-llm/Card Layout.md +286 -0
  41. package/docs-llm/Card.md +619 -0
  42. package/docs-llm/Checkbox.md +218 -0
  43. package/docs-llm/Chip.md +291 -0
  44. package/docs-llm/Clickable.md +160 -0
  45. package/docs-llm/Code.md +292 -0
  46. package/docs-llm/Collapsible Panel.md +744 -0
  47. package/docs-llm/Color.md +253 -0
  48. package/docs-llm/Column Layout.md +391 -0
  49. package/docs-llm/Combo Box.md +540 -0
  50. package/docs-llm/Control Group.md +594 -0
  51. package/docs-llm/Date.md +270 -0
  52. package/docs-llm/Definition List.md +278 -0
  53. package/docs-llm/Divider.md +216 -0
  54. package/docs-llm/Drawer.md +414 -0
  55. package/docs-llm/Dropdown.md +472 -0
  56. package/docs-llm/Dual Listbox.md +325 -0
  57. package/docs-llm/File.md +653 -0
  58. package/docs-llm/Form Rows.md +374 -0
  59. package/docs-llm/Heading.md +179 -0
  60. package/docs-llm/Image.md +109 -0
  61. package/docs-llm/JSON Tree.md +260 -0
  62. package/docs-llm/Layer.md +74 -0
  63. package/docs-llm/Layout.md +50 -0
  64. package/docs-llm/Link.md +318 -0
  65. package/docs-llm/List.md +189 -0
  66. package/docs-llm/Markdown.md +179 -0
  67. package/docs-llm/Menu.md +735 -0
  68. package/docs-llm/Message Bar.md +236 -0
  69. package/docs-llm/Message.md +248 -0
  70. package/docs-llm/Modal.md +443 -0
  71. package/docs-llm/Monogram.md +159 -0
  72. package/docs-llm/Multiselect.md +937 -0
  73. package/docs-llm/Number.md +298 -0
  74. package/docs-llm/Paginator.md +395 -0
  75. package/docs-llm/Paragraph.md +148 -0
  76. package/docs-llm/Phone Number.md +254 -0
  77. package/docs-llm/Popover.md +166 -0
  78. package/docs-llm/Progress.md +141 -0
  79. package/docs-llm/Radio Bar.md +303 -0
  80. package/docs-llm/Radio List.md +350 -0
  81. package/docs-llm/Resize.md +362 -0
  82. package/docs-llm/Screen Reader Content.md +73 -0
  83. package/docs-llm/Scroll Container Context.md +155 -0
  84. package/docs-llm/Scroll.md +152 -0
  85. package/docs-llm/Search.md +381 -0
  86. package/docs-llm/Select.md +985 -0
  87. package/docs-llm/Side Panel.md +777 -0
  88. package/docs-llm/Slider.md +339 -0
  89. package/docs-llm/Sliding Panels.md +340 -0
  90. package/docs-llm/Split Button.md +295 -0
  91. package/docs-llm/Static Content.md +90 -0
  92. package/docs-llm/Step Bar.md +292 -0
  93. package/docs-llm/Switch.md +268 -0
  94. package/docs-llm/Tab Bar.md +439 -0
  95. package/docs-llm/Tab Layout.md +398 -0
  96. package/docs-llm/Table.md +2642 -0
  97. package/docs-llm/Text Area.md +253 -0
  98. package/docs-llm/Text.md +339 -0
  99. package/docs-llm/Tooltip.md +325 -0
  100. package/docs-llm/Transition Open.md +406 -0
  101. package/docs-llm/Tree.md +586 -0
  102. package/docs-llm/Typography.md +125 -0
  103. package/docs-llm/Wait Spinner.md +121 -0
  104. package/docs-llm/llms.txt +97 -0
  105. package/package.json +6 -5
  106. package/types/src/Box/Box.d.ts +2 -10
  107. package/types/src/Drawer/Body.d.ts +17 -0
  108. package/types/src/Drawer/Drawer.d.ts +114 -0
  109. package/types/src/Drawer/DrawerContext.d.ts +11 -0
  110. package/types/src/Drawer/Footer.d.ts +25 -0
  111. package/types/src/Drawer/Header.d.ts +41 -0
  112. package/types/src/Drawer/docs/examples/Basic.d.ts +6 -0
  113. package/types/src/Drawer/docs/examples/ContainerPosition.d.ts +7 -0
  114. package/types/src/Drawer/docs/examples/InitialFocus.d.ts +9 -0
  115. package/types/src/Drawer/docs/examples/InlinePosition.d.ts +7 -0
  116. package/types/src/Drawer/docs/examples/PagePosition.d.ts +7 -0
  117. package/types/src/Drawer/index.d.ts +2 -0
  118. package/types/src/JSONTree/JSONTree.d.ts +12 -5
  119. package/types/src/JSONTree/renderTreeItems.d.ts +2 -1
  120. package/types/src/Menu/Item.d.ts +2 -1
  121. package/types/src/Menu/docs/examples/SelectableCheckbox.d.ts +7 -0
  122. package/types/src/Modal/Modal.d.ts +1 -2
  123. package/types/src/Select/Option.d.ts +6 -3
  124. package/types/src/Select/Select.d.ts +8 -5
  125. package/types/src/Select/docs/examples/Dimmed.d.ts +7 -0
  126. package/types/src/SelectBase/OptionBase.d.ts +6 -3
  127. package/types/src/SelectBase/SelectBase.d.ts +8 -3
  128. package/types/src/SidePanel/SidePanel.d.ts +43 -2
  129. package/types/src/SidePanel/docs/examples/DockLayout.d.ts +17 -0
  130. package/types/src/SidePanel/docs/examples/InitialFocus.d.ts +9 -0
  131. package/types/src/TransitionOpen/TransitionOpen.d.ts +29 -4
  132. package/types/src/useKeyPress/index.d.ts +9 -2
  133. package/types/src/useOnClickOutside/index.d.ts +2 -0
  134. package/types/src/useOnClickOutside/useOnClickOutside.d.ts +4 -0
  135. package/useKeyPress.js +23 -18
  136. package/useOnClickOutside.d.ts +2 -0
  137. package/useOnClickOutside.js +79 -0
  138. package/types/src/RadioList/docs/examples/Row.d.ts +0 -6
@@ -0,0 +1,325 @@
1
+ # Dual Listbox
2
+
3
+ ## Overview
4
+
5
+
6
+
7
+ > Image: Illustration of a dual listbox component
8
+
9
+
10
+
11
+
12
+ ## When to use this component
13
+ - When you need to manage or transfer content between two lists.
14
+ - A clear visual distinction between available and selected items is required.
15
+
16
+
17
+
18
+ ## When to use another component
19
+ - Consider a `Radio List` when only one item from a list needs to be selected
20
+ - When space is extremely limited and a compact selection is needed, use `Multiselect`
21
+ - Consider `Table` or `List` when representing hierarchical data or key-value pairs
22
+
23
+
24
+ ```mermaid
25
+ graph TD
26
+ accDescr: Decision tree that guides on when to use the DualListbox component or something else
27
+ A(Do you need to represent hierarchical data?) -- Yes --- B(Table or List)
28
+ A -- No --- C(Do you need to select many items?)
29
+ C -- Yes --- D(Do you need to transfer items between lists?)
30
+ D -- Yes --- E(Dual listbox)
31
+ D -- No --- F(Multiselect)
32
+ C -- No --- G(Radio list)
33
+ ```
34
+
35
+ ### Check out
36
+ - [Radio List][1]
37
+ - [Multiselect][2]
38
+ - [Table] [3]
39
+ - [List][4]
40
+
41
+
42
+ ## Usage
43
+ ### Use descriptive names for each list box when applicable.
44
+ The default names for each list box are “Source” and “Target”, but they can be changed to accurately reflect the data within each list.
45
+
46
+ > Image: The image shows a do-and-don’t comparison between two Dual Listboxes. The image with the heart eyes emoji shows a Dual Listbox with a source label of
47
+
48
+
49
+ ### Use a controlled dual list box for bulk transfers.
50
+ If it is anticipated that the user will be moving numerous items, a controlled dual listbox allows users to revert changes, providing greater control and preventing accidental bulk modifications.
51
+
52
+ > Image: The image shows a Dual Listbox where the left list is labeled
53
+
54
+
55
+ ### Confirming high-impact changes
56
+ If the dual list box will create major changes in the page or workflow, include a confirmation button, such as “Apply” or “Save” so users understand that their changes will be finalized.
57
+
58
+ > Image: The image shows a Dual Listbox where the left list is labeled ‘Available countries’ and the right is labeled ‘Enabled countries. A button labeled ‘Apply’ is underneath the Dual Listbox component to allow users to confirm the choices they made.
59
+
60
+
61
+
62
+ ### Modal placement for expanded space
63
+ When limited space prevents the effective display of a dual listbox, consider placing it within a modal. Ensure the modal includes a clear confirmation button.
64
+
65
+ > Image: The image shows a Dual Listbox inside of a Modal component titled ‘Publish components’. The left list is labeled ‘Available components’ and the right list is labeled ‘Released components’. The Modal footer has two buttons; the left one says ‘Cancel’ and the right one says ‘Apply’.
66
+
67
+
68
+ [1]: ./RadioList
69
+ [2]: ./Multiselect
70
+ [3]: ./Table
71
+ [4]: ./List
72
+
73
+ ## Examples
74
+
75
+
76
+ ### Uncontrolled
77
+
78
+ ```typescript
79
+ import React from 'react';
80
+
81
+ import DualListbox, { Option } from '@splunk/react-ui/DualListbox';
82
+
83
+
84
+ function Uncontrolled() {
85
+ return (
86
+ <DualListbox
87
+ lists={[
88
+ { name: 'list-1', label: 'Source' },
89
+ { name: 'list-2', label: 'Target' },
90
+ ]}
91
+ >
92
+ <Option id="option-0" label="Alpha" value="alpha" />
93
+ <Option id="option-1" label="Beta" value="beta" />
94
+ <Option id="option-2" label="Gamma" value="gamma" />
95
+ <Option id="option-3" label="Delta" value="delta" />
96
+ <Option id="option-4" label="Epsilon" value="epsilon" />
97
+ </DualListbox>
98
+ );
99
+ }
100
+
101
+ export default Uncontrolled;
102
+ ```
103
+
104
+
105
+
106
+ ### optionValues
107
+
108
+ ```typescript
109
+ import React, { useState } from 'react';
110
+
111
+ import Button from '@splunk/react-ui/Button';
112
+ import DualListbox, {
113
+ Option,
114
+ DualListboxChangeHandler,
115
+ DualListboxSelectHandler,
116
+ } from '@splunk/react-ui/DualListbox';
117
+ import ScreenReaderContent from '@splunk/react-ui/ScreenReaderContent';
118
+
119
+ const optionValues = ['Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon'];
120
+
121
+
122
+ const Controlled = () => {
123
+ const [twoValues, setTwoValues] = useState<string[]>([]);
124
+ const [oneSelectedValues, setOneSelectedValues] = useState<string[]>([]);
125
+ const [twoSelectedValues, setTwoSelectedValues] = useState<string[]>([]);
126
+ const [screenReaderMessage, setScreenReaderMessage] = useState<string>('');
127
+
128
+ const handleChange: DualListboxChangeHandler = (
129
+ event,
130
+ { targetListName, targetValues, sourceValues, screenReaderMessage: message }
131
+ ) => {
132
+ if (targetListName === 'list-1') {
133
+ setTwoSelectedValues([]);
134
+ setTwoValues(sourceValues);
135
+ } else {
136
+ setOneSelectedValues([]);
137
+ setTwoValues(targetValues);
138
+ }
139
+ setScreenReaderMessage(message);
140
+ };
141
+
142
+ const handleSelect: DualListboxSelectHandler = (event, { values, listName }) => {
143
+ if (listName === 'list-1') {
144
+ setOneSelectedValues(values);
145
+ } else {
146
+ setTwoSelectedValues(values);
147
+ }
148
+ };
149
+
150
+ const handleResetClick = () => {
151
+ setOneSelectedValues([]);
152
+ setTwoSelectedValues([]);
153
+ setTwoValues([]);
154
+ // If the state of the DualListbox is being altered externally, it needs to be messaged.
155
+ setScreenReaderMessage('Source and Target listbox values reset');
156
+ };
157
+
158
+ const twoSet = new Set(twoValues);
159
+ const twoSelectedSet = new Set(twoSelectedValues);
160
+ const oneSelectedSet = new Set(oneSelectedValues);
161
+
162
+ const options = optionValues.map((value) => {
163
+ const isList2Item = twoSet.has(value);
164
+ let isSelected = false;
165
+ if (isList2Item) {
166
+ isSelected = twoSelectedSet.has(value);
167
+ } else {
168
+ isSelected = oneSelectedSet.has(value);
169
+ }
170
+
171
+ return (
172
+ <Option
173
+ id={`controlled-id-${value}`}
174
+ key={value}
175
+ label={value}
176
+ value={value}
177
+ selected={isSelected}
178
+ listName={isList2Item ? 'list-2' : 'list-1'}
179
+ />
180
+ );
181
+ });
182
+
183
+ return (
184
+ <>
185
+ <Button label="Reset lists" onClick={handleResetClick} />
186
+ <DualListbox
187
+ controlled
188
+ onChange={handleChange}
189
+ onSelect={handleSelect}
190
+ lists={[
191
+ { name: 'list-1', label: 'Source' },
192
+ { name: 'list-2', label: 'Target' },
193
+ ]}
194
+ >
195
+ {options}
196
+ </DualListbox>
197
+ {}
198
+ <ScreenReaderContent aria-live="assertive">{screenReaderMessage}</ScreenReaderContent>
199
+ </>
200
+ );
201
+ };
202
+
203
+ export default Controlled;
204
+ ```
205
+
206
+
207
+
208
+ ### Fill
209
+
210
+ Dynamic size example.
211
+
212
+ ```typescript
213
+ import React from 'react';
214
+
215
+ import DualListbox, { Option } from '@splunk/react-ui/DualListbox';
216
+
217
+
218
+ function Fill() {
219
+ return (
220
+ <div
221
+ style={{
222
+ height: '500px',
223
+ position: 'relative',
224
+ width: '800px',
225
+ }}
226
+ >
227
+ <DualListbox
228
+ fill
229
+ lists={[
230
+ { name: 'list-1', label: 'Source' },
231
+ { name: 'list-2', label: 'Target' },
232
+ ]}
233
+ >
234
+ <Option id="option-0" label="Alpha" value="alpha" />
235
+ <Option id="option-1" label="Beta" value="beta" />
236
+ <Option id="option-2" label="Gamma" value="gamma" />
237
+ <Option id="option-3" label="Delta" value="delta" />
238
+ <Option id="option-4" label="Epsilon" value="epsilon" />
239
+ </DualListbox>
240
+ </div>
241
+ );
242
+ }
243
+
244
+ export default Fill;
245
+ ```
246
+
247
+
248
+
249
+
250
+ ## API
251
+
252
+
253
+ ### DualListbox API
254
+
255
+ #### Props
256
+
257
+ | Name | Type | Required | Default | Description |
258
+ |------|------|------|------|------|
259
+ | children | React.ReactNode | no | | All children must be instances of `DualListbox.Option`. |
260
+ | controlled | boolean | no | false | When true, `Options`'s `listName` and `selected` state props are fully controlled. |
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
+ | fill | boolean | no | false | When true, fill height and width of the relative parent container. |
263
+ | inline | boolean | no | false | When false, display as inline-block with the default width. Ignored if `fill=true` set. |
264
+ | lists | ListboxConfig[] | yes | | List identifiers. `name` should map to child `Option`s `listName` prop, and will be returned with event calls. `label` will be used for visual and assistive text. |
265
+ | onChange | DualListboxChangeHandler | no | | Callback for selected options moving from one list to another. |
266
+ | onSelect | DualListboxSelectHandler | no | | Callback for single selected/de-select actions. |
267
+
268
+ #### Types
269
+
270
+ | Name | Type | Description |
271
+ |------|------|------|
272
+ | DualListboxChangeHandler | ( event: \| React.MouseEvent<HTMLButtonElement> \| React.MouseEvent<HTMLLIElement> \| React.KeyboardEvent<HTMLUListElement>, data: { /** * The values being changed. */ affectedValues: string[]; /** * The a11y text describing the move action. * If `controlled="true"` the presentation of the text MUST be implemented by the consumer. */ screenReaderMessage: string; /** * The list `name` associated to the source of the move action. */ sourceListName: string; /** * The values now contained within the source list. */ sourceValues: string[]; /** * The list `name` associated to the target of the move action. */ targetListName: string; /** * The values now contained within the target list. */ targetValues: string[]; } ) => void | |
273
+ | DualListboxSelectHandler | ( event: \| React.MouseEvent<HTMLLIElement> \| React.KeyboardEvent<HTMLUListElement> \| React.ChangeEvent<HTMLInputElement>, data: { /** * The list `name` associated to the batch action. */ listName: string; /** * The values marked as selected with the given list. */ values: string[]; } ) => void | |
274
+
275
+
276
+
277
+
278
+
279
+ ## Accessibility
280
+
281
+ ## Visual Design
282
+ - Color contrast ratio **MUST** be:
283
+ - &gt= 4.5:1 for normal text: 14 pt (typically 18.66px) and bold or larger [SC 1.4.3][1]
284
+ - Focus State: If the focus ring has a radius of [SC 1.4.11][2]
285
+ - &lt 3px: &gt= 4.5.1 between button &lt&gt focus &lt&gt background
286
+ - &gt 3px: &gt= 3.1 button button &lt&gt focus &lt&gt background
287
+
288
+ ## States
289
+ - Color contrast does not apply to a disabled child elements in DualListbox
290
+
291
+ ## Interaction Model
292
+ - **MUST** be perceivable and functional when when zoomed from 50-200% [SC 1.4.4][3] [SC 1.4.10][4]
293
+ - **SHOULD** use button semantics to be addressed by screen reader
294
+ - Icon buttons **MUST** have a tooltip that describes its function on hover [SC 1.4.13][5]
295
+ - **MUST** have keyboard navigation [SC 2.1][6]
296
+ - <kbd>Tab</kbd> and <kbd>Shift</kbd>+<kbd>Tab</kbd> to move through interactive elements within the DualListbox.
297
+ - <kbd>Space</kbd> changes the selection state of the focused option.
298
+ - <kbd>Down Arrow</kbd> moves focus to the next option.
299
+ - <kbd>Up Arrow</kbd> moves focus to the previous option.
300
+ - <kbd>Home</kbd> moves focus to the first option.
301
+ - <kbd>End</kbd> moves focus to the last option.
302
+ - <kbd>Shift</kbd>+<kbd>Down Arrow</kbd> moves focus to and selects the next option.
303
+ - <kbd>Shift</kbd>+<kbd>Up Arrow</kbd> moves focus to and selects the previous option.
304
+ - <kbd>Control</kbd>+<kbd>Shift</kbd>+<kbd>Home</kbd> selects from the focused option to the beginning of the list.
305
+ - <kbd>Control</kbd>+<kbd>Shift</kbd>+<kbd>End</kbd> selects from the focused option to the end of the list.
306
+ - <kbd>Control</kbd>+<kbd>A</kbd> selects all options in the list. If all options are selected, unselects all options.
307
+ - <kbd>Command</kbd>+<kbd>A</kbd> (macOS) selects all options in the list. If all options are selected, unselects all options.
308
+ - <kbd>Enter</kbd> performs an add only when focus is in the available options list.
309
+ - <kbd>Delete</kbd> performs a remove only when focus is in the chosen options list.
310
+
311
+ ## Implementation
312
+ - When pressing a button without a change in context, focus **MUST NOT** be lost (i.e. a refresh button refreshes a table or data visualization)
313
+ - **MUST** have a visible focus border [SC 2.4.7][7]
314
+ - **MUST** use HTML semantics: `<ul>` or `<ol>` with `<li>` child elements, or `<dl>` with `<dt>` and `<dd>` child elements [SC 1.3.1][8]
315
+
316
+ [1]: https://www.w3.org/TR/WCAG21/#contrast-minimum
317
+ [2]: https://www.w3.org/TR/WCAG21/#non-text-contrast
318
+ [3]: https://www.w3.org/WAI/GL/UNDERSTANDING-WCAG20/visual-audio-contrast-scale.html
319
+ [4]: https://www.w3.org/WAI/WCAG21/Understanding/reflow.html
320
+ [5]: https://www.w3.org/TR/WCAG21/#content-on-hover-or-focus
321
+ [6]: https://www.w3.org/TR/WCAG21/#keyboard-accessible
322
+ [7]: https://www.w3.org/TR/WCAG21/#focus-visible
323
+ [8]: https://www.w3.org/TR/WCAG21/#info-and-relationships
324
+
325
+