@patternfly/react-docs 7.6.0-prerelease.8 → 7.6.0-prerelease.9
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/CHANGELOG.md +6 -0
- package/LICENSE +21 -0
- package/package.json +12 -11
- package/patternfly-docs/generated/components/about-modal/react.js +0 -149
- package/patternfly-docs/generated/components/accordion/react.js +0 -262
- package/patternfly-docs/generated/components/action-list/react.js +0 -144
- package/patternfly-docs/generated/components/alert/react-demos.js +0 -56
- package/patternfly-docs/generated/components/alert/react.js +0 -1433
- package/patternfly-docs/generated/components/avatar/react.js +0 -166
- package/patternfly-docs/generated/components/back-to-top/react-demos.js +0 -60
- package/patternfly-docs/generated/components/back-to-top/react.js +0 -77
- package/patternfly-docs/generated/components/backdrop/react.js +0 -64
- package/patternfly-docs/generated/components/background-image/react.js +0 -62
- package/patternfly-docs/generated/components/badge/react.js +0 -97
- package/patternfly-docs/generated/components/banner/react-demos.js +0 -57
- package/patternfly-docs/generated/components/banner/react.js +0 -148
- package/patternfly-docs/generated/components/brand/react.js +0 -142
- package/patternfly-docs/generated/components/breadcrumb/react.js +0 -206
- package/patternfly-docs/generated/components/button/react-demos.js +0 -57
- package/patternfly-docs/generated/components/button/react.js +0 -826
- package/patternfly-docs/generated/components/card/react-demos.js +0 -201
- package/patternfly-docs/generated/components/card/react.js +0 -1015
- package/patternfly-docs/generated/components/charts/area-chart/-Victory.js +0 -1350
- package/patternfly-docs/generated/components/charts/bar-chart/-Victory.js +0 -1334
- package/patternfly-docs/generated/components/charts/box-plot-chart/-Victory.js +0 -1282
- package/patternfly-docs/generated/components/charts/bullet-chart/-Victory.js +0 -848
- package/patternfly-docs/generated/components/charts/colors-for-charts/-Victory.js +0 -192
- package/patternfly-docs/generated/components/charts/donut-chart/-Victory.js +0 -426
- package/patternfly-docs/generated/components/charts/donut-utilization-chart/-Victory.js +0 -804
- package/patternfly-docs/generated/components/charts/legends/-Victory.js +0 -3230
- package/patternfly-docs/generated/components/charts/line-chart/-Victory.js +0 -1178
- package/patternfly-docs/generated/components/charts/line-chart/ECharts.js +0 -525
- package/patternfly-docs/generated/components/charts/patterns/-Victory.js +0 -3382
- package/patternfly-docs/generated/components/charts/pie-chart/-Victory.js +0 -377
- package/patternfly-docs/generated/components/charts/resize-observer/-Victory.js +0 -2475
- package/patternfly-docs/generated/components/charts/sankey-chart/ECharts.js +0 -538
- package/patternfly-docs/generated/components/charts/scatter-chart/-Victory.js +0 -1551
- package/patternfly-docs/generated/components/charts/skeletons/-Victory.js +0 -4115
- package/patternfly-docs/generated/components/charts/sparkline-chart/-Victory.js +0 -955
- package/patternfly-docs/generated/components/charts/stack-chart/-Victory.js +0 -1173
- package/patternfly-docs/generated/components/charts/threshold-chart/-Victory.js +0 -1166
- package/patternfly-docs/generated/components/charts/tooltips/-Victory.js +0 -413
- package/patternfly-docs/generated/components/chip/react-deprecated.js +0 -323
- package/patternfly-docs/generated/components/clipboard-copy/react.js +0 -373
- package/patternfly-docs/generated/components/code-block/react.js +0 -148
- package/patternfly-docs/generated/components/code-editor/react.js +0 -659
- package/patternfly-docs/generated/components/compass/react-demos.js +0 -147
- package/patternfly-docs/generated/components/compass/react.js +0 -440
- package/patternfly-docs/generated/components/content/react.js +0 -248
- package/patternfly-docs/generated/components/data-list/react-demos.js +0 -90
- package/patternfly-docs/generated/components/data-list/react.js +0 -709
- package/patternfly-docs/generated/components/date-and-time/calendar-month/react.js +0 -283
- package/patternfly-docs/generated/components/date-and-time/date-and-time-picker/react-demos.js +0 -64
- package/patternfly-docs/generated/components/date-and-time/date-picker/react-demos.js +0 -83
- package/patternfly-docs/generated/components/date-and-time/date-picker/react.js +0 -395
- package/patternfly-docs/generated/components/date-and-time/time-picker/react.js +0 -241
- package/patternfly-docs/generated/components/description-list/react-demos.js +0 -58
- package/patternfly-docs/generated/components/description-list/react.js +0 -743
- package/patternfly-docs/generated/components/divider/react.js +0 -126
- package/patternfly-docs/generated/components/drag-and-drop/react-demos.js +0 -351
- package/patternfly-docs/generated/components/drag-and-drop/react-deprecated.js +0 -184
- package/patternfly-docs/generated/components/drag-and-drop/react.js +0 -137
- package/patternfly-docs/generated/components/drawer/react.js +0 -598
- package/patternfly-docs/generated/components/dual-list-selector/react-deprecated.js +0 -772
- package/patternfly-docs/generated/components/dual-list-selector/react.js +0 -594
- package/patternfly-docs/generated/components/empty-state/react.js +0 -199
- package/patternfly-docs/generated/components/expandable-section/react-demos.js +0 -65
- package/patternfly-docs/generated/components/expandable-section/react.js +0 -408
- package/patternfly-docs/generated/components/file-upload/multiple-file-upload/react-demos.js +0 -52
- package/patternfly-docs/generated/components/file-upload/multiple-file-upload/react.js +0 -398
- package/patternfly-docs/generated/components/file-upload/simple-file-upload/react.js +0 -749
- package/patternfly-docs/generated/components/forms/checkbox/react.js +0 -222
- package/patternfly-docs/generated/components/forms/form/react.js +0 -1106
- package/patternfly-docs/generated/components/forms/form-select/react.js +0 -208
- package/patternfly-docs/generated/components/forms/radio/react.js +0 -212
- package/patternfly-docs/generated/components/forms/text-area/react.js +0 -160
- package/patternfly-docs/generated/components/forms/text-input/react.js +0 -216
- package/patternfly-docs/generated/components/helper-text/react-demos.js +0 -180
- package/patternfly-docs/generated/components/helper-text/react.js +0 -164
- package/patternfly-docs/generated/components/hero/react.js +0 -88
- package/patternfly-docs/generated/components/hint/react.js +0 -169
- package/patternfly-docs/generated/components/icon/react.js +0 -215
- package/patternfly-docs/generated/components/input-group/react.js +0 -182
- package/patternfly-docs/generated/components/jump-links/react-demos.js +0 -154
- package/patternfly-docs/generated/components/jump-links/react.js +0 -212
- package/patternfly-docs/generated/components/label/react-demos.js +0 -57
- package/patternfly-docs/generated/components/label/react.js +0 -417
- package/patternfly-docs/generated/components/list/react.js +0 -175
- package/patternfly-docs/generated/components/login-page/react.js +0 -587
- package/patternfly-docs/generated/components/masthead/react-demos.js +0 -79
- package/patternfly-docs/generated/components/masthead/react.js +0 -291
- package/patternfly-docs/generated/components/menus/application-launcher/react-demos.js +0 -769
- package/patternfly-docs/generated/components/menus/context-selector/react-demos.js +0 -665
- package/patternfly-docs/generated/components/menus/custom-menus/react-demos.js +0 -187
- package/patternfly-docs/generated/components/menus/dropdown/react-templates.js +0 -163
- package/patternfly-docs/generated/components/menus/dropdown/react.js +0 -998
- package/patternfly-docs/generated/components/menus/menu/react.js +0 -1540
- package/patternfly-docs/generated/components/menus/menu-toggle/react.js +0 -747
- package/patternfly-docs/generated/components/menus/options-menu/react-demos.js +0 -508
- package/patternfly-docs/generated/components/menus/select/react-templates.js +0 -257
- package/patternfly-docs/generated/components/menus/select/react.js +0 -998
- package/patternfly-docs/generated/components/modal/react-deprecated.js +0 -554
- package/patternfly-docs/generated/components/modal/react.js +0 -597
- package/patternfly-docs/generated/components/navigation/react-demos.js +0 -356
- package/patternfly-docs/generated/components/navigation/react.js +0 -409
- package/patternfly-docs/generated/components/notification-badge/react.js +0 -196
- package/patternfly-docs/generated/components/notification-drawer/react-demos.js +0 -107
- package/patternfly-docs/generated/components/notification-drawer/react.js +0 -394
- package/patternfly-docs/generated/components/number-input/react.js +0 -210
- package/patternfly-docs/generated/components/overflow-menu/react.js +0 -274
- package/patternfly-docs/generated/components/page/react-demos.js +0 -149
- package/patternfly-docs/generated/components/page/react.js +0 -1352
- package/patternfly-docs/generated/components/pagination/react.js +0 -492
- package/patternfly-docs/generated/components/panel/react.js +0 -236
- package/patternfly-docs/generated/components/popover/react.js +0 -390
- package/patternfly-docs/generated/components/progress/react-demos.js +0 -59
- package/patternfly-docs/generated/components/progress/react.js +0 -283
- package/patternfly-docs/generated/components/progress-stepper/react-demos.js +0 -45
- package/patternfly-docs/generated/components/progress-stepper/react.js +0 -219
- package/patternfly-docs/generated/components/search-input/react-demos.js +0 -113
- package/patternfly-docs/generated/components/search-input/react.js +0 -263
- package/patternfly-docs/generated/components/sidebar/react.js +0 -236
- package/patternfly-docs/generated/components/simple-list/react.js +0 -200
- package/patternfly-docs/generated/components/skeleton/react-demos.js +0 -44
- package/patternfly-docs/generated/components/skeleton/react.js +0 -122
- package/patternfly-docs/generated/components/skip-to-content/react.js +0 -73
- package/patternfly-docs/generated/components/slider/react.js +0 -309
- package/patternfly-docs/generated/components/spinner/react.js +0 -111
- package/patternfly-docs/generated/components/switch/react.js +0 -163
- package/patternfly-docs/generated/components/table/react-demos.js +0 -355
- package/patternfly-docs/generated/components/table/react-deprecated.js +0 -1350
- package/patternfly-docs/generated/components/table/react.js +0 -3241
- package/patternfly-docs/generated/components/tabs/react-demos.js +0 -108
- package/patternfly-docs/generated/components/tabs/react.js +0 -1359
- package/patternfly-docs/generated/components/text-input-group/react-demos.js +0 -152
- package/patternfly-docs/generated/components/text-input-group/react.js +0 -278
- package/patternfly-docs/generated/components/tile/react-deprecated.js +0 -242
- package/patternfly-docs/generated/components/timestamp/react.js +0 -283
- package/patternfly-docs/generated/components/title/react.js +0 -94
- package/patternfly-docs/generated/components/toggle-group/react.js +0 -299
- package/patternfly-docs/generated/components/toolbar/react-demos.js +0 -66
- package/patternfly-docs/generated/components/toolbar/react.js +0 -932
- package/patternfly-docs/generated/components/tooltip/react.js +0 -241
- package/patternfly-docs/generated/components/tree-view/react.js +0 -429
- package/patternfly-docs/generated/components/truncate/react.js +0 -211
- package/patternfly-docs/generated/components/wizard/react-demos.js +0 -87
- package/patternfly-docs/generated/components/wizard/react-deprecated.js +0 -788
- package/patternfly-docs/generated/components/wizard/react.js +0 -986
- package/patternfly-docs/generated/developer-guides/open-ui-automation/react.js +0 -285
- package/patternfly-docs/generated/foundations-and-styles/layouts/bullseye/react.js +0 -70
- package/patternfly-docs/generated/foundations-and-styles/layouts/flex/react.js +0 -506
- package/patternfly-docs/generated/foundations-and-styles/layouts/gallery/react.js +0 -94
- package/patternfly-docs/generated/foundations-and-styles/layouts/grid/react.js +0 -272
- package/patternfly-docs/generated/foundations-and-styles/layouts/level/react.js +0 -87
- package/patternfly-docs/generated/foundations-and-styles/layouts/split/react.js +0 -124
- package/patternfly-docs/generated/foundations-and-styles/layouts/stack/react.js +0 -112
- package/patternfly-docs/generated/index.js +0 -1769
- package/patternfly-docs/generated/patterns/card-view/react-demos.js +0 -78
- package/patternfly-docs/generated/patterns/filters/react-demos.js +0 -141
- package/patternfly-docs/generated/patterns/password-generator/react-demos.js +0 -51
- package/patternfly-docs/generated/patterns/password-strength/react-demos.js +0 -61
- package/patternfly-docs/generated/patterns/primary-detail/react-demos.js +0 -124
- package/patternfly-docs/generated/patterns/right-to-left/react-demos.js +0 -81
|
@@ -1,594 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components';
|
|
3
|
-
import { Fragment, useEffect, useMemo, useState } from 'react';
|
|
4
|
-
import RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon';
|
|
5
|
-
import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';
|
|
6
|
-
import AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon';
|
|
7
|
-
import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';
|
|
8
|
-
import RhMicronsSortDownSmallToLargeIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-sort-down-small-to-large-icon';
|
|
9
|
-
import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
|
|
10
|
-
import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon';
|
|
11
|
-
import { DragDropSort, DragDropContainer, Droppable as NewDroppable } from '@patternfly/react-drag-drop';
|
|
12
|
-
const pageData = {
|
|
13
|
-
"id": "Dual list selector",
|
|
14
|
-
"section": "components",
|
|
15
|
-
"subsection": "",
|
|
16
|
-
"deprecated": false,
|
|
17
|
-
"template": false,
|
|
18
|
-
"beta": false,
|
|
19
|
-
"demo": false,
|
|
20
|
-
"newImplementationLink": false,
|
|
21
|
-
"source": "react",
|
|
22
|
-
"tabName": null,
|
|
23
|
-
"slug": "/components/dual-list-selector/react",
|
|
24
|
-
"sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/react-core/src/components/DualListSelector/examples/DualListSelector.md",
|
|
25
|
-
"relPath": "packages/react-core/src/components/DualListSelector/examples/DualListSelector.md",
|
|
26
|
-
"propComponents": [
|
|
27
|
-
{
|
|
28
|
-
"name": "DualListSelector",
|
|
29
|
-
"description": "Acts as a container for all other DualListSelector sub-components when using a\ncomposable dual list selector.",
|
|
30
|
-
"props": [
|
|
31
|
-
{
|
|
32
|
-
"name": "children",
|
|
33
|
-
"type": "React.ReactNode",
|
|
34
|
-
"description": "Content to be rendered in the dual list selector."
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
"name": "className",
|
|
38
|
-
"type": "string",
|
|
39
|
-
"description": "Additional classes applied to the dual list selector."
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"name": "hasAnimations",
|
|
43
|
-
"type": "boolean",
|
|
44
|
-
"description": "Flag indicating whether a tree dual list selector has animations. This will always render\nnested dual list selector items rather than dynamically rendering them. This prop will be removed in\nthe next breaking change release in favor of defaulting to always-rendered items."
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"name": "id",
|
|
48
|
-
"type": "string",
|
|
49
|
-
"description": "ID of the dual list selector."
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"name": "isTree",
|
|
53
|
-
"type": "boolean",
|
|
54
|
-
"description": "Flag indicating if the dual list selector uses trees instead of simple lists.",
|
|
55
|
-
"defaultValue": "false"
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
"name": "DualListSelectorPane",
|
|
61
|
-
"description": "Acts as the container for a list of options that are either available or chosen,\ndepending on the pane type (available or chosen). A search input and other actions,\nsuch as sorting, can also be passed into this sub-component.",
|
|
62
|
-
"props": [
|
|
63
|
-
{
|
|
64
|
-
"name": "actions",
|
|
65
|
-
"type": "React.ReactNode[]",
|
|
66
|
-
"description": "Actions to place above the pane."
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
"name": "children",
|
|
70
|
-
"type": "React.ReactNode",
|
|
71
|
-
"description": "A dual list selector list or dual list selector tree to be rendered in the pane."
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
"name": "className",
|
|
75
|
-
"type": "string",
|
|
76
|
-
"description": "Additional classes applied to the dual list selector pane.",
|
|
77
|
-
"defaultValue": "''"
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
"name": "id",
|
|
81
|
-
"type": "string",
|
|
82
|
-
"description": "ID of the pane."
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"name": "isChosen",
|
|
86
|
-
"type": "boolean",
|
|
87
|
-
"description": "Flag indicating if this pane is the chosen pane.",
|
|
88
|
-
"defaultValue": "false"
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
"name": "isDisabled",
|
|
92
|
-
"type": "boolean",
|
|
93
|
-
"description": "Flag indicating whether the component is disabled.",
|
|
94
|
-
"defaultValue": "false"
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
"name": "listMinHeight",
|
|
98
|
-
"type": "string",
|
|
99
|
-
"description": "Minimum height of the list of options rendered in the pane. *"
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
"name": "onSearch",
|
|
103
|
-
"type": "(event: React.ChangeEvent<HTMLInputElement>) => void",
|
|
104
|
-
"description": "Callback for search input. To be used when isSearchable is true."
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
"name": "searchInput",
|
|
108
|
-
"type": "React.ReactNode",
|
|
109
|
-
"description": "A search input placed above the list at the top of the pane, before actions."
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
"name": "status",
|
|
113
|
-
"type": "string",
|
|
114
|
-
"description": "Status to display above the pane.",
|
|
115
|
-
"defaultValue": "''"
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
"name": "title",
|
|
119
|
-
"type": "React.ReactNode",
|
|
120
|
-
"description": "Title of the pane.",
|
|
121
|
-
"defaultValue": "''"
|
|
122
|
-
}
|
|
123
|
-
]
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
"name": "DualListSelectorList",
|
|
127
|
-
"description": "Acts as the container for DualListSelectorListItem sub-components.",
|
|
128
|
-
"props": [
|
|
129
|
-
{
|
|
130
|
-
"name": "children",
|
|
131
|
-
"type": "React.ReactNode",
|
|
132
|
-
"description": "Content rendered inside the dual list selector list."
|
|
133
|
-
}
|
|
134
|
-
]
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
"name": "DualListSelectorListItem",
|
|
138
|
-
"description": "Creates an individual option that can be selected and moved between the\ndual list selector panes. This is contained within the DualListSelectorList sub-component.",
|
|
139
|
-
"props": [
|
|
140
|
-
{
|
|
141
|
-
"name": "children",
|
|
142
|
-
"type": "React.ReactNode",
|
|
143
|
-
"description": "Content rendered inside the dual list selector."
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
"name": "className",
|
|
147
|
-
"type": "string",
|
|
148
|
-
"description": "Additional classes applied to the dual list selector."
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
"name": "draggableButtonAriaLabel",
|
|
152
|
-
"type": "string",
|
|
153
|
-
"description": "Accessible label for the draggable button on draggable list items."
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
"name": "id",
|
|
157
|
-
"type": "string",
|
|
158
|
-
"description": "ID of the option."
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
"name": "isDisabled",
|
|
162
|
-
"type": "boolean",
|
|
163
|
-
"description": "Flag indicating if the dual list selector is in a disabled state."
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
"name": "isDraggable",
|
|
167
|
-
"type": "boolean",
|
|
168
|
-
"description": "Flag indicating this item is draggable for reordering."
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
"name": "isSelected",
|
|
172
|
-
"type": "boolean",
|
|
173
|
-
"description": "Flag indicating the list item is currently selected."
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
"name": "onOptionSelect",
|
|
177
|
-
"type": "(event: React.MouseEvent | React.ChangeEvent | React.KeyboardEvent, id?: string) => void",
|
|
178
|
-
"description": "Callback fired when an option is selected."
|
|
179
|
-
}
|
|
180
|
-
]
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
"name": "DualListSelectorControlsWrapper",
|
|
184
|
-
"description": "Acts as the container for the DualListSelectorControl sub-components.",
|
|
185
|
-
"props": [
|
|
186
|
-
{
|
|
187
|
-
"name": "aria-label",
|
|
188
|
-
"type": "string",
|
|
189
|
-
"description": "Accessible label for the dual list selector controls wrapper."
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
"name": "children",
|
|
193
|
-
"type": "React.ReactNode",
|
|
194
|
-
"description": "Content to be rendered inside of the controls wrapper."
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
"name": "className",
|
|
198
|
-
"type": "string",
|
|
199
|
-
"description": "Additional classes added to the wrapper."
|
|
200
|
-
}
|
|
201
|
-
]
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
"name": "DualListSelectorControl",
|
|
205
|
-
"description": "Renders an individual control button for moving selected options between each\ndual list selector pane.",
|
|
206
|
-
"props": [
|
|
207
|
-
{
|
|
208
|
-
"name": "aria-label",
|
|
209
|
-
"type": "string",
|
|
210
|
-
"description": "Accessible label for the dual list selector control."
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
"name": "children",
|
|
214
|
-
"type": "React.ReactNode",
|
|
215
|
-
"description": "Content to be rendered in the dual list selector control."
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
"name": "className",
|
|
219
|
-
"type": "string",
|
|
220
|
-
"description": "Additional classes applied to the dual list selector control."
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
"name": "icon",
|
|
224
|
-
"type": "React.ReactNode",
|
|
225
|
-
"description": "Icon to be rendered in the dual list selector control."
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
"name": "isDisabled",
|
|
229
|
-
"type": "boolean",
|
|
230
|
-
"description": "Flag indicating the control is disabled."
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
"name": "onClick",
|
|
234
|
-
"type": "(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void",
|
|
235
|
-
"description": "Callback fired when dual list selector control is selected."
|
|
236
|
-
},
|
|
237
|
-
{
|
|
238
|
-
"name": "tooltipContent",
|
|
239
|
-
"type": "React.ReactNode",
|
|
240
|
-
"description": "Content to be displayed in a tooltip on hover of control."
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
"name": "tooltipProps",
|
|
244
|
-
"type": "any",
|
|
245
|
-
"description": "Additional tooltip properties passed to the tooltip."
|
|
246
|
-
}
|
|
247
|
-
]
|
|
248
|
-
},
|
|
249
|
-
{
|
|
250
|
-
"name": "DualListSelectorTree",
|
|
251
|
-
"description": "Used in place of the DualListSelectorListItem sub-component when building a\ncomposable dual list selector with a tree.",
|
|
252
|
-
"props": [
|
|
253
|
-
{
|
|
254
|
-
"name": "data",
|
|
255
|
-
"type": "DualListSelectorTreeItemData[] | (() => DualListSelectorTreeItemData[])",
|
|
256
|
-
"description": "Data of the tree view.",
|
|
257
|
-
"required": true
|
|
258
|
-
},
|
|
259
|
-
{
|
|
260
|
-
"name": "defaultAllExpanded",
|
|
261
|
-
"type": "boolean",
|
|
262
|
-
"description": "Sets the default expanded behavior.",
|
|
263
|
-
"defaultValue": "false"
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
"name": "hasBadges",
|
|
267
|
-
"type": "boolean",
|
|
268
|
-
"description": "Flag indicating if all options should have badges.",
|
|
269
|
-
"defaultValue": "false"
|
|
270
|
-
},
|
|
271
|
-
{
|
|
272
|
-
"name": "id",
|
|
273
|
-
"type": "string",
|
|
274
|
-
"description": "ID of the tree view."
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
"name": "isDisabled",
|
|
278
|
-
"type": "boolean",
|
|
279
|
-
"description": "Flag indicating if the dual list selector tree is in the disabled state.",
|
|
280
|
-
"defaultValue": "false"
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
"name": "onOptionCheck",
|
|
284
|
-
"type": "(\n event: React.MouseEvent | React.ChangeEvent<HTMLInputElement> | React.KeyboardEvent,\n isChecked: boolean,\n itemData: DualListSelectorTreeItemData\n) => void",
|
|
285
|
-
"description": "Callback fired when an option is checked."
|
|
286
|
-
}
|
|
287
|
-
]
|
|
288
|
-
},
|
|
289
|
-
{
|
|
290
|
-
"name": "DualListSelectorTreeItemData",
|
|
291
|
-
"description": "",
|
|
292
|
-
"props": [
|
|
293
|
-
{
|
|
294
|
-
"name": "badgeProps",
|
|
295
|
-
"type": "any",
|
|
296
|
-
"description": "Additional properties to pass to the option badge."
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
"name": "checkProps",
|
|
300
|
-
"type": "any",
|
|
301
|
-
"description": "Additional properties to pass to the option checkbox."
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
"name": "children",
|
|
305
|
-
"type": "DualListSelectorTreeItemData[]",
|
|
306
|
-
"description": "Content rendered inside the dual list selector."
|
|
307
|
-
},
|
|
308
|
-
{
|
|
309
|
-
"name": "className",
|
|
310
|
-
"type": "string",
|
|
311
|
-
"description": "Additional classes applied to the dual list selector."
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
"name": "defaultExpanded",
|
|
315
|
-
"type": "boolean",
|
|
316
|
-
"description": "Flag indicating this option is expanded by default."
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
"name": "hasBadge",
|
|
320
|
-
"type": "boolean",
|
|
321
|
-
"description": "Flag indicating this option has a badge."
|
|
322
|
-
},
|
|
323
|
-
{
|
|
324
|
-
"name": "id",
|
|
325
|
-
"type": "string",
|
|
326
|
-
"description": "ID of the option.",
|
|
327
|
-
"required": true
|
|
328
|
-
},
|
|
329
|
-
{
|
|
330
|
-
"name": "isChecked",
|
|
331
|
-
"type": "boolean",
|
|
332
|
-
"description": "Checked state of the option.",
|
|
333
|
-
"required": true
|
|
334
|
-
},
|
|
335
|
-
{
|
|
336
|
-
"name": "isDisabled",
|
|
337
|
-
"type": "boolean",
|
|
338
|
-
"description": "Flag indicating whether the component is disabled."
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
"name": "onOptionCheck",
|
|
342
|
-
"type": "(\n event: React.MouseEvent | React.ChangeEvent<HTMLInputElement> | React.KeyboardEvent,\n isChecked: boolean,\n isChosen: boolean,\n itemData: DualListSelectorTreeItemData\n ) => void",
|
|
343
|
-
"description": "Callback fired when an option is checked."
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
"name": "parentId",
|
|
347
|
-
"type": "string",
|
|
348
|
-
"description": "Parent ID of an option."
|
|
349
|
-
},
|
|
350
|
-
{
|
|
351
|
-
"name": "text",
|
|
352
|
-
"type": "string",
|
|
353
|
-
"description": "Text of the option.",
|
|
354
|
-
"required": true
|
|
355
|
-
}
|
|
356
|
-
]
|
|
357
|
-
}
|
|
358
|
-
],
|
|
359
|
-
"cssPrefix": [
|
|
360
|
-
"pf-v6-c-dual-list-selector"
|
|
361
|
-
],
|
|
362
|
-
"examples": [
|
|
363
|
-
"Basic",
|
|
364
|
-
"Basic with tooltips",
|
|
365
|
-
"Basic with search",
|
|
366
|
-
"Using more complex options with actions",
|
|
367
|
-
"With tree",
|
|
368
|
-
"Draggable",
|
|
369
|
-
"Draggable with multiple drop zones"
|
|
370
|
-
]
|
|
371
|
-
};
|
|
372
|
-
pageData.liveContext = {
|
|
373
|
-
Fragment,
|
|
374
|
-
useEffect,
|
|
375
|
-
useMemo,
|
|
376
|
-
useState,
|
|
377
|
-
RhMicronsDoubleCaretLeftIcon,
|
|
378
|
-
AngleLeftIcon,
|
|
379
|
-
AngleDoubleRightIcon,
|
|
380
|
-
AngleRightIcon,
|
|
381
|
-
RhMicronsSortDownSmallToLargeIcon,
|
|
382
|
-
SearchIcon,
|
|
383
|
-
RhUiEllipsisVerticalFillIcon,
|
|
384
|
-
DragDropSort,
|
|
385
|
-
DragDropContainer,
|
|
386
|
-
NewDroppable
|
|
387
|
-
};
|
|
388
|
-
pageData.examples = {
|
|
389
|
-
'Basic': props =>
|
|
390
|
-
<Example {...pageData} {...props} {...{"code":"import { useState } from 'react';\nimport {\n DualListSelector,\n DualListSelectorPane,\n DualListSelectorList,\n DualListSelectorListItem,\n DualListSelectorControlsWrapper,\n DualListSelectorControl\n} from '@patternfly/react-core';\nimport RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon';\nimport AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';\nimport AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon';\nimport AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';\n\ninterface Option {\n text: string;\n selected: boolean;\n isVisible: boolean;\n}\n\nexport const DualListSelectorBasic: React.FunctionComponent = () => {\n const [availableOptions, setAvailableOptions] = useState<Option[]>([\n { text: 'Option 1', selected: false, isVisible: true },\n { text: 'Option 2', selected: false, isVisible: true },\n { text: 'Option 3', selected: false, isVisible: true },\n { text: 'Option 4', selected: false, isVisible: true }\n ]);\n const [chosenOptions, setChosenOptions] = useState<Option[]>([]);\n\n // callback for moving selected options between lists\n const moveSelected = (fromAvailable: boolean) => {\n const sourceOptions = fromAvailable ? availableOptions : chosenOptions;\n const destinationOptions = fromAvailable ? chosenOptions : availableOptions;\n for (let i = 0; i < sourceOptions.length; i++) {\n const option = sourceOptions[i];\n if (option.selected && option.isVisible) {\n sourceOptions.splice(i, 1);\n destinationOptions.push(option);\n option.selected = false;\n i--;\n }\n }\n if (fromAvailable) {\n setAvailableOptions([...sourceOptions]);\n setChosenOptions([...destinationOptions]);\n } else {\n setChosenOptions([...sourceOptions]);\n setAvailableOptions([...destinationOptions]);\n }\n };\n\n // callback for moving all options between lists\n const moveAll = (fromAvailable: boolean) => {\n if (fromAvailable) {\n setChosenOptions([...availableOptions.filter((option) => option.isVisible), ...chosenOptions]);\n setAvailableOptions([...availableOptions.filter((option) => !option.isVisible)]);\n } else {\n setAvailableOptions([...chosenOptions.filter((option) => option.isVisible), ...availableOptions]);\n setChosenOptions([...chosenOptions.filter((option) => !option.isVisible)]);\n }\n };\n\n // callback when option is selected\n const onOptionSelect = (\n event: React.MouseEvent | React.ChangeEvent | React.KeyboardEvent,\n index: number,\n isChosen: boolean\n ) => {\n if (isChosen) {\n const newChosen = [...chosenOptions];\n newChosen[index].selected = !chosenOptions[index].selected;\n setChosenOptions(newChosen);\n } else {\n const newAvailable = [...availableOptions];\n newAvailable[index].selected = !availableOptions[index].selected;\n setAvailableOptions(newAvailable);\n }\n };\n\n return (\n <DualListSelector>\n <DualListSelectorPane\n title=\"Available options\"\n status={`${availableOptions.filter((option) => option.selected && option.isVisible).length} of ${\n availableOptions.filter((option) => option.isVisible).length\n } options selected`}\n >\n <DualListSelectorList>\n {availableOptions.map((option, index) =>\n option.isVisible ? (\n <DualListSelectorListItem\n key={index}\n isSelected={option.selected}\n id={`basic-available-option-${index}`}\n onOptionSelect={(e) => onOptionSelect(e, index, false)}\n >\n {option.text}\n </DualListSelectorListItem>\n ) : null\n )}\n </DualListSelectorList>\n </DualListSelectorPane>\n <DualListSelectorControlsWrapper>\n <DualListSelectorControl\n isDisabled={!availableOptions.some((option) => option.selected)}\n onClick={() => moveSelected(true)}\n aria-label=\"Add selected\"\n icon={<AngleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={availableOptions.length === 0}\n onClick={() => moveAll(true)}\n aria-label=\"Add all\"\n icon={<AngleDoubleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={chosenOptions.length === 0}\n onClick={() => moveAll(false)}\n aria-label=\"Remove all\"\n icon={<RhMicronsDoubleCaretLeftIcon />}\n />\n <DualListSelectorControl\n onClick={() => moveSelected(false)}\n isDisabled={!chosenOptions.some((option) => option.selected)}\n aria-label=\"Remove selected\"\n icon={<AngleLeftIcon />}\n />\n </DualListSelectorControlsWrapper>\n <DualListSelectorPane\n title=\"Chosen options\"\n status={`${chosenOptions.filter((option) => option.selected && option.isVisible).length} of ${\n chosenOptions.filter((option) => option.isVisible).length\n } options selected`}\n isChosen\n >\n <DualListSelectorList>\n {chosenOptions.map((option, index) =>\n option.isVisible ? (\n <DualListSelectorListItem\n key={index}\n isSelected={option.selected}\n id={`composable-basic-chosen-option-${index}`}\n onOptionSelect={(e) => onOptionSelect(e, index, true)}\n >\n {option.text}\n </DualListSelectorListItem>\n ) : null\n )}\n </DualListSelectorList>\n </DualListSelectorPane>\n </DualListSelector>\n );\n};\n","title":"Basic","lang":"ts","className":""}}>
|
|
391
|
-
|
|
392
|
-
</Example>,
|
|
393
|
-
'Basic with tooltips': props =>
|
|
394
|
-
<Example {...pageData} {...props} {...{"code":"import { useState } from 'react';\nimport {\n DualListSelector,\n DualListSelectorPane,\n DualListSelectorList,\n DualListSelectorListItem,\n DualListSelectorControlsWrapper,\n DualListSelectorControl\n} from '@patternfly/react-core';\nimport RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon';\nimport AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';\nimport AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon';\nimport AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';\n\ninterface Option {\n text: string;\n selected: boolean;\n isVisible: boolean;\n}\n\nexport const DualListSelectorBasic: React.FunctionComponent = () => {\n const [availableOptions, setAvailableOptions] = useState<Option[]>([\n { text: 'Option 1', selected: false, isVisible: true },\n { text: 'Option 2', selected: false, isVisible: true },\n { text: 'Option 3', selected: false, isVisible: true },\n { text: 'Option 4', selected: false, isVisible: true }\n ]);\n const [chosenOptions, setChosenOptions] = useState<Option[]>([]);\n\n // callback for moving selected options between lists\n const moveSelected = (fromAvailable: boolean) => {\n const sourceOptions = fromAvailable ? availableOptions : chosenOptions;\n const destinationOptions = fromAvailable ? chosenOptions : availableOptions;\n for (let i = 0; i < sourceOptions.length; i++) {\n const option = sourceOptions[i];\n if (option.selected && option.isVisible) {\n sourceOptions.splice(i, 1);\n destinationOptions.push(option);\n option.selected = false;\n i--;\n }\n }\n if (fromAvailable) {\n setAvailableOptions([...sourceOptions]);\n setChosenOptions([...destinationOptions]);\n } else {\n setChosenOptions([...sourceOptions]);\n setAvailableOptions([...destinationOptions]);\n }\n };\n\n // callback for moving all options between lists\n const moveAll = (fromAvailable: boolean) => {\n if (fromAvailable) {\n setChosenOptions([...availableOptions.filter((option) => option.isVisible), ...chosenOptions]);\n setAvailableOptions([...availableOptions.filter((option) => !option.isVisible)]);\n } else {\n setAvailableOptions([...chosenOptions.filter((option) => option.isVisible), ...availableOptions]);\n setChosenOptions([...chosenOptions.filter((option) => !option.isVisible)]);\n }\n };\n\n // callback when option is selected\n const onOptionSelect = (\n event: React.MouseEvent | React.ChangeEvent | React.KeyboardEvent,\n index: number,\n isChosen: boolean\n ) => {\n if (isChosen) {\n const newChosen = [...chosenOptions];\n newChosen[index].selected = !chosenOptions[index].selected;\n setChosenOptions(newChosen);\n } else {\n const newAvailable = [...availableOptions];\n newAvailable[index].selected = !availableOptions[index].selected;\n setAvailableOptions(newAvailable);\n }\n };\n\n return (\n <DualListSelector>\n <DualListSelectorPane\n title=\"Available options\"\n status={`${availableOptions.filter((option) => option.selected && option.isVisible).length} of ${\n availableOptions.filter((option) => option.isVisible).length\n } options selected`}\n >\n <DualListSelectorList>\n {availableOptions.map((option, index) =>\n option.isVisible ? (\n <DualListSelectorListItem\n key={index}\n isSelected={option.selected}\n id={`tooltips-available-option-${index}`}\n onOptionSelect={(e) => onOptionSelect(e, index, false)}\n >\n {option.text}\n </DualListSelectorListItem>\n ) : null\n )}\n </DualListSelectorList>\n </DualListSelectorPane>\n <DualListSelectorControlsWrapper>\n <DualListSelectorControl\n isDisabled={!availableOptions.some((option) => option.selected)}\n onClick={() => moveSelected(true)}\n aria-label=\"Add selected\"\n tooltipContent=\"Add selected\"\n tooltipProps={{ position: 'top', 'aria-live': 'off' }}\n icon={<AngleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={availableOptions.length === 0}\n onClick={() => moveAll(true)}\n aria-label=\"Add all\"\n tooltipContent=\"Add all\"\n tooltipProps={{ position: 'right', 'aria-live': 'off' }}\n icon={<AngleDoubleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={chosenOptions.length === 0}\n onClick={() => moveAll(false)}\n aria-label=\"Remove all\"\n tooltipContent=\"Remove all\"\n tooltipProps={{ position: 'left', 'aria-live': 'off' }}\n icon={<RhMicronsDoubleCaretLeftIcon />}\n />\n <DualListSelectorControl\n onClick={() => moveSelected(false)}\n isDisabled={!chosenOptions.some((option) => option.selected)}\n aria-label=\"Remove selected\"\n tooltipContent=\"Remove selected\"\n tooltipProps={{ position: 'bottom', 'aria-live': 'off' }}\n icon={<AngleLeftIcon />}\n />\n </DualListSelectorControlsWrapper>\n <DualListSelectorPane\n title=\"Chosen options\"\n status={`${chosenOptions.filter((option) => option.selected && option.isVisible).length} of ${\n chosenOptions.filter((option) => option.isVisible).length\n } options selected`}\n isChosen\n >\n <DualListSelectorList>\n {chosenOptions.map((option, index) =>\n option.isVisible ? (\n <DualListSelectorListItem\n key={index}\n isSelected={option.selected}\n id={`composable-tooltips-chosen-option-${index}`}\n onOptionSelect={(e) => onOptionSelect(e, index, true)}\n >\n {option.text}\n </DualListSelectorListItem>\n ) : null\n )}\n </DualListSelectorList>\n </DualListSelectorPane>\n </DualListSelector>\n );\n};\n","title":"Basic with tooltips","lang":"ts","className":""}}>
|
|
395
|
-
|
|
396
|
-
</Example>,
|
|
397
|
-
'Basic with search': props =>
|
|
398
|
-
<Example {...pageData} {...props} {...{"code":"import { useState } from 'react';\nimport {\n Button,\n DualListSelector,\n DualListSelectorPane,\n DualListSelectorList,\n DualListSelectorListItem,\n DualListSelectorControlsWrapper,\n DualListSelectorControl,\n SearchInput,\n EmptyState,\n EmptyStateVariant,\n EmptyStateFooter,\n EmptyStateBody,\n EmptyStateActions\n} from '@patternfly/react-core';\nimport RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon';\nimport AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';\nimport AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon';\nimport AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';\nimport SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';\n\ninterface Option {\n text: string;\n selected: boolean;\n isVisible: boolean;\n}\n\nexport const DualListSelectorSearch: React.FunctionComponent = () => {\n const [availableOptions, setAvailableOptions] = useState<Option[]>([\n { text: 'Option 1', selected: false, isVisible: true },\n { text: 'Option 2', selected: false, isVisible: true },\n { text: 'Option 3', selected: false, isVisible: true },\n { text: 'Option 4', selected: false, isVisible: true }\n ]);\n\n const [chosenOptions, setChosenOptions] = useState<Option[]>([]);\n const [availableFilter, setAvailableFilter] = useState('');\n const [chosenFilter, setChosenFilter] = useState('');\n\n // callback for moving selected options between lists\n const moveSelected = (fromAvailable: boolean) => {\n const sourceOptions = fromAvailable ? availableOptions : chosenOptions;\n const destinationOptions = fromAvailable ? chosenOptions : availableOptions;\n for (let i = 0; i < sourceOptions.length; i++) {\n const option = sourceOptions[i];\n if (option.selected && option.isVisible) {\n sourceOptions.splice(i, 1);\n destinationOptions.push(option);\n option.selected = false;\n i--;\n }\n }\n if (fromAvailable) {\n setAvailableOptions([...sourceOptions]);\n setChosenOptions([...destinationOptions]);\n } else {\n setChosenOptions([...sourceOptions]);\n setAvailableOptions([...destinationOptions]);\n }\n };\n\n // callback for moving all options between lists\n const moveAll = (fromAvailable: boolean) => {\n if (fromAvailable) {\n setChosenOptions([...availableOptions.filter((option) => option.isVisible), ...chosenOptions]);\n setAvailableOptions([...availableOptions.filter((option) => !option.isVisible)]);\n } else {\n setAvailableOptions([...chosenOptions.filter((option) => option.isVisible), ...availableOptions]);\n setChosenOptions([...chosenOptions.filter((option) => !option.isVisible)]);\n }\n };\n\n // callback when option is selected\n const onOptionSelect = (\n event: React.MouseEvent | React.ChangeEvent | React.KeyboardEvent,\n index: number,\n isChosen: boolean\n ) => {\n if (isChosen) {\n const newChosen = [...chosenOptions];\n newChosen[index].selected = !chosenOptions[index].selected;\n setChosenOptions(newChosen);\n } else {\n const newAvailable = [...availableOptions];\n newAvailable[index].selected = !availableOptions[index].selected;\n setAvailableOptions(newAvailable);\n }\n };\n\n const onFilterChange = (value: string, isAvailable: boolean) => {\n isAvailable ? setAvailableFilter(value) : setChosenFilter(value);\n const toFilter = isAvailable ? [...availableOptions] : [...chosenOptions];\n toFilter.forEach((option) => {\n option.isVisible = value === '' || option.text.toLowerCase().includes(value.toLowerCase());\n });\n };\n\n // builds a search input - used in each dual list selector pane\n const buildSearchInput = (isAvailable: boolean) => (\n <SearchInput\n value={isAvailable ? availableFilter : chosenFilter}\n onChange={(_event, value) => onFilterChange(value, isAvailable)}\n onClear={() => onFilterChange('', isAvailable)}\n aria-label={isAvailable ? 'Search available options' : 'Search chosen options'}\n />\n );\n\n const buildEmptyState = (isAvailable: boolean) => (\n <EmptyState titleText=\"No results found\" variant={EmptyStateVariant.sm} headingLevel=\"h4\" icon={SearchIcon}>\n <EmptyStateBody>No results match the filter criteria. Clear all filters and try again.</EmptyStateBody>\n <EmptyStateFooter>\n <EmptyStateActions>\n <Button variant=\"link\" onClick={() => onFilterChange('', isAvailable)}>\n Clear all filters\n </Button>\n </EmptyStateActions>\n </EmptyStateFooter>\n </EmptyState>\n );\n\n return (\n <DualListSelector>\n <DualListSelectorPane\n title=\"Available options\"\n status={`${availableOptions.filter((option) => option.selected && option.isVisible).length} of ${\n availableOptions.filter((option) => option.isVisible).length\n } options selected`}\n searchInput={buildSearchInput(true)}\n listMinHeight=\"300px\"\n >\n {availableFilter !== '' &&\n availableOptions.filter((option) => option.isVisible).length === 0 &&\n buildEmptyState(true)}\n\n <DualListSelectorList>\n {availableOptions.map((option, index) =>\n option.isVisible ? (\n <DualListSelectorListItem\n key={index}\n isSelected={option.selected}\n id={`search-available-option-${index}`}\n onOptionSelect={(e) => onOptionSelect(e, index, false)}\n >\n {option.text}\n </DualListSelectorListItem>\n ) : null\n )}\n </DualListSelectorList>\n </DualListSelectorPane>\n <DualListSelectorControlsWrapper>\n <DualListSelectorControl\n isDisabled={!availableOptions.some((option) => option.selected)}\n onClick={() => moveSelected(true)}\n aria-label=\"Add selected\"\n icon={<AngleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={availableOptions.length === 0}\n onClick={() => moveAll(true)}\n aria-label=\"Add all\"\n icon={<AngleDoubleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={chosenOptions.length === 0}\n onClick={() => moveAll(false)}\n aria-label=\"Remove all\"\n icon={<RhMicronsDoubleCaretLeftIcon />}\n />\n <DualListSelectorControl\n onClick={() => moveSelected(false)}\n isDisabled={!chosenOptions.some((option) => option.selected)}\n aria-label=\"Remove selected\"\n icon={<AngleLeftIcon />}\n />\n </DualListSelectorControlsWrapper>\n <DualListSelectorPane\n title=\"Chosen options\"\n status={`${chosenOptions.filter((option) => option.selected && option.isVisible).length} of ${\n chosenOptions.filter((option) => option.isVisible).length\n } options selected`}\n searchInput={buildSearchInput(false)}\n listMinHeight=\"300px\"\n isChosen\n >\n {chosenFilter !== '' &&\n chosenOptions.filter((option) => option.isVisible).length === 0 &&\n buildEmptyState(false)}\n {chosenOptions.filter((option) => option.isVisible).length > 0 && (\n <DualListSelectorList>\n {chosenOptions.map((option, index) =>\n option.isVisible ? (\n <DualListSelectorListItem\n key={index}\n isSelected={option.selected}\n id={`composable-search-chosen-option-${index}`}\n onOptionSelect={(e) => onOptionSelect(e, index, true)}\n >\n {option.text}\n </DualListSelectorListItem>\n ) : null\n )}\n </DualListSelectorList>\n )}\n </DualListSelectorPane>\n </DualListSelector>\n );\n};\n","title":"Basic with search","lang":"ts","className":""}}>
|
|
399
|
-
|
|
400
|
-
</Example>,
|
|
401
|
-
'Using more complex options with actions': props =>
|
|
402
|
-
<Example {...pageData} {...props} {...{"code":"import { Fragment, useState } from 'react';\nimport {\n Button,\n ButtonVariant,\n Checkbox,\n Dropdown,\n DropdownList,\n DropdownItem,\n DualListSelector,\n DualListSelectorPane,\n DualListSelectorList,\n DualListSelectorListItem,\n DualListSelectorControlsWrapper,\n DualListSelectorControl,\n SearchInput,\n EmptyState,\n EmptyStateVariant,\n EmptyStateFooter,\n EmptyStateBody,\n EmptyStateActions,\n MenuToggle,\n MenuToggleElement\n} from '@patternfly/react-core';\nimport RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon';\nimport AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';\nimport AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon';\nimport AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';\nimport RhMicronsSortDownSmallToLargeIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-sort-down-small-to-large-icon';\nimport SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';\nimport RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon';\n\ninterface Option {\n text: string;\n selected: boolean;\n isVisible: boolean;\n}\n\nexport const DualListSelectorComplexOptionsActionsNext: React.FunctionComponent = () => {\n const [availableOptions, setAvailableOptions] = useState<Option[]>([\n { text: 'Option 1', selected: false, isVisible: true },\n { text: 'Option 2', selected: false, isVisible: true },\n { text: 'Option 3', selected: false, isVisible: true },\n { text: 'Option 4', selected: false, isVisible: true }\n ]);\n\n const [chosenOptions, setChosenOptions] = useState<Option[]>([]);\n const [isAvailableKebabOpen, setIsAvailableKebabOpen] = useState(false);\n const [isChosenKebabOpen, setIsChosenKebabOpen] = useState(false);\n const [availableFilter, setAvailableFilter] = useState('');\n const [chosenFilter, setChosenFilter] = useState('');\n const [isDisabled, setIsDisabled] = useState(false);\n\n // callback for moving selected options between lists\n const moveSelected = (fromAvailable: boolean) => {\n const sourceOptions = fromAvailable ? availableOptions : chosenOptions;\n const destinationOptions = fromAvailable ? chosenOptions : availableOptions;\n for (let i = 0; i < sourceOptions.length; i++) {\n const option = sourceOptions[i];\n if (option.selected && option.isVisible) {\n sourceOptions.splice(i, 1);\n destinationOptions.push(option);\n option.selected = false;\n i--;\n }\n }\n if (fromAvailable) {\n setAvailableOptions([...sourceOptions]);\n setChosenOptions([...destinationOptions]);\n } else {\n setChosenOptions([...sourceOptions]);\n setAvailableOptions([...destinationOptions]);\n }\n };\n\n // callback for moving all options between lists\n const moveAll = (fromAvailable: boolean) => {\n if (fromAvailable) {\n setChosenOptions([...availableOptions.filter((option) => option.isVisible), ...chosenOptions]);\n setAvailableOptions([...availableOptions.filter((option) => !option.isVisible)]);\n } else {\n setAvailableOptions([...chosenOptions.filter((option) => option.isVisible), ...availableOptions]);\n setChosenOptions([...chosenOptions.filter((option) => !option.isVisible)]);\n }\n };\n\n // callback when option is selected\n const onOptionSelect = (\n event: React.MouseEvent | React.ChangeEvent | React.KeyboardEvent,\n index: number,\n isChosen: boolean\n ) => {\n if (isChosen) {\n const newChosen = [...chosenOptions];\n newChosen[index].selected = !chosenOptions[index].selected;\n setChosenOptions(newChosen);\n } else {\n const newAvailable = [...availableOptions];\n newAvailable[index].selected = !availableOptions[index].selected;\n setAvailableOptions(newAvailable);\n }\n };\n\n const onFilterChange = (value: string, isAvailable: boolean) => {\n isAvailable ? setAvailableFilter(value) : setChosenFilter(value);\n const toFilter = isAvailable ? [...availableOptions] : [...chosenOptions];\n toFilter.forEach((option) => {\n option.isVisible = value === '' || option.text.toLowerCase().includes(value.toLowerCase());\n });\n };\n\n // builds a search input - used in each dual list selector pane\n const buildSearchInput = (isAvailable: boolean) => (\n <SearchInput\n value={isAvailable ? availableFilter : chosenFilter}\n onChange={(_event, value) => onFilterChange(value, isAvailable)}\n onClear={() => onFilterChange('', isAvailable)}\n isDisabled={isDisabled}\n aria-label={isAvailable ? 'Search available options' : 'Search chosen options'}\n />\n );\n\n // builds a sort control - passed to both dual list selector panes\n const buildSort = (isAvailable: boolean) => {\n const onSort = () => {\n const toSort = isAvailable ? [...availableOptions] : [...chosenOptions];\n toSort.sort((a, b) => {\n if (a.text > b.text) {\n return 1;\n }\n if (a.text < b.text) {\n return -1;\n }\n return 0;\n });\n if (isAvailable) {\n setAvailableOptions(toSort);\n } else {\n setChosenOptions(toSort);\n }\n };\n\n const onToggle = (pane: string) => {\n if (pane === 'available') {\n setIsAvailableKebabOpen(!isAvailableKebabOpen);\n } else {\n setIsChosenKebabOpen(!isChosenKebabOpen);\n }\n };\n\n return isAvailable\n ? [\n <Button\n variant={ButtonVariant.plain}\n onClick={onSort}\n aria-label=\"Sort Available\"\n key=\"availableSortButton\"\n isDisabled={isDisabled}\n icon={<RhMicronsSortDownSmallToLargeIcon />}\n />,\n <Dropdown\n toggle={(toggleRef: React.Ref<MenuToggleElement>) => (\n <MenuToggle\n ref={toggleRef}\n isDisabled={isDisabled}\n isExpanded={isAvailableKebabOpen}\n onClick={() => onToggle('available')}\n variant=\"plain\"\n id=\"complex-available-toggle\"\n aria-label=\"Complex actions example available kebab toggle\"\n icon={<RhUiEllipsisVerticalFillIcon />}\n />\n )}\n isOpen={isAvailableKebabOpen}\n onOpenChange={(isOpen: boolean) => setIsAvailableKebabOpen(isOpen)}\n onSelect={() => setIsAvailableKebabOpen(false)}\n key=\"availableDropdown\"\n >\n <DropdownList>\n <DropdownItem key=\"available action\">Available Action</DropdownItem>\n <DropdownItem key=\"available link\" to=\"#\" onClick={(event: any) => event.preventDefault()}>\n Available Link\n </DropdownItem>\n </DropdownList>\n </Dropdown>\n ]\n : [\n <Button\n variant={ButtonVariant.plain}\n onClick={onSort}\n aria-label=\"Sort Chosen\"\n key=\"chosenSortButton\"\n isDisabled={isDisabled}\n icon={<RhMicronsSortDownSmallToLargeIcon />}\n />,\n <Dropdown\n toggle={(toggleRef: React.Ref<MenuToggleElement>) => (\n <MenuToggle\n ref={toggleRef}\n isDisabled={isDisabled}\n isExpanded={isChosenKebabOpen}\n onClick={() => onToggle('chosen')}\n variant=\"plain\"\n id=\"complex-chosen-toggle\"\n aria-label=\"Complex actions example chosen kebab toggle\"\n icon={<RhUiEllipsisVerticalFillIcon />}\n />\n )}\n isOpen={isChosenKebabOpen}\n onOpenChange={(isOpen: boolean) => setIsChosenKebabOpen(isOpen)}\n onSelect={() => setIsChosenKebabOpen(false)}\n key=\"chosenDropdown\"\n >\n <DropdownList>\n <DropdownItem key=\"chosen action\">Chosen Action</DropdownItem>\n <DropdownItem key=\"chosen link\" to=\"#\" onClick={(event: any) => event.preventDefault()}>\n Chosen Link\n </DropdownItem>\n </DropdownList>\n </Dropdown>\n ];\n };\n\n const buildEmptyState = (isAvailable: boolean) => (\n <EmptyState headingLevel=\"h4\" titleText=\"No results found\" icon={SearchIcon} variant={EmptyStateVariant.sm}>\n <EmptyStateBody>No results match the filter criteria. Clear all filters and try again.</EmptyStateBody>\n <EmptyStateFooter>\n <EmptyStateActions>\n <Button variant=\"link\" onClick={() => onFilterChange('', isAvailable)}>\n Clear all filters\n </Button>\n </EmptyStateActions>\n </EmptyStateFooter>\n </EmptyState>\n );\n\n return (\n <Fragment>\n <DualListSelector>\n <DualListSelectorPane\n title=\"Available options\"\n status={`${availableOptions.filter((option) => option.selected && option.isVisible).length} of ${\n availableOptions.filter((option) => option.isVisible).length\n } options selected`}\n searchInput={buildSearchInput(true)}\n actions={[buildSort(true)]}\n listMinHeight=\"300px\"\n isDisabled={isDisabled}\n >\n {availableFilter !== '' &&\n availableOptions.filter((option) => option.isVisible).length === 0 &&\n buildEmptyState(true)}\n\n <DualListSelectorList>\n {availableOptions.map((option, index) =>\n option.isVisible ? (\n <DualListSelectorListItem\n key={index}\n isSelected={option.selected}\n id={`complex-available-option-${index}`}\n onOptionSelect={(e) => onOptionSelect(e, index, false)}\n isDisabled={isDisabled}\n >\n {option.text}\n </DualListSelectorListItem>\n ) : null\n )}\n </DualListSelectorList>\n </DualListSelectorPane>\n <DualListSelectorControlsWrapper>\n <DualListSelectorControl\n isDisabled={!availableOptions.some((option) => option.selected) || isDisabled}\n onClick={() => moveSelected(true)}\n aria-label=\"Add selected\"\n icon={<AngleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={availableOptions.length === 0 || isDisabled}\n onClick={() => moveAll(true)}\n aria-label=\"Add all\"\n icon={<AngleDoubleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={chosenOptions.length === 0 || isDisabled}\n onClick={() => moveAll(false)}\n aria-label=\"Remove all\"\n icon={<RhMicronsDoubleCaretLeftIcon />}\n />\n <DualListSelectorControl\n onClick={() => moveSelected(false)}\n isDisabled={!chosenOptions.some((option) => option.selected) || isDisabled}\n aria-label=\"Remove selected\"\n icon={<AngleLeftIcon />}\n />\n </DualListSelectorControlsWrapper>\n <DualListSelectorPane\n title=\"Chosen options\"\n status={`${chosenOptions.filter((option) => option.selected && option.isVisible).length} of ${\n chosenOptions.filter((option) => option.isVisible).length\n } options selected`}\n searchInput={buildSearchInput(false)}\n actions={[buildSort(false)]}\n listMinHeight=\"300px\"\n isChosen\n >\n {chosenFilter !== '' &&\n chosenOptions.filter((option) => option.isVisible).length === 0 &&\n buildEmptyState(false)}\n {chosenOptions.filter((option) => option.isVisible).length > 0 && (\n <DualListSelectorList>\n {chosenOptions.map((option, index) =>\n option.isVisible ? (\n <DualListSelectorListItem\n key={index}\n isSelected={option.selected}\n id={`composable-complex-chosen-option-${index}`}\n onOptionSelect={(e) => onOptionSelect(e, index, true)}\n isDisabled={isDisabled}\n >\n {option.text}\n </DualListSelectorListItem>\n ) : null\n )}\n </DualListSelectorList>\n )}\n </DualListSelectorPane>\n </DualListSelector>\n <Checkbox\n key=\"isDisabled\"\n id=\"isDisabled\"\n label=\"isDisabled\"\n aria-label=\"isDisabled\"\n isChecked={isDisabled}\n onChange={() => setIsDisabled(!isDisabled)}\n />\n </Fragment>\n );\n};\n","title":"Using more complex options with actions","lang":"ts","className":""}}>
|
|
403
|
-
|
|
404
|
-
</Example>,
|
|
405
|
-
'With tree': props =>
|
|
406
|
-
<Example {...pageData} {...props} {...{"code":"import { useMemo, useState } from 'react';\nimport {\n DualListSelector,\n DualListSelectorPane,\n DualListSelectorList,\n DualListSelectorControlsWrapper,\n DualListSelectorControl,\n DualListSelectorTree,\n DualListSelectorTreeItemData,\n SearchInput,\n Button,\n EmptyState,\n EmptyStateVariant,\n EmptyStateFooter,\n EmptyStateBody,\n EmptyStateActions\n} from '@patternfly/react-core';\nimport RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon';\nimport AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';\nimport AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon';\nimport AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';\nimport SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';\n\ninterface FoodNode {\n id: string;\n text: string;\n children?: FoodNode[];\n}\n\ninterface ExampleProps {\n data: FoodNode[];\n}\n\nexport const DualListSelectorComposableTree: React.FunctionComponent<ExampleProps> = ({ data }: ExampleProps) => {\n const [checkedLeafIds, setCheckedLeafIds] = useState<string[]>([]);\n const [chosenLeafIds, setChosenLeafIds] = useState<string[]>(['beans', 'beef', 'chicken', 'tofu']);\n const [chosenFilter, setChosenFilter] = useState<string>('');\n const [availableFilter, setAvailableFilter] = useState<string>('');\n\n // helper function to build memoized lists\n const buildTextById = (node: FoodNode): { [key: string]: string } => {\n let textById = {};\n if (!node) {\n return textById;\n }\n textById[node.id] = node.text;\n if (node.children) {\n node.children.forEach((child) => {\n textById = { ...textById, ...buildTextById(child) };\n });\n }\n return textById;\n };\n\n // helper function to build memoized lists\n const getDescendantLeafIds = (node: FoodNode): string[] => {\n if (!node.children || !node.children.length) {\n return [node.id];\n } else {\n let childrenIds: string[] = [];\n node.children.forEach((child) => {\n childrenIds = [...childrenIds, ...getDescendantLeafIds(child)];\n });\n return childrenIds;\n }\n };\n\n // helper function to build memoized lists\n const getLeavesById = (node: FoodNode): { [key: string]: string[] } => {\n let leavesById = {};\n if (!node.children || !node.children.length) {\n leavesById[node.id] = [node.id];\n } else {\n node.children.forEach((child) => {\n leavesById[node.id] = getDescendantLeafIds(node);\n leavesById = { ...leavesById, ...getLeavesById(child) };\n });\n }\n return leavesById;\n };\n\n // Builds a map of child leaf nodes by node id - memoized so that it only rebuilds the list if the data changes.\n const { memoizedLeavesById, memoizedAllLeaves, memoizedNodeTexts } = useMemo(() => {\n let leavesById = {};\n let allLeaves: string[] = [];\n let nodeTexts = {};\n data.forEach((foodNode) => {\n nodeTexts = { ...nodeTexts, ...buildTextById(foodNode) };\n leavesById = { ...leavesById, ...getLeavesById(foodNode) };\n allLeaves = [...allLeaves, ...getDescendantLeafIds(foodNode)];\n });\n return {\n memoizedLeavesById: leavesById,\n memoizedAllLeaves: allLeaves,\n memoizedNodeTexts: nodeTexts\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [data]);\n\n const matchesFilter = (value: string, filter: string) => value.toLowerCase().includes(filter.trim().toLowerCase());\n\n const getVisibleLeafIds = (leafIds: string[], filter: string) => {\n const filterMatchingNodeIds = Object.keys(memoizedLeavesById).filter((nodeId) =>\n matchesFilter(memoizedNodeTexts[nodeId], filter)\n );\n const filterMatchingLeafIds = filterMatchingNodeIds.map((nodeId) => memoizedLeavesById[nodeId]).flat();\n return leafIds.filter((leafId) => filterMatchingLeafIds.includes(leafId));\n };\n\n const availableLeafIds = memoizedAllLeaves.filter((leafId) => !chosenLeafIds.includes(leafId));\n const visibleChosenLeafIds = getVisibleLeafIds(chosenLeafIds, chosenFilter);\n const visibleAvailableLeafIds = getVisibleLeafIds(availableLeafIds, availableFilter);\n\n const moveChecked = (toChosen: boolean) => {\n const visibleCheckedChosenLeafIds = checkedLeafIds.filter((leafId) => visibleChosenLeafIds.includes(leafId));\n const visibleCheckedAvailableLeafIds = checkedLeafIds.filter((leafId) => visibleAvailableLeafIds.includes(leafId));\n\n setChosenLeafIds(\n (prevChosenIds) =>\n toChosen\n ? [...prevChosenIds, ...visibleCheckedAvailableLeafIds] // add visible checked ids to chosen list\n : prevChosenIds.filter((x) => !visibleCheckedChosenLeafIds.includes(x)) // remove visible checked ids from chosen list\n );\n\n // uncheck checked ids that just moved\n setCheckedLeafIds((prevChecked) =>\n toChosen\n ? prevChecked.filter((x) => !visibleCheckedAvailableLeafIds.includes(x))\n : prevChecked.filter((x) => !visibleCheckedChosenLeafIds.includes(x))\n );\n };\n\n const moveAll = (toChosen: boolean) => {\n if (toChosen) {\n setChosenLeafIds((prevChosenIds) => [...prevChosenIds, ...visibleAvailableLeafIds]);\n } else {\n setChosenLeafIds((prevChosenIds) => prevChosenIds.filter((id) => !visibleChosenLeafIds.includes(id)));\n }\n };\n\n const areAllDescendantsSelected = (node: FoodNode, isChosen: boolean) =>\n memoizedLeavesById[node.id].every(\n (id) => checkedLeafIds.includes(id) && (isChosen ? chosenLeafIds.includes(id) : !chosenLeafIds.includes(id))\n );\n const areSomeDescendantsSelected = (node: FoodNode, isChosen: boolean) =>\n memoizedLeavesById[node.id].some(\n (id) => checkedLeafIds.includes(id) && (isChosen ? chosenLeafIds.includes(id) : !chosenLeafIds.includes(id))\n );\n\n const isNodeChecked = (node: FoodNode, isChosen: boolean) => {\n if (areAllDescendantsSelected(node, isChosen)) {\n return true;\n }\n if (areSomeDescendantsSelected(node, isChosen)) {\n return false;\n }\n return false;\n };\n\n const onOptionCheck = (\n event: React.MouseEvent | React.ChangeEvent<HTMLInputElement> | React.KeyboardEvent,\n isChecked: boolean,\n node: DualListSelectorTreeItemData,\n isChosen: boolean\n ) => {\n const nodeIdsToCheck = memoizedLeavesById[node.id].filter((id) =>\n isChosen ? visibleChosenLeafIds.includes(id) : visibleAvailableLeafIds.includes(id)\n );\n\n setCheckedLeafIds((prevChecked) => {\n const otherCheckedNodeNames = prevChecked.filter((id) => !nodeIdsToCheck.includes(id));\n return !isChecked ? otherCheckedNodeNames : [...otherCheckedNodeNames, ...nodeIdsToCheck];\n });\n };\n\n // builds a search input - used in each dual list selector pane\n const buildSearchInput = (isChosen: boolean) => {\n const onChange = (value) => (isChosen ? setChosenFilter(value) : setAvailableFilter(value));\n\n return (\n <SearchInput\n value={isChosen ? chosenFilter : availableFilter}\n onChange={(_event, value) => onChange(value)}\n onClear={() => onChange('')}\n aria-label={isChosen ? 'Search chosen items' : 'Search available items'}\n />\n );\n };\n\n // Builds the DualListSelectorTreeItems from the FoodNodes\n const buildOptions = (\n isChosen: boolean,\n [node, ...remainingNodes]: FoodNode[],\n hasParentMatch: boolean\n ): DualListSelectorTreeItemData[] => {\n if (!node) {\n return [];\n }\n\n const isChecked = isNodeChecked(node, isChosen);\n\n const filterValue = isChosen ? chosenFilter : availableFilter;\n const descendentLeafIds = memoizedLeavesById[node.id];\n const descendentsOnThisPane = isChosen\n ? descendentLeafIds.filter((id) => chosenLeafIds.includes(id))\n : descendentLeafIds.filter((id) => !chosenLeafIds.includes(id));\n\n const hasMatchingChildren =\n filterValue && descendentsOnThisPane.some((id) => matchesFilter(memoizedNodeTexts[id], filterValue));\n const isFilterMatch = filterValue && matchesFilter(node.text, filterValue) && descendentsOnThisPane.length > 0;\n\n // A node is displayed if either of the following is true:\n // - There is no filter value and this node or its descendents belong on this pane\n // - There is a filter value and this node or one of this node's descendents or ancestors match on this pane\n const isDisplayed =\n (!filterValue && descendentsOnThisPane.length > 0) ||\n hasMatchingChildren ||\n (hasParentMatch && descendentsOnThisPane.length > 0) ||\n isFilterMatch;\n\n return [\n ...(isDisplayed\n ? [\n {\n id: node.id,\n text: node.text,\n isChecked,\n checkProps: { 'aria-label': `Select ${node.text}` },\n hasBadge: node.children && node.children.length > 0,\n badgeProps: { isRead: true },\n defaultExpanded: isChosen ? !!chosenFilter : !!availableFilter,\n children: node.children\n ? buildOptions(isChosen, node.children, isFilterMatch || hasParentMatch)\n : undefined\n }\n ]\n : []),\n ...(!isDisplayed && node.children && node.children.length\n ? buildOptions(isChosen, node.children, hasParentMatch)\n : []),\n ...(remainingNodes ? buildOptions(isChosen, remainingNodes, hasParentMatch) : [])\n ];\n };\n\n const buildPane = (isChosen: boolean): React.ReactNode => {\n const options: DualListSelectorTreeItemData[] = buildOptions(isChosen, data, false);\n const numOptions = isChosen ? visibleChosenLeafIds.length : visibleAvailableLeafIds.length;\n const numSelected = checkedLeafIds.filter((id) =>\n isChosen ? visibleChosenLeafIds.includes(id) : visibleAvailableLeafIds.includes(id)\n ).length;\n const status = `${numSelected} of ${numOptions} options selected`;\n const filterApplied = isChosen ? chosenFilter !== '' : availableFilter !== '';\n return (\n <DualListSelectorPane\n title={isChosen ? 'Chosen' : 'Available'}\n status={status}\n searchInput={buildSearchInput(isChosen)}\n isChosen={isChosen}\n listMinHeight=\"300px\"\n >\n {filterApplied && options.length === 0 && (\n <EmptyState headingLevel=\"h4\" titleText=\"No results found\" icon={SearchIcon} variant={EmptyStateVariant.sm}>\n <EmptyStateBody>No results match the filter criteria. Clear all filters and try again.</EmptyStateBody>\n <EmptyStateFooter>\n <EmptyStateActions>\n <Button variant=\"link\" onClick={() => (isChosen ? setChosenFilter('') : setAvailableFilter(''))}>\n Clear all filters\n </Button>\n </EmptyStateActions>\n </EmptyStateFooter>\n </EmptyState>\n )}\n {options.length > 0 && (\n <DualListSelectorList>\n <DualListSelectorTree\n data={options}\n onOptionCheck={(e, isChecked, itemData) => onOptionCheck(e, isChecked, itemData, isChosen)}\n />\n </DualListSelectorList>\n )}\n </DualListSelectorPane>\n );\n };\n\n return (\n <DualListSelector hasAnimations isTree>\n {buildPane(false)}\n <DualListSelectorControlsWrapper>\n <DualListSelectorControl\n isDisabled={!checkedLeafIds.filter((x) => visibleAvailableLeafIds.includes(x)).length}\n onClick={() => moveChecked(true)}\n aria-label=\"Add selected\"\n icon={<AngleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={chosenLeafIds.length === memoizedAllLeaves.length}\n onClick={() => moveAll(true)}\n aria-label=\"Add all\"\n icon={<AngleDoubleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={chosenLeafIds.length === 0}\n onClick={() => moveAll(false)}\n aria-label=\"Remove all\"\n icon={<RhMicronsDoubleCaretLeftIcon />}\n />\n <DualListSelectorControl\n onClick={() => moveChecked(false)}\n isDisabled={!checkedLeafIds.filter((x) => visibleChosenLeafIds.includes(x)).length}\n aria-label=\"Remove selected\"\n icon={<AngleLeftIcon />}\n />\n </DualListSelectorControlsWrapper>\n {buildPane(true)}\n </DualListSelector>\n );\n};\n\nexport const DualListSelectorComposableTreeExample: React.FunctionComponent = () => (\n <DualListSelectorComposableTree\n data={[\n {\n id: 'fruits',\n text: 'Fruits',\n children: [\n { id: 'apple', text: 'Apple' },\n {\n id: 'berries',\n text: 'Berries',\n children: [\n { id: 'blueberry', text: 'Blueberry' },\n { id: 'strawberry', text: 'Strawberry' }\n ]\n },\n { id: 'banana', text: 'Banana' }\n ]\n },\n { id: 'bread', text: 'Bread' },\n {\n id: 'vegetables',\n text: 'Vegetables',\n children: [\n { id: 'broccoli', text: 'Broccoli' },\n { id: 'cauliflower', text: 'Cauliflower' }\n ]\n },\n {\n id: 'proteins',\n text: 'Proteins',\n children: [\n { id: 'beans', text: 'Beans' },\n {\n id: 'meats',\n text: 'Meats',\n children: [\n {\n id: 'beef',\n text: 'Beef'\n },\n {\n id: 'chicken',\n text: 'Chicken'\n }\n ]\n },\n { id: 'tofu', text: 'Tofu' }\n ]\n }\n ]}\n />\n);\n","title":"With tree","lang":"ts","className":""}}>
|
|
407
|
-
|
|
408
|
-
</Example>,
|
|
409
|
-
'Draggable': props =>
|
|
410
|
-
<Example {...pageData} {...props} {...{"code":"import { useState } from 'react';\nimport {\n DualListSelector,\n DualListSelectorPane,\n DualListSelectorList,\n DualListSelectorListItem,\n DualListSelectorControlsWrapper,\n DualListSelectorControl\n} from '@patternfly/react-core';\nimport { DragDropSort, DraggableObject } from '@patternfly/react-drag-drop';\n\nimport RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon';\nimport AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';\nimport AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon';\nimport AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';\n\nexport const ComposableDualListSelector: React.FunctionComponent = () => {\n const [ignoreNextOptionSelect, setIgnoreNextOptionSelect] = useState(false);\n const [availableOptions, setAvailableOptions] = useState<DraggableObject[]>([\n { id: 'Apple', content: 'Apple', props: { key: 'Apple', isSelected: false } },\n { id: 'Banana', content: 'Banana', props: { key: 'Banana', isSelected: false } },\n { id: 'Pineapple', content: 'Pineapple', props: { key: 'Pineapple', isSelected: false } }\n ]);\n\n const [chosenOptions, setChosenOptions] = useState<DraggableObject[]>([\n { id: 'Orange', content: 'Orange', props: { key: 'Orange', isSelected: false } },\n { id: 'Grape', content: 'Grape', props: { key: 'Grape', isSelected: false } },\n { id: 'Peach', content: 'Peach', props: { key: 'Peach', isSelected: false } },\n { id: 'Strawberry', content: 'Strawberry', props: { key: 'Strawberry', isSelected: false } }\n ]);\n\n const moveSelected = (fromAvailable) => {\n const sourceOptions = fromAvailable ? availableOptions : chosenOptions;\n const destinationOptions = fromAvailable ? chosenOptions : availableOptions;\n for (let i = 0; i < sourceOptions.length; i++) {\n const option = sourceOptions[i];\n if (option.props.isSelected) {\n sourceOptions.splice(i, 1);\n destinationOptions.push(option);\n option.props.isSelected = false;\n i--;\n }\n }\n if (fromAvailable) {\n setAvailableOptions([...sourceOptions]);\n setChosenOptions([...destinationOptions]);\n } else {\n setChosenOptions([...sourceOptions]);\n setAvailableOptions([...destinationOptions]);\n }\n };\n\n const moveAll = (fromAvailable) => {\n if (fromAvailable) {\n setChosenOptions([...availableOptions, ...chosenOptions]);\n setAvailableOptions([]);\n } else {\n setAvailableOptions([...chosenOptions, ...availableOptions]);\n setChosenOptions([]);\n }\n };\n\n const onOptionSelect = (event, index, isChosen) => {\n if (ignoreNextOptionSelect) {\n setIgnoreNextOptionSelect(false);\n return;\n }\n if (isChosen) {\n const newChosen = [...chosenOptions];\n newChosen[index].props.isSelected = !chosenOptions[index].props.isSelected;\n setChosenOptions(newChosen);\n } else {\n const newAvailable = [...availableOptions];\n newAvailable[index].props.isSelected = !availableOptions[index].props.isSelected;\n setAvailableOptions(newAvailable);\n }\n };\n\n return (\n <DualListSelector>\n <DualListSelectorPane\n title=\"Available\"\n status={`${availableOptions.filter((x) => x.props.isSelected).length} of ${\n availableOptions.length\n } options selected`}\n >\n <DualListSelectorList>\n {availableOptions.map((option, index) => (\n <DualListSelectorListItem\n key={index}\n isSelected={option.props.isSelected}\n id={`composable-available-option-${option.content}`}\n onOptionSelect={(e) => onOptionSelect(e, index, false)}\n >\n {option.content}\n </DualListSelectorListItem>\n ))}\n </DualListSelectorList>\n </DualListSelectorPane>\n <DualListSelectorControlsWrapper aria-label=\"Selector controls\">\n <DualListSelectorControl\n isDisabled={!availableOptions.some((option) => option.props.isSelected)}\n onClick={() => moveSelected(true)}\n aria-label=\"Add selected\"\n icon={<AngleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={availableOptions.length === 0}\n onClick={() => moveAll(true)}\n aria-label=\"Add all\"\n icon={<AngleDoubleRightIcon />}\n />\n <DualListSelectorControl\n isDisabled={chosenOptions.length === 0}\n onClick={() => moveAll(false)}\n aria-label=\"Remove all\"\n icon={<RhMicronsDoubleCaretLeftIcon />}\n />\n <DualListSelectorControl\n onClick={() => moveSelected(false)}\n isDisabled={!chosenOptions.some((option) => option.props.isSelected)}\n aria-label=\"Remove selected\"\n icon={<AngleLeftIcon />}\n />\n </DualListSelectorControlsWrapper>\n <DualListSelectorPane\n title=\"Chosen\"\n status={`${chosenOptions.filter((x) => x.props.isSelected).length} of ${chosenOptions.length} options selected`}\n isChosen\n >\n <DragDropSort\n items={chosenOptions.map((option, index) => ({\n ...option,\n props: {\n key: option.props.key,\n isSelected: option.props.isSelected,\n onOptionSelect: (e) => onOptionSelect(e, index, true)\n }\n }))}\n onDrop={(_, newItems) => {\n setChosenOptions(newItems);\n }}\n variant=\"DualListSelectorList\"\n >\n <DualListSelectorList />\n </DragDropSort>\n </DualListSelectorPane>\n </DualListSelector>\n );\n};\n","title":"Draggable","lang":"ts","className":""}}>
|
|
411
|
-
|
|
412
|
-
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
413
|
-
{`To enable drag and drop, wrap the `}
|
|
414
|
-
|
|
415
|
-
<code {...{"className":"ws-code "}}>
|
|
416
|
-
{`<DualListSelectorList>`}
|
|
417
|
-
</code>
|
|
418
|
-
{` component with `}
|
|
419
|
-
|
|
420
|
-
<code {...{"className":"ws-code "}}>
|
|
421
|
-
{`<DragDropSort>`}
|
|
422
|
-
</code>
|
|
423
|
-
{`, define the `}
|
|
424
|
-
|
|
425
|
-
<code {...{"className":"ws-code "}}>
|
|
426
|
-
{`variant`}
|
|
427
|
-
</code>
|
|
428
|
-
{` property as "DualListSelectorList", and pass both the sortable items and `}
|
|
429
|
-
|
|
430
|
-
<code {...{"className":"ws-code "}}>
|
|
431
|
-
{`onDrop`}
|
|
432
|
-
</code>
|
|
433
|
-
{` callback to `}
|
|
434
|
-
|
|
435
|
-
<code {...{"className":"ws-code "}}>
|
|
436
|
-
{`<DragDropSort>`}
|
|
437
|
-
</code>
|
|
438
|
-
{`. `}
|
|
439
|
-
|
|
440
|
-
<code {...{"className":"ws-code "}}>
|
|
441
|
-
{`<DragDropSort>`}
|
|
442
|
-
</code>
|
|
443
|
-
{` will create the component's usual children internally based on the items property, so children inside the `}
|
|
444
|
-
|
|
445
|
-
<code {...{"className":"ws-code "}}>
|
|
446
|
-
{`<DualListSelectorList>`}
|
|
447
|
-
</code>
|
|
448
|
-
{` should not be passed to the wrapped component.`}
|
|
449
|
-
</p>
|
|
450
|
-
|
|
451
|
-
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
452
|
-
{`Full drag and drop details can be found on the `}
|
|
453
|
-
|
|
454
|
-
<PatternflyThemeLink {...{"to":"/components/drag-and-drop","className":""}}>
|
|
455
|
-
{`drag and drop`}
|
|
456
|
-
</PatternflyThemeLink>
|
|
457
|
-
{` component page.`}
|
|
458
|
-
</p>
|
|
459
|
-
</Example>,
|
|
460
|
-
'Draggable with multiple drop zones': props =>
|
|
461
|
-
<Example {...pageData} {...props} {...{"code":"import { useEffect, useState } from 'react';\nimport {\n DualListSelector,\n DualListSelectorPane,\n DualListSelectorList,\n DualListSelectorControlsWrapper,\n DualListSelectorControl\n} from '@patternfly/react-core';\nimport { DragDropContainer, DraggableObject, Droppable as NewDroppable } from '@patternfly/react-drag-drop';\n\nimport RhMicronsDoubleCaretLeftIcon from '@patternfly/react-icons/dist/esm/icons/rh-microns-double-caret-left-icon';\nimport AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';\nimport AngleDoubleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-double-right-icon';\nimport AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon';\n\nexport const DragDropContainerDualListSelector: React.FunctionComponent = () => {\n const [ignoreNextOptionSelect, setIgnoreNextOptionSelect] = useState(false);\n const [availableOptions, setAvailableOptions] = useState<DraggableObject[]>([\n { id: 'Apple', content: 'Apple', props: { key: 'Apple', isSelected: false } },\n { id: 'Banana', content: 'Banana', props: { key: 'Banana', isSelected: false } },\n { id: 'Pineapple', content: 'Pineapple', props: { key: 'Pineapple', isSelected: false } }\n ]);\n\n const [chosenOptions, setChosenOptions] = useState<DraggableObject[]>([\n { id: 'Orange', content: 'Orange', props: { key: 'Orange', isSelected: false } },\n { id: 'Grape', content: 'Grape', props: { key: 'Grape', isSelected: false } },\n { id: 'Peach', content: 'Peach', props: { key: 'Peach', isSelected: false } },\n { id: 'Strawberry', content: 'Strawberry', props: { key: 'Strawberry', isSelected: false } }\n ]);\n\n const [allDraggableItems, setAllItems] = useState<Record<string, DraggableObject[]>>({\n available: availableOptions.map((option, index) => ({\n ...option,\n props: {\n key: option.props.key,\n isSelected: option.props.isSelected,\n onOptionSelect: (e) => onOptionSelect(e, index, false)\n }\n })),\n chosen: chosenOptions.map((option, index) => ({\n ...option,\n props: {\n key: option.props.key,\n isSelected: option.props.isSelected,\n onOptionSelect: (e) => onOptionSelect(e, index, true)\n }\n }))\n });\n\n const handleDragOperation = (_event: any, items: Record<string, DraggableObject[]>) => {\n setAvailableOptions(items.available);\n setChosenOptions(items.chosen);\n setAllItems(items);\n };\n\n useEffect(() => {\n setAllItems({\n available: availableOptions.map((option, index) => ({\n ...option,\n props: {\n key: option.props.key,\n isSelected: option.props.isSelected,\n onOptionSelect: (e) => onOptionSelect(e, index, false)\n }\n })),\n chosen: chosenOptions.map((option, index) => ({\n ...option,\n props: {\n key: option.props.key,\n isSelected: option.props.isSelected,\n onOptionSelect: (e) => onOptionSelect(e, index, true)\n }\n }))\n });\n }, [availableOptions, chosenOptions]);\n\n const moveSelected = (fromAvailable) => {\n const sourceOptions = fromAvailable ? availableOptions : chosenOptions;\n const destinationOptions = fromAvailable ? chosenOptions : availableOptions;\n for (let i = 0; i < sourceOptions.length; i++) {\n const option = sourceOptions[i];\n if (option.props.isSelected) {\n sourceOptions.splice(i, 1);\n destinationOptions.push(option);\n option.props.isSelected = false;\n i--;\n }\n }\n if (fromAvailable) {\n setAvailableOptions([...sourceOptions]);\n setChosenOptions([...destinationOptions]);\n } else {\n setChosenOptions([...sourceOptions]);\n setAvailableOptions([...destinationOptions]);\n }\n };\n\n const moveAll = (fromAvailable) => {\n if (fromAvailable) {\n setChosenOptions([...availableOptions, ...chosenOptions]);\n setAvailableOptions([]);\n } else {\n setAvailableOptions([...chosenOptions, ...availableOptions]);\n setChosenOptions([]);\n }\n };\n\n const onOptionSelect = (event, index, isChosen) => {\n if (ignoreNextOptionSelect) {\n setIgnoreNextOptionSelect(false);\n return;\n }\n if (isChosen) {\n const newChosen = [...chosenOptions];\n newChosen[index].props.isSelected = !chosenOptions[index].props.isSelected;\n setChosenOptions(newChosen);\n } else {\n const newAvailable = [...availableOptions];\n newAvailable[index].props.isSelected = !availableOptions[index].props.isSelected;\n setAvailableOptions(newAvailable);\n }\n };\n\n return (\n <DragDropContainer\n items={allDraggableItems}\n onDrop={handleDragOperation}\n onContainerMove={handleDragOperation}\n onCancel={handleDragOperation}\n variant=\"DualListSelectorList\"\n >\n <DualListSelector>\n <DualListSelectorPane\n title=\"Available\"\n status={`${availableOptions.filter((x) => x.props.isSelected).length} of ${\n availableOptions.length\n } options selected`}\n >\n <NewDroppable\n id=\"available\"\n items={allDraggableItems.available}\n variant=\"DualListSelectorList\"\n wrapper={<DualListSelectorList />}\n />\n </DualListSelectorPane>\n <DualListSelectorControlsWrapper aria-label=\"Selector controls\">\n <DualListSelectorControl\n isDisabled={!availableOptions.some((option) => option.props.isSelected)}\n onClick={() => moveSelected(true)}\n aria-label=\"Add selected\"\n >\n <AngleRightIcon />\n </DualListSelectorControl>\n <DualListSelectorControl\n isDisabled={availableOptions.length === 0}\n onClick={() => moveAll(true)}\n aria-label=\"Add all\"\n >\n <AngleDoubleRightIcon />\n </DualListSelectorControl>\n <DualListSelectorControl\n isDisabled={chosenOptions.length === 0}\n onClick={() => moveAll(false)}\n aria-label=\"Remove all\"\n >\n <RhMicronsDoubleCaretLeftIcon />\n </DualListSelectorControl>\n <DualListSelectorControl\n onClick={() => moveSelected(false)}\n isDisabled={!chosenOptions.some((option) => option.props.isSelected)}\n aria-label=\"Remove selected\"\n >\n <AngleLeftIcon />\n </DualListSelectorControl>\n </DualListSelectorControlsWrapper>\n <DualListSelectorPane\n title=\"Chosen\"\n status={`${chosenOptions.filter((x) => x.props.isSelected).length} of ${chosenOptions.length} options selected`}\n isChosen\n >\n <NewDroppable\n id=\"chosen\"\n items={allDraggableItems.chosen}\n variant=\"DualListSelectorList\"\n wrapper={<DualListSelectorList />}\n />\n </DualListSelectorPane>\n </DualListSelector>\n </DragDropContainer>\n );\n};\n","title":"Draggable with multiple drop zones","lang":"ts","className":""}}>
|
|
462
|
-
|
|
463
|
-
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
464
|
-
{`To enable multiple drop zones, wrap the `}
|
|
465
|
-
|
|
466
|
-
<code {...{"className":"ws-code "}}>
|
|
467
|
-
{`<DualListSelector>`}
|
|
468
|
-
</code>
|
|
469
|
-
{` component with `}
|
|
470
|
-
|
|
471
|
-
<code {...{"className":"ws-code "}}>
|
|
472
|
-
{`<DragDropContainer>`}
|
|
473
|
-
</code>
|
|
474
|
-
{`, and create the desired amount of `}
|
|
475
|
-
|
|
476
|
-
<code {...{"className":"ws-code "}}>
|
|
477
|
-
{`<Droppable>`}
|
|
478
|
-
</code>
|
|
479
|
-
{` components within `}
|
|
480
|
-
|
|
481
|
-
<code {...{"className":"ws-code "}}>
|
|
482
|
-
{`<DragDropContainer>`}
|
|
483
|
-
</code>
|
|
484
|
-
{`. `}
|
|
485
|
-
|
|
486
|
-
<code {...{"className":"ws-code "}}>
|
|
487
|
-
{`<Droppable>`}
|
|
488
|
-
</code>
|
|
489
|
-
{` components should be located where `}
|
|
490
|
-
|
|
491
|
-
<code {...{"className":"ws-code "}}>
|
|
492
|
-
{`<DualListSelectorList>`}
|
|
493
|
-
</code>
|
|
494
|
-
{` usually would go for each pane to be made draggable.`}
|
|
495
|
-
</p>
|
|
496
|
-
|
|
497
|
-
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
498
|
-
{`Each `}
|
|
499
|
-
|
|
500
|
-
<code {...{"className":"ws-code "}}>
|
|
501
|
-
{`<Droppable>`}
|
|
502
|
-
</code>
|
|
503
|
-
{` should define the `}
|
|
504
|
-
|
|
505
|
-
<code {...{"className":"ws-code "}}>
|
|
506
|
-
{`wrapper`}
|
|
507
|
-
</code>
|
|
508
|
-
{` property as the component that acts as the drop zone, `}
|
|
509
|
-
|
|
510
|
-
<code {...{"className":"ws-code "}}>
|
|
511
|
-
{`<DualListSelectorList>`}
|
|
512
|
-
</code>
|
|
513
|
-
{`, and the `}
|
|
514
|
-
|
|
515
|
-
<code {...{"className":"ws-code "}}>
|
|
516
|
-
{`items`}
|
|
517
|
-
</code>
|
|
518
|
-
{` property of their respective draggable items as an array of `}
|
|
519
|
-
|
|
520
|
-
<code {...{"className":"ws-code "}}>
|
|
521
|
-
{`<DraggableObject>`}
|
|
522
|
-
</code>
|
|
523
|
-
{` data. `}
|
|
524
|
-
|
|
525
|
-
<code {...{"className":"ws-code "}}>
|
|
526
|
-
{`<DragDropContainer>`}
|
|
527
|
-
</code>
|
|
528
|
-
{` should be passed the `}
|
|
529
|
-
|
|
530
|
-
<code {...{"className":"ws-code "}}>
|
|
531
|
-
{`onDrop`}
|
|
532
|
-
</code>
|
|
533
|
-
{`, `}
|
|
534
|
-
|
|
535
|
-
<code {...{"className":"ws-code "}}>
|
|
536
|
-
{`onContainerMove`}
|
|
537
|
-
</code>
|
|
538
|
-
{`, and `}
|
|
539
|
-
|
|
540
|
-
<code {...{"className":"ws-code "}}>
|
|
541
|
-
{`onCancel`}
|
|
542
|
-
</code>
|
|
543
|
-
{` callbacks to handle items being dropped, items moving between droppable containers, and what happens if the drag is cancelled respectively. `}
|
|
544
|
-
|
|
545
|
-
<code {...{"className":"ws-code "}}>
|
|
546
|
-
{`<DragDropContainer>`}
|
|
547
|
-
</code>
|
|
548
|
-
{` should also be given a `}
|
|
549
|
-
|
|
550
|
-
<code {...{"className":"ws-code "}}>
|
|
551
|
-
{`Record`}
|
|
552
|
-
</code>
|
|
553
|
-
{` representing all sortable drop zones' items. Both components should define the `}
|
|
554
|
-
|
|
555
|
-
<code {...{"className":"ws-code "}}>
|
|
556
|
-
{`variant`}
|
|
557
|
-
</code>
|
|
558
|
-
{` property as "DualListSelectorList".`}
|
|
559
|
-
</p>
|
|
560
|
-
|
|
561
|
-
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
562
|
-
{`Full drag and drop details can be found on the `}
|
|
563
|
-
|
|
564
|
-
<PatternflyThemeLink {...{"to":"/components/drag-and-drop","className":""}}>
|
|
565
|
-
{`drag and drop`}
|
|
566
|
-
</PatternflyThemeLink>
|
|
567
|
-
{` component page.`}
|
|
568
|
-
</p>
|
|
569
|
-
</Example>
|
|
570
|
-
};
|
|
571
|
-
|
|
572
|
-
const Component = () => (
|
|
573
|
-
<React.Fragment>
|
|
574
|
-
<AutoLinkHeader {...{"id":"examples","headingLevel":"h2","className":"ws-title ws-h2"}}>
|
|
575
|
-
{`Examples`}
|
|
576
|
-
</AutoLinkHeader>
|
|
577
|
-
<p {...{"className":"pf-v6-c-content--p pf-m-editorial ws-p "}}>
|
|
578
|
-
{`The dual list selector is built in a composable manner to make customization easier. The standard sub-component relationships are arranged as follows:`}
|
|
579
|
-
</p>
|
|
580
|
-
<Example {...{"code":"<DualListSelector>\n <DualListSelectorPane>\n <DualListSelectorList>\n <DualListSelectorListItem />\n </DualListSelectorList>\n </DualListSelectorPane>\n\n <DualListSelectorControlsWrapper>\n <DualListSelectorControl /> /* A standard Dual list selector has 4 controls */\n </DualListSelectorControlsWrapper>\n\n <DualListSelectorPane isChosen>\n <DualListSelectorList>\n <DualListSelectorListItem />\n </DualListSelectorList>\n </DualListSelectorPane>\n</DualListSelector>","lang":"noLive","className":""}}>
|
|
581
|
-
</Example>
|
|
582
|
-
{React.createElement(pageData.examples["Basic"])}
|
|
583
|
-
{React.createElement(pageData.examples["Basic with tooltips"])}
|
|
584
|
-
{React.createElement(pageData.examples["Basic with search"])}
|
|
585
|
-
{React.createElement(pageData.examples["Using more complex options with actions"])}
|
|
586
|
-
{React.createElement(pageData.examples["With tree"])}
|
|
587
|
-
{React.createElement(pageData.examples["Draggable"])}
|
|
588
|
-
{React.createElement(pageData.examples["Draggable with multiple drop zones"])}
|
|
589
|
-
</React.Fragment>
|
|
590
|
-
);
|
|
591
|
-
Component.displayName = 'ComponentsDualListSelectorReactDocs';
|
|
592
|
-
Component.pageData = pageData;
|
|
593
|
-
|
|
594
|
-
export default Component;
|