@splunk/react-ui 5.7.1 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Accordion.js +6 -6
- package/Anchor.js +2 -1
- package/Box.js +83 -34
- package/CHANGELOG.md +51 -0
- package/Calendar.js +134 -134
- package/Clickable.js +131 -94
- package/CollapsiblePanel.js +175 -137
- package/ComboBox.js +32 -27
- package/ControlGroup.js +92 -91
- package/DefinitionList.js +9 -9
- package/Drawer.d.ts +2 -0
- package/Drawer.js +679 -0
- package/Dropdown.js +27 -18
- package/DualListbox.js +1 -1
- package/File.js +35 -35
- package/JSONTree.js +73 -72
- package/Link.js +2 -2
- package/MIGRATION.md +10 -0
- package/Menu.js +403 -261
- package/Modal.js +263 -252
- package/Monogram.js +2 -2
- package/Multiselect.js +551 -385
- package/Number.js +2 -1
- package/Paginator.js +14 -12
- package/Popover.js +4 -1
- package/README.md +11 -0
- package/RadioBar.js +1 -1
- package/Search.js +111 -95
- package/Select.js +42 -40
- package/SelectBase.js +819 -715
- package/SidePanel.js +346 -167
- package/SlidingPanels.js +11 -11
- package/StepBar.js +7 -7
- package/Switch.js +5 -5
- package/Table.js +116 -119
- package/Text.js +48 -48
- 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 +292 -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 +939 -0
- package/docs-llm/Notifications.md +46 -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 +591 -0
- package/docs-llm/Typography.md +125 -0
- package/docs-llm/Wait Spinner.md +121 -0
- package/docs-llm/llms.txt +101 -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/Multiselect/Compact.d.ts +8 -3
- package/types/src/Multiselect/Multiselect.d.ts +8 -3
- package/types/src/Multiselect/Normal.d.ts +8 -3
- package/types/src/Multiselect/Option.d.ts +6 -3
- package/types/src/Multiselect/docs/examples/Disabled.d.ts +1 -0
- 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,985 @@
|
|
|
1
|
+
# Select
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
> Image: Illustration of a select 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 choose one option from a list of predefined options without having to render the whole list unless in focus.
|
|
15
|
+
- Users need filtering or sorting, such as in a product list or table.
|
|
16
|
+
|
|
17
|
+
## When to use another component
|
|
18
|
+
- If the list of options is small and you don't need to conserve space, consider using Radio List or Radio Bar to minimize steps.
|
|
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
|
+
- Use Radio List or a Switch - Toggle for yes/no or true/false questions.
|
|
21
|
+
|
|
22
|
+
```mermaid
|
|
23
|
+
graph TD
|
|
24
|
+
accDescr: Decision tree that guides on when to use the Select component or something else
|
|
25
|
+
A(Does the user need to select more options?) -- Yes --- B(Switch - Checkbox or Multiselect)
|
|
26
|
+
A -- No --- C(Does the user need to create custom input value?)
|
|
27
|
+
C -- Yes --- D(Combobox)
|
|
28
|
+
C -- No --- E(Are there less than 5 options and you don't need to conserve space?)
|
|
29
|
+
E -- Yes --- F(Radio List or Radio Bar)
|
|
30
|
+
E -- No --- G(Select)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Check out
|
|
34
|
+
- [Radio List][1]
|
|
35
|
+
- [Radio Bar][2]
|
|
36
|
+
- [Combo Box][3]
|
|
37
|
+
- [Switch][4]
|
|
38
|
+
- [Multiselect][5]
|
|
39
|
+
- [Dropdown][6]
|
|
40
|
+
|
|
41
|
+
## Behaviors
|
|
42
|
+
|
|
43
|
+
### Appearance
|
|
44
|
+
The appearance property changes the Select to any button appearance or a link for use in sentences.
|
|
45
|
+
|
|
46
|
+
> Image: Image showing three Select components with different appearances: default, subtle and link.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### Filtering
|
|
50
|
+
An additonal search bar can be included in the menu to allow users to filter through options.
|
|
51
|
+
|
|
52
|
+
> Image: Image showing a Select in a focus state with an additional search box within the menu for filtering.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
### Descriptions, headings and dividers, or footers
|
|
57
|
+
For complex lists, additional affordances such as descriptions, headings and dividers, or footers can be added.
|
|
58
|
+
|
|
59
|
+
> Image: Image showing three Select components in focus state with different menu appearances, menu item descriptions, menu headers and dividers, and footers.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
## Usage
|
|
63
|
+
|
|
64
|
+
### Leave enough space for selections
|
|
65
|
+
Consider the width of the Select to leave enough space for multiple selections.
|
|
66
|
+
|
|
67
|
+
> Image: In this example, there is a Chart type Select and Save chart button in a form. In the first example with heart eyes emoji, the Select is wide enough that the selected option, Line chart, is completely visible. In the second example with a grimacing emoji, the Select width is shorter so that the label of the selected option is truncated.
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Error
|
|
71
|
+
Validation and error messages help users to understand and resolve problems. The error message should inform users what the problem is and how to fix it.
|
|
72
|
+
|
|
73
|
+
> Image: Examples of a Select with an error message. In the first example with heart eyes emoji, the error message says
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
### Mutually exclusive options
|
|
77
|
+
Each option should be distinct so that users can clearly differentiate between them.
|
|
78
|
+
|
|
79
|
+
> Image: Examples of mutual exclusivity: The first example with the heart eyes emoji shows a Select with the options,
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
#### Options order
|
|
83
|
+
Order your list of options in a way that will make the most sense. This could be by the most commonly selected option, numerically, or alphabetical.
|
|
84
|
+
> Image: Two examples of a Select component labeled
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
#### Limit options
|
|
88
|
+
Limit the number of options as not too overwhelm people with too many options.
|
|
89
|
+
|
|
90
|
+
## Content
|
|
91
|
+
|
|
92
|
+
### Be concise
|
|
93
|
+
Keep options short and compact so that they fit in the input box.
|
|
94
|
+
|
|
95
|
+
> Image: Examples of option label length: The first example with the heart eyes emoji has three options with the titles:
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
### Avoid punctuation and articles (“the”, “an”, “a”)
|
|
99
|
+
Be descriptive, not instructional. If the selection needs more explanation, use help text below the field.
|
|
100
|
+
|
|
101
|
+
> Image: Examples of label punctuation: The first example with the heart eyes emoji shows a Select with the title,
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
[1]: ./Radiolist
|
|
105
|
+
[2]: ./Radiobar
|
|
106
|
+
[3]: ./ComboBox
|
|
107
|
+
[4]: ./Switch
|
|
108
|
+
[5]: ./Multiselect
|
|
109
|
+
[6]: ./Dropdown
|
|
110
|
+
|
|
111
|
+
## Examples
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
### Controlled
|
|
115
|
+
|
|
116
|
+
Select requires a value prop and an onChange callback to update the value prop for most use cases.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import React, { useState } from 'react';
|
|
120
|
+
|
|
121
|
+
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
function Basic() {
|
|
125
|
+
const [value, setValue] = useState<string | number | boolean>('5');
|
|
126
|
+
|
|
127
|
+
const handleChange: SelectChangeHandler = (e, { value: newValue }) => {
|
|
128
|
+
setValue(newValue);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<Select value={value} onChange={handleChange}>
|
|
133
|
+
<Select.Option label="Area chart" value="1" />
|
|
134
|
+
<Select.Option label="Bar chart" value="2" />
|
|
135
|
+
<Select.Option label="Bubble chart" value="3" />
|
|
136
|
+
<Select.Option label="Column chart" value="4" />
|
|
137
|
+
<Select.Option label="Line chart" value="5" />
|
|
138
|
+
<Select.Option label="Pie chart" value="6" />
|
|
139
|
+
<Select.Option label="Scatter chart" value="7" />
|
|
140
|
+
</Select>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export default Basic;
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
### Uncontrolled
|
|
150
|
+
|
|
151
|
+
Alternatively, Select can be uncontrolled and optionally provided a defaultValue. The onChange callback still fires. The value prop cannot be set or updated externally.
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import React from 'react';
|
|
155
|
+
|
|
156
|
+
import Select from '@splunk/react-ui/Select';
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
function Uncontrolled() {
|
|
160
|
+
return (
|
|
161
|
+
<Select defaultValue="1">
|
|
162
|
+
<Select.Option label="Area chart" value="1" />
|
|
163
|
+
<Select.Option label="Bar chart" value="2" />
|
|
164
|
+
<Select.Option label="Bubble chart" value="3" />
|
|
165
|
+
<Select.Option label="Column chart" value="4" />
|
|
166
|
+
<Select.Option label="Line chart" value="5" />
|
|
167
|
+
<Select.Option label="Pie chart" value="6" />
|
|
168
|
+
<Select.Option label="Scatter chart" value="7" />
|
|
169
|
+
</Select>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export default Uncontrolled;
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
### enterpriseIconProps
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import React, { useState } from 'react';
|
|
182
|
+
|
|
183
|
+
import ChartArea from '@splunk/react-icons/ChartArea';
|
|
184
|
+
import ChartBar from '@splunk/react-icons/ChartBar';
|
|
185
|
+
import ChartBubble from '@splunk/react-icons/ChartBubble';
|
|
186
|
+
import ChartColumn from '@splunk/react-icons/ChartColumn';
|
|
187
|
+
import ChartLine from '@splunk/react-icons/ChartLine';
|
|
188
|
+
import ChartPie from '@splunk/react-icons/ChartPie';
|
|
189
|
+
import ChartScatter from '@splunk/react-icons/ChartScatter';
|
|
190
|
+
import EnterpriseChartArea from '@splunk/react-icons/enterprise/ChartArea';
|
|
191
|
+
import EnterpriseChartBar from '@splunk/react-icons/enterprise/ChartBar';
|
|
192
|
+
import EnterpriseChartBubble from '@splunk/react-icons/enterprise/ChartBubble';
|
|
193
|
+
import EnterpriseChartColumn from '@splunk/react-icons/enterprise/ChartColumn';
|
|
194
|
+
import EnterpriseChartLine from '@splunk/react-icons/enterprise/ChartLine';
|
|
195
|
+
import EnterpriseChartPie from '@splunk/react-icons/enterprise/ChartPie';
|
|
196
|
+
import EnterpriseChartScatter from '@splunk/react-icons/enterprise/ChartScatter';
|
|
197
|
+
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
|
|
198
|
+
import { useSplunkTheme } from '@splunk/themes';
|
|
199
|
+
|
|
200
|
+
const enterpriseIconProps = {
|
|
201
|
+
hideDefaultTooltip: true,
|
|
202
|
+
screenReaderText: null,
|
|
203
|
+
size: '16px',
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const enterpriseIcons = {
|
|
207
|
+
'Area chart': <EnterpriseChartArea {...enterpriseIconProps} />,
|
|
208
|
+
'Bar chart': <EnterpriseChartBar {...enterpriseIconProps} />,
|
|
209
|
+
'Bubble chart': <EnterpriseChartBubble {...enterpriseIconProps} />,
|
|
210
|
+
'Column chart': <EnterpriseChartColumn {...enterpriseIconProps} />,
|
|
211
|
+
'Line chart': <EnterpriseChartLine {...enterpriseIconProps} />,
|
|
212
|
+
'Pie chart': <EnterpriseChartPie {...enterpriseIconProps} />,
|
|
213
|
+
'Scatter chart': <EnterpriseChartScatter {...enterpriseIconProps} />,
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const prismaIconProps = {
|
|
217
|
+
height: 20,
|
|
218
|
+
width: 20,
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const prismaIcons = {
|
|
222
|
+
'Area chart': <ChartArea {...prismaIconProps} />,
|
|
223
|
+
'Bar chart': <ChartBar {...prismaIconProps} />,
|
|
224
|
+
'Bubble chart': <ChartBubble {...prismaIconProps} />,
|
|
225
|
+
'Column chart': <ChartColumn {...prismaIconProps} />,
|
|
226
|
+
'Line chart': <ChartLine {...prismaIconProps} />,
|
|
227
|
+
'Pie chart': <ChartPie {...prismaIconProps} />,
|
|
228
|
+
'Scatter chart': <ChartScatter {...prismaIconProps} />,
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
function Icons() {
|
|
233
|
+
const [value, setValue] = useState<string | number | boolean>('Chart5');
|
|
234
|
+
|
|
235
|
+
const handleChange: SelectChangeHandler = (e, { value: key }) => {
|
|
236
|
+
setValue(key);
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const { isEnterprise } = useSplunkTheme();
|
|
240
|
+
const iconMap = isEnterprise ? enterpriseIcons : prismaIcons;
|
|
241
|
+
|
|
242
|
+
return (
|
|
243
|
+
<Select value={value} onChange={handleChange}>
|
|
244
|
+
<Select.Option label="Area chart" icon={iconMap['Area chart']} value="Chart1" />
|
|
245
|
+
<Select.Option label="Bar chart" icon={iconMap['Bar chart']} value="Chart2" />
|
|
246
|
+
<Select.Option label="Bubble chart" icon={iconMap['Bubble chart']} value="Chart3" />
|
|
247
|
+
<Select.Option label="Column chart" icon={iconMap['Column chart']} value="Chart4" />
|
|
248
|
+
<Select.Option label="Line chart" icon={iconMap['Line chart']} value="Chart5" />
|
|
249
|
+
<Select.Option label="Pie chart" icon={iconMap['Pie chart']} value="Chart6" />
|
|
250
|
+
<Select.Option label="Scatter chart" icon={iconMap['Scatter chart']} value="Chart7" />
|
|
251
|
+
</Select>
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export default Icons;
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
### Prefixed Label
|
|
261
|
+
|
|
262
|
+
When used outside of a Control Group, it is useful to inline the label inside the button.
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import React, { useState } from 'react';
|
|
266
|
+
|
|
267
|
+
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
function Prefix() {
|
|
271
|
+
const [selectedValue, setSelectedValue] = useState<string | number | boolean>('5');
|
|
272
|
+
|
|
273
|
+
const handleChange: SelectChangeHandler = (e, { value: newValue }) => {
|
|
274
|
+
setSelectedValue(newValue);
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<Select prefixLabel="Chart" value={selectedValue} onChange={handleChange}>
|
|
279
|
+
<Select.Option label="Area chart" value="1" />
|
|
280
|
+
<Select.Option label="Bar chart" value="2" />
|
|
281
|
+
<Select.Option label="Bubble chart" value="3" />
|
|
282
|
+
<Select.Option label="Column chart" value="4" />
|
|
283
|
+
<Select.Option label="Line chart" value="5" />
|
|
284
|
+
<Select.Option label="Pie chart" value="6" />
|
|
285
|
+
<Select.Option label="Scatter chart" value="7" />
|
|
286
|
+
</Select>
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export default Prefix;
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
### Appearance
|
|
296
|
+
|
|
297
|
+
The appearance prop changes the toggle to any button appearance, or a link for use in sentences.
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
import React, { useState } from 'react';
|
|
301
|
+
|
|
302
|
+
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
function Appearance() {
|
|
306
|
+
const [value, setValue] = useState<string | number | boolean>('4');
|
|
307
|
+
|
|
308
|
+
const handleChange: SelectChangeHandler = (e, { value: newValue }) => {
|
|
309
|
+
setValue(newValue);
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
return (
|
|
313
|
+
<Select appearance="subtle" value={value} onChange={handleChange}>
|
|
314
|
+
<Select.Option label="Area chart" value="1" />
|
|
315
|
+
<Select.Option label="Bar chart" value="2" />
|
|
316
|
+
<Select.Option label="Bubble chart" value="3" />
|
|
317
|
+
<Select.Option label="Column chart" value="4" />
|
|
318
|
+
<Select.Option label="Line chart" value="5" />
|
|
319
|
+
<Select.Option label="Pie chart" value="6" />
|
|
320
|
+
<Select.Option label="Scatter chart" value="7" />
|
|
321
|
+
</Select>
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export default Appearance;
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
### Descriptions
|
|
331
|
+
|
|
332
|
+
Descriptions can be placed below or to the right of the label.
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
import React, { useState } from 'react';
|
|
336
|
+
|
|
337
|
+
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
function Descriptions() {
|
|
341
|
+
const [selectedValue, setSelectedValue] = useState<string | number | boolean>('1');
|
|
342
|
+
|
|
343
|
+
const handleChange: SelectChangeHandler = (e, { value: newValue }) => {
|
|
344
|
+
setSelectedValue(newValue);
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
return (
|
|
348
|
+
<Select value={selectedValue} onChange={handleChange} menuStyle={{ width: 350 }}>
|
|
349
|
+
<Select.Option
|
|
350
|
+
label="Statistics table"
|
|
351
|
+
description="Recommended"
|
|
352
|
+
descriptionPosition="right"
|
|
353
|
+
value="1"
|
|
354
|
+
/>
|
|
355
|
+
<Select.Divider />
|
|
356
|
+
<Select.Option
|
|
357
|
+
label="Choropleth map"
|
|
358
|
+
description="A map with colored regions"
|
|
359
|
+
value="2"
|
|
360
|
+
/>
|
|
361
|
+
<Select.Option
|
|
362
|
+
label="Cluster map"
|
|
363
|
+
description="A map with overlaid circles"
|
|
364
|
+
value="3"
|
|
365
|
+
/>
|
|
366
|
+
</Select>
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export default Descriptions;
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
### Error
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
import React from 'react';
|
|
379
|
+
|
|
380
|
+
import Select from '@splunk/react-ui/Select';
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
function SelectError() {
|
|
384
|
+
return (
|
|
385
|
+
<Select defaultValue="1" error>
|
|
386
|
+
<Select.Option label="Area chart" value="1" />
|
|
387
|
+
<Select.Option label="Bar chart" value="2" />
|
|
388
|
+
<Select.Option label="Bubble chart" value="3" />
|
|
389
|
+
<Select.Option label="Column chart" value="4" />
|
|
390
|
+
<Select.Option label="Line chart" value="5" />
|
|
391
|
+
<Select.Option label="Pie chart" value="6" />
|
|
392
|
+
<Select.Option label="Scatter chart" value="7" />
|
|
393
|
+
</Select>
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export default SelectError;
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
### longLabel
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
import React, { useState } from 'react';
|
|
406
|
+
|
|
407
|
+
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
|
|
408
|
+
|
|
409
|
+
const longLabel = 'A very long label truncation truncation truncation truncation';
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
function Truncate() {
|
|
413
|
+
const [selectedValue, setSelectedValue] = useState<string | number | boolean>('1');
|
|
414
|
+
|
|
415
|
+
const handleChange: SelectChangeHandler = (e, { value: newValue }) => {
|
|
416
|
+
setSelectedValue(newValue);
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
return (
|
|
420
|
+
<Select
|
|
421
|
+
prefixLabel="Direction"
|
|
422
|
+
style={{ maxWidth: '300px' }}
|
|
423
|
+
value={selectedValue}
|
|
424
|
+
onChange={handleChange}
|
|
425
|
+
>
|
|
426
|
+
<Select.Option label={longLabel} truncate value="1" />
|
|
427
|
+
<Select.Option label={longLabel} truncate value="2" />
|
|
428
|
+
<Select.Option label={longLabel} value="3" />
|
|
429
|
+
<Select.Option label={longLabel} value="4" />
|
|
430
|
+
</Select>
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export default Truncate;
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
### Headings and Dividers
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
import React, { useState } from 'react';
|
|
443
|
+
|
|
444
|
+
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
function Headings() {
|
|
448
|
+
const [selectedValue, setSelectedValue] = useState<string | number | boolean>('Chart5');
|
|
449
|
+
|
|
450
|
+
const handleChange: SelectChangeHandler = (e, { value: newValue }) => {
|
|
451
|
+
setSelectedValue(newValue);
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
return (
|
|
455
|
+
<Select value={selectedValue} onChange={handleChange} filter>
|
|
456
|
+
<Select.Option label="Events" value="Basic1" />
|
|
457
|
+
<Select.Divider />
|
|
458
|
+
<Select.Option label="Statistics table" value="Basic2" />
|
|
459
|
+
<Select.Heading>Chart</Select.Heading>
|
|
460
|
+
<Select.Option label="Area chart" value="Chart1" />
|
|
461
|
+
<Select.Option label="Bar chart" value="Chart2" />
|
|
462
|
+
<Select.Option label="Bubble chart" value="Chart3" />
|
|
463
|
+
<Select.Option label="Column chart" value="Chart4" />
|
|
464
|
+
<Select.Option label="Line chart" value="Chart5" />
|
|
465
|
+
<Select.Option label="Pie chart" value="Chart6" />
|
|
466
|
+
<Select.Option label="Scatter chart" value="Chart7" />
|
|
467
|
+
<Select.Heading>Map</Select.Heading>
|
|
468
|
+
<Select.Option label="Choropleth map" value="Map1" />
|
|
469
|
+
<Select.Option label="Cluster map" value="Map2" />
|
|
470
|
+
<Select.Heading>Value</Select.Heading>
|
|
471
|
+
<Select.Option label="Filler gauge" value="Value1" />
|
|
472
|
+
<Select.Option label="Marker gauge" value="Value2" />
|
|
473
|
+
<Select.Option label="Radial gauge" value="Value3" />
|
|
474
|
+
<Select.Option label="Single value" value="Value4" />
|
|
475
|
+
</Select>
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export default Headings;
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
### Children
|
|
485
|
+
|
|
486
|
+
children replace label when provided. label is still used for matching to the filter.
|
|
487
|
+
|
|
488
|
+
```typescript
|
|
489
|
+
import React, { useState } from 'react';
|
|
490
|
+
|
|
491
|
+
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
function Children() {
|
|
495
|
+
const [selectedValue, setSelectedValue] = useState<string | number | boolean>('5');
|
|
496
|
+
|
|
497
|
+
const handleChange: SelectChangeHandler = (e, { value: newValue }) => {
|
|
498
|
+
setSelectedValue(newValue);
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
return (
|
|
502
|
+
<Select value={selectedValue} onChange={handleChange}>
|
|
503
|
+
<Select.Option label="Chart: Area" value="1">
|
|
504
|
+
Chart: <b>Area</b>
|
|
505
|
+
</Select.Option>
|
|
506
|
+
<Select.Option label="Chart: Bar" value="2">
|
|
507
|
+
Chart: <b>Bar</b>
|
|
508
|
+
</Select.Option>
|
|
509
|
+
<Select.Option label="Chart: Bubble" value="3">
|
|
510
|
+
Chart: <b>Bubble</b>
|
|
511
|
+
</Select.Option>
|
|
512
|
+
<Select.Option label="Chart: Column" value="4">
|
|
513
|
+
Chart: <b>Column</b>
|
|
514
|
+
</Select.Option>
|
|
515
|
+
<Select.Option label="Chart: Line" value="5">
|
|
516
|
+
Chart: <b>Line</b>
|
|
517
|
+
</Select.Option>
|
|
518
|
+
<Select.Option label="Chart: Pie" value="6">
|
|
519
|
+
Chart: <b>Pie</b>
|
|
520
|
+
</Select.Option>
|
|
521
|
+
<Select.Option label="Chart: Scatter" value="7">
|
|
522
|
+
Chart: <b>Scatter</b>
|
|
523
|
+
</Select.Option>
|
|
524
|
+
</Select>
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export default Children;
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
### Filter Select Items
|
|
534
|
+
|
|
535
|
+
An additional filter box can be enabled.
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
import React, { useState } from 'react';
|
|
539
|
+
|
|
540
|
+
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
function Filter() {
|
|
544
|
+
const [selectedValue, setSelectedValue] = useState<string | number | boolean>('Chart5');
|
|
545
|
+
|
|
546
|
+
const handleChange: SelectChangeHandler = (e, { value: newValue }) => {
|
|
547
|
+
setSelectedValue(newValue);
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
return (
|
|
551
|
+
<Select value={selectedValue} filter onChange={handleChange}>
|
|
552
|
+
<Select.Option label="Events" value="Basic1" />
|
|
553
|
+
<Select.Option label="Statistics table" value="Basic2" />
|
|
554
|
+
<Select.Heading>Chart</Select.Heading>
|
|
555
|
+
<Select.Option label="Area chart" value="Chart1" />
|
|
556
|
+
<Select.Option label="Bar chart" value="Chart2" />
|
|
557
|
+
<Select.Option label="Bubble chart" value="Chart3" disabled="dimmed" />
|
|
558
|
+
<Select.Option label="Column chart" value="Chart4" />
|
|
559
|
+
<Select.Option label="Line chart" value="Chart5" />
|
|
560
|
+
<Select.Option label="Pie chart" value="Chart6" />
|
|
561
|
+
<Select.Option label="Scatter chart" value="Chart7" />
|
|
562
|
+
<Select.Heading>Map</Select.Heading>
|
|
563
|
+
<Select.Option label="Choropleth map" value="Map1" />
|
|
564
|
+
<Select.Option label="Cluster map" value="Map2" />
|
|
565
|
+
<Select.Heading>Value</Select.Heading>
|
|
566
|
+
<Select.Option label="Filler gauge" value="Value1" />
|
|
567
|
+
<Select.Option label="Marker gauge" value="Value2" />
|
|
568
|
+
<Select.Option label="Radial gauge" value="Value3" />
|
|
569
|
+
<Select.Option label="Single value" value="Value4" />
|
|
570
|
+
</Select>
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
export default Filter;
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
### Fetching
|
|
580
|
+
|
|
581
|
+
It's possible to populate the Options from a server. Here, that behavior is simulated. This simplified example only matches the start of the label. The matchRange prop may be set manually to reflect the matching algorithm used to filter the results. Otherwise matching text is not shown.
|
|
582
|
+
|
|
583
|
+
```typescript
|
|
584
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
585
|
+
|
|
586
|
+
import useFetchOptions, {
|
|
587
|
+
isMovieOption,
|
|
588
|
+
Movie,
|
|
589
|
+
MovieOption,
|
|
590
|
+
} from '@splunk/react-ui/fixtures/useFetchOptions';
|
|
591
|
+
import Select, { SelectChangeHandler, SelectFilterChangeHandler } from '@splunk/react-ui/Select';
|
|
592
|
+
import { _ } from '@splunk/ui-utils/i18n';
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
function Fetching() {
|
|
596
|
+
const [fullCount, setFullCount] = useState(0);
|
|
597
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
598
|
+
const [options, setOptions] = useState<MovieOption[]>([]);
|
|
599
|
+
const [selectedValue, setSelectedValue] = useState<string | number | boolean>('');
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
const { fetch, getFullCount, getOption, stop } = useFetchOptions();
|
|
603
|
+
|
|
604
|
+
const handleFetch = useCallback(
|
|
605
|
+
(keyword = '') => {
|
|
606
|
+
setIsLoading(true);
|
|
607
|
+
fetch(keyword)
|
|
608
|
+
.then((newOptions) => {
|
|
609
|
+
setIsLoading(false);
|
|
610
|
+
setOptions(newOptions);
|
|
611
|
+
setFullCount(getFullCount());
|
|
612
|
+
})
|
|
613
|
+
.catch((error) => {
|
|
614
|
+
if (!error.isCanceled) {
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
},
|
|
619
|
+
[fetch, getFullCount]
|
|
620
|
+
);
|
|
621
|
+
|
|
622
|
+
useEffect(() => {
|
|
623
|
+
handleFetch();
|
|
624
|
+
|
|
625
|
+
return () => {
|
|
626
|
+
stop();
|
|
627
|
+
};
|
|
628
|
+
}, [handleFetch, stop]);
|
|
629
|
+
|
|
630
|
+
const handleChange: SelectChangeHandler = useCallback((e, { value: newValue }) => {
|
|
631
|
+
setSelectedValue(newValue);
|
|
632
|
+
}, []);
|
|
633
|
+
|
|
634
|
+
const handleFilterChange: SelectFilterChangeHandler = useCallback(
|
|
635
|
+
(e, { keyword }) => {
|
|
636
|
+
handleFetch(keyword);
|
|
637
|
+
},
|
|
638
|
+
[handleFetch]
|
|
639
|
+
);
|
|
640
|
+
|
|
641
|
+
const createOption = (movie: Movie | MovieOption, isSelected = false) => (
|
|
642
|
+
|
|
643
|
+
<Select.Option
|
|
644
|
+
hidden={!!isSelected}
|
|
645
|
+
key={isSelected ? `selected-${movie.id}` : movie.id}
|
|
646
|
+
label={movie.title}
|
|
647
|
+
matchRanges={isMovieOption(movie) ? movie.matchRanges : undefined}
|
|
648
|
+
value={movie.id}
|
|
649
|
+
/>
|
|
650
|
+
);
|
|
651
|
+
|
|
652
|
+
const generateOptions = useCallback(() => {
|
|
653
|
+
let selectedOption;
|
|
654
|
+
if (selectedValue) {
|
|
655
|
+
const selectedMovie = getOption(selectedValue as number);
|
|
656
|
+
if (selectedMovie) {
|
|
657
|
+
selectedOption = createOption(selectedMovie, true);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if (isLoading) {
|
|
662
|
+
// Only return the selected item
|
|
663
|
+
return selectedOption;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
const list = options.map((movie) => createOption(movie));
|
|
667
|
+
if (selectedOption) {
|
|
668
|
+
list.push(selectedOption);
|
|
669
|
+
}
|
|
670
|
+
return list;
|
|
671
|
+
}, [selectedValue, isLoading, options, getOption]);
|
|
672
|
+
|
|
673
|
+
const footerMessage = useCallback(() => {
|
|
674
|
+
if (fullCount > options.length && !isLoading) {
|
|
675
|
+
return _('%1 of %2 movies')
|
|
676
|
+
.replace('%1', options.length.toString())
|
|
677
|
+
.replace('%2', fullCount.toString());
|
|
678
|
+
}
|
|
679
|
+
return null;
|
|
680
|
+
}, [fullCount, options.length, isLoading]);
|
|
681
|
+
|
|
682
|
+
return (
|
|
683
|
+
<Select
|
|
684
|
+
value={selectedValue}
|
|
685
|
+
filter="controlled"
|
|
686
|
+
placeholder={_('Select a movie...')}
|
|
687
|
+
menuStyle={{ width: 300 }}
|
|
688
|
+
onChange={handleChange}
|
|
689
|
+
onFilterChange={handleFilterChange}
|
|
690
|
+
isLoadingOptions={isLoading}
|
|
691
|
+
footerMessage={footerMessage()}
|
|
692
|
+
>
|
|
693
|
+
{generateOptions()}
|
|
694
|
+
</Select>
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
export default Fetching;
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
### Load more on scroll bottom
|
|
704
|
+
|
|
705
|
+
This example is similar to the example for fetching. You can 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 fetches more results and appends them to the current Options. Once all items are loaded, the onScrollBottom prop should be set to null.
|
|
706
|
+
|
|
707
|
+
```typescript
|
|
708
|
+
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
|
709
|
+
|
|
710
|
+
import useFetchOptions, {
|
|
711
|
+
isMovieOption,
|
|
712
|
+
Movie,
|
|
713
|
+
MovieOption,
|
|
714
|
+
} from '@splunk/react-ui/fixtures/useFetchOptions';
|
|
715
|
+
import Select, { SelectChangeHandler, SelectFilterChangeHandler } from '@splunk/react-ui/Select';
|
|
716
|
+
import { _ } from '@splunk/ui-utils/i18n';
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
function LoadMoreOnScrollBottom() {
|
|
720
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
721
|
+
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
722
|
+
const [options, setOptions] = useState<MovieOption[]>([]);
|
|
723
|
+
const [selectedValue, setSelectedValue] = useState<string | number | boolean>('');
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
const { fetch, fetchMore, getFullCount, getOption, stop } = useFetchOptions();
|
|
727
|
+
|
|
728
|
+
const handleFetch = useCallback(
|
|
729
|
+
(keyword: string = '') => {
|
|
730
|
+
setIsLoading(true);
|
|
731
|
+
fetch(keyword)
|
|
732
|
+
.then((newOptions) => {
|
|
733
|
+
setOptions(newOptions);
|
|
734
|
+
setIsLoading(false);
|
|
735
|
+
setIsLoadingMore(false);
|
|
736
|
+
})
|
|
737
|
+
.catch((error) => {
|
|
738
|
+
if (!error.isCanceled) {
|
|
739
|
+
throw error;
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
},
|
|
743
|
+
[fetch]
|
|
744
|
+
);
|
|
745
|
+
|
|
746
|
+
useEffect(() => {
|
|
747
|
+
handleFetch();
|
|
748
|
+
|
|
749
|
+
return () => {
|
|
750
|
+
stop();
|
|
751
|
+
};
|
|
752
|
+
}, [handleFetch, stop]);
|
|
753
|
+
|
|
754
|
+
const handleFetchMore = useCallback(() => {
|
|
755
|
+
if (isLoadingMore) return;
|
|
756
|
+
setIsLoadingMore(true);
|
|
757
|
+
fetchMore(options)
|
|
758
|
+
.then((newOptions) => {
|
|
759
|
+
setOptions(newOptions);
|
|
760
|
+
setIsLoading(false);
|
|
761
|
+
setIsLoadingMore(false);
|
|
762
|
+
})
|
|
763
|
+
.catch((error) => {
|
|
764
|
+
if (!error.isCanceled) {
|
|
765
|
+
throw error;
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
}, [isLoadingMore, fetchMore, options]);
|
|
769
|
+
|
|
770
|
+
const handleChange: SelectChangeHandler = useCallback((e, { value: newValue }) => {
|
|
771
|
+
setSelectedValue(newValue);
|
|
772
|
+
}, []);
|
|
773
|
+
|
|
774
|
+
const handleFilterChange: SelectFilterChangeHandler = useCallback(
|
|
775
|
+
(e, { keyword }) => {
|
|
776
|
+
handleFetch(keyword);
|
|
777
|
+
},
|
|
778
|
+
[handleFetch]
|
|
779
|
+
);
|
|
780
|
+
|
|
781
|
+
const handleScrollBottom = useCallback(() => {
|
|
782
|
+
if (!isLoadingMore) {
|
|
783
|
+
handleFetchMore();
|
|
784
|
+
}
|
|
785
|
+
}, [isLoadingMore, handleFetchMore]);
|
|
786
|
+
|
|
787
|
+
const createOption = useCallback(
|
|
788
|
+
(movie: Movie, isSelected = false) => (
|
|
789
|
+
|
|
790
|
+
<Select.Option
|
|
791
|
+
hidden={!!isSelected}
|
|
792
|
+
key={isSelected ? `selected-${movie.id}` : movie.id}
|
|
793
|
+
label={movie.title}
|
|
794
|
+
matchRanges={isMovieOption(movie) ? movie.matchRanges : undefined}
|
|
795
|
+
value={movie.id}
|
|
796
|
+
/>
|
|
797
|
+
),
|
|
798
|
+
[]
|
|
799
|
+
);
|
|
800
|
+
|
|
801
|
+
const generateOptions = useMemo(() => {
|
|
802
|
+
// The selected item always has to be in the option list, but can be hidden
|
|
803
|
+
let selectedOption;
|
|
804
|
+
if (selectedValue) {
|
|
805
|
+
const selectedMovie = getOption(selectedValue as number);
|
|
806
|
+
if (selectedMovie) {
|
|
807
|
+
selectedOption = createOption(selectedMovie, true);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
if (isLoading) {
|
|
812
|
+
// Only return the selected item
|
|
813
|
+
return selectedOption ? [selectedOption] : [];
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
const list = options.map((movie) => createOption(movie));
|
|
817
|
+
if (selectedOption) {
|
|
818
|
+
list.push(selectedOption);
|
|
819
|
+
}
|
|
820
|
+
return list;
|
|
821
|
+
}, [selectedValue, isLoading, options, getOption, createOption]);
|
|
822
|
+
|
|
823
|
+
const footerMessage = useMemo(
|
|
824
|
+
() =>
|
|
825
|
+
_('%1 movies %2')
|
|
826
|
+
.replace('%1', getFullCount().toString())
|
|
827
|
+
.replace('%2', isLoadingMore ? _('(Loading more movies)') : ''),
|
|
828
|
+
[getFullCount, isLoadingMore]
|
|
829
|
+
);
|
|
830
|
+
|
|
831
|
+
const scrollBottom = getFullCount() === options.length ? undefined : handleScrollBottom;
|
|
832
|
+
|
|
833
|
+
return (
|
|
834
|
+
<Select
|
|
835
|
+
value={selectedValue}
|
|
836
|
+
filter="controlled"
|
|
837
|
+
placeholder={_('Select a movie...')}
|
|
838
|
+
menuStyle={{ width: 300 }}
|
|
839
|
+
onChange={handleChange}
|
|
840
|
+
onFilterChange={handleFilterChange}
|
|
841
|
+
onScrollBottom={scrollBottom}
|
|
842
|
+
isLoadingOptions={isLoading}
|
|
843
|
+
footerMessage={footerMessage}
|
|
844
|
+
>
|
|
845
|
+
{generateOptions}
|
|
846
|
+
</Select>
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
export default LoadMoreOnScrollBottom;
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
### Dimmed
|
|
856
|
+
|
|
857
|
+
If you absolutely need to disable a Select use a dimmed Select. When the disabled prop is set to "dimmed", the Select does not respond to events but can still receive focus to ensure users can navigate to the Select when using assistive technologies. This also sets aria-disabled to true.
|
|
858
|
+
|
|
859
|
+
```typescript
|
|
860
|
+
import React, { useState } from 'react';
|
|
861
|
+
|
|
862
|
+
import Select, { SelectChangeHandler } from '@splunk/react-ui/Select';
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
function Dimmed() {
|
|
866
|
+
const [selectedValue, setSelectedValue] = useState<string | number | boolean>('Chart5');
|
|
867
|
+
|
|
868
|
+
const handleChange: SelectChangeHandler = (e, { value: newValue }) => {
|
|
869
|
+
setSelectedValue(newValue);
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
return (
|
|
873
|
+
<Select value={selectedValue} filter onChange={handleChange} disabled="dimmed">
|
|
874
|
+
<Select.Option label="Area chart" value="Chart1" />
|
|
875
|
+
<Select.Option label="Bar chart" value="Chart2" />
|
|
876
|
+
<Select.Option label="Bubble chart" value="Chart3" />
|
|
877
|
+
<Select.Option label="Column chart" value="Chart4" />
|
|
878
|
+
<Select.Option label="Line chart" value="Chart5" />
|
|
879
|
+
<Select.Option label="Pie chart" value="Chart6" />
|
|
880
|
+
<Select.Option label="Scatter chart" value="Chart7" />
|
|
881
|
+
</Select>
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
export default Dimmed;
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
## API
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
### Select API
|
|
895
|
+
|
|
896
|
+
#### Props
|
|
897
|
+
|
|
898
|
+
| Name | Type | Required | Default | Description |
|
|
899
|
+
|------|------|------|------|------|
|
|
900
|
+
| allowKeyMatching | boolean | no | true | Whether or not to allow entered keyboard printable characters to match options. Keymatching is disabled when using filtering or loading. |
|
|
901
|
+
| animateLoading | boolean | no | | Whether or not to show the wait spinner when loading. It's recommended to set this to `true` when loading may take more than one second. |
|
|
902
|
+
| appearance | 'default' \| 'link' \| 'subtle' | no | 'default' | **DEPRECATED**: Value 'link' Change the style of the button or link. The `link` value is deprecated and will be removed in a future major version. |
|
|
903
|
+
| append | boolean | no | | Remove rounding from the right side of the toggle. |
|
|
904
|
+
| children | React.ReactNode | no | | `children` should be `Select.Option`, `Select.Header`, or `Select.Divider`. |
|
|
905
|
+
| 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. This property is effective only when filter is enabled. |
|
|
906
|
+
| defaultValue | string \| number \| boolean | no | | Set this property instead of value to keep the value uncontrolled. |
|
|
907
|
+
| describedBy | string | no | | The id of the description. When placed in a ControlGroup, this is automatically set to the ControlGroup's help component. |
|
|
908
|
+
| disabled | boolean \| 'dimmed' \| 'disabled' | no | | Prevents user interaction and adds disabled styling. If set to `dimmed`, the component is able to receive focus. If set to `disabled`, the component is unable to receive focus (as a result of setting the html `disabled` attribute). |
|
|
909
|
+
| elementRef | React.Ref<HTMLButtonElement> | no | | A React ref which is set to the DOM element when the component mounts, and null when it unmounts. |
|
|
910
|
+
| error | boolean | no | | Highlight the field as having an error. The button will turn red. |
|
|
911
|
+
| 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. This can also be used to fetch new results. |
|
|
912
|
+
| footerMessage | React.ReactNode | no | | The footer message can show additional information, such as a truncation message. |
|
|
913
|
+
| inline | boolean | no | true | Make the control an inline block with variable width. |
|
|
914
|
+
| inputId | string | no | | An id for the input, which may be necessary for accessibility, such as for aria attributes. |
|
|
915
|
+
| inputRef | React.Ref<HTMLInputElement> | no | | A React ref which is set to the input element when the component mounts and null when it unmounts. |
|
|
916
|
+
| isLoadingOptions | boolean | no | | |
|
|
917
|
+
| labelText | string | no | | Text presented in the label for this field. This is used to supply this text along with the current value to a screen reader. |
|
|
918
|
+
| labelledBy | string | no | | The id of the label. When placed in a ControlGroup, this is automatically set to the ControlGroup's label. This property is not used when `labelText` is provided. |
|
|
919
|
+
| loadingMessage | React.ReactNode | no | | The loading message to show when isLoadingOptions. |
|
|
920
|
+
| menuStyle | React.CSSProperties | no | | |
|
|
921
|
+
| 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. |
|
|
922
|
+
| 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. |
|
|
923
|
+
| onChange | SelectChangeHandler | 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. |
|
|
924
|
+
| onClose | () => void | no | | A callback function invoked when the popover closes. |
|
|
925
|
+
| onFilterChange | SelectFilterChangeHandler | 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. |
|
|
926
|
+
| onOpen | () => void | no | | A callback function invoked when the popover opens. |
|
|
927
|
+
| onScroll | React.UIEventHandler<Element> | no | | A callback function invoked when the menu is scrolled. |
|
|
928
|
+
| onScrollBottom | SelectScrollBottomHandler | 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. |
|
|
929
|
+
| placeholder | string | no | _('Select...') | If 'value' is undefined or doesn't match an item, the Button will display this text. |
|
|
930
|
+
| prefixLabel | string | no | | When used outside of a control group, it can be useful to include the label on the toggle. |
|
|
931
|
+
| prepend | boolean | no | | Remove rounding from the left side of the toggle. |
|
|
932
|
+
| repositionMode | 'none' \| 'flip' | no | | See `repositionMode` on `Popover` for details. |
|
|
933
|
+
| suffixLabel | string | no | | Places this string after the selected label. |
|
|
934
|
+
| toggleContent | 'optionChildren' \| 'optionLabel' | no | 'optionChildren' | Controls whether the `children` or `label` of the selected `Option` is rendered on the toggle button. |
|
|
935
|
+
| value | string \| number \| boolean | no | | Value will be matched to one of the children to deduce the label and/or icon for the toggle. |
|
|
936
|
+
|
|
937
|
+
#### Types
|
|
938
|
+
|
|
939
|
+
| Name | Type | Description |
|
|
940
|
+
|------|------|------|
|
|
941
|
+
| SelectChangeHandler | ( event: React.MouseEvent<HTMLButtonElement> \| React.KeyboardEvent<HTMLInputElement>, data: { name?: string; value: string \| number \| boolean; } ) => void | |
|
|
942
|
+
| SelectFilterChangeHandler | ( event: \| React.ChangeEvent<HTMLInputElement> \| React.MouseEvent<HTMLSpanElement> \| React.KeyboardEvent, data: { keyword: string } ) => void | |
|
|
943
|
+
| SelectScrollBottomHandler | ( event: \| React.UIEvent<HTMLDivElement> \| React.KeyboardEvent<HTMLInputElement> \| React.KeyboardEvent<HTMLButtonElement> \| null ) => void | |
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
### Select.Option API
|
|
948
|
+
|
|
949
|
+
An option within a `Select`. Any elements passed to it should be memoized.
|
|
950
|
+
|
|
951
|
+
#### Props
|
|
952
|
+
|
|
953
|
+
| Name | Type | Required | Default | Description |
|
|
954
|
+
|------|------|------|------|------|
|
|
955
|
+
| children | React.ReactNode | no | | When provided, `children` is rendered instead of the `label`. Caution: The element(s) passed here must be pure. |
|
|
956
|
+
| description | string | no | | Additional information to explain the option, such as "Recommended". |
|
|
957
|
+
| descriptionPosition | 'right' \| 'bottom' | no | 'bottom' | The description text may appear to the right of the label or under the label. |
|
|
958
|
+
| disabled | boolean \| 'dimmed' \| 'disabled' | no | | Prevents user interaction and adds disabled styling. If set to `dimmed`, the component is able to receive focus. If set to `disabled`, the component is unable to receive focus (as a result of setting the html `disabled` attribute). |
|
|
959
|
+
| elementRef | React.Ref<HTMLAnchorElement \| HTMLButtonElement> | no | | A React ref which is set to the DOM element when the component mounts, and null when it unmounts. |
|
|
960
|
+
| 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. |
|
|
961
|
+
| 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. |
|
|
962
|
+
| 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. |
|
|
963
|
+
| 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. |
|
|
964
|
+
| truncate | boolean | no | | When `true`, wrapping is disabled and any additional text is ellipsised. |
|
|
965
|
+
| value | string \| number \| boolean | yes | | The label and/or icon will be placed on the Control's toggle if it matches this value. |
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
### Select.Heading API
|
|
970
|
+
|
|
971
|
+
A non-interactive `Menu` item used to separate and label groups of `Menu` items.
|
|
972
|
+
|
|
973
|
+
#### Props
|
|
974
|
+
|
|
975
|
+
| Name | Type | Required | Default | Description |
|
|
976
|
+
|------|------|------|------|------|
|
|
977
|
+
| children | React.ReactNode | no | | |
|
|
978
|
+
| outerStyle | React.CSSProperties | no | | |
|
|
979
|
+
| 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`. |
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
|