@splunk/react-ui 5.7.0 → 5.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/Accordion.js +6 -6
  2. package/Box.js +83 -34
  3. package/CHANGELOG.md +34 -0
  4. package/CollapsiblePanel.js +11 -11
  5. package/ComboBox.js +31 -27
  6. package/ControlGroup.js +92 -91
  7. package/DefinitionList.js +9 -9
  8. package/Drawer.d.ts +2 -0
  9. package/Drawer.js +679 -0
  10. package/DualListbox.js +1 -1
  11. package/JSONTree.js +73 -72
  12. package/Link.js +2 -2
  13. package/MIGRATION.md +10 -0
  14. package/Menu.js +338 -240
  15. package/Modal.js +127 -109
  16. package/Multiselect.js +437 -351
  17. package/Paginator.js +14 -12
  18. package/Popover.js +4 -1
  19. package/README.md +11 -0
  20. package/RadioBar.js +1 -1
  21. package/Search.js +103 -88
  22. package/Select.js +42 -40
  23. package/SelectBase.js +374 -328
  24. package/SidePanel.js +346 -167
  25. package/SlidingPanels.js +11 -11
  26. package/StepBar.js +7 -7
  27. package/Switch.js +5 -5
  28. package/Text.js +24 -24
  29. package/TextArea.js +7 -7
  30. package/TransitionOpen.js +204 -185
  31. package/docs-llm/Accordion.md +267 -0
  32. package/docs-llm/Anchor Menu.md +115 -0
  33. package/docs-llm/Anchor.md +54 -0
  34. package/docs-llm/AnimationToggle.md +254 -0
  35. package/docs-llm/Avatar.md +298 -0
  36. package/docs-llm/Badge.md +212 -0
  37. package/docs-llm/Breadcrumbs.md +306 -0
  38. package/docs-llm/Button Group.md +53 -0
  39. package/docs-llm/Button.md +361 -0
  40. package/docs-llm/Card Layout.md +286 -0
  41. package/docs-llm/Card.md +619 -0
  42. package/docs-llm/Checkbox.md +218 -0
  43. package/docs-llm/Chip.md +291 -0
  44. package/docs-llm/Clickable.md +160 -0
  45. package/docs-llm/Code.md +292 -0
  46. package/docs-llm/Collapsible Panel.md +744 -0
  47. package/docs-llm/Color.md +253 -0
  48. package/docs-llm/Column Layout.md +391 -0
  49. package/docs-llm/Combo Box.md +540 -0
  50. package/docs-llm/Control Group.md +594 -0
  51. package/docs-llm/Date.md +270 -0
  52. package/docs-llm/Definition List.md +278 -0
  53. package/docs-llm/Divider.md +216 -0
  54. package/docs-llm/Drawer.md +414 -0
  55. package/docs-llm/Dropdown.md +472 -0
  56. package/docs-llm/Dual Listbox.md +325 -0
  57. package/docs-llm/File.md +653 -0
  58. package/docs-llm/Form Rows.md +374 -0
  59. package/docs-llm/Heading.md +179 -0
  60. package/docs-llm/Image.md +109 -0
  61. package/docs-llm/JSON Tree.md +260 -0
  62. package/docs-llm/Layer.md +74 -0
  63. package/docs-llm/Layout.md +50 -0
  64. package/docs-llm/Link.md +318 -0
  65. package/docs-llm/List.md +189 -0
  66. package/docs-llm/Markdown.md +179 -0
  67. package/docs-llm/Menu.md +735 -0
  68. package/docs-llm/Message Bar.md +236 -0
  69. package/docs-llm/Message.md +248 -0
  70. package/docs-llm/Modal.md +443 -0
  71. package/docs-llm/Monogram.md +159 -0
  72. package/docs-llm/Multiselect.md +937 -0
  73. package/docs-llm/Number.md +298 -0
  74. package/docs-llm/Paginator.md +395 -0
  75. package/docs-llm/Paragraph.md +148 -0
  76. package/docs-llm/Phone Number.md +254 -0
  77. package/docs-llm/Popover.md +166 -0
  78. package/docs-llm/Progress.md +141 -0
  79. package/docs-llm/Radio Bar.md +303 -0
  80. package/docs-llm/Radio List.md +350 -0
  81. package/docs-llm/Resize.md +362 -0
  82. package/docs-llm/Screen Reader Content.md +73 -0
  83. package/docs-llm/Scroll Container Context.md +155 -0
  84. package/docs-llm/Scroll.md +152 -0
  85. package/docs-llm/Search.md +381 -0
  86. package/docs-llm/Select.md +985 -0
  87. package/docs-llm/Side Panel.md +777 -0
  88. package/docs-llm/Slider.md +339 -0
  89. package/docs-llm/Sliding Panels.md +340 -0
  90. package/docs-llm/Split Button.md +295 -0
  91. package/docs-llm/Static Content.md +90 -0
  92. package/docs-llm/Step Bar.md +292 -0
  93. package/docs-llm/Switch.md +268 -0
  94. package/docs-llm/Tab Bar.md +439 -0
  95. package/docs-llm/Tab Layout.md +398 -0
  96. package/docs-llm/Table.md +2642 -0
  97. package/docs-llm/Text Area.md +253 -0
  98. package/docs-llm/Text.md +339 -0
  99. package/docs-llm/Tooltip.md +325 -0
  100. package/docs-llm/Transition Open.md +406 -0
  101. package/docs-llm/Tree.md +586 -0
  102. package/docs-llm/Typography.md +125 -0
  103. package/docs-llm/Wait Spinner.md +121 -0
  104. package/docs-llm/llms.txt +97 -0
  105. package/package.json +6 -5
  106. package/types/src/Box/Box.d.ts +2 -10
  107. package/types/src/Drawer/Body.d.ts +17 -0
  108. package/types/src/Drawer/Drawer.d.ts +114 -0
  109. package/types/src/Drawer/DrawerContext.d.ts +11 -0
  110. package/types/src/Drawer/Footer.d.ts +25 -0
  111. package/types/src/Drawer/Header.d.ts +41 -0
  112. package/types/src/Drawer/docs/examples/Basic.d.ts +6 -0
  113. package/types/src/Drawer/docs/examples/ContainerPosition.d.ts +7 -0
  114. package/types/src/Drawer/docs/examples/InitialFocus.d.ts +9 -0
  115. package/types/src/Drawer/docs/examples/InlinePosition.d.ts +7 -0
  116. package/types/src/Drawer/docs/examples/PagePosition.d.ts +7 -0
  117. package/types/src/Drawer/index.d.ts +2 -0
  118. package/types/src/JSONTree/JSONTree.d.ts +12 -5
  119. package/types/src/JSONTree/renderTreeItems.d.ts +2 -1
  120. package/types/src/Menu/Item.d.ts +2 -1
  121. package/types/src/Menu/docs/examples/SelectableCheckbox.d.ts +7 -0
  122. package/types/src/Modal/Modal.d.ts +1 -2
  123. package/types/src/Select/Option.d.ts +6 -3
  124. package/types/src/Select/Select.d.ts +8 -5
  125. package/types/src/Select/docs/examples/Dimmed.d.ts +7 -0
  126. package/types/src/SelectBase/OptionBase.d.ts +6 -3
  127. package/types/src/SelectBase/SelectBase.d.ts +8 -3
  128. package/types/src/SidePanel/SidePanel.d.ts +43 -2
  129. package/types/src/SidePanel/docs/examples/DockLayout.d.ts +17 -0
  130. package/types/src/SidePanel/docs/examples/InitialFocus.d.ts +9 -0
  131. package/types/src/TransitionOpen/TransitionOpen.d.ts +29 -4
  132. package/types/src/useKeyPress/index.d.ts +9 -2
  133. package/types/src/useOnClickOutside/index.d.ts +2 -0
  134. package/types/src/useOnClickOutside/useOnClickOutside.d.ts +4 -0
  135. package/useKeyPress.js +23 -18
  136. package/useOnClickOutside.d.ts +2 -0
  137. package/useOnClickOutside.js +79 -0
  138. package/types/src/RadioList/docs/examples/Row.d.ts +0 -6
