playbook_ui 16.1.0.pre.alpha.play276813969 → 16.1.0.pre.alpha.play277814027
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +12 -2
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +33 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background_custom.jsx +71 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background_custom.md +4 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +14 -5
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_default.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +11 -46
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.html.erb +3 -6
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.jsx +0 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.md +1 -3
- data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +4 -10
- data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +0 -9
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +2 -7
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +0 -4
- data/app/pb_kits/playbook/pb_dropdown/index.js +73 -125
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +0 -16
- data/app/pb_kits/playbook/pb_dropdown/utilities/clickOutsideHelper.tsx +0 -6
- data/app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.html.erb +1 -0
- data/app/pb_kits/playbook/pb_form/pb_form_validation.js +9 -2
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.scss +0 -7
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +549 -638
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_label.html.erb +3 -3
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_label.jsx +7 -4
- data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.test.jsx +4 -4
- data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +10 -0
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_default.html.erb +3 -3
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_default.jsx +3 -0
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_default.md +1 -0
- data/app/pb_kits/playbook/pb_textarea/textarea.html.erb +25 -9
- data/app/pb_kits/playbook/pb_textarea/textarea.rb +7 -1
- data/app/pb_kits/playbook/pb_time_picker/_time_picker.tsx +97 -11
- data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_on_handler.jsx +5 -2
- data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_required_indicator.html.erb +6 -0
- data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_required_indicator.jsx +16 -0
- data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_required_indicator.md +3 -0
- data/app/pb_kits/playbook/pb_time_picker/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_time_picker/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_time_picker/time_picker.rb +3 -0
- data/app/pb_kits/playbook/pb_time_picker/time_picker.test.jsx +47 -1
- data/dist/chunks/_typeahead-CWA5wlah.js +1 -0
- data/dist/chunks/vendor.js +3 -3
- data/dist/menu.yml +2 -2
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +10 -4
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_label.md +0 -3
- data/dist/chunks/_typeahead-C4YsbA48.js +0 -1
|
@@ -26,688 +26,599 @@ import {
|
|
|
26
26
|
getExpandedItems,
|
|
27
27
|
} from "./_helper_functions";
|
|
28
28
|
|
|
29
|
-
interface MultiLevelSelectComponent
|
|
30
|
-
|
|
31
|
-
>
|
|
29
|
+
interface MultiLevelSelectComponent
|
|
30
|
+
extends React.ForwardRefExoticComponent<
|
|
31
|
+
MultiLevelSelectProps & React.RefAttributes<HTMLInputElement>
|
|
32
|
+
> {
|
|
32
33
|
Options: typeof MultiLevelSelectOptions;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
type MultiLevelSelectProps = {
|
|
36
|
-
aria?: { [key: string]: string }
|
|
37
|
-
className?: string
|
|
38
|
-
data?: { [key: string]: string }
|
|
39
|
-
disabled?: boolean
|
|
40
|
-
error?: string
|
|
41
|
-
htmlOptions?: {
|
|
42
|
-
id?: string
|
|
43
|
-
inputDisplay?: "pills" | "none"
|
|
44
|
-
inputName?: string
|
|
45
|
-
label?: string
|
|
46
|
-
name?: string
|
|
47
|
-
required?: boolean
|
|
48
|
-
returnAllSelected?: boolean
|
|
49
|
-
showCheckedChildren?: boolean
|
|
50
|
-
treeData?: { [key: string]: string }[] | any
|
|
51
|
-
onChange?: (event: { target: { name?: string; value: any } }) => void
|
|
52
|
-
onSelect?: (prop: { [key: string]: any }) => void
|
|
53
|
-
selectedIds?: string[] | any
|
|
54
|
-
variant?: "multi" | "single"
|
|
55
|
-
wrapped?: boolean
|
|
56
|
-
pillColor?:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
37
|
+
aria?: { [key: string]: string }
|
|
38
|
+
className?: string
|
|
39
|
+
data?: { [key: string]: string }
|
|
40
|
+
disabled?: boolean
|
|
41
|
+
error?: string
|
|
42
|
+
htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
|
|
43
|
+
id?: string
|
|
44
|
+
inputDisplay?: "pills" | "none"
|
|
45
|
+
inputName?: string
|
|
46
|
+
label?: string
|
|
47
|
+
name?: string
|
|
48
|
+
required?: boolean
|
|
49
|
+
returnAllSelected?: boolean
|
|
50
|
+
showCheckedChildren?: boolean
|
|
51
|
+
treeData?: { [key: string]: string; }[] | any
|
|
52
|
+
onChange?: (event: { target: { name?: string; value: any } }) => void
|
|
53
|
+
onSelect?: (prop: { [key: string]: any }) => void
|
|
54
|
+
selectedIds?: string[] | any
|
|
55
|
+
variant?: "multi" | "single"
|
|
56
|
+
wrapped?: boolean
|
|
57
|
+
pillColor?: "primary" | "neutral" | "success" | "warning" | "error" | "info" | "data_1" | "data_2" | "data_3" | "data_4" | "data_5" | "data_6" | "data_7" | "data_8" | "windows" | "siding" | "roofing" | "doors" | "gutters" | "solar" | "insulation" | "accessories",
|
|
58
|
+
} & GlobalProps
|
|
59
|
+
|
|
60
|
+
const MultiLevelSelect = forwardRef<HTMLInputElement, MultiLevelSelectProps>((props) => {
|
|
61
|
+
const {
|
|
62
|
+
aria = {},
|
|
63
|
+
className,
|
|
64
|
+
data = {},
|
|
65
|
+
disabled = false,
|
|
66
|
+
error,
|
|
67
|
+
htmlOptions = {},
|
|
68
|
+
id,
|
|
69
|
+
inputDisplay = "pills",
|
|
70
|
+
inputName,
|
|
71
|
+
name,
|
|
72
|
+
label,
|
|
73
|
+
required = false,
|
|
74
|
+
returnAllSelected = false,
|
|
75
|
+
showCheckedChildren = true,
|
|
76
|
+
treeData,
|
|
77
|
+
onChange = () => null,
|
|
78
|
+
onSelect = () => null,
|
|
79
|
+
selectedIds,
|
|
80
|
+
variant = "multi",
|
|
81
|
+
children,
|
|
82
|
+
wrapped,
|
|
83
|
+
pillColor = "primary"
|
|
84
|
+
} = props
|
|
85
|
+
|
|
86
|
+
const ariaProps = buildAriaProps(aria);
|
|
87
|
+
const dataProps = buildDataProps(data);
|
|
88
|
+
const htmlProps = buildHtmlProps(htmlOptions);
|
|
89
|
+
const classes = classnames(
|
|
90
|
+
buildCss("pb_multi_level_select"),
|
|
91
|
+
error && "error",
|
|
92
|
+
globalProps(props),
|
|
93
|
+
className
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const dropdownRef = useRef(null);
|
|
97
|
+
|
|
98
|
+
// State for whether dropdown is open or closed
|
|
99
|
+
const [isDropdownClosed, setIsDropdownClosed] = useState(true);
|
|
100
|
+
// State from onChange for textinput, to use for filtering to create typeahead
|
|
101
|
+
const [filterItem, setFilterItem] = useState("");
|
|
102
|
+
// FormattedData with checked and parent_id added
|
|
103
|
+
const [formattedData, setFormattedData] = useState([]);
|
|
104
|
+
// State for the return of returnAllSelected
|
|
105
|
+
const [returnedArray, setReturnedArray] = useState([]);
|
|
106
|
+
// State for default return
|
|
107
|
+
const [defaultReturn, setDefaultReturn] = useState([]);
|
|
108
|
+
// Get expanded items from treeData
|
|
109
|
+
const initialExpandedItems = getExpandedItems(treeData, selectedIds, showCheckedChildren);
|
|
110
|
+
// Initialize state with expanded items
|
|
111
|
+
const [expanded, setExpanded] = useState(initialExpandedItems);
|
|
112
|
+
|
|
113
|
+
// Single Select specific state
|
|
114
|
+
const [singleSelectedItem, setSingleSelectedItem] = useState({
|
|
115
|
+
id: [],
|
|
116
|
+
value: "",
|
|
117
|
+
item: [],
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const arrowDownElementId = `arrow_down_${id}`
|
|
121
|
+
const arrowUpElementId = `arrow_up_${id}`
|
|
122
|
+
|
|
123
|
+
const modifyRecursive = (tree: { [key: string]: any }[], check: boolean) => {
|
|
124
|
+
if (!Array.isArray(tree)) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
return tree.map((item: { [key: string]: any }) => {
|
|
128
|
+
if (!item.disabled) {
|
|
129
|
+
item.checked = check;
|
|
130
|
+
}
|
|
131
|
+
item.children = modifyRecursive(item.children, check);
|
|
132
|
+
return item;
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Function to map over data and add parent_id + depth property to each item
|
|
137
|
+
const addCheckedAndParentProperty = (
|
|
138
|
+
treeData: { [key: string]: any }[],
|
|
139
|
+
selectedIds: string[],
|
|
140
|
+
parent_id: string | null = null,
|
|
141
|
+
depth = 0,
|
|
142
|
+
parentDisabled = false
|
|
143
|
+
) => {
|
|
144
|
+
if (!Array.isArray(treeData)) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
return treeData.map((item: { [key: string]: any } | any) => {
|
|
148
|
+
// An item is disabled if it is explicitly set as disabled or if its parent is disabled
|
|
149
|
+
const isDisabled = item.disabled || (parentDisabled && !returnAllSelected);
|
|
150
|
+
|
|
151
|
+
const newItem = {
|
|
152
|
+
...item,
|
|
153
|
+
checked: Boolean(
|
|
154
|
+
selectedIds && selectedIds.length && selectedIds.includes(item.id)
|
|
155
|
+
),
|
|
156
|
+
parent_id,
|
|
157
|
+
depth,
|
|
158
|
+
disabled: isDisabled,
|
|
159
|
+
};
|
|
160
|
+
if (newItem.children && newItem.children.length > 0) {
|
|
161
|
+
const children =
|
|
162
|
+
item.checked && !returnAllSelected
|
|
163
|
+
? modifyRecursive(item.children, true)
|
|
164
|
+
: item.children;
|
|
165
|
+
newItem.children = addCheckedAndParentProperty(
|
|
166
|
+
children,
|
|
167
|
+
selectedIds,
|
|
168
|
+
newItem.id,
|
|
169
|
+
depth + 1,
|
|
170
|
+
isDisabled
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
return newItem;
|
|
174
|
+
});
|
|
175
|
+
};
|
|
116
176
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// State for whether dropdown is open or closed
|
|
120
|
-
const [isDropdownClosed, setIsDropdownClosed] = useState(true);
|
|
121
|
-
// State from onChange for textinput, to use for filtering to create typeahead
|
|
122
|
-
const [filterItem, setFilterItem] = useState("");
|
|
123
|
-
// FormattedData with checked and parent_id added
|
|
124
|
-
const [formattedData, setFormattedData] = useState([]);
|
|
125
|
-
// State for the return of returnAllSelected
|
|
126
|
-
const [returnedArray, setReturnedArray] = useState([]);
|
|
127
|
-
// State for default return
|
|
128
|
-
const [defaultReturn, setDefaultReturn] = useState([]);
|
|
129
|
-
// Get expanded items from treeData
|
|
130
|
-
const initialExpandedItems = getExpandedItems(
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
const formattedData = addCheckedAndParentProperty(
|
|
131
179
|
treeData,
|
|
132
|
-
selectedIds
|
|
133
|
-
showCheckedChildren,
|
|
180
|
+
variant === "single" ? [selectedIds?.[0]] : selectedIds
|
|
134
181
|
);
|
|
135
|
-
// Initialize state with expanded items
|
|
136
|
-
const [expanded, setExpanded] = useState(initialExpandedItems);
|
|
137
|
-
|
|
138
|
-
// Single Select specific state
|
|
139
|
-
const [singleSelectedItem, setSingleSelectedItem] = useState({
|
|
140
|
-
id: [],
|
|
141
|
-
value: "",
|
|
142
|
-
item: [],
|
|
143
|
-
});
|
|
144
182
|
|
|
145
|
-
|
|
146
|
-
const arrowUpElementId = `arrow_up_${id}`;
|
|
147
|
-
// Control id for label htmlFor: use suffix to avoid conflict with outer div's id
|
|
148
|
-
const sanitizeForId = (str: string) =>
|
|
149
|
-
str.toLowerCase().replace(/\s+/g, "_").replace(/[^a-z0-9_]/g, "");
|
|
150
|
-
const labelForId = id
|
|
151
|
-
? `${id}_input`
|
|
152
|
-
: (name ? sanitizeForId(name) : null) ||
|
|
153
|
-
(label ? sanitizeForId(label) : null) ||
|
|
154
|
-
"multiselect_input";
|
|
155
|
-
const errorId = error ? `${labelForId}-error` : undefined;
|
|
156
|
-
|
|
157
|
-
const modifyRecursive = (
|
|
158
|
-
tree: { [key: string]: any }[],
|
|
159
|
-
check: boolean,
|
|
160
|
-
) => {
|
|
161
|
-
if (!Array.isArray(tree)) {
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
return tree.map((item: { [key: string]: any }) => {
|
|
165
|
-
if (!item.disabled) {
|
|
166
|
-
item.checked = check;
|
|
167
|
-
}
|
|
168
|
-
item.children = modifyRecursive(item.children, check);
|
|
169
|
-
return item;
|
|
170
|
-
});
|
|
171
|
-
};
|
|
183
|
+
setFormattedData(formattedData);
|
|
172
184
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
return treeData.map((item: { [key: string]: any } | any) => {
|
|
185
|
-
// An item is disabled if it is explicitly set as disabled or if its parent is disabled
|
|
186
|
-
const isDisabled =
|
|
187
|
-
item.disabled || (parentDisabled && !returnAllSelected);
|
|
188
|
-
|
|
189
|
-
const newItem = {
|
|
190
|
-
...item,
|
|
191
|
-
checked: Boolean(
|
|
192
|
-
selectedIds && selectedIds.length && selectedIds.includes(item.id),
|
|
193
|
-
),
|
|
194
|
-
parent_id,
|
|
195
|
-
depth,
|
|
196
|
-
disabled: isDisabled,
|
|
197
|
-
};
|
|
198
|
-
if (newItem.children && newItem.children.length > 0) {
|
|
199
|
-
const children =
|
|
200
|
-
item.checked && !returnAllSelected
|
|
201
|
-
? modifyRecursive(item.children, true)
|
|
202
|
-
: item.children;
|
|
203
|
-
newItem.children = addCheckedAndParentProperty(
|
|
204
|
-
children,
|
|
205
|
-
selectedIds,
|
|
206
|
-
newItem.id,
|
|
207
|
-
depth + 1,
|
|
208
|
-
isDisabled,
|
|
185
|
+
if (variant === "single") {
|
|
186
|
+
// No selectedIds, reset state
|
|
187
|
+
if (selectedIds?.length === 0 || !selectedIds?.length) {
|
|
188
|
+
setSingleSelectedItem({ id: [], value: "", item: [] });
|
|
189
|
+
} else {
|
|
190
|
+
// If there is a selectedId but no current item, set the selectedItem
|
|
191
|
+
if (selectedIds?.length !== 0 && !singleSelectedItem.value) {
|
|
192
|
+
const selectedItem = filterFormattedDataById(
|
|
193
|
+
formattedData,
|
|
194
|
+
selectedIds[0]
|
|
209
195
|
);
|
|
210
|
-
}
|
|
211
|
-
return newItem;
|
|
212
|
-
});
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
useEffect(() => {
|
|
216
|
-
const formattedData = addCheckedAndParentProperty(
|
|
217
|
-
treeData,
|
|
218
|
-
variant === "single" ? [selectedIds?.[0]] : selectedIds,
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
setFormattedData(formattedData);
|
|
222
|
-
|
|
223
|
-
if (variant === "single") {
|
|
224
|
-
// No selectedIds, reset state
|
|
225
|
-
if (selectedIds?.length === 0 || !selectedIds?.length) {
|
|
226
|
-
setSingleSelectedItem({ id: [], value: "", item: [] });
|
|
227
|
-
} else {
|
|
228
|
-
// If there is a selectedId but no current item, set the selectedItem
|
|
229
|
-
if (selectedIds?.length !== 0 && !singleSelectedItem.value) {
|
|
230
|
-
const selectedItem = filterFormattedDataById(
|
|
231
|
-
formattedData,
|
|
232
|
-
selectedIds[0],
|
|
233
|
-
);
|
|
234
|
-
|
|
235
|
-
if (!selectedItem.length) {
|
|
236
|
-
setSingleSelectedItem({ id: [], value: "", item: [] });
|
|
237
|
-
} else {
|
|
238
|
-
const { id, label } = selectedItem[0];
|
|
239
|
-
setSingleSelectedItem({
|
|
240
|
-
id: [id],
|
|
241
|
-
value: label,
|
|
242
|
-
item: selectedItem,
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}, [treeData, selectedIds]);
|
|
249
196
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
setReturnedArray(getCheckedItems(formattedData));
|
|
253
|
-
} else if (variant === "single") {
|
|
254
|
-
setDefaultReturn(singleSelectedItem.item);
|
|
255
|
-
} else {
|
|
256
|
-
setDefaultReturn(getDefaultCheckedItems(formattedData));
|
|
257
|
-
}
|
|
258
|
-
}, [formattedData]);
|
|
259
|
-
|
|
260
|
-
useEffect(() => {
|
|
261
|
-
// Function to handle clicks outside the dropdown
|
|
262
|
-
const handleClickOutside = (event: any) => {
|
|
263
|
-
// Don't close if clicking on the associated label
|
|
264
|
-
const labelEl = document.querySelector(`label[for="${labelForId}"]`);
|
|
265
|
-
if (labelEl?.contains(event.target)) return;
|
|
266
|
-
|
|
267
|
-
if (
|
|
268
|
-
dropdownRef.current &&
|
|
269
|
-
!dropdownRef.current.contains(event.target) &&
|
|
270
|
-
event.target.id !== arrowDownElementId &&
|
|
271
|
-
event.target.id !== arrowUpElementId
|
|
272
|
-
) {
|
|
273
|
-
setIsDropdownClosed(true);
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
// Attach the event listener
|
|
277
|
-
window.addEventListener("click", handleClickOutside);
|
|
278
|
-
// Clean up the event listener on unmount
|
|
279
|
-
return () => {
|
|
280
|
-
window.removeEventListener("click", handleClickOutside);
|
|
281
|
-
};
|
|
282
|
-
}, [labelForId]);
|
|
283
|
-
|
|
284
|
-
useEffect(() => {
|
|
285
|
-
if (id) {
|
|
286
|
-
// Attach the clear function to the window, scoped by the id
|
|
287
|
-
(window as any)[`clearMultiLevelSelect_${id}`] = () => {
|
|
288
|
-
const resetData = modifyRecursive(formattedData, false);
|
|
289
|
-
setFormattedData(resetData);
|
|
290
|
-
setReturnedArray([]);
|
|
291
|
-
setDefaultReturn([]);
|
|
292
|
-
setSingleSelectedItem({ id: [], value: "", item: [] });
|
|
293
|
-
onSelect([]);
|
|
294
|
-
};
|
|
295
|
-
return () => {
|
|
296
|
-
delete (window as any)[`clearMultiLevelSelect_${id}`];
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
}, [formattedData, id, onSelect]);
|
|
300
|
-
|
|
301
|
-
// Iterate over tree, find item and set checked or unchecked
|
|
302
|
-
const modifyValue = (
|
|
303
|
-
id: string,
|
|
304
|
-
tree: { [key: string]: any }[],
|
|
305
|
-
check: boolean,
|
|
306
|
-
) => {
|
|
307
|
-
if (!Array.isArray(tree)) {
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
return tree.map((item: any) => {
|
|
311
|
-
if (item.id != id)
|
|
312
|
-
item.children = modifyValue(id, item.children, check);
|
|
313
|
-
else {
|
|
314
|
-
if (!item.disabled) {
|
|
315
|
-
item.checked = check;
|
|
316
|
-
}
|
|
317
|
-
if (variant === "single") {
|
|
318
|
-
// Single select: no children should be checked
|
|
319
|
-
item.children = modifyRecursive(item.children, !check);
|
|
197
|
+
if (!selectedItem.length) {
|
|
198
|
+
setSingleSelectedItem({ id: [], value: "", item: [] });
|
|
320
199
|
} else {
|
|
321
|
-
|
|
200
|
+
const { id, label } = selectedItem[0];
|
|
201
|
+
setSingleSelectedItem({ id: [id], value: label, item: selectedItem });
|
|
322
202
|
}
|
|
323
203
|
}
|
|
324
|
-
|
|
325
|
-
return item;
|
|
326
|
-
});
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
// Clone tree, check items + children
|
|
330
|
-
const checkItem = (item: { [key: string]: any }) => {
|
|
331
|
-
const tree = cloneDeep(formattedData);
|
|
332
|
-
if (returnAllSelected) {
|
|
333
|
-
return modifyValue(item.id, tree, true);
|
|
334
|
-
} else {
|
|
335
|
-
const checkedTree = modifyValue(item.id, tree, true);
|
|
336
|
-
return recursiveCheckParent(item, checkedTree);
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
// Clone tree, uncheck items + children
|
|
341
|
-
const unCheckItem = (item: { [key: string]: any }) => {
|
|
342
|
-
const tree = cloneDeep(formattedData);
|
|
343
|
-
if (returnAllSelected) {
|
|
344
|
-
return modifyValue(item.id, tree, false);
|
|
345
|
-
} else {
|
|
346
|
-
const uncheckedTree = modifyValue(item.id, tree, false);
|
|
347
|
-
return getAncestorsOfUnchecked(uncheckedTree, item);
|
|
348
|
-
}
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
// setFormattedData with proper properties
|
|
352
|
-
const changeItem = (item: { [key: string]: any }, check: boolean) => {
|
|
353
|
-
const tree = check ? checkItem(item) : unCheckItem(item);
|
|
354
|
-
setFormattedData(tree);
|
|
355
|
-
|
|
356
|
-
return tree;
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
// Click event for x on form pill
|
|
360
|
-
const handlePillClose = (
|
|
361
|
-
event: any,
|
|
362
|
-
clickedItem: { [key: string]: any },
|
|
363
|
-
) => {
|
|
364
|
-
// Prevents the dropdown from closing when clicking on the pill
|
|
365
|
-
event.stopPropagation();
|
|
366
|
-
const updatedTree = changeItem(clickedItem, false);
|
|
367
|
-
// Logic for removing items from returnArray or defaultReturn when pills clicked
|
|
368
|
-
if (returnAllSelected) {
|
|
369
|
-
onSelect(getCheckedItems(updatedTree));
|
|
370
|
-
onChange({ target: { name, value: getCheckedItems(updatedTree) } });
|
|
371
|
-
} else {
|
|
372
|
-
onSelect(getDefaultCheckedItems(updatedTree));
|
|
373
|
-
onChange({
|
|
374
|
-
target: { name, value: getDefaultCheckedItems(updatedTree) },
|
|
375
|
-
});
|
|
376
204
|
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
205
|
+
}
|
|
206
|
+
}, [treeData, selectedIds]);
|
|
207
|
+
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
if (returnAllSelected) {
|
|
210
|
+
setReturnedArray(getCheckedItems(formattedData));
|
|
211
|
+
} else if (variant === "single") {
|
|
212
|
+
setDefaultReturn(singleSelectedItem.item);
|
|
213
|
+
} else {
|
|
214
|
+
setDefaultReturn(getDefaultCheckedItems(formattedData));
|
|
215
|
+
}
|
|
216
|
+
}, [formattedData]);
|
|
217
|
+
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
// Function to handle clicks outside the dropdown
|
|
220
|
+
const handleClickOutside = (event: any) => {
|
|
389
221
|
if (
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
222
|
+
dropdownRef.current &&
|
|
223
|
+
!dropdownRef.current.contains(event.target) &&
|
|
224
|
+
event.target.id !== arrowDownElementId &&
|
|
225
|
+
event.target.id !== arrowUpElementId
|
|
393
226
|
) {
|
|
394
|
-
|
|
227
|
+
setIsDropdownClosed(true)
|
|
395
228
|
}
|
|
396
|
-
setIsDropdownClosed(!isDropdownClosed);
|
|
397
229
|
};
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
setFilterItem("");
|
|
404
|
-
|
|
405
|
-
const filtered = filterFormattedDataById(formattedData, clickedItem);
|
|
406
|
-
const updatedTree = changeItem(filtered[0], check);
|
|
407
|
-
if (returnAllSelected) {
|
|
408
|
-
onSelect(getCheckedItems(updatedTree));
|
|
409
|
-
onChange({ target: { name, value: getCheckedItems(updatedTree) } });
|
|
410
|
-
} else {
|
|
411
|
-
onSelect(getDefaultCheckedItems(updatedTree));
|
|
412
|
-
onChange({
|
|
413
|
-
target: { name, value: getDefaultCheckedItems(updatedTree) },
|
|
414
|
-
});
|
|
415
|
-
}
|
|
230
|
+
// Attach the event listener
|
|
231
|
+
window.addEventListener("click", handleClickOutside);
|
|
232
|
+
// Clean up the event listener on unmount
|
|
233
|
+
return () => {
|
|
234
|
+
window.removeEventListener("click", handleClickOutside);
|
|
416
235
|
};
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
//
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
236
|
+
}, []);
|
|
237
|
+
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
if (id) {
|
|
240
|
+
// Attach the clear function to the window, scoped by the id
|
|
241
|
+
(window as any)[`clearMultiLevelSelect_${id}`] = () => {
|
|
242
|
+
const resetData = modifyRecursive(formattedData, false);
|
|
243
|
+
setFormattedData(resetData);
|
|
244
|
+
setReturnedArray([]);
|
|
245
|
+
setDefaultReturn([]);
|
|
246
|
+
setSingleSelectedItem({ id: [], value: "", item: [] });
|
|
247
|
+
onSelect([]);
|
|
248
|
+
};
|
|
249
|
+
return () => {
|
|
250
|
+
delete (window as any)[`clearMultiLevelSelect_${id}`];
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}, [formattedData, id, onSelect]);
|
|
254
|
+
|
|
255
|
+
// Iterate over tree, find item and set checked or unchecked
|
|
256
|
+
const modifyValue = (
|
|
257
|
+
id: string,
|
|
258
|
+
tree: { [key: string]: any }[],
|
|
259
|
+
check: boolean
|
|
260
|
+
) => {
|
|
261
|
+
if (!Array.isArray(tree)) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
return tree.map((item: any) => {
|
|
265
|
+
if (item.id != id) item.children = modifyValue(id, item.children, check);
|
|
266
|
+
else {
|
|
267
|
+
if (!item.disabled) {
|
|
268
|
+
item.checked = check;
|
|
269
|
+
}
|
|
270
|
+
if (variant === "single") {
|
|
271
|
+
// Single select: no children should be checked
|
|
272
|
+
item.children = modifyRecursive(item.children, !check);
|
|
273
|
+
} else {
|
|
274
|
+
item.children = modifyRecursive(item.children, check);
|
|
275
|
+
}
|
|
431
276
|
}
|
|
432
277
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
);
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
278
|
+
return item;
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// Clone tree, check items + children
|
|
283
|
+
const checkItem = (item: { [key: string]: any }) => {
|
|
284
|
+
const tree = cloneDeep(formattedData);
|
|
285
|
+
if (returnAllSelected) {
|
|
286
|
+
return modifyValue(item.id, tree, true);
|
|
287
|
+
} else {
|
|
288
|
+
const checkedTree = modifyValue(item.id, tree, true);
|
|
289
|
+
return recursiveCheckParent(item, checkedTree);
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// Clone tree, uncheck items + children
|
|
294
|
+
const unCheckItem = (item: { [key: string]: any }) => {
|
|
295
|
+
const tree = cloneDeep(formattedData);
|
|
296
|
+
if (returnAllSelected) {
|
|
297
|
+
return modifyValue(item.id, tree, false);
|
|
298
|
+
} else {
|
|
299
|
+
const uncheckedTree = modifyValue(item.id, tree, false);
|
|
300
|
+
return getAncestorsOfUnchecked(uncheckedTree, item);
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// setFormattedData with proper properties
|
|
305
|
+
const changeItem = (item: { [key: string]: any }, check: boolean) => {
|
|
306
|
+
const tree = check ? checkItem(item) : unCheckItem(item);
|
|
307
|
+
setFormattedData(tree);
|
|
308
|
+
|
|
309
|
+
return tree;
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// Click event for x on form pill
|
|
313
|
+
const handlePillClose = (event: any, clickedItem: { [key: string]: any }) => {
|
|
314
|
+
// Prevents the dropdown from closing when clicking on the pill
|
|
315
|
+
event.stopPropagation();
|
|
316
|
+
const updatedTree = changeItem(clickedItem, false);
|
|
317
|
+
// Logic for removing items from returnArray or defaultReturn when pills clicked
|
|
318
|
+
if (returnAllSelected) {
|
|
319
|
+
onSelect(getCheckedItems(updatedTree));
|
|
320
|
+
onChange({ target: { name, value: getCheckedItems(updatedTree) } });
|
|
321
|
+
} else {
|
|
322
|
+
onSelect(getDefaultCheckedItems(updatedTree));
|
|
323
|
+
onChange({ target: { name, value: getDefaultCheckedItems(updatedTree) } });
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// Handle click on input wrapper(entire div with pills, typeahead, etc) so it doesn't close when input or form pill is clicked
|
|
328
|
+
const handleInputWrapperClick = (e: any) => {
|
|
329
|
+
if (
|
|
330
|
+
e.target.id === "multiselect_input" ||
|
|
331
|
+
e.target.classList.contains("pb_form_pill_tag") ||
|
|
332
|
+
disabled
|
|
333
|
+
) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
setIsDropdownClosed(!isDropdownClosed);
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
// Main function to handle any click inside dropdown
|
|
340
|
+
const handledropdownItemClick = (e: any, check: boolean) => {
|
|
341
|
+
const clickedItem = e.target.parentNode.id;
|
|
342
|
+
// Setting filterItem to "" will clear textinput and clear typeahead
|
|
343
|
+
setFilterItem("");
|
|
344
|
+
|
|
345
|
+
const filtered = filterFormattedDataById(formattedData, clickedItem);
|
|
346
|
+
const updatedTree = changeItem(filtered[0], check);
|
|
347
|
+
if (returnAllSelected) {
|
|
348
|
+
onSelect(getCheckedItems(updatedTree));
|
|
349
|
+
onChange({ target: { name, value: getCheckedItems(updatedTree) } });
|
|
350
|
+
} else {
|
|
351
|
+
onSelect(getDefaultCheckedItems(updatedTree));
|
|
352
|
+
onChange({ target: { name, value: getDefaultCheckedItems(updatedTree) } });
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
// Single select
|
|
357
|
+
const handleRadioButtonClick = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
358
|
+
const { id, value: inputText } = e.target;
|
|
359
|
+
// The radio button needs a unique ID, this grabs the ID before the hyphen
|
|
360
|
+
const selectedItemID = id.match(/^[^-]*/)[0];
|
|
361
|
+
|
|
362
|
+
// Check if the item is disabled - if so, don't allow selection (safety check in addition to native disabled attribute)
|
|
363
|
+
const clickedItem = filterFormattedDataById(formattedData, selectedItemID);
|
|
364
|
+
if (clickedItem.length > 0 && clickedItem[0].disabled) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Reset tree checked state, triggering useEffect
|
|
369
|
+
const treeWithNoSelections = modifyRecursive(formattedData, false);
|
|
370
|
+
// Update tree with single selection
|
|
371
|
+
const treeWithSelectedItem = modifyValue(
|
|
372
|
+
selectedItemID,
|
|
373
|
+
treeWithNoSelections,
|
|
374
|
+
true
|
|
375
|
+
);
|
|
376
|
+
const selectedItem = filterFormattedDataById(
|
|
377
|
+
treeWithSelectedItem,
|
|
378
|
+
selectedItemID
|
|
379
|
+
);
|
|
485
380
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
381
|
+
setFormattedData(treeWithSelectedItem);
|
|
382
|
+
setSingleSelectedItem({
|
|
383
|
+
id: [selectedItemID],
|
|
384
|
+
value: inputText,
|
|
385
|
+
item: selectedItem,
|
|
386
|
+
});
|
|
387
|
+
// Reset the filter to always display dropdown options on click
|
|
388
|
+
setFilterItem("");
|
|
389
|
+
setIsDropdownClosed(true);
|
|
390
|
+
|
|
391
|
+
onSelect(selectedItem);
|
|
392
|
+
onChange({ target: { name, value: selectedItem } });
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// Single select: reset the tree state upon typing
|
|
396
|
+
const handleRadioInputChange = (inputText: string) => {
|
|
397
|
+
modifyRecursive(formattedData, false);
|
|
398
|
+
setDefaultReturn([]);
|
|
399
|
+
setSingleSelectedItem({ id: [], value: inputText, item: [] });
|
|
400
|
+
setFilterItem(inputText);
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
const isTreeRowExpanded = (item: any) => expanded.indexOf(item.id) > -1;
|
|
404
|
+
|
|
405
|
+
// Handle click on chevron toggles in dropdown
|
|
406
|
+
const handleToggleClick = (id: string, event: React.MouseEvent) => {
|
|
407
|
+
event.stopPropagation();
|
|
408
|
+
const clickedItem = filterFormattedDataById(formattedData, id);
|
|
409
|
+
if (clickedItem) {
|
|
410
|
+
let expandedArray = [...expanded];
|
|
411
|
+
const itemExpanded = isTreeRowExpanded(clickedItem[0]);
|
|
412
|
+
|
|
413
|
+
if (itemExpanded)
|
|
414
|
+
expandedArray = expandedArray.filter((i) => i != clickedItem[0].id);
|
|
415
|
+
else expandedArray.push(clickedItem[0].id);
|
|
416
|
+
|
|
417
|
+
setExpanded(expandedArray);
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
const itemsSelectedLength = () => {
|
|
422
|
+
let items;
|
|
423
|
+
if (returnAllSelected && returnedArray && returnedArray.length) {
|
|
424
|
+
items = returnedArray.length;
|
|
425
|
+
} else if (!returnAllSelected && defaultReturn && defaultReturn.length) {
|
|
426
|
+
items = defaultReturn.length;
|
|
427
|
+
}
|
|
428
|
+
return items;
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
// Rendering formattedData to UI based on typeahead
|
|
432
|
+
const renderNestedOptions = (items: { [key: string]: string; }[] | any ) => {
|
|
433
|
+
const hasOptionsChild = React.Children.toArray(props.children).some(
|
|
434
|
+
(child) => React.isValidElement(child) && child.type === MultiLevelSelect.Options
|
|
435
|
+
);
|
|
495
436
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
437
|
+
if (hasOptionsChild) {
|
|
438
|
+
return React.Children.map(props.children, (child) => {
|
|
439
|
+
if (React.isValidElement(child) && child.type === MultiLevelSelect.Options) {
|
|
440
|
+
return React.cloneElement(child, { items });
|
|
441
|
+
}
|
|
442
|
+
return null;
|
|
443
|
+
});
|
|
444
|
+
} else {
|
|
445
|
+
// If no children, use the default rendering
|
|
446
|
+
return (
|
|
447
|
+
<MultiLevelSelectOptions items={items} />
|
|
502
448
|
);
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
return (
|
|
454
|
+
<div
|
|
455
|
+
{...ariaProps}
|
|
456
|
+
{...dataProps}
|
|
457
|
+
{...htmlProps}
|
|
458
|
+
className={classes}
|
|
459
|
+
id={id}
|
|
460
|
+
>
|
|
461
|
+
{label &&
|
|
462
|
+
<Caption
|
|
463
|
+
marginBottom="xs"
|
|
464
|
+
text={label}
|
|
465
|
+
/>
|
|
517
466
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
467
|
+
<MultiLevelSelectContext.Provider value={{
|
|
468
|
+
variant,
|
|
469
|
+
inputName,
|
|
470
|
+
renderNestedOptions,
|
|
471
|
+
isTreeRowExpanded,
|
|
472
|
+
handleToggleClick,
|
|
473
|
+
handleRadioButtonClick,
|
|
474
|
+
handledropdownItemClick,
|
|
475
|
+
filterItem,
|
|
476
|
+
}}>
|
|
477
|
+
<div className="wrapper"
|
|
478
|
+
ref={dropdownRef}
|
|
527
479
|
>
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
onClick={handleLabelClick}
|
|
531
|
-
>
|
|
532
|
-
<Caption
|
|
533
|
-
className="pb_multi_level_select_kit_label"
|
|
534
|
-
marginBottom="xs"
|
|
535
|
-
text={label}
|
|
536
|
-
/>
|
|
537
|
-
</label>
|
|
538
|
-
)}
|
|
539
|
-
<MultiLevelSelectContext.Provider
|
|
540
|
-
value={{
|
|
541
|
-
variant,
|
|
542
|
-
inputName,
|
|
543
|
-
renderNestedOptions,
|
|
544
|
-
isTreeRowExpanded,
|
|
545
|
-
handleToggleClick,
|
|
546
|
-
handleRadioButtonClick,
|
|
547
|
-
handledropdownItemClick,
|
|
548
|
-
filterItem,
|
|
549
|
-
}}
|
|
480
|
+
<div className="input_wrapper"
|
|
481
|
+
onClick={handleInputWrapperClick}
|
|
550
482
|
>
|
|
551
|
-
<div className="
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
483
|
+
<div className="input_inner_container">
|
|
484
|
+
{variant === "single" && defaultReturn.length !== 0
|
|
485
|
+
? defaultReturn.map((selectedItem) => (
|
|
486
|
+
<input
|
|
487
|
+
disabled={disabled}
|
|
488
|
+
key={selectedItem.id}
|
|
489
|
+
name={`${name}[]`}
|
|
490
|
+
required={required}
|
|
491
|
+
type="hidden"
|
|
492
|
+
value={selectedItem.id}
|
|
493
|
+
/>
|
|
494
|
+
))
|
|
495
|
+
: null}
|
|
496
|
+
|
|
497
|
+
{variant !== "single" && (
|
|
498
|
+
<>
|
|
499
|
+
{returnAllSelected && returnedArray.length !== 0
|
|
500
|
+
? returnedArray.map((item) => (
|
|
560
501
|
<input
|
|
561
502
|
disabled={disabled}
|
|
562
|
-
key={
|
|
503
|
+
key={item.id}
|
|
563
504
|
name={`${name}[]`}
|
|
564
505
|
required={required}
|
|
565
506
|
type="hidden"
|
|
566
|
-
value={
|
|
507
|
+
value={item.id}
|
|
567
508
|
/>
|
|
568
509
|
))
|
|
569
510
|
: null}
|
|
570
511
|
|
|
571
|
-
{
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
))
|
|
584
|
-
: null}
|
|
585
|
-
|
|
586
|
-
{!returnAllSelected
|
|
587
|
-
? defaultReturn.map((item) => (
|
|
588
|
-
<input
|
|
589
|
-
disabled={disabled}
|
|
590
|
-
key={item.id}
|
|
591
|
-
name={`${name}[]`}
|
|
592
|
-
required={required}
|
|
593
|
-
type="hidden"
|
|
594
|
-
value={item.id}
|
|
595
|
-
/>
|
|
596
|
-
))
|
|
597
|
-
: null}
|
|
598
|
-
|
|
599
|
-
{returnAllSelected &&
|
|
600
|
-
returnedArray.length !== 0 &&
|
|
601
|
-
inputDisplay === "pills"
|
|
602
|
-
? returnedArray.map((item, index) => (
|
|
603
|
-
<FormPill
|
|
604
|
-
color={pillColor}
|
|
605
|
-
key={index}
|
|
606
|
-
onClick={(event: any) =>
|
|
607
|
-
handlePillClose(event, item)
|
|
608
|
-
}
|
|
609
|
-
text={item.label}
|
|
610
|
-
wrapped={wrapped}
|
|
611
|
-
/>
|
|
612
|
-
))
|
|
613
|
-
: null}
|
|
614
|
-
|
|
615
|
-
{!returnAllSelected &&
|
|
616
|
-
defaultReturn.length !== 0 &&
|
|
617
|
-
inputDisplay === "pills"
|
|
618
|
-
? defaultReturn.map((item, index) => (
|
|
619
|
-
<FormPill
|
|
620
|
-
color={pillColor}
|
|
621
|
-
key={index}
|
|
622
|
-
onClick={(event: any) =>
|
|
623
|
-
handlePillClose(event, item)
|
|
624
|
-
}
|
|
625
|
-
text={item.label}
|
|
626
|
-
wrapped={wrapped}
|
|
627
|
-
/>
|
|
628
|
-
))
|
|
629
|
-
: null}
|
|
630
|
-
|
|
631
|
-
{returnAllSelected &&
|
|
632
|
-
returnedArray.length !== 0 &&
|
|
633
|
-
inputDisplay === "pills" && <br />}
|
|
634
|
-
|
|
635
|
-
{!returnAllSelected &&
|
|
636
|
-
defaultReturn.length !== 0 &&
|
|
637
|
-
inputDisplay === "pills" && <br />}
|
|
638
|
-
</>
|
|
639
|
-
)}
|
|
640
|
-
|
|
641
|
-
<input
|
|
642
|
-
aria-describedby={errorId}
|
|
643
|
-
aria-invalid={!!error}
|
|
644
|
-
disabled={disabled}
|
|
645
|
-
id={labelForId}
|
|
646
|
-
onChange={(e) => {
|
|
647
|
-
variant === "single"
|
|
648
|
-
? handleRadioInputChange(e.target.value)
|
|
649
|
-
: setFilterItem(e.target.value);
|
|
650
|
-
}}
|
|
651
|
-
onClick={() => setIsDropdownClosed(false)}
|
|
652
|
-
onFocus={() => !disabled && setIsDropdownClosed(false)}
|
|
653
|
-
placeholder={
|
|
654
|
-
inputDisplay === "none" && itemsSelectedLength()
|
|
655
|
-
? `${itemsSelectedLength()} ${
|
|
656
|
-
itemsSelectedLength() === 1 ? "item" : "items"
|
|
657
|
-
} selected`
|
|
658
|
-
: "Start typing..."
|
|
659
|
-
}
|
|
660
|
-
required={required}
|
|
661
|
-
value={singleSelectedItem.value || filterItem}
|
|
662
|
-
/>
|
|
663
|
-
</div>
|
|
664
|
-
|
|
665
|
-
{isDropdownClosed ? (
|
|
666
|
-
<div id={arrowDownElementId}
|
|
667
|
-
key="chevron-down"
|
|
668
|
-
>
|
|
669
|
-
<Icon icon="chevron-down"
|
|
670
|
-
id={arrowDownElementId}
|
|
671
|
-
size="xs"
|
|
672
|
-
/>
|
|
673
|
-
</div>
|
|
674
|
-
) : (
|
|
675
|
-
<div id={arrowUpElementId}
|
|
676
|
-
key="chevron-up"
|
|
677
|
-
>
|
|
678
|
-
<Icon icon="chevron-up"
|
|
679
|
-
id={arrowUpElementId}
|
|
680
|
-
size="xs"
|
|
681
|
-
/>
|
|
682
|
-
</div>
|
|
683
|
-
)}
|
|
684
|
-
</div>
|
|
512
|
+
{!returnAllSelected
|
|
513
|
+
? defaultReturn.map((item) => (
|
|
514
|
+
<input
|
|
515
|
+
disabled={disabled}
|
|
516
|
+
key={item.id}
|
|
517
|
+
name={`${name}[]`}
|
|
518
|
+
required={required}
|
|
519
|
+
type="hidden"
|
|
520
|
+
value={item.id}
|
|
521
|
+
/>
|
|
522
|
+
))
|
|
523
|
+
: null}
|
|
685
524
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
525
|
+
{returnAllSelected &&
|
|
526
|
+
returnedArray.length !== 0 &&
|
|
527
|
+
inputDisplay === "pills"
|
|
528
|
+
? returnedArray.map((item, index) => (
|
|
529
|
+
<FormPill
|
|
530
|
+
color={pillColor}
|
|
531
|
+
key={index}
|
|
532
|
+
onClick={(event: any) => handlePillClose(event, item)}
|
|
533
|
+
text={item.label}
|
|
534
|
+
wrapped={wrapped}
|
|
535
|
+
/>
|
|
536
|
+
))
|
|
537
|
+
: null}
|
|
538
|
+
|
|
539
|
+
{!returnAllSelected &&
|
|
540
|
+
defaultReturn.length !== 0 &&
|
|
541
|
+
inputDisplay === "pills"
|
|
542
|
+
? defaultReturn.map((item, index) => (
|
|
543
|
+
<FormPill
|
|
544
|
+
color={pillColor}
|
|
545
|
+
key={index}
|
|
546
|
+
onClick={(event: any) => handlePillClose(event, item)}
|
|
547
|
+
text={item.label}
|
|
548
|
+
wrapped={wrapped}
|
|
549
|
+
/>
|
|
550
|
+
))
|
|
551
|
+
: null}
|
|
552
|
+
|
|
553
|
+
{returnAllSelected &&
|
|
554
|
+
returnedArray.length !== 0 &&
|
|
555
|
+
inputDisplay === "pills" && <br />}
|
|
556
|
+
|
|
557
|
+
{!returnAllSelected &&
|
|
558
|
+
defaultReturn.length !== 0 &&
|
|
559
|
+
inputDisplay === "pills" && <br />}
|
|
560
|
+
</>
|
|
561
|
+
)}
|
|
562
|
+
|
|
563
|
+
<input
|
|
564
|
+
disabled={disabled}
|
|
565
|
+
id="multiselect_input"
|
|
566
|
+
onChange={(e) => {
|
|
567
|
+
variant === "single"
|
|
568
|
+
? handleRadioInputChange(e.target.value)
|
|
569
|
+
: setFilterItem(e.target.value);
|
|
570
|
+
}}
|
|
571
|
+
onClick={() => setIsDropdownClosed(false)}
|
|
572
|
+
placeholder={
|
|
573
|
+
inputDisplay === "none" && itemsSelectedLength()
|
|
574
|
+
? `${itemsSelectedLength()} ${
|
|
575
|
+
itemsSelectedLength() === 1 ? "item" : "items"
|
|
576
|
+
} selected`
|
|
577
|
+
: "Start typing..."
|
|
578
|
+
}
|
|
579
|
+
required={required}
|
|
580
|
+
value={singleSelectedItem.value || filterItem}
|
|
581
|
+
/>
|
|
695
582
|
</div>
|
|
696
|
-
|
|
697
|
-
|
|
583
|
+
|
|
584
|
+
{isDropdownClosed ? (
|
|
585
|
+
<div id={arrowDownElementId}
|
|
586
|
+
key="chevron-down">
|
|
587
|
+
<Icon
|
|
588
|
+
icon="chevron-down"
|
|
589
|
+
id={arrowDownElementId}
|
|
590
|
+
size="xs"
|
|
591
|
+
/>
|
|
592
|
+
</div>
|
|
593
|
+
) : (
|
|
594
|
+
<div id={arrowUpElementId}
|
|
595
|
+
key="chevron-up">
|
|
596
|
+
<Icon
|
|
597
|
+
icon="chevron-up"
|
|
598
|
+
id={arrowUpElementId}
|
|
599
|
+
size="xs"
|
|
600
|
+
/>
|
|
601
|
+
</div>
|
|
602
|
+
)}
|
|
603
|
+
</div>
|
|
604
|
+
|
|
605
|
+
<div className={`dropdown_menu ${isDropdownClosed ? "close" : "open"}`}>
|
|
606
|
+
{renderNestedOptions(
|
|
607
|
+
filterItem ? findByFilter(formattedData, filterItem) : formattedData
|
|
608
|
+
)}
|
|
609
|
+
</div>
|
|
610
|
+
</div>
|
|
611
|
+
</MultiLevelSelectContext.Provider>
|
|
612
|
+
{error &&
|
|
698
613
|
<Body
|
|
699
|
-
aria={{ atomic: "true", live: "polite" }}
|
|
700
614
|
dark={props.dark}
|
|
701
|
-
htmlOptions={{ role: "alert" }}
|
|
702
|
-
id={errorId}
|
|
703
615
|
status="negative"
|
|
704
616
|
text={error}
|
|
705
617
|
/>
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
) as MultiLevelSelectComponent;
|
|
618
|
+
}
|
|
619
|
+
</div>
|
|
620
|
+
);
|
|
621
|
+
}) as MultiLevelSelectComponent;
|
|
711
622
|
|
|
712
623
|
MultiLevelSelect.displayName = "MultiLevelSelect";
|
|
713
624
|
MultiLevelSelect.Options = MultiLevelSelectOptions;
|