@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.
- package/Accordion.js +6 -6
- package/Box.js +83 -34
- package/CHANGELOG.md +34 -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 +204 -185
- 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,937 @@
|
|
|
1
|
+
# Multiselect
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
> Image: Illustration of a Multiselect component.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<Message appearance="fill" type="info">
|
|
10
|
+
<div>All data entry components should be wrapped in a <Link to="ControlGroup">Control Group</Link> to provide a label, error states, and help or error text, ensuring an accessible experience for all users.</div>
|
|
11
|
+
</Message>
|
|
12
|
+
|
|
13
|
+
## When to use this component
|
|
14
|
+
- To select one or multiple options from a list of choices.
|
|
15
|
+
- There are a large number of options. For instance, in a form for filtering search results or making multiple selections from a list of categories.
|
|
16
|
+
|
|
17
|
+
## When to use another component
|
|
18
|
+
- If the user is only required to select one pre-determined option, use `Select` or `Radio List`.
|
|
19
|
+
- If the user is only required to select one option, but needs to create a custom value in addition to selecting from a list, use `Combo Box`.
|
|
20
|
+
- If the options have long names, a list of `Checkboxes` can be used to avoid label truncation.
|
|
21
|
+
|
|
22
|
+
```mermaid
|
|
23
|
+
graph TD
|
|
24
|
+
accDescr: Decision tree that guides on when to use the Multiselect component or something else
|
|
25
|
+
A(Does the user need to select more options?) -- Yes --- B(Are the options lengthy?)
|
|
26
|
+
B -- Yes --- C(Switch - checkbox)
|
|
27
|
+
B -- No --- D(Multiselect)
|
|
28
|
+
A -- No --- E(Does the user need to create custom input value?)
|
|
29
|
+
E -- Yes --- F(Combobox)
|
|
30
|
+
E -- No --- G(Select)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Check out
|
|
34
|
+
- [Select][1]
|
|
35
|
+
- [Radio List][2]
|
|
36
|
+
- [Switch - Checkbox][3]
|
|
37
|
+
- [Combo Box][4]
|
|
38
|
+
|
|
39
|
+
## Behaviors
|
|
40
|
+
|
|
41
|
+
### Default
|
|
42
|
+
Default Multiselect uses removable chips as its value and grows vertically as chips are added.
|
|
43
|
+
|
|
44
|
+
> Image: Image showing the default Multiselect component, which uses chips to display each option. The image shows that when additional selections are made, the Multiselect height grows to fit another row of chips.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
### Compact
|
|
49
|
+
When compact is `true`, Multiselect will never grow vertically. Compact uses a string separated by commas with a count. Note that this compact is different than compact density, which only affects size of the component.
|
|
50
|
+
|
|
51
|
+
> Image: Image showing the compact Multiselect component, which uses a string separated by commas with a count to display the total selection.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
### Compact with Select all appearance
|
|
55
|
+
When compact is `true`, the Select all appearance displays Select and Clear all actions as a menu-item for improved keyboard and screen reader usability.
|
|
56
|
+
|
|
57
|
+
> Image: Image showing the compact Multiselect component in a focus state including a `Select all` button that allows users to select all possible options.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### New Value
|
|
61
|
+
Optionally, users can be allowed to add arbitrary values.
|
|
62
|
+
|
|
63
|
+
> Image: Image showing examples of the Multiselect component with a new value, Hello World, typed in the input box. The first example is a default Multiselect while the second is a compact Multiselect.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
### Matching
|
|
67
|
+
Options can be populated from a server to allow field matching.
|
|
68
|
+
|
|
69
|
+
> Image: Image showing a Multiselect component in a focus state with the word chart typed in the input box, resulting in the list of options being filtered to only show options that have the word chart in the title.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
### Filtering
|
|
73
|
+
When compact is `true`, a search bar is included in the menu to allow users to filter through options.
|
|
74
|
+
|
|
75
|
+
> Image: Image showing a compact Multiselect component in a focus state with the word Line typed in the search box. The menu is filtered down to only show the options, Line (new value) and Line chart.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
### Footers
|
|
79
|
+
Footers can provide additional context on the options.
|
|
80
|
+
|
|
81
|
+
> Image: Image showing a compact Multiselect component in a focus state with a footer with the label, 10 charts.
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
### Leave enough space for selections
|
|
87
|
+
Consider the width of the Multiselect to leave enough space for multiple selections.
|
|
88
|
+
|
|
89
|
+
> Image: In this image, there is a Multiselect and Text Input components in a form. In the first example with heart eyes emoji, the components are vertically stacked. In the second example with a grimacing emoji, the components are horizontally stacked, resulting in the width of the Multiselect shorter and the height being elongated to display the selection.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
### Use the compact variant for large selections
|
|
93
|
+
Consider using the compact design when users are expected to select a large number of options.
|
|
94
|
+
|
|
95
|
+
> Image: In this image, there is a Multiselect component with 6 selected options. In the first example with heart eyes emoji, the Multiselect uses the compact design, while in the second example with a grimacing emoji, it is in the default style. The second example is three times taller than the first to display all six options as chips.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## Content
|
|
99
|
+
|
|
100
|
+
### Be concise
|
|
101
|
+
Keep labels short and compact so that they fit in the input box.
|
|
102
|
+
|
|
103
|
+
> Image: Examples of option label length: The first example with the heart eyes emoji has three options with the titles:
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
[1]: ./Select
|
|
107
|
+
[2]: ./RadioList
|
|
108
|
+
[3]: ./Switch
|
|
109
|
+
[4]: ./ComboBox
|
|
110
|
+
|
|
111
|
+
## Examples
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
### Controlled
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import React, { useCallback, useState } from 'react';
|
|
118
|
+
|
|
119
|
+
import Multiselect, { MultiselectChangeHandler } from '@splunk/react-ui/Multiselect';
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
function Controlled() {
|
|
123
|
+
const [selectedValues, setSelectedValues] = useState<(string | number | boolean)[]>(['1', '5']);
|
|
124
|
+
|
|
125
|
+
const handleChange: MultiselectChangeHandler = useCallback((e, { values }) => {
|
|
126
|
+
setSelectedValues(values);
|
|
127
|
+
}, []);
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<Multiselect values={selectedValues} onChange={handleChange} inline>
|
|
131
|
+
<Multiselect.Option label="Area chart" value="1" />
|
|
132
|
+
<Multiselect.Option label="Bar chart" value="2" />
|
|
133
|
+
<Multiselect.Option label="Bubble chart" value="3" />
|
|
134
|
+
<Multiselect.Option label="Column chart" value="4" />
|
|
135
|
+
<Multiselect.Option label="Line chart" value="5" />
|
|
136
|
+
<Multiselect.Option label="Pie chart" value="6" />
|
|
137
|
+
<Multiselect.Option label="Scatter chart" value="7" />
|
|
138
|
+
</Multiselect>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export default Controlled;
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
### defaultValues
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import React from 'react';
|
|
151
|
+
|
|
152
|
+
import Multiselect from '@splunk/react-ui/Multiselect';
|
|
153
|
+
|
|
154
|
+
const defaultValues = ['1', '5'];
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
function Uncontrolled() {
|
|
158
|
+
return (
|
|
159
|
+
<Multiselect defaultValues={defaultValues} inline>
|
|
160
|
+
<Multiselect.Option label="Area chart" value="1" />
|
|
161
|
+
<Multiselect.Option label="Bar chart" value="2" />
|
|
162
|
+
<Multiselect.Option label="Bubble chart" value="3" />
|
|
163
|
+
<Multiselect.Option label="Column chart" value="4" />
|
|
164
|
+
<Multiselect.Option label="Line chart" value="5" />
|
|
165
|
+
<Multiselect.Option label="Pie chart" value="6" />
|
|
166
|
+
<Multiselect.Option label="Scatter chart" value="7" />
|
|
167
|
+
</Multiselect>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export default Uncontrolled;
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
### values
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import React from 'react';
|
|
180
|
+
|
|
181
|
+
import Multiselect from '@splunk/react-ui/Multiselect';
|
|
182
|
+
|
|
183
|
+
const values = ['Value1', 'Chart5'];
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
function Headings() {
|
|
187
|
+
return (
|
|
188
|
+
<Multiselect inline allowNewValues defaultValues={values}>
|
|
189
|
+
<Multiselect.Option label="Events" value="Basic1" />
|
|
190
|
+
<Multiselect.Divider />
|
|
191
|
+
<Multiselect.Option label="Statistics table" value="Basic2" />
|
|
192
|
+
<Multiselect.Heading>Chart</Multiselect.Heading>
|
|
193
|
+
<Multiselect.Option label="Area chart" value="Chart1" />
|
|
194
|
+
<Multiselect.Option label="Bar chart" value="Chart2" />
|
|
195
|
+
<Multiselect.Option label="Bubble chart" value="Chart3" />
|
|
196
|
+
<Multiselect.Option label="Column chart" value="Chart4" />
|
|
197
|
+
<Multiselect.Option label="Line chart" value="Chart5" />
|
|
198
|
+
<Multiselect.Option label="Pie chart" value="Chart6" />
|
|
199
|
+
<Multiselect.Option label="Scatter chart" value="Chart7" />
|
|
200
|
+
<Multiselect.Heading>Map</Multiselect.Heading>
|
|
201
|
+
<Multiselect.Option label="Choropleth map" value="Map1" />
|
|
202
|
+
<Multiselect.Option label="Cluster map" value="Map2" />
|
|
203
|
+
<Multiselect.Heading>Value</Multiselect.Heading>
|
|
204
|
+
<Multiselect.Option label="Filler gauge" value="Value1" />
|
|
205
|
+
<Multiselect.Option label="Marker gauge" value="Value2" />
|
|
206
|
+
<Multiselect.Option label="Radial gauge" value="Value3" />
|
|
207
|
+
<Multiselect.Option label="Single value" value="Value4" />
|
|
208
|
+
</Multiselect>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export default Headings;
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
### New Values
|
|
218
|
+
|
|
219
|
+
Optionally, users can be allowed to add arbitrary values.
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import React, { useCallback, useState } from 'react';
|
|
223
|
+
|
|
224
|
+
import Multiselect, { MultiselectChangeHandler } from '@splunk/react-ui/Multiselect';
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
function NewValues() {
|
|
228
|
+
const [selectedValues, setSelectedValues] = useState<(string | number | boolean)[]>([
|
|
229
|
+
'Line Chart',
|
|
230
|
+
'Map',
|
|
231
|
+
'Table',
|
|
232
|
+
]);
|
|
233
|
+
|
|
234
|
+
const handleChange: MultiselectChangeHandler = useCallback((e, { values }) => {
|
|
235
|
+
setSelectedValues(values);
|
|
236
|
+
}, []);
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<Multiselect allowNewValues values={selectedValues} onChange={handleChange} inline>
|
|
240
|
+
<Multiselect.Option label="Area chart" value="Area chart" />
|
|
241
|
+
<Multiselect.Option label="Bar chart" value="Bar chart" />
|
|
242
|
+
<Multiselect.Option label="Bubble chart" value="Bubble chart" />
|
|
243
|
+
<Multiselect.Option label="Column chart" value="Column chart" />
|
|
244
|
+
<Multiselect.Option label="Line chart" value="Line chart" />
|
|
245
|
+
<Multiselect.Option label="Pie chart" value="Pie chart" />
|
|
246
|
+
<Multiselect.Option label="Scatter chart" value="Scatter chart" />
|
|
247
|
+
</Multiselect>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export default NewValues;
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
### defaultValues
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import React from 'react';
|
|
260
|
+
|
|
261
|
+
import ChartArea from '@splunk/react-icons/ChartArea';
|
|
262
|
+
import ChartBar from '@splunk/react-icons/ChartBar';
|
|
263
|
+
import ChartBubble from '@splunk/react-icons/ChartBubble';
|
|
264
|
+
import ChartColumn from '@splunk/react-icons/ChartColumn';
|
|
265
|
+
import ChartLine from '@splunk/react-icons/ChartLine';
|
|
266
|
+
import ChartPie from '@splunk/react-icons/ChartPie';
|
|
267
|
+
import ChartScatter from '@splunk/react-icons/ChartScatter';
|
|
268
|
+
import Multiselect from '@splunk/react-ui/Multiselect';
|
|
269
|
+
|
|
270
|
+
const defaultValues = ['1', '5'];
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
function Icons() {
|
|
274
|
+
return (
|
|
275
|
+
<Multiselect defaultValues={defaultValues} inline>
|
|
276
|
+
<Multiselect.Option label="Area chart" icon={<ChartArea />} value="1" />
|
|
277
|
+
<Multiselect.Option label="Bar chart" icon={<ChartBar />} value="2" />
|
|
278
|
+
<Multiselect.Option label="Bubble chart" icon={<ChartBubble />} value="3" />
|
|
279
|
+
<Multiselect.Option label="Column chart" icon={<ChartColumn />} value="4" />
|
|
280
|
+
<Multiselect.Option label="Line chart" icon={<ChartLine />} value="5" />
|
|
281
|
+
<Multiselect.Option label="Pie chart" icon={<ChartPie />} value="6" />
|
|
282
|
+
<Multiselect.Option label="Scatter chart" icon={<ChartScatter />} value="7" />
|
|
283
|
+
</Multiselect>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export default Icons;
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
### Error
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import React, { useCallback, useState } from 'react';
|
|
296
|
+
|
|
297
|
+
import Multiselect, { MultiselectChangeHandler } from '@splunk/react-ui/Multiselect';
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
function MultiselectError() {
|
|
301
|
+
const [selectedValues, setSelectedValues] = useState<(string | number | boolean)[]>(['1', '5']);
|
|
302
|
+
|
|
303
|
+
const handleChange: MultiselectChangeHandler = useCallback((e, { values }) => {
|
|
304
|
+
setSelectedValues(values);
|
|
305
|
+
}, []);
|
|
306
|
+
|
|
307
|
+
return (
|
|
308
|
+
<Multiselect values={selectedValues} onChange={handleChange} error inline>
|
|
309
|
+
<Multiselect.Option label="Area chart" value="1" />
|
|
310
|
+
<Multiselect.Option label="Bar chart" value="2" />
|
|
311
|
+
<Multiselect.Option label="Bubble chart" value="3" />
|
|
312
|
+
<Multiselect.Option label="Column chart" value="4" />
|
|
313
|
+
<Multiselect.Option label="Line chart" value="5" />
|
|
314
|
+
<Multiselect.Option label="Pie chart" value="6" />
|
|
315
|
+
<Multiselect.Option label="Scatter chart" value="7" />
|
|
316
|
+
</Multiselect>
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export default MultiselectError;
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
### Disabled
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
import React, { useCallback, useState } from 'react';
|
|
329
|
+
|
|
330
|
+
import Multiselect, { MultiselectChangeHandler } from '@splunk/react-ui/Multiselect';
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
function Disabled() {
|
|
334
|
+
const [selectedValues, setSelectedValues] = useState<(string | number | boolean)[]>(['1', '5']);
|
|
335
|
+
|
|
336
|
+
const handleChange: MultiselectChangeHandler = useCallback((e, { values }) => {
|
|
337
|
+
setSelectedValues(values);
|
|
338
|
+
}, []);
|
|
339
|
+
|
|
340
|
+
return (
|
|
341
|
+
<Multiselect values={selectedValues} onChange={handleChange} disabled inline>
|
|
342
|
+
<Multiselect.Option label="Area chart" value="1" />
|
|
343
|
+
<Multiselect.Option label="Bar chart" value="2" />
|
|
344
|
+
<Multiselect.Option label="Bubble chart" value="3" />
|
|
345
|
+
<Multiselect.Option label="Column chart" value="4" />
|
|
346
|
+
<Multiselect.Option label="Line chart" value="5" />
|
|
347
|
+
<Multiselect.Option label="Pie chart" value="6" />
|
|
348
|
+
<Multiselect.Option label="Scatter chart" value="7" />
|
|
349
|
+
</Multiselect>
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export default Disabled;
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
### Children
|
|
359
|
+
|
|
360
|
+
children replace label when provided. label is still used for matching to the filter.
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
import React, { useCallback, useState } from 'react';
|
|
364
|
+
|
|
365
|
+
import Multiselect, { MultiselectChangeHandler } from '@splunk/react-ui/Multiselect';
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
function Children() {
|
|
369
|
+
const [selectedValues, setSelectedValues] = useState<(string | number | boolean)[]>(['1', '5']);
|
|
370
|
+
|
|
371
|
+
const handleChange: MultiselectChangeHandler = useCallback((e, { values }) => {
|
|
372
|
+
setSelectedValues(values);
|
|
373
|
+
}, []);
|
|
374
|
+
|
|
375
|
+
return (
|
|
376
|
+
<Multiselect values={selectedValues} onChange={handleChange} inline>
|
|
377
|
+
<Multiselect.Option label="Chart: Area" value="1">
|
|
378
|
+
Chart: <b>Area</b>
|
|
379
|
+
</Multiselect.Option>
|
|
380
|
+
<Multiselect.Option label="Chart: Bar" value="2">
|
|
381
|
+
Chart: <b>Bar</b>
|
|
382
|
+
</Multiselect.Option>
|
|
383
|
+
<Multiselect.Option label="Chart: Bubble" value="3">
|
|
384
|
+
Chart: <b>Bubble</b>
|
|
385
|
+
</Multiselect.Option>
|
|
386
|
+
<Multiselect.Option label="Chart: Column" value="4">
|
|
387
|
+
Chart: <b>Column</b>
|
|
388
|
+
</Multiselect.Option>
|
|
389
|
+
<Multiselect.Option label="Chart: Line" value="5">
|
|
390
|
+
Chart: <b>Line</b>
|
|
391
|
+
</Multiselect.Option>
|
|
392
|
+
<Multiselect.Option label="Chart: Pie" value="6">
|
|
393
|
+
Chart: <b>Pie</b>
|
|
394
|
+
</Multiselect.Option>
|
|
395
|
+
<Multiselect.Option label="Chart: Scatter" value="7">
|
|
396
|
+
Chart: <b>Scatter</b>
|
|
397
|
+
</Multiselect.Option>
|
|
398
|
+
</Multiselect>
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export default Children;
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
### Tab to confirm new value
|
|
408
|
+
|
|
409
|
+
If a new value is entered and there are no other Options available, pressing the Tab key will confirm the new value.
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
import React, { useCallback, useState } from 'react';
|
|
413
|
+
|
|
414
|
+
import Multiselect, { MultiselectChangeHandler } from '@splunk/react-ui/Multiselect';
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
function TabInput() {
|
|
418
|
+
const [selectedValues, setSelectedValues] = useState<(string | number | boolean)[]>(['1', '5']);
|
|
419
|
+
|
|
420
|
+
const handleChange: MultiselectChangeHandler = useCallback((e, { values }) => {
|
|
421
|
+
setSelectedValues(values);
|
|
422
|
+
}, []);
|
|
423
|
+
|
|
424
|
+
return (
|
|
425
|
+
<Multiselect
|
|
426
|
+
values={selectedValues}
|
|
427
|
+
onChange={handleChange}
|
|
428
|
+
inline
|
|
429
|
+
tabConfirmsNewValue
|
|
430
|
+
allowNewValues
|
|
431
|
+
>
|
|
432
|
+
<Multiselect.Option label="Area chart" value="1" />
|
|
433
|
+
<Multiselect.Option label="Bar chart" value="2" />
|
|
434
|
+
<Multiselect.Option label="Bubble chart" value="3" />
|
|
435
|
+
<Multiselect.Option label="Column chart" value="4" />
|
|
436
|
+
<Multiselect.Option label="Line chart" value="5" />
|
|
437
|
+
<Multiselect.Option label="Pie chart" value="6" />
|
|
438
|
+
<Multiselect.Option label="Scatter chart" value="7" />
|
|
439
|
+
</Multiselect>
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export default TabInput;
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
### Customize selected Options
|
|
449
|
+
|
|
450
|
+
It's possible to customize the appearance of selected Options.
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
import React, { useCallback, useState } from 'react';
|
|
454
|
+
|
|
455
|
+
import Multiselect, { MultiselectChangeHandler } from '@splunk/react-ui/Multiselect';
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
function CustomizeSelected() {
|
|
459
|
+
const [selectedValues, setSelectedValues] = useState<(string | number | boolean)[]>([
|
|
460
|
+
'1',
|
|
461
|
+
'4',
|
|
462
|
+
'5',
|
|
463
|
+
]);
|
|
464
|
+
|
|
465
|
+
const handleChange: MultiselectChangeHandler = useCallback((e, { values }) => {
|
|
466
|
+
setSelectedValues(values);
|
|
467
|
+
}, []);
|
|
468
|
+
|
|
469
|
+
return (
|
|
470
|
+
<Multiselect values={selectedValues} onChange={handleChange} inline>
|
|
471
|
+
<Multiselect.Option label="Area chart" value="1" selectedAppearance="warning" />
|
|
472
|
+
<Multiselect.Option label="Bar chart" value="2" />
|
|
473
|
+
<Multiselect.Option label="Bubble chart" value="3" />
|
|
474
|
+
<Multiselect.Option label="Column chart" value="4" selectedAppearance="error" />
|
|
475
|
+
<Multiselect.Option label="Line chart" value="5" />
|
|
476
|
+
<Multiselect.Option label="Pie chart" value="6" />
|
|
477
|
+
<Multiselect.Option label="Scatter chart" value="7" />
|
|
478
|
+
</Multiselect>
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
export default CustomizeSelected;
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
### defaultPlaceholder
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
491
|
+
|
|
492
|
+
import useFetchOptions, {
|
|
493
|
+
isMovieOption,
|
|
494
|
+
Movie,
|
|
495
|
+
MovieOption,
|
|
496
|
+
} from '@splunk/react-ui/fixtures/useFetchOptions';
|
|
497
|
+
import Multiselect, {
|
|
498
|
+
MultiselectChangeHandler,
|
|
499
|
+
MultiselectFilterChangeHandler,
|
|
500
|
+
} from '@splunk/react-ui/Multiselect';
|
|
501
|
+
import { _ } from '@splunk/ui-utils/i18n';
|
|
502
|
+
|
|
503
|
+
const defaultPlaceholder = _('Select a movie...');
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
function Fetching() {
|
|
507
|
+
const [fullCount, setFullCount] = useState(0);
|
|
508
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
509
|
+
const [options, setOptions] = useState<MovieOption[]>([]);
|
|
510
|
+
const [selectedValues, setSelectedValues] = useState<(string | number | boolean)[]>([10, 30]);
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
const { fetch, getFullCount, getSelectedOptions, stop } = useFetchOptions();
|
|
514
|
+
|
|
515
|
+
const handleFetch = useCallback(
|
|
516
|
+
(keyword?: string) => {
|
|
517
|
+
setIsLoading(true);
|
|
518
|
+
|
|
519
|
+
fetch(keyword)
|
|
520
|
+
.then((fetchedOptions) => {
|
|
521
|
+
setIsLoading(false);
|
|
522
|
+
setOptions(fetchedOptions);
|
|
523
|
+
setFullCount(getFullCount());
|
|
524
|
+
})
|
|
525
|
+
.catch((error) => {
|
|
526
|
+
if (!error.isCanceled) throw error;
|
|
527
|
+
});
|
|
528
|
+
},
|
|
529
|
+
[fetch, getFullCount]
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
const handleChange: MultiselectChangeHandler = useCallback(
|
|
533
|
+
(e, { values }) => {
|
|
534
|
+
setSelectedValues(values);
|
|
535
|
+
handleFetch();
|
|
536
|
+
},
|
|
537
|
+
[handleFetch]
|
|
538
|
+
);
|
|
539
|
+
|
|
540
|
+
const handleFilterChange: MultiselectFilterChangeHandler = useCallback(
|
|
541
|
+
(e, { keyword }) => {
|
|
542
|
+
handleFetch(keyword);
|
|
543
|
+
},
|
|
544
|
+
[handleFetch]
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
useEffect(() => {
|
|
548
|
+
handleFetch();
|
|
549
|
+
|
|
550
|
+
return () => {
|
|
551
|
+
stop();
|
|
552
|
+
};
|
|
553
|
+
}, [handleFetch, stop]);
|
|
554
|
+
|
|
555
|
+
const createOption = useCallback(
|
|
556
|
+
(movie: Movie | MovieOption, isSelected = false) => (
|
|
557
|
+
|
|
558
|
+
<Multiselect.Option
|
|
559
|
+
hidden={isSelected}
|
|
560
|
+
key={isSelected ? `selected-${movie.id}` : movie.id}
|
|
561
|
+
label={movie.title}
|
|
562
|
+
matchRanges={isMovieOption(movie) ? movie.matchRanges : undefined}
|
|
563
|
+
value={movie.id}
|
|
564
|
+
/>
|
|
565
|
+
),
|
|
566
|
+
[]
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
const generateOptions = useMemo(() => {
|
|
570
|
+
// The selected items always have to be in the option list, but can be hidden
|
|
571
|
+
let selectedOptions: React.ReactElement[] = [];
|
|
572
|
+
if (selectedValues.length) {
|
|
573
|
+
const selectedMovies = getSelectedOptions(selectedValues as number[]);
|
|
574
|
+
selectedOptions = selectedMovies.map((movie) => createOption(movie, true));
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (isLoading) {
|
|
578
|
+
// Only return the select items
|
|
579
|
+
return selectedOptions;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const list = options.map((movie) => createOption(movie));
|
|
583
|
+
return list.concat(selectedOptions);
|
|
584
|
+
}, [selectedValues, isLoading, options, getSelectedOptions, createOption]);
|
|
585
|
+
|
|
586
|
+
const footerMessage = useMemo(() => {
|
|
587
|
+
if (fullCount > options.length && !isLoading) {
|
|
588
|
+
return _('%1 of %2 movies')
|
|
589
|
+
.replace('%1', options.length.toString())
|
|
590
|
+
.replace('%2', fullCount.toString());
|
|
591
|
+
}
|
|
592
|
+
return null;
|
|
593
|
+
}, [fullCount, options.length, isLoading]);
|
|
594
|
+
|
|
595
|
+
return (
|
|
596
|
+
<Multiselect
|
|
597
|
+
values={selectedValues}
|
|
598
|
+
placeholder={defaultPlaceholder}
|
|
599
|
+
onChange={handleChange}
|
|
600
|
+
controlledFilter
|
|
601
|
+
onFilterChange={handleFilterChange}
|
|
602
|
+
isLoadingOptions={isLoading}
|
|
603
|
+
footerMessage={footerMessage}
|
|
604
|
+
inline
|
|
605
|
+
>
|
|
606
|
+
{generateOptions}
|
|
607
|
+
</Multiselect>
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
export default Fetching;
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
### Load more on scroll bottom
|
|
617
|
+
|
|
618
|
+
Similar example as fetching but it's also possible to append more Options from a server when the list is scrolled to the bottom. Here, that behavior is simulated. The onScrollBottom prop is a function that should fetch more results and append them to the current Options. Once all items are loaded, the onScrollBottom prop should be set to null.
|
|
619
|
+
|
|
620
|
+
```typescript
|
|
621
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
622
|
+
|
|
623
|
+
import useFetchOptions, {
|
|
624
|
+
isMovieOption,
|
|
625
|
+
Movie,
|
|
626
|
+
MovieOption,
|
|
627
|
+
} from '@splunk/react-ui/fixtures/useFetchOptions';
|
|
628
|
+
import Multiselect, {
|
|
629
|
+
MultiselectChangeHandler,
|
|
630
|
+
MultiselectFilterChangeHandler,
|
|
631
|
+
} from '@splunk/react-ui/Multiselect';
|
|
632
|
+
import { _ } from '@splunk/ui-utils/i18n';
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
function LoadMoreOnScrollBottom() {
|
|
636
|
+
const [fullCount, setFullCount] = useState(0);
|
|
637
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
638
|
+
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
639
|
+
const [options, setOptions] = useState<MovieOption[]>([]);
|
|
640
|
+
const [selectedValues, setSelectedValues] = useState<(string | number | boolean)[]>([10, 30]);
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
const { fetch, fetchMore, getFullCount, getSelectedOptions, stop } = useFetchOptions();
|
|
644
|
+
|
|
645
|
+
const handleFetch = useCallback(
|
|
646
|
+
(keyword?: string) => {
|
|
647
|
+
setIsLoading(true);
|
|
648
|
+
|
|
649
|
+
fetch(keyword)
|
|
650
|
+
.then((fetchedOptions) => {
|
|
651
|
+
setIsLoading(false);
|
|
652
|
+
setOptions(fetchedOptions);
|
|
653
|
+
setFullCount(getFullCount());
|
|
654
|
+
})
|
|
655
|
+
.catch((error) => {
|
|
656
|
+
if (!error.isCanceled) throw error;
|
|
657
|
+
});
|
|
658
|
+
},
|
|
659
|
+
[fetch, getFullCount]
|
|
660
|
+
);
|
|
661
|
+
|
|
662
|
+
const handleChange: MultiselectChangeHandler = useCallback(
|
|
663
|
+
(e, { values }) => {
|
|
664
|
+
setSelectedValues(values);
|
|
665
|
+
handleFetch();
|
|
666
|
+
},
|
|
667
|
+
[handleFetch]
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
const handleFetchMore = useCallback(
|
|
671
|
+
(currentOptions: MovieOption[]) => {
|
|
672
|
+
setIsLoadingMore(true);
|
|
673
|
+
|
|
674
|
+
fetchMore(currentOptions)
|
|
675
|
+
.then((fetchedOptions) => {
|
|
676
|
+
setOptions(fetchedOptions);
|
|
677
|
+
setIsLoading(false);
|
|
678
|
+
setIsLoadingMore(false);
|
|
679
|
+
setFullCount(getFullCount());
|
|
680
|
+
})
|
|
681
|
+
.catch((error) => {
|
|
682
|
+
if (!error.isCanceled) {
|
|
683
|
+
throw error;
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
},
|
|
687
|
+
[fetchMore, getFullCount]
|
|
688
|
+
);
|
|
689
|
+
|
|
690
|
+
const handleFilterChange: MultiselectFilterChangeHandler = useCallback(
|
|
691
|
+
(e, { keyword }) => {
|
|
692
|
+
handleFetch(keyword);
|
|
693
|
+
},
|
|
694
|
+
[handleFetch]
|
|
695
|
+
);
|
|
696
|
+
|
|
697
|
+
const handleScrollBottom = useCallback(() => {
|
|
698
|
+
if (!isLoadingMore) {
|
|
699
|
+
handleFetchMore(options);
|
|
700
|
+
}
|
|
701
|
+
}, [handleFetchMore, isLoadingMore, options]);
|
|
702
|
+
|
|
703
|
+
useEffect(() => {
|
|
704
|
+
handleFetch();
|
|
705
|
+
|
|
706
|
+
return () => {
|
|
707
|
+
stop();
|
|
708
|
+
};
|
|
709
|
+
}, [handleFetch, stop]);
|
|
710
|
+
|
|
711
|
+
const createOption = useCallback(
|
|
712
|
+
(movie: Movie | MovieOption, isSelected = false) => (
|
|
713
|
+
|
|
714
|
+
<Multiselect.Option
|
|
715
|
+
hidden={isSelected}
|
|
716
|
+
key={isSelected ? `selected-${movie.id}` : movie.id}
|
|
717
|
+
label={movie.title}
|
|
718
|
+
matchRanges={isMovieOption(movie) ? movie.matchRanges : undefined}
|
|
719
|
+
value={movie.id}
|
|
720
|
+
/>
|
|
721
|
+
),
|
|
722
|
+
[]
|
|
723
|
+
);
|
|
724
|
+
|
|
725
|
+
const generateOptions = useMemo(() => {
|
|
726
|
+
// The selected items always have to be in the option list, but can be hidden
|
|
727
|
+
let selectedOptions: React.ReactElement[] = [];
|
|
728
|
+
if (selectedValues.length) {
|
|
729
|
+
const selectedMovies = getSelectedOptions(selectedValues as number[]);
|
|
730
|
+
selectedOptions = selectedMovies.map((movie) => createOption(movie, true));
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (isLoading) {
|
|
734
|
+
// Only return the select items
|
|
735
|
+
return selectedOptions;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const list = options.map((movie) => createOption(movie));
|
|
739
|
+
return list.concat(selectedOptions);
|
|
740
|
+
}, [createOption, getSelectedOptions, isLoading, options, selectedValues]);
|
|
741
|
+
|
|
742
|
+
const footerMessage = useMemo(() => {
|
|
743
|
+
if (fullCount > options.length && !isLoading) {
|
|
744
|
+
return _('%1 of %2 movies')
|
|
745
|
+
.replace('%1', options.length.toString())
|
|
746
|
+
.replace('%2', fullCount.toString());
|
|
747
|
+
}
|
|
748
|
+
return null;
|
|
749
|
+
}, [fullCount, options.length, isLoading]);
|
|
750
|
+
|
|
751
|
+
return (
|
|
752
|
+
<Multiselect
|
|
753
|
+
values={selectedValues}
|
|
754
|
+
placeholder={_('Select a movie...')}
|
|
755
|
+
onChange={handleChange}
|
|
756
|
+
controlledFilter
|
|
757
|
+
onFilterChange={handleFilterChange}
|
|
758
|
+
onScrollBottom={fullCount === options.length ? undefined : handleScrollBottom} // Disable when all items are loaded.
|
|
759
|
+
isLoadingOptions={isLoading}
|
|
760
|
+
footerMessage={footerMessage}
|
|
761
|
+
inline
|
|
762
|
+
>
|
|
763
|
+
{generateOptions}
|
|
764
|
+
</Multiselect>
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
export default LoadMoreOnScrollBottom;
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
### data
|
|
774
|
+
|
|
775
|
+
```typescript
|
|
776
|
+
import React, { useCallback, useState } from 'react';
|
|
777
|
+
|
|
778
|
+
import Multiselect, { MultiselectChangeHandler } from '@splunk/react-ui/Multiselect';
|
|
779
|
+
|
|
780
|
+
const data = [
|
|
781
|
+
'Area chart',
|
|
782
|
+
'Bar chart',
|
|
783
|
+
'Bubble chart',
|
|
784
|
+
'Column chart',
|
|
785
|
+
'Line chart',
|
|
786
|
+
'Pie chart',
|
|
787
|
+
'Scatter chart',
|
|
788
|
+
];
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
function Compact() {
|
|
792
|
+
const [optionValues, setValues] = useState<(number | boolean | string)[]>([
|
|
793
|
+
'Area chart',
|
|
794
|
+
'Line chart',
|
|
795
|
+
]);
|
|
796
|
+
const [options, setOptions] = useState(data);
|
|
797
|
+
|
|
798
|
+
const multiselectOptions = options.map((v, i) => {
|
|
799
|
+
if (i === options.length - 1) {
|
|
800
|
+
return <Multiselect.Option key={v} label={v} value={v} disabled />;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
return <Multiselect.Option key={v} label={v} value={v} />;
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
const handleChange: MultiselectChangeHandler = useCallback(
|
|
807
|
+
(e, { values }) => setValues(values),
|
|
808
|
+
[]
|
|
809
|
+
);
|
|
810
|
+
|
|
811
|
+
const handleClose = useCallback(() => {
|
|
812
|
+
const optionSet = new Set<number | boolean | string>(options);
|
|
813
|
+
optionValues.forEach((v) => {
|
|
814
|
+
if (!optionSet.has(v)) {
|
|
815
|
+
setOptions([v as string, ...options]);
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
}, [optionValues, options]);
|
|
819
|
+
|
|
820
|
+
return (
|
|
821
|
+
<Multiselect
|
|
822
|
+
values={optionValues}
|
|
823
|
+
onChange={handleChange}
|
|
824
|
+
onClose={handleClose}
|
|
825
|
+
inline
|
|
826
|
+
allowNewValues
|
|
827
|
+
compact
|
|
828
|
+
selectAllAppearance="checkbox"
|
|
829
|
+
>
|
|
830
|
+
{multiselectOptions}
|
|
831
|
+
</Multiselect>
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
export default Compact;
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
## API
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
### Multiselect API
|
|
845
|
+
|
|
846
|
+
#### Props
|
|
847
|
+
|
|
848
|
+
| Name | Type | Required | Default | Description |
|
|
849
|
+
|------|------|------|------|------|
|
|
850
|
+
| allowNewValues | boolean | no | | Allow the user to add arbitrary values. |
|
|
851
|
+
| animateLoading | boolean | no | | |
|
|
852
|
+
| append | boolean | no | | Append removes rounded borders and the border from the right side. |
|
|
853
|
+
| children | React.ReactNode | no | | `children` should be `Multiselect.Option`, `Multiselect.Heading`, or `Multiselect.Divider`. |
|
|
854
|
+
| compact | boolean | no | | When compact, options are shown as checkboxes and the input is a single line. This is useful when placing the Multiselect in a horizontal bar, such as a filter. |
|
|
855
|
+
| controlledFilter | boolean | no | | If true, this component will not handle filtering. The parent must update the Options based on the onFilterChange value. Ignored in `compact` mode if the `filter` prop is provided. |
|
|
856
|
+
| defaultPlacement | 'above' \| 'below' \| 'vertical' | no | 'vertical' | The default placement of the dropdown menu. It might be rendered in a different direction depending upon the space available. |
|
|
857
|
+
| defaultValues | (string \| number \| boolean)[] | no | | Set this property instead of value to keep the value uncontrolled. |
|
|
858
|
+
| describedBy | string | no | | The id of the description. When placed in a ControlGroup, this is automatically set to the ControlGroup's help component. |
|
|
859
|
+
| disabled | boolean | no | | Disable adding and removing. |
|
|
860
|
+
| elementRef | React.Ref<HTMLButtonElement \| HTMLDivElement> | no | | A React ref which is set to the DOM element when the component mounts, and null when it unmounts. |
|
|
861
|
+
| error | boolean | no | | Display as in an error. |
|
|
862
|
+
| filter | boolean \| 'controlled' | no | | Determines whether to show the filter box. When true, the children are automatically filtered based on the label. When controlled, the parent component must provide a onFilterChange callback and update the children. Only supported when `compact=true`. |
|
|
863
|
+
| footerMessage | React.ReactNode | no | | The footer message can show additional information, such as a truncation message. |
|
|
864
|
+
| inline | boolean | no | | Make the control an inline block with variable width. |
|
|
865
|
+
| inputId | string | no | | An id for the input, which may be necessary for accessibility, such as for aria attributes. |
|
|
866
|
+
| inputRef | React.Ref<HTMLInputElement> | no | | A React ref which is set to the input element when the component mounts and null when it unmounts. |
|
|
867
|
+
| isLoadingOptions | boolean | no | | |
|
|
868
|
+
| labelledBy | string | no | | The id of the label. When placed in a ControlGroup, this is automatically set to the ControlGroup's label. |
|
|
869
|
+
| loadingMessage | React.ReactNode | no | | The loading message to show when isLoadingOptions. |
|
|
870
|
+
| menuStyle | React.CSSProperties | no | | Style properties to apply to the Menu. This is primarily used to override the width of the menu should it need to be wider than the toggle Button. |
|
|
871
|
+
| 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. |
|
|
872
|
+
| noOptionsMessage | React.ReactNode | no | _('No matches') | The noOptionsMessage is shown when there are no children and it's not loading, such as when there are no Options matching the filter. This can be customized to the type of content, for example: "No matching dashboards". You can insert other content, such as an error message, or communicate a minimum number of characters to enter to see results. |
|
|
873
|
+
| onChange | MultiselectChangeHandler | no | | A callback to receive the change events. If values is set, this callback is required. This must set the values prop to retain the change. |
|
|
874
|
+
| onClose | () => void | no | | A callback function invoked when the popover closes. |
|
|
875
|
+
| onFilterChange | MultiselectFilterChangeHandler | no | | A callback with the change event and value of the filter box. Providing this callback and setting controlledFilter to true enables you to filter and update the children by other criteria. |
|
|
876
|
+
| onOpen | () => void | no | | A callback function invoked when the popover opens. |
|
|
877
|
+
| onScroll | React.UIEventHandler<Element> | no | | A callback function invoked when the menu is scrolled. |
|
|
878
|
+
| onScrollBottom | MultiselectScrollBottomHandler | no | | A callback function for loading additional list items. Called when the list is scrolled to the bottom or all items in the list are visible. This is called with an event argument if this is the result of a scroll. This should be set this to `null` when all items are loaded. |
|
|
879
|
+
| placeholder | string | no | _('Select...') | If 'value' is undefined or doesn't match an item, the Button will display this text. |
|
|
880
|
+
| prepend | boolean | no | | Prepend removes rounded borders from the left side. |
|
|
881
|
+
| repositionMode | 'none' \| 'flip' | no | 'flip' | See `repositionMode` on `Popover` for details. |
|
|
882
|
+
| selectAllAppearance | 'buttongroup' \| 'checkbox' \| 'none' | no | | **DEPRECATED**: Value 'buttongroup' Determines how to display Select all/Clear all. Only supported when `compact=true`. The 'buttongroup' value is deprecated and will be removed in a future major version. |
|
|
883
|
+
| showSelectedValuesFirst | 'nextOpen' \| 'immediately' \| 'never' | no | | When `compact=true`, move selected values to the top of the list on next open (default), immediately, or not at all. |
|
|
884
|
+
| tabConfirmsNewValue | boolean | no | | Pressing Tab while entering an input confirms the new value. Requires `allowNewValues`. |
|
|
885
|
+
| values | (string \| number \| boolean)[] | no | | Value will be matched to one of the children to deduce the label and/or icon for the toggle. |
|
|
886
|
+
|
|
887
|
+
#### Types
|
|
888
|
+
|
|
889
|
+
| Name | Type | Description |
|
|
890
|
+
|------|------|------|
|
|
891
|
+
| MultiselectChangeHandler | ( event: React.MouseEvent<HTMLButtonElement> \| React.KeyboardEvent<HTMLInputElement>, data: { name?: string; reason?: SelectBaseChangeReason; values: (string \| number \| boolean)[]; } ) => void | |
|
|
892
|
+
| MultiselectFilterChangeHandler | ( event: \| React.ChangeEvent<HTMLInputElement> \| React.FocusEvent<HTMLInputElement> \| React.MouseEvent<HTMLSpanElement> \| React.KeyboardEvent, data: { keyword: string } ) => void | |
|
|
893
|
+
| MultiselectScrollBottomHandler | ( event: React.UIEvent<HTMLDivElement> \| React.KeyboardEvent<HTMLInputElement> \| null ) => void | |
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
### Multiselect.Option API
|
|
898
|
+
|
|
899
|
+
An option within a `Multiselect`.
|
|
900
|
+
|
|
901
|
+
#### Props
|
|
902
|
+
|
|
903
|
+
| Name | Type | Required | Default | Description |
|
|
904
|
+
|------|------|------|------|------|
|
|
905
|
+
| children | React.ReactNode | no | | When provided, `children` is rendered instead of the `label`. Caution: The element(s) passed here must be pure. |
|
|
906
|
+
| description | string | no | | Additional information to explain the option, such as "Recommended". |
|
|
907
|
+
| descriptionPosition | 'right' \| 'bottom' | no | 'bottom' | The description text may appear to the right of the label or under the label. |
|
|
908
|
+
| disabled | boolean | no | | If disabled=true, the option is grayed out and cannot be clicked. |
|
|
909
|
+
| hidden | boolean | no | | Adding hidden options can be useful for resolving the selected display label and icon, when the option should not be in the list. This scenario can arise when Select's filter is controlled, because the selected item may be filtered out; and when a legacy option is valid, but should no longer be displayed as a selectable option. |
|
|
910
|
+
| icon | React.ReactNode | no | | The icon to show before the label. See the @splunk/react-icons package for drop in icons. Caution: The element(s) passed here must be pure. All icons in the react-icons package are pure. |
|
|
911
|
+
| label | string | yes | | The text to show for the option when `children` is not defined. When filtering, the `label` is used for matching to the filter text. |
|
|
912
|
+
| matchRanges | { start: number; end: number }[] | no | | Sections of the label string to highlight as a match. This is automatically set for uncontrolled filters, so it's not normally necessary to set this property when using filtering. |
|
|
913
|
+
| selectedAppearance | 'info' \| 'success' \| 'warning' \| 'error' | no | | The `Chip` appearance to use if the option is selected. Not supported in compact mode. |
|
|
914
|
+
| selectedBackgroundColor | string | no | | The `Chip` background color to use if the option is selected. Not supported in compact mode. |
|
|
915
|
+
| selectedForegroundColor | string | no | | The `Chip` foreground color to use if the option is selected. Not supported in compact mode. |
|
|
916
|
+
| truncate | boolean | no | | When `true`, wrapping is disabled and any additional text is ellipsised. |
|
|
917
|
+
| value | string \| number \| boolean | yes | | The label and/or icon will be placed on the Control's toggle if it matches this value. |
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
### Multiselect.Heading API
|
|
922
|
+
|
|
923
|
+
A non-interactive `Menu` item used to separate and label groups of `Menu` items.
|
|
924
|
+
|
|
925
|
+
#### Props
|
|
926
|
+
|
|
927
|
+
| Name | Type | Required | Default | Description |
|
|
928
|
+
|------|------|------|------|------|
|
|
929
|
+
| children | React.ReactNode | no | | |
|
|
930
|
+
| outerStyle | React.CSSProperties | no | | |
|
|
931
|
+
| title | boolean | no | | Renders this heading as a title to describe the whole `Menu`, which should only be enabled for the first heading in a `Menu`. |
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
|