@@ -0,0 +1,777 @@
1
+ # Side Panel
2
+
3
+ ## Examples
4
+
5
+
6
+ ### Basic
7
+
8
+ The size of the Panels is determined by the size of the content or by directly setting innerStyle.
9
+
10
+ ```typescript
11
+ import React, { useState } from 'react';
12
+
13
+ import Button from '@splunk/react-ui/Button';
14
+ import SidePanel from '@splunk/react-ui/SidePanel';
15
+
16
+ type Position = 'leftOpen' | 'rightOpen' | 'topOpen' | 'bottomOpen';
17
+
18
+
19
+ function Basic() {
20
+ const [leftOpen, setLeftOpen] = useState(false);
21
+ const [rightOpen, setRightOpen] = useState(false);
22
+ const [topOpen, setTopOpen] = useState(false);
23
+ const [bottomOpen, setBottomOpen] = useState(false);
24
+
25
+ const handleRequestOpen = (dockPosition: Position) => {
26
+ if (dockPosition === 'bottomOpen') {
27
+ setBottomOpen(true);
28
+ } else if (dockPosition === 'leftOpen') {
29
+ setLeftOpen(true);
30
+ } else if (dockPosition === 'rightOpen') {
31
+ setRightOpen(true);
32
+ } else if (dockPosition === 'topOpen') {
33
+ setTopOpen(true);
34
+ }
35
+ };
36
+
37
+ const openLeftPanel = () => {
38
+ handleRequestOpen('leftOpen');
39
+ };
40
+
41
+ const openRightPanel = () => {
42
+ handleRequestOpen('rightOpen');
43
+ };
44
+
45
+ const openTopPanel = () => {
46
+ handleRequestOpen('topOpen');
47
+ };
48
+
49
+ const openBottomPanel = () => {
50
+ handleRequestOpen('bottomOpen');
51
+ };
52
+
53
+ const handleRequestClose = () => {
54
+ setLeftOpen(false);
55
+ setRightOpen(false);
56
+ setTopOpen(false);
57
+ setBottomOpen(false);
58
+ };
59
+
60
+ return (
61
+ <>
62
+ <Button key="left" onClick={openLeftPanel} label="left" />
63
+ <Button key="right" onClick={openRightPanel} label="right" />
64
+ <Button key="top" onClick={openTopPanel} label="top" />
65
+ <Button key="bottom" onClick={openBottomPanel} label="bottom" />
66
+ <SidePanel
67
+ open={leftOpen}
68
+ dockPosition="left"
69
+ onRequestClose={handleRequestClose}
70
+ innerStyle={{ width: 300 }}
71
+ >
72
+ This is a Panel
73
+ </SidePanel>
74
+ <SidePanel
75
+ open={rightOpen}
76
+ dockPosition="right"
77
+ onRequestClose={handleRequestClose}
78
+ innerStyle={{ width: 300 }}
79
+ >
80
+ This is a Panel
81
+ </SidePanel>
82
+ <SidePanel
83
+ open={topOpen}
84
+ dockPosition="top"
85
+ onRequestClose={handleRequestClose}
86
+ innerStyle={{ height: 300 }}
87
+ >
88
+ This is a Panel
89
+ </SidePanel>
90
+ <SidePanel
91
+ open={bottomOpen}
92
+ dockPosition="bottom"
93
+ onRequestClose={handleRequestClose}
94
+ innerStyle={{ height: 300 }}
95
+ >
96
+ This is a Panel
97
+ </SidePanel>
98
+ </>
99
+ );
100
+ }
101
+
102
+ export default Basic;
103
+ ```
104
+
105
+
106
+
107
+ ### Complex
108
+
109
+ Composition with other components.
110
+
111
+ ```typescript
112
+ import React, { useState } from 'react';
113
+
114
+ import styled from 'styled-components';
115
+
116
+ import ChartArea from '@splunk/react-icons/ChartArea';
117
+ import ChartBar from '@splunk/react-icons/ChartBar';
118
+ import ChartBubble from '@splunk/react-icons/ChartBubble';
119
+ import ChartChoroplethMap from '@splunk/react-icons/ChartChoroplethMap';
120
+ import ChartColumn from '@splunk/react-icons/ChartColumn';
121
+ import ChartGauge from '@splunk/react-icons/ChartGauge';
122
+ import ChartGaugeFiller from '@splunk/react-icons/ChartGaugeFiller';
123
+ import ChartGaugeMarker from '@splunk/react-icons/ChartGaugeMarker';
124
+ import ChartLine from '@splunk/react-icons/ChartLine';
125
+ import ChartPie from '@splunk/react-icons/ChartPie';
126
+ import ChartScatter from '@splunk/react-icons/ChartScatter';
127
+ import ChartSingleValueRadial from '@splunk/react-icons/ChartSingleValueRadial';
128
+ import ChevronsSlash from '@splunk/react-icons/ChevronsSlash';
129
+ import CrossIcon from '@splunk/react-icons/Cross';
130
+ import GeoTag from '@splunk/react-icons/GeoTag';
131
+ import List from '@splunk/react-icons/List';
132
+ import TableIcon from '@splunk/react-icons/Table';
133
+ import Button from '@splunk/react-ui/Button';
134
+ import CollapsiblePanel from '@splunk/react-ui/CollapsiblePanel';
135
+ import Heading from '@splunk/react-ui/Heading';
136
+ import Menu from '@splunk/react-ui/Menu';
137
+ import Search from '@splunk/react-ui/Search';
138
+ import SidePanel from '@splunk/react-ui/SidePanel';
139
+
140
+
141
+ function Composition() {
142
+ const StyledButton = styled(Button)`
143
+ float: right;
144
+ `;
145
+
146
+ const [open, setOpen] = useState(false);
147
+
148
+ const handleOpen = () => {
149
+ setOpen(true);
150
+ };
151
+
152
+ const handleClose = () => {
153
+ setOpen(false);
154
+ };
155
+
156
+ const headerStyle: React.CSSProperties = {
157
+ width: '100%',
158
+ padding: '10px',
159
+ boxSizing: 'border-box',
160
+ display: 'table',
161
+ position: 'relative',
162
+ };
163
+
164
+ const menuStyle: React.CSSProperties = {
165
+ width: 300,
166
+ };
167
+
168
+ return (
169
+ <div>
170
+ <Button onClick={handleOpen} label="Add Panels" />
171
+ <SidePanel
172
+ dockPosition="right"
173
+ open={open}
174
+ onRequestClose={handleClose}
175
+ useLayerForClickAway={false}
176
+ innerStyle={{ width: 300, display: 'flex', flexDirection: 'column' }}
177
+ >
178
+ <div style={headerStyle}>
179
+ <StyledButton
180
+ appearance="subtle"
181
+ onClick={handleClose}
182
+ icon={<CrossIcon width={20} height={20} />}
183
+ />
184
+
185
+ <Heading level={4}>Add title</Heading>
186
+ <Search placeholder="Find..." />
187
+ </div>
188
+ <div style={{ flex: '1 0 0px', overflowY: 'auto' }}>
189
+ <CollapsiblePanel title="New (15)" defaultOpen>
190
+ <Menu style={menuStyle}>
191
+ <Menu.Item startAdornment={<List />}>Events</Menu.Item>
192
+ <Menu.Item startAdornment={<TableIcon />}>Statistic table</Menu.Item>
193
+ <Menu.Item startAdornment={<ChartArea />}>Area chart</Menu.Item>
194
+ <Menu.Item startAdornment={<ChartBar />}>Bar chart</Menu.Item>
195
+ <Menu.Item startAdornment={<ChartBubble />}>Bubble chart</Menu.Item>
196
+ <Menu.Item startAdornment={<ChartColumn />}>Column chart</Menu.Item>
197
+ <Menu.Item startAdornment={<ChartLine />}>Line chart</Menu.Item>
198
+ <Menu.Item startAdornment={<ChartPie />}>Pie chart</Menu.Item>
199
+ <Menu.Item startAdornment={<ChartScatter />}>Scatter chart</Menu.Item>
200
+ <Menu.Item startAdornment={<ChartChoroplethMap />}>
201
+ Choropleth map
202
+ </Menu.Item>
203
+ <Menu.Item startAdornment={<GeoTag />}>Cluster map</Menu.Item>
204
+ <Menu.Item startAdornment={<ChartGaugeFiller />}>
205
+ Filler gauge
206
+ </Menu.Item>
207
+ <Menu.Item startAdornment={<ChartGaugeMarker />}>
208
+ Marker gauge
209
+ </Menu.Item>
210
+ <Menu.Item startAdornment={<ChartGauge />}>Radial gauge</Menu.Item>
211
+ <Menu.Item startAdornment={<ChartSingleValueRadial />}>
212
+ Single value
213
+ </Menu.Item>
214
+ </Menu>
215
+ </CollapsiblePanel>
216
+ <CollapsiblePanel title="New from report (4)">
217
+ <Menu style={menuStyle}>
218
+ <Menu.Item startAdornment={<List />}>
219
+ Errors in the last 24 hours
220
+ </Menu.Item>
221
+ <Menu.Item startAdornment={<List />}>Errors in the last hour</Menu.Item>
222
+ <Menu.Item startAdornment={<List />}>License Usage Data Cube</Menu.Item>
223
+ <Menu.Item startAdornment={<List />}>
224
+ Splunk errors last 24 hours
225
+ </Menu.Item>
226
+ </Menu>
227
+ </CollapsiblePanel>
228
+ <CollapsiblePanel title="Clone from Dashboard (3)">
229
+ <CollapsiblePanel title="Integrity check of installed files">
230
+ <Menu style={menuStyle}>
231
+ <Menu.Item startAdornment={<ChevronsSlash />}>
232
+ Untitled Panel
233
+ </Menu.Item>
234
+ <Menu.Item startAdornment={<TableIcon />}>Untitled Panel</Menu.Item>
235
+ <Menu.Item startAdornment={<ChevronsSlash />}>
236
+ Untitled Panel
237
+ </Menu.Item>
238
+ </Menu>
239
+ </CollapsiblePanel>
240
+ </CollapsiblePanel>
241
+ <CollapsiblePanel title="Add prebuilt Panel (0)" />
242
+ </div>
243
+ </SidePanel>
244
+ </div>
245
+ );
246
+ }
247
+
248
+ export default Composition;
249
+ ```
250
+
251
+
252
+
253
+ ### Change Panel Size
254
+
255
+ ```typescript
256
+ import React, { useState } from 'react';
257
+
258
+ import Button from '@splunk/react-ui/Button';
259
+ import ControlGroup from '@splunk/react-ui/ControlGroup';
260
+ import Number, { NumberChangeHandler } from '@splunk/react-ui/Number';
261
+ import SidePanel from '@splunk/react-ui/SidePanel';
262
+
263
+
264
+ function ChangeWidth() {
265
+ const [open, setOpen] = useState(false);
266
+ const [panelSize, setPanelSize] = useState<number | undefined>(300);
267
+
268
+ const togglePanelOpen = () => {
269
+ setOpen(!open);
270
+ };
271
+
272
+ const handleChangePanelSize: NumberChangeHandler = (e, { value }) => {
273
+ setPanelSize(value);
274
+ };
275
+
276
+ return (
277
+ <div>
278
+ <ControlGroup label="Panel size:" controlsLayout="none">
279
+ <Number
280
+ inline
281
+ value={panelSize}
282
+ onChange={handleChangePanelSize}
283
+ style={{ width: 90 }}
284
+ />
285
+ </ControlGroup>
286
+
287
+ <Button onClick={togglePanelOpen} label="Open Panel" />
288
+ <SidePanel
289
+ open={open}
290
+ dockPosition="right"
291
+ onRequestClose={togglePanelOpen}
292
+ innerStyle={{ width: panelSize ?? 300 }}
293
+ >
294
+ This is a Panel
295
+ </SidePanel>
296
+ </div>
297
+ );
298
+ }
299
+
300
+ export default ChangeWidth;
301
+ ```
302
+
303
+
304
+
305
+ ### exampleContent
306
+
307
+ ```typescript
308
+ import React, { useState } from 'react';
309
+
310
+ import Button from '@splunk/react-ui/Button';
311
+ import ControlGroup from '@splunk/react-ui/ControlGroup';
312
+ import RadioBar, { RadioBarChangeHandler } from '@splunk/react-ui/RadioBar';
313
+ import SidePanel from '@splunk/react-ui/SidePanel';
314
+
315
+ const exampleContent =
316
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent blandit quis justo sed rutrum. Vivamus vehicula consequat metus nec lobortis. Phasellus tempus tempus ultrices. Nullam imperdiet leo pretium massa congue, a tristique mi porttitor. Vivamus bibendum lectus id mattis laoreet. Quisque venenatis ipsum pharetra diam ultricies, nec euismod massa pharetra. Nulla facilisi. In mattis leo eu facilisis fermentum.';
317
+
318
+ const PageTop = () => {
319
+ const [open, setOpen] = useState(false);
320
+
321
+ return (
322
+ <div style={{ border: '2px dashed #999' }}>
323
+ <SidePanel
324
+ open={open}
325
+ dockPosition="top"
326
+ onRequestClose={() => setOpen(false)}
327
+ dockLayout="page"
328
+ >
329
+ <div style={{ padding: 20 }}>
330
+ <h4>Page Panel</h4>
331
+ <p>
332
+ Positions relative to the viewport. Takes full viewport width and overlays
333
+ all content.
334
+ </p>
335
+ <Button onClick={() => setOpen(false)} label="Close" />
336
+ </div>
337
+ </SidePanel>
338
+
339
+ <div style={{ padding: 20 }}>
340
+ <h3>Page Top</h3>
341
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
342
+ </div>
343
+ </div>
344
+ );
345
+ };
346
+
347
+ const PageBottom = () => {
348
+ const [open, setOpen] = useState(false);
349
+
350
+ return (
351
+ <div style={{ border: '2px dashed #999' }}>
352
+ <div style={{ padding: 20 }}>
353
+ <h3>Page Bottom</h3>
354
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
355
+ </div>
356
+
357
+ <SidePanel
358
+ open={open}
359
+ dockPosition="bottom"
360
+ onRequestClose={() => setOpen(false)}
361
+ dockLayout="page"
362
+ >
363
+ <div style={{ padding: 20 }}>
364
+ <h4>Page Panel</h4>
365
+ <p>
366
+ Positions relative to the viewport. Takes full viewport width and overlays
367
+ all content.
368
+ </p>
369
+ <Button onClick={() => setOpen(false)} label="Close" />
370
+ </div>
371
+ </SidePanel>
372
+ </div>
373
+ );
374
+ };
375
+
376
+ const PageLeft = () => {
377
+ const [open, setOpen] = useState(false);
378
+
379
+ return (
380
+ <div style={{ border: '2px dashed #999' }}>
381
+ <SidePanel
382
+ open={open}
383
+ dockPosition="left"
384
+ onRequestClose={() => setOpen(false)}
385
+ dockLayout="page"
386
+ >
387
+ <div style={{ width: '200px', padding: 20 }}>
388
+ <h4>Page Panel</h4>
389
+ <p>
390
+ Positions relative to the viewport. Takes full viewport height and overlays
391
+ all content.
392
+ </p>
393
+ <Button onClick={() => setOpen(false)} label="Close" />
394
+ </div>
395
+ </SidePanel>
396
+
397
+ <div style={{ padding: 20 }}>
398
+ <h3>Page Left</h3>
399
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
400
+ </div>
401
+ </div>
402
+ );
403
+ };
404
+
405
+ const PageRight = () => {
406
+ const [open, setOpen] = useState(false);
407
+
408
+ return (
409
+ <div style={{ border: '2px dashed #999' }}>
410
+ <div style={{ padding: 20 }}>
411
+ <h3>Page Right</h3>
412
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
413
+ </div>
414
+
415
+ <SidePanel
416
+ open={open}
417
+ dockPosition="right"
418
+ onRequestClose={() => setOpen(false)}
419
+ dockLayout="page"
420
+ >
421
+ <div style={{ width: '200px', padding: 20 }}>
422
+ <h4>Page Panel</h4>
423
+ <p>
424
+ Positions relative to the viewport. Takes full viewport height and overlays
425
+ all content.
426
+ </p>
427
+ <Button onClick={() => setOpen(false)} label="Close" />
428
+ </div>
429
+ </SidePanel>
430
+ </div>
431
+ );
432
+ };
433
+
434
+ const ContainerTop = () => {
435
+ const [open, setOpen] = useState(false);
436
+
437
+ return (
438
+ <div style={{ border: '2px dashed #999', position: 'relative' }}>
439
+ <SidePanel open={open} dockPosition="top" dockLayout="container">
440
+ <div style={{ padding: 20 }}>
441
+ <h4>Container Panel</h4>
442
+ <p>Positions to the nearest positioned ancestor (this container).</p>
443
+ <Button onClick={() => setOpen(false)} label="Close" />
444
+ </div>
445
+ </SidePanel>
446
+
447
+ <div style={{ padding: 20 }}>
448
+ <h3>Container Top</h3>
449
+ <p>{exampleContent}</p>
450
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
451
+ </div>
452
+ </div>
453
+ );
454
+ };
455
+
456
+ const ContainerBottom = () => {
457
+ const [open, setOpen] = useState(false);
458
+
459
+ return (
460
+ <div style={{ border: '2px dashed #999', position: 'relative' }}>
461
+ <div style={{ padding: 20 }}>
462
+ <h3>Container Bottom</h3>
463
+ <p>{exampleContent}</p>
464
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
465
+ </div>
466
+
467
+ <SidePanel open={open} dockPosition="bottom" dockLayout="container">
468
+ <div style={{ padding: 20 }}>
469
+ <h4>Container Panel</h4>
470
+ <p>Positions to the nearest positioned ancestor (this container).</p>
471
+ <Button onClick={() => setOpen(false)} label="Close" />
472
+ </div>
473
+ </SidePanel>
474
+ </div>
475
+ );
476
+ };
477
+
478
+ const ContainerLeft = () => {
479
+ const [open, setOpen] = useState(false);
480
+
481
+ return (
482
+ <div style={{ border: '2px dashed #999', position: 'relative' }}>
483
+ <SidePanel open={open} dockPosition="left" dockLayout="container">
484
+ <div style={{ width: '200px', padding: 20 }}>
485
+ <h4>Container Panel</h4>
486
+ <p>Positions to the nearest positioned ancestor (this container).</p>
487
+ <Button onClick={() => setOpen(false)} label="Close" />
488
+ </div>
489
+ </SidePanel>
490
+
491
+ <div style={{ padding: 20 }}>
492
+ <h3>Container Left</h3>
493
+ <p>{exampleContent}</p>
494
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
495
+ </div>
496
+ </div>
497
+ );
498
+ };
499
+
500
+ const ContainerRight = () => {
501
+ const [open, setOpen] = useState(false);
502
+
503
+ return (
504
+ <div style={{ border: '2px dashed #999', position: 'relative' }}>
505
+ <div style={{ padding: 20 }}>
506
+ <h3>Container Right</h3>
507
+ <p>{exampleContent}</p>
508
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
509
+ </div>
510
+
511
+ <SidePanel open={open} dockPosition="right" dockLayout="container">
512
+ <div style={{ width: '200px', padding: 20 }}>
513
+ <h4>Container Panel</h4>
514
+ <p>Positions to the nearest positioned ancestor (this container).</p>
515
+ <Button onClick={() => setOpen(false)} label="Close" />
516
+ </div>
517
+ </SidePanel>
518
+ </div>
519
+ );
520
+ };
521
+
522
+ const InlineTop = () => {
523
+ const [open, setOpen] = useState(false);
524
+
525
+ return (
526
+ <div style={{ border: '2px dashed #999' }}>
527
+ <SidePanel open={open} dockPosition="top" dockLayout="inline">
528
+ <div style={{ padding: 20 }}>
529
+ <h4>Inline Panel</h4>
530
+ <p>Renders inline pushing content down.</p>
531
+ <Button onClick={() => setOpen(false)} label="Close" />
532
+ </div>
533
+ </SidePanel>
534
+
535
+ <div style={{ padding: 20 }}>
536
+ <h3>Inline Top</h3>
537
+ <p>{exampleContent}</p>
538
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
539
+ </div>
540
+ </div>
541
+ );
542
+ };
543
+
544
+ const InlineBottom = () => {
545
+ const [open, setOpen] = useState(false);
546
+
547
+ return (
548
+ <div style={{ border: '2px dashed #999' }}>
549
+ <div style={{ padding: 20 }}>
550
+ <h3>Inline Bottom</h3>
551
+ <p>{exampleContent}</p>
552
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
553
+ </div>
554
+
555
+ <SidePanel open={open} dockPosition="bottom" dockLayout="inline">
556
+ <div style={{ padding: 20 }}>
557
+ <h4>Inline Panel</h4>
558
+ <p>Renders inline after content..</p>
559
+ <Button onClick={() => setOpen(false)} label="Close" />
560
+ </div>
561
+ </SidePanel>
562
+ </div>
563
+ );
564
+ };
565
+
566
+ const InlineLeft = () => {
567
+ const [open, setOpen] = useState(false);
568
+
569
+ return (
570
+ <div style={{ border: '2px dashed #999', display: 'flex', flexDirection: 'row' }}>
571
+ <SidePanel open={open} dockPosition="left" dockLayout="inline">
572
+ <div style={{ width: '200px', padding: 20 }}>
573
+ <h4>Inline Panel</h4>
574
+ <p>Renders inline pushing content to the side.</p>
575
+ <Button onClick={() => setOpen(false)} label="Close" />
576
+ </div>
577
+ </SidePanel>
578
+
579
+ <div style={{ flex: 1, padding: 20 }}>
580
+ <h3>Inline Left</h3>
581
+ <p>{exampleContent}</p>
582
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
583
+ </div>
584
+ </div>
585
+ );
586
+ };
587
+
588
+ const InlineRight = () => {
589
+ const [open, setOpen] = useState(false);
590
+
591
+ return (
592
+ <div style={{ border: '2px dashed #999', display: 'flex', flexDirection: 'row' }}>
593
+ <div style={{ flex: 1, padding: 20 }}>
594
+ <h3>Inline Right</h3>
595
+ <p>{exampleContent}</p>
596
+ <Button onClick={() => setOpen(!open)} label="Toggle Panel" />
597
+ </div>
598
+
599
+ <SidePanel open={open} dockPosition="right" dockLayout="inline">
600
+ <div style={{ width: '200px', padding: 20 }}>
601
+ <h4>Inline Panel</h4>
602
+ <p>Renders inline pushing content to the side.</p>
603
+ <Button onClick={() => setOpen(false)} label="Close" />
604
+ </div>
605
+ </SidePanel>
606
+ </div>
607
+ );
608
+ };
609
+
610
+
611
+ function DockLayout() {
612
+ const [dockPosition, setDockPosition] = useState<'top' | 'bottom' | 'left' | 'right'>('right');
613
+ const [dockLayout, setDockLayout] = useState<'page' | 'container' | 'inline'>('page');
614
+
615
+ const handleDockPositionChange: RadioBarChangeHandler = (e, { value }) => {
616
+ setDockPosition(value as 'top' | 'bottom' | 'left' | 'right');
617
+ };
618
+
619
+ const handleDockLayoutChange: RadioBarChangeHandler = (e, { value }) => {
620
+ setDockLayout(value as 'page' | 'container' | 'inline');
621
+ };
622
+
623
+ const componentMap = {
624
+ page: {
625
+ top: PageTop,
626
+ bottom: PageBottom,
627
+ left: PageLeft,
628
+ right: PageRight,
629
+ },
630
+ container: {
631
+ top: ContainerTop,
632
+ bottom: ContainerBottom,
633
+ left: ContainerLeft,
634
+ right: ContainerRight,
635
+ },
636
+ inline: {
637
+ top: InlineTop,
638
+ bottom: InlineBottom,
639
+ left: InlineLeft,
640
+ right: InlineRight,
641
+ },
642
+ };
643
+
644
+ const SelectedComponent = componentMap[dockLayout][dockPosition];
645
+
646
+ return (
647
+ <div style={{ width: '800px' }}>
648
+ <div style={{ marginBottom: 20 }}>
649
+ <p>
650
+ Select a dock position and layout mode, then click the button to see how the
651
+ panel behaves:
652
+ </p>
653
+
654
+ <ControlGroup label="Dock Position" controlsLayout="none">
655
+ <RadioBar value={dockPosition} onChange={handleDockPositionChange}>
656
+ <RadioBar.Option value="left" label="Left" />
657
+ <RadioBar.Option value="right" label="Right" />
658
+ <RadioBar.Option value="top" label="Top" />
659
+ <RadioBar.Option value="bottom" label="Bottom" />
660
+ </RadioBar>
661
+ </ControlGroup>
662
+
663
+ <ControlGroup label="Dock Layout" controlsLayout="none">
664
+ <RadioBar value={dockLayout} onChange={handleDockLayoutChange}>
665
+ <RadioBar.Option value="page" label="Page" />
666
+ <RadioBar.Option value="container" label="Container" />
667
+ <RadioBar.Option value="inline" label="Inline" />
668
+ </RadioBar>
669
+ </ControlGroup>
670
+ </div>
671
+
672
+ <SelectedComponent />
673
+ </div>
674
+ );
675
+ }
676
+
677
+ export default DockLayout;
678
+ ```
679
+
680
+
681
+
682
+ ### Initial focus
683
+
684
+ Initial focus can be set to a different element using the `initialFocus` prop. Use `'first'` to focus the first focusable element, `'container'` to focus the panel itself, or pass a ref to a specific element.
685
+
686
+ ```typescript
687
+ import React, { useCallback, useState } from 'react';
688
+
689
+ import Button from '@splunk/react-ui/Button';
690
+ import P from '@splunk/react-ui/Paragraph';
691
+ import SidePanel from '@splunk/react-ui/SidePanel';
692
+
693
+
694
+ function InitialFocus() {
695
+ const [acceptButton, setAcceptButton] = useState<HTMLButtonElement | null>();
696
+ const acceptButtonRef = useCallback((el: HTMLButtonElement | null) => setAcceptButton(el), []);
697
+
698
+ const [open, setOpen] = useState(false);
699
+
700
+ const handleRequestOpen = () => {
701
+ setOpen(true);
702
+ };
703
+
704
+ const handleRequestClose = () => {
705
+ setOpen(false);
706
+ };
707
+
708
+ return (
709
+ <>
710
+ <Button onClick={handleRequestOpen} label="Open Panel" />
711
+ <SidePanel
712
+ initialFocus={acceptButton}
713
+ onRequestClose={handleRequestClose}
714
+ open={open}
715
+ dockPosition="right"
716
+ innerStyle={{ width: 400 }}
717
+ >
718
+ <div style={{ padding: 20 }}>
719
+ <P>
720
+ This panel demonstrates how to set initial focus to a specific element. When
721
+ the panel opens, focus is set to the Accept button instead of the first
722
+ focusable element.
723
+ </P>
724
+ <div style={{ display: 'flex', gap: 8, marginTop: 16 }}>
725
+ <Button
726
+ appearance="secondary"
727
+ onClick={handleRequestClose}
728
+ label="Cancel"
729
+ />
730
+ <Button appearance="primary" elementRef={acceptButtonRef} label="Accept" />
731
+ </div>
732
+ </div>
733
+ </SidePanel>
734
+ </>
735
+ );
736
+ }
737
+
738
+ export default InitialFocus;
739
+ ```
740
+
741
+
742
+
743
+
744
+ ## API
745
+
746
+
747
+ ### SidePanel API
748
+
749
+ #### Props
750
+
751
+ | Name | Type | Required | Default | Description |
752
+ |------|------|------|------|------|
753
+ | children | React.ReactNode | no | | |
754
+ | dockLayout | 'page' \| 'container' \| 'inline' | no | 'page' | The layout mode for the panel. - page: Positions relative to the viewport (default) - container: Positions relative to nearest positioned ancestor - inline: Renders inline allowing content to reflow around the panel |
755
+ | dockPosition | 'top' \| 'bottom' \| 'left' \| 'right' | no | 'right' | The position of the Panel on the screen. |
756
+ | elementRef | React.Ref<HTMLDivElement> | no | | A React ref which is set to the DOM element when the component mounts and null when it unmounts. |
757
+ | initialFocus | \| 'first' \| 'container' \| (React.Component & { focus: () => void }) \| HTMLElement \| null | no | | Allows focus to be set to a component other than the default. Supports `'first'` (first focusable element), `'container'` (the panel itself), or a ref. Note: Panel should be in view on open. |
758
+ | innerClassName | string | no | | The inner element can control the width of the side bar when placed left or right and the height when placed top or bottom. |
759
+ | innerStyle | React.CSSProperties | no | | The inner element can control the width of the side bar when placed left or right and the height when placed top or bottom. |
760
+ | onAnimationEnd | () => void | no | | A function called when the open / close animation ends. |
761
+ | onRequestClose | SidePanelRequestCloseHandler | no | | Only applies to dockLayout=page because other dockLayout modes do not support closing via the escape key or click away. A function that is called when a close event occurs. The callback is passed a reason and the event. Generally, this callback should be used to toggle the `open` prop. |
762
+ | open | boolean | no | | Indicates the current open state of the panel. |
763
+ | outerClassName | string | no | | The outer element grows to the width of the side bar when placed left or right or the height when placed top or bottom. It has minimal styles: a white background and a box shadow. Adding styles to this container can be useful when the sidebar must be shorter than the width or height of the page or when multiple sidebars are shown. |
764
+ | outerStyle | React.CSSProperties | no | | The outer element grows to the width of the side bar when placed left or right or the height when placed top or bottom. It has minimal styles: a white background and a box shadow. Adding styles to this container can be useful when the sidebar must be shorter than the width or height of the page or when multiple sidebars are shown. |
765
+ | returnFocus | \| React.MutableRefObject<(React.Component & { focus: () => void }) \| HTMLElement \| null> \| (() => void) | no | | Pass the ref of the invoking element (or other element that follows the logical flow of the application) to automatically move focus to the invoking element on SidePanel close. If using a ref is not possible, you can pass a function that sets focus to the appropriate element. This function will be called when the panel closes. |
766
+ | useLayerForClickAway | boolean | no | true | Only applies to dockLayout=page because other dockLayout modes do not support closing via click away. Indicates whether to add an overlay mask on the whole page, blocking other interactions while the Panel is open. |
767
+
768
+ #### Types
769
+
770
+ | Name | Type | Description |
771
+ |------|------|------|
772
+ | SidePanelRequestCloseHandler | (data: { event: React.MouseEvent<HTMLDivElement> \| MouseEvent \| KeyboardEvent \| TouchEvent; reason: 'clickAway' \| 'escapeKey'; }) => void | |
773
+
774
+
775
+
776
+
777
+