playbook_ui 14.20.0.pre.rc.2 → 14.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +61 -35
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +36 -22
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +6 -19
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.jsx +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.md +3 -1
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +1 -1
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +77 -19
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.html.erb +31 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.md +5 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.jsx +56 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.jsx +58 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.html.erb +20 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.html.erb +19 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.html.erb +20 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.jsx +57 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.html.erb +50 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.jsx +105 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.html.erb +22 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.jsx +67 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +11 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +5 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +3 -3
- data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +16 -2
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +34 -13
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +3 -1
- data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +0 -6
- data/app/pb_kits/playbook/pb_dropdown/index.js +334 -41
- data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +39 -12
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +16 -12
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +78 -12
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +58 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +1 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +1 -0
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +73 -3
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.jsx +23 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.md +1 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
- data/dist/chunks/_typeahead-MUu4QW0I.js +22 -0
- data/dist/chunks/_weekday_stacked-CZJor-EY.js +45 -0
- data/dist/chunks/lazysizes-DHz07jlL.js +1 -0
- data/dist/chunks/lib-DFF1N868.js +29 -0
- data/dist/chunks/{pb_form_validation-WWvUXPKD.js → pb_form_validation-D1Bwm-op.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-doc.js +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/kit_base.rb +3 -3
- data/lib/playbook/version.rb +1 -1
- metadata +27 -8
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.html.erb +0 -10
- data/dist/chunks/_typeahead-B9-s4j4U.js +0 -22
- data/dist/chunks/_weekday_stacked-CvzpmXD5.js +0 -45
- data/dist/chunks/lazysizes-B7xYodB-.js +0 -1
- data/dist/chunks/lib-B20MXZcW.js +0 -29
@@ -13,6 +13,7 @@ const DROPDOWN_PLACEHOLDER = "[data-dropdown-placeholder]";
|
|
13
13
|
const DROPDOWN_INPUT = "#dropdown-selected-option";
|
14
14
|
const SEARCH_INPUT_SELECTOR = "[data-dropdown-autocomplete]";
|
15
15
|
const SEARCH_BAR_SELECTOR = "[data-dropdown-search]";
|
16
|
+
const CLEAR_ICON_SELECTOR = "#dropdown_clear_icon";
|
16
17
|
|
17
18
|
export default class PbDropdown extends PbEnhancedElement {
|
18
19
|
static get selector() {
|
@@ -20,11 +21,18 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
20
21
|
}
|
21
22
|
|
22
23
|
get target() {
|
23
|
-
return this.element.
|
24
|
+
return this.element.querySelector(CONTAINER_SELECTOR);
|
24
25
|
}
|
25
26
|
|
27
|
+
selectedOptions = new Set();
|
28
|
+
clearBtn = null;
|
29
|
+
|
26
30
|
connect() {
|
27
31
|
this.keyboardHandler = new PbDropdownKeyboard(this);
|
32
|
+
this.isMultiSelect = this.element.dataset.pbDropdownMultiSelect === "true";
|
33
|
+
this.formPillProps = this.element.dataset.formPillProps
|
34
|
+
? JSON.parse(this.element.dataset.formPillProps)
|
35
|
+
: {};
|
28
36
|
this.setDefaultValue();
|
29
37
|
this.bindEventListeners();
|
30
38
|
this.bindSearchInput();
|
@@ -32,6 +40,26 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
32
40
|
this.handleFormValidation();
|
33
41
|
this.handleFormReset();
|
34
42
|
this.bindSearchBar();
|
43
|
+
this.updatePills();
|
44
|
+
|
45
|
+
this.clearBtn = this.element.querySelector(CLEAR_ICON_SELECTOR);
|
46
|
+
if (this.clearBtn) {
|
47
|
+
this.clearBtn.style.display = "none";
|
48
|
+
this.clearBtn.addEventListener("click", (e) => {
|
49
|
+
e.stopPropagation();
|
50
|
+
this.clearSelection();
|
51
|
+
});
|
52
|
+
}
|
53
|
+
this.updateClearButton();
|
54
|
+
}
|
55
|
+
|
56
|
+
updateClearButton() {
|
57
|
+
if (!this.clearBtn) return;
|
58
|
+
const hasSelection = this.isMultiSelect
|
59
|
+
? this.selectedOptions.size > 0
|
60
|
+
: Boolean(this.element.querySelector(DROPDOWN_INPUT).value);
|
61
|
+
|
62
|
+
this.clearBtn.style.display = hasSelection ? "" : "none";
|
35
63
|
}
|
36
64
|
|
37
65
|
bindEventListeners() {
|
@@ -52,7 +80,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
52
80
|
bindSearchBar() {
|
53
81
|
this.searchBar = this.element.querySelector(SEARCH_BAR_SELECTOR);
|
54
82
|
if (!this.searchBar) return;
|
55
|
-
|
83
|
+
|
56
84
|
this.searchBar.addEventListener("input", (e) =>
|
57
85
|
this.handleSearch(e.target.value)
|
58
86
|
);
|
@@ -73,11 +101,28 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
73
101
|
);
|
74
102
|
}
|
75
103
|
|
104
|
+
adjustDropdownHeight() {
|
105
|
+
if (this.target.classList.contains("open")) {
|
106
|
+
const el = this.target;
|
107
|
+
el.style.height = "auto";
|
108
|
+
requestAnimationFrame(() => {
|
109
|
+
const newHeight = el.scrollHeight + "px";
|
110
|
+
el.offsetHeight; // force reflow
|
111
|
+
el.style.height = newHeight;
|
112
|
+
});
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
76
116
|
handleSearch(term = "") {
|
77
117
|
const lcTerm = term.toLowerCase();
|
78
118
|
this.element.querySelectorAll(OPTION_SELECTOR).forEach((opt) => {
|
79
|
-
|
80
|
-
|
119
|
+
//make it so that if the option is selected, it will not show up in the search results
|
120
|
+
if (this.isMultiSelect && this.selectedOptions.has(opt.dataset.dropdownOptionLabel)) {
|
121
|
+
opt.style.display = "none";
|
122
|
+
return;
|
123
|
+
}
|
124
|
+
const label = JSON.parse(opt.dataset.dropdownOptionLabel)
|
125
|
+
.label.toString()
|
81
126
|
.toLowerCase();
|
82
127
|
|
83
128
|
// hide or show option
|
@@ -85,15 +130,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
85
130
|
opt.style.display = match ? "" : "none";
|
86
131
|
});
|
87
132
|
|
88
|
-
|
89
|
-
const el = this.target;
|
90
|
-
el.style.height = "auto";
|
91
|
-
requestAnimationFrame(() => {
|
92
|
-
const newHeight = el.scrollHeight + "px";
|
93
|
-
el.offsetHeight; // force reflow
|
94
|
-
el.style.height = newHeight;
|
95
|
-
});
|
96
|
-
}
|
133
|
+
this.adjustDropdownHeight();
|
97
134
|
}
|
98
135
|
|
99
136
|
handleOptionClick(event) {
|
@@ -102,10 +139,26 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
102
139
|
|
103
140
|
if (option) {
|
104
141
|
const value = option.dataset.dropdownOptionLabel;
|
105
|
-
|
106
|
-
|
142
|
+
if (this.isMultiSelect) {
|
143
|
+
const alreadySelected = this.selectedOptions.has(value);
|
144
|
+
if (alreadySelected) {
|
145
|
+
this.selectedOptions.delete(value);
|
146
|
+
} else {
|
147
|
+
this.selectedOptions.add(value);
|
148
|
+
}
|
149
|
+
this.updatePills();
|
150
|
+
this.syncHiddenInputs();
|
151
|
+
if (this.searchInput && this.isMultiSelect) {
|
152
|
+
this.searchInput.value = "";
|
153
|
+
this.handleBackspaceClear();
|
154
|
+
}
|
155
|
+
} else {
|
156
|
+
hiddenInput.value = JSON.parse(value).id;
|
157
|
+
}
|
107
158
|
|
159
|
+
this.clearFormValidation(hiddenInput);
|
108
160
|
this.onOptionSelected(value, option);
|
161
|
+
this.updateClearButton();
|
109
162
|
}
|
110
163
|
}
|
111
164
|
|
@@ -137,6 +190,31 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
137
190
|
}
|
138
191
|
}
|
139
192
|
|
193
|
+
emitSelectionChange() {
|
194
|
+
let detail;
|
195
|
+
|
196
|
+
if (this.isMultiSelect) {
|
197
|
+
detail = Array.from(this.selectedOptions).map(JSON.parse);
|
198
|
+
} else {
|
199
|
+
const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
|
200
|
+
detail = hiddenInput.value
|
201
|
+
? JSON.parse(
|
202
|
+
this.element.querySelector(
|
203
|
+
OPTION_SELECTOR +
|
204
|
+
`[data-dropdown-option-label*='"id":"${hiddenInput.value}"']`
|
205
|
+
).dataset.dropdownOptionLabel
|
206
|
+
)
|
207
|
+
: null;
|
208
|
+
}
|
209
|
+
this.element.setAttribute("data-option-selected", JSON.stringify(detail));
|
210
|
+
this.element.dispatchEvent(
|
211
|
+
new CustomEvent("pb:dropdown:selected", {
|
212
|
+
detail,
|
213
|
+
bubbles: true,
|
214
|
+
})
|
215
|
+
);
|
216
|
+
}
|
217
|
+
|
140
218
|
onOptionSelected(value, selectedOption) {
|
141
219
|
const triggerElement = this.element.querySelector(DROPDOWN_TRIGGER_DISPLAY);
|
142
220
|
const customDisplayElement = this.element.querySelector(
|
@@ -144,29 +222,22 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
144
222
|
);
|
145
223
|
|
146
224
|
if (triggerElement) {
|
147
|
-
|
148
|
-
|
149
|
-
triggerElement.textContent =
|
150
|
-
this.
|
151
|
-
const selectedObj = JSON.parse(value);
|
152
|
-
this.element.dispatchEvent(
|
153
|
-
new CustomEvent("pb:dropdown:selected", {
|
154
|
-
detail: selectedObj,
|
155
|
-
bubbles: true,
|
156
|
-
})
|
157
|
-
);
|
158
|
-
} else {
|
159
|
-
triggerElement.textContent = selectedLabel
|
225
|
+
if (!this.isMultiSelect) {
|
226
|
+
const selectedLabel = JSON.parse(value).label;
|
227
|
+
triggerElement.textContent = selectedLabel;
|
228
|
+
this.emitSelectionChange();
|
160
229
|
}
|
161
230
|
if (customDisplayElement) {
|
231
|
+
triggerElement.textContent = "";
|
162
232
|
customDisplayElement.style.display = "block";
|
163
233
|
customDisplayElement.style.paddingRight = "8px";
|
164
234
|
}
|
165
235
|
}
|
166
236
|
|
167
237
|
const autocompleteInput = this.element.querySelector(SEARCH_INPUT_SELECTOR);
|
168
|
-
if (autocompleteInput){
|
238
|
+
if (autocompleteInput && !this.isMultiSelect) {
|
169
239
|
autocompleteInput.value = JSON.parse(value).label;
|
240
|
+
this.emitSelectionChange();
|
170
241
|
}
|
171
242
|
|
172
243
|
const customTrigger = this.element.querySelector(CUSTOM_DISPLAY_SELECTOR);
|
@@ -178,10 +249,24 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
178
249
|
}
|
179
250
|
|
180
251
|
const options = this.element.querySelectorAll(OPTION_SELECTOR);
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
252
|
+
if (this.isMultiSelect) {
|
253
|
+
this.emitSelectionChange();
|
254
|
+
Array.from(this.selectedOptions).map((option) => {
|
255
|
+
if (
|
256
|
+
JSON.parse(option).id ===
|
257
|
+
JSON.parse(selectedOption.dataset.dropdownOptionLabel).id
|
258
|
+
) {
|
259
|
+
selectedOption.style.display = "none";
|
260
|
+
this.adjustDropdownHeight();
|
261
|
+
}
|
262
|
+
});
|
263
|
+
} else {
|
264
|
+
options.forEach((option) => {
|
265
|
+
option.classList.remove("pb_dropdown_option_selected");
|
266
|
+
});
|
267
|
+
selectedOption.classList.add("pb_dropdown_option_selected");
|
268
|
+
}
|
269
|
+
this.updateClearButton();
|
185
270
|
}
|
186
271
|
|
187
272
|
showElement(elem) {
|
@@ -255,21 +340,66 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
255
340
|
errorLabelElement.remove();
|
256
341
|
}
|
257
342
|
}
|
343
|
+
if (this.isMultiSelect) {
|
344
|
+
if (this.selectedOptions.size > 0) {
|
345
|
+
const dropdownWrapperElement = input.closest(".dropdown_wrapper");
|
346
|
+
dropdownWrapperElement.classList.remove("error");
|
347
|
+
const errorLabelElement = dropdownWrapperElement.querySelector(
|
348
|
+
".pb_body_kit_negative"
|
349
|
+
);
|
350
|
+
if (errorLabelElement) {
|
351
|
+
errorLabelElement.remove();
|
352
|
+
}
|
353
|
+
}
|
354
|
+
}
|
258
355
|
}
|
259
356
|
|
260
357
|
setDefaultValue() {
|
261
358
|
const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
|
262
|
-
const
|
263
|
-
|
359
|
+
const optionEls = Array.from(
|
360
|
+
this.element.querySelectorAll(OPTION_SELECTOR)
|
361
|
+
);
|
264
362
|
const defaultValue = hiddenInput.dataset.defaultValue || "";
|
265
|
-
|
363
|
+
if (!defaultValue) return;
|
364
|
+
|
365
|
+
if (this.isMultiSelect) {
|
366
|
+
const ids = defaultValue.split(",");
|
367
|
+
ids.forEach((id) => {
|
368
|
+
const selectedOption = optionEls.find((opt) => {
|
369
|
+
try {
|
370
|
+
return JSON.parse(opt.dataset.dropdownOptionLabel).id === id;
|
371
|
+
} catch {
|
372
|
+
return false;
|
373
|
+
}
|
374
|
+
});
|
375
|
+
if (!selectedOption) {
|
376
|
+
console.warn(`Dropdown default ID ${id} not found`);
|
377
|
+
return;
|
378
|
+
}
|
266
379
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
380
|
+
const raw = selectedOption.dataset.dropdownOptionLabel;
|
381
|
+
this.selectedOptions.add(raw);
|
382
|
+
|
383
|
+
selectedOption.style.display = "none";
|
384
|
+
});
|
385
|
+
|
386
|
+
this.updatePills();
|
387
|
+
this.updateClearButton();
|
388
|
+
this.adjustDropdownHeight();
|
389
|
+
this.syncHiddenInputs();
|
390
|
+
} else {
|
391
|
+
hiddenInput.value = defaultValue;
|
392
|
+
const selectedOption = optionEls.find((opt) => {
|
393
|
+
try {
|
394
|
+
return (
|
395
|
+
JSON.parse(opt.dataset.dropdownOptionLabel).id === defaultValue
|
396
|
+
);
|
397
|
+
} catch {
|
398
|
+
return false;
|
399
|
+
}
|
272
400
|
});
|
401
|
+
if (!selectedOption) return;
|
402
|
+
|
273
403
|
selectedOption.classList.add("pb_dropdown_option_selected");
|
274
404
|
this.setTriggerElementText(
|
275
405
|
JSON.parse(selectedOption.dataset.dropdownOptionLabel).label
|
@@ -292,12 +422,32 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
292
422
|
const options = this.element.querySelectorAll(OPTION_SELECTOR);
|
293
423
|
options.forEach((option) => {
|
294
424
|
option.classList.remove("pb_dropdown_option_selected");
|
425
|
+
option.style.display = "";
|
295
426
|
});
|
296
427
|
|
297
428
|
hiddenInput.value = "";
|
298
429
|
|
299
430
|
const defaultPlaceholder = this.element.querySelector(DROPDOWN_PLACEHOLDER);
|
300
431
|
this.setTriggerElementText(defaultPlaceholder.dataset.dropdownPlaceholder);
|
432
|
+
|
433
|
+
if (this.searchInput) {
|
434
|
+
this.searchInput.value = "";
|
435
|
+
if (this.target.classList.contains("open")) {
|
436
|
+
const el = this.target;
|
437
|
+
el.style.height = "auto";
|
438
|
+
requestAnimationFrame(() => {
|
439
|
+
const newHeight = el.scrollHeight + "px";
|
440
|
+
el.offsetHeight; // force reflow
|
441
|
+
el.style.height = newHeight;
|
442
|
+
});
|
443
|
+
}
|
444
|
+
}
|
445
|
+
if (this.isMultiSelect) {
|
446
|
+
this.selectedOptions.clear();
|
447
|
+
this.updatePills();
|
448
|
+
this.updateClearButton();
|
449
|
+
this.syncHiddenInputs();
|
450
|
+
}
|
301
451
|
}
|
302
452
|
|
303
453
|
setTriggerElementText(text) {
|
@@ -306,4 +456,147 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
306
456
|
triggerElement.textContent = text;
|
307
457
|
}
|
308
458
|
}
|
459
|
+
|
460
|
+
updatePills() {
|
461
|
+
if (!this.isMultiSelect) return;
|
462
|
+
|
463
|
+
const wrapper = this.element.querySelector("#dropdown_pills_wrapper");
|
464
|
+
const placeholder = this.element.querySelector(
|
465
|
+
"#dropdown_trigger_display_multi_select"
|
466
|
+
);
|
467
|
+
if (!wrapper) return;
|
468
|
+
|
469
|
+
wrapper.innerHTML = "";
|
470
|
+
// Show or hide the placeholder based on selected options
|
471
|
+
if (placeholder) {
|
472
|
+
if (this.selectedOptions.size > 0) {
|
473
|
+
placeholder.style.display = "none";
|
474
|
+
} else {
|
475
|
+
placeholder.style.display = "";
|
476
|
+
}
|
477
|
+
}
|
478
|
+
|
479
|
+
Array.from(this.selectedOptions).map((option) => {
|
480
|
+
// Create a form pill for each selected option
|
481
|
+
const pill = document.createElement("div");
|
482
|
+
const color = this.formPillProps.color || "primary";
|
483
|
+
pill.classList.add(`pb_form_pill_kit_${color}`, "mr_xs");
|
484
|
+
if (this.formPillProps.size === "small") {
|
485
|
+
pill.classList.add("small");
|
486
|
+
}
|
487
|
+
pill.tabIndex = 0;
|
488
|
+
pill.dataset.pillId = JSON.parse(option).id;
|
489
|
+
const innerDiv = document.createElement("h3");
|
490
|
+
innerDiv.className = "pb_title_kit_size_4 pb_form_pill_text";
|
491
|
+
innerDiv.textContent = JSON.parse(option).label;
|
492
|
+
pill.appendChild(innerDiv);
|
493
|
+
|
494
|
+
const closeIcon = document.createElement("div");
|
495
|
+
closeIcon.className = "pb_form_pill_close";
|
496
|
+
closeIcon.innerHTML = `<svg class="pb_custom_icon svg-inline--fa svg_${
|
497
|
+
this.formPillProps.size === "small" ? "xs" : "sm"
|
498
|
+
} svg_fw" xmlns="http://www.w3.org/2000/svg" width="auto" height="auto" viewBox="0 0 31 25"><path fill="currentColor" d="M23.0762 6.77734L17.4512 12.4023L23.0293 17.9805C23.498 18.4023 23.498 19.1055 23.0293 19.5273C22.6074 19.9961 21.9043 19.9961 21.4824 19.5273L15.8574 13.9492L10.2793 19.5273C9.85742 19.9961 9.1543 19.9961 8.73242 19.5273C8.26367 19.1055 8.26367 18.4023 8.73242 17.9336L14.3105 12.3555L8.73242 6.77734C8.26367 6.35547 8.26367 5.65234 8.73242 5.18359C9.1543 4.76172 9.85742 4.76172 10.3262 5.18359L15.9043 10.8086L21.4824 5.23047C21.9043 4.76172 22.6074 4.76172 23.0762 5.23047C23.498 5.65234 23.498 6.35547 23.0762 6.77734Z"/></svg>`;
|
499
|
+
pill.appendChild(closeIcon);
|
500
|
+
|
501
|
+
closeIcon.addEventListener("click", (e) => {
|
502
|
+
e.stopPropagation();
|
503
|
+
const id = pill.dataset.pillId;
|
504
|
+
this.selectedOptions.delete(option);
|
505
|
+
|
506
|
+
const optEl = this.element.querySelector(
|
507
|
+
`${OPTION_SELECTOR}[data-dropdown-option-label*='"id":${JSON.stringify(
|
508
|
+
id
|
509
|
+
)}']`
|
510
|
+
);
|
511
|
+
if (optEl) {
|
512
|
+
optEl.style.display = "";
|
513
|
+
if (this.target.classList.contains("open")) {
|
514
|
+
this.showElement(this.target);
|
515
|
+
}
|
516
|
+
}
|
517
|
+
|
518
|
+
this.updatePills();
|
519
|
+
this.updateClearButton();
|
520
|
+
this.emitSelectionChange();
|
521
|
+
this.syncHiddenInputs();
|
522
|
+
});
|
523
|
+
wrapper.appendChild(pill);
|
524
|
+
});
|
525
|
+
}
|
526
|
+
|
527
|
+
clearSelection() {
|
528
|
+
if (this.isMultiSelect) {
|
529
|
+
this.selectedOptions.clear();
|
530
|
+
this.element.querySelectorAll(OPTION_SELECTOR).forEach((opt) => {
|
531
|
+
opt.style.display = "";
|
532
|
+
});
|
533
|
+
if (this.target.classList.contains("open")) {
|
534
|
+
this.showElement(this.target);
|
535
|
+
}
|
536
|
+
}
|
537
|
+
const customDisplay = this.element.querySelector(
|
538
|
+
"#dropdown_trigger_custom_display"
|
539
|
+
);
|
540
|
+
if (customDisplay) {
|
541
|
+
customDisplay.style.display = "none";
|
542
|
+
}
|
543
|
+
this.resetDropdownValue();
|
544
|
+
this.updatePills();
|
545
|
+
this.updateClearButton();
|
546
|
+
this.syncHiddenInputs();
|
547
|
+
this.emitSelectionChange();
|
548
|
+
}
|
549
|
+
|
550
|
+
syncHiddenInputs() {
|
551
|
+
if (!this.isMultiSelect) return;
|
552
|
+
this.element
|
553
|
+
.querySelectorAll('input[data-generated="true"]')
|
554
|
+
.forEach((n) => n.remove());
|
555
|
+
|
556
|
+
const baseInput = this.element.querySelector(DROPDOWN_INPUT);
|
557
|
+
if (!baseInput) return;
|
558
|
+
// for multi_select, for each selectedOption, create a hidden input
|
559
|
+
const name = baseInput.getAttribute("name");
|
560
|
+
this.selectedOptions.forEach((raw) => {
|
561
|
+
const id = JSON.parse(raw).id;
|
562
|
+
const inp = document.createElement("input");
|
563
|
+
inp.type = "hidden";
|
564
|
+
inp.name = name;
|
565
|
+
inp.value = id;
|
566
|
+
inp.dataset.generated = "true";
|
567
|
+
baseInput.insertAdjacentElement("afterend", inp);
|
568
|
+
});
|
569
|
+
baseInput.value = "";
|
570
|
+
}
|
571
|
+
|
572
|
+
handleBackspaceClear() {
|
573
|
+
if (!this.isMultiSelect) {
|
574
|
+
this.element.querySelectorAll(OPTION_SELECTOR).forEach((opt) => {
|
575
|
+
opt.classList.remove("pb_dropdown_option_selected");
|
576
|
+
opt.style.display = "";
|
577
|
+
this.adjustDropdownHeight();
|
578
|
+
});
|
579
|
+
|
580
|
+
const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
|
581
|
+
if (hiddenInput) hiddenInput.value = "";
|
582
|
+
|
583
|
+
const placeholder = this.element.querySelector(DROPDOWN_PLACEHOLDER);
|
584
|
+
if (placeholder)
|
585
|
+
this.setTriggerElementText(placeholder.dataset.dropdownPlaceholder);
|
586
|
+
}
|
587
|
+
if (this.isMultiSelect) {
|
588
|
+
this.element.querySelectorAll(OPTION_SELECTOR).forEach((opt) => {
|
589
|
+
const optValue = opt.dataset.dropdownOptionLabel;
|
590
|
+
if (
|
591
|
+
this.selectedOptions.size > 0 &&
|
592
|
+
this.selectedOptions.has(optValue)
|
593
|
+
) {
|
594
|
+
opt.style.display = "none";
|
595
|
+
} else {
|
596
|
+
opt.style.display = "";
|
597
|
+
}
|
598
|
+
this.adjustDropdownHeight();
|
599
|
+
});
|
600
|
+
}
|
601
|
+
}
|
309
602
|
}
|
@@ -27,6 +27,13 @@ export class PbDropdownKeyboard {
|
|
27
27
|
}
|
28
28
|
}
|
29
29
|
|
30
|
+
getVisibleOptions() {
|
31
|
+
// We only want to return the options that are visible
|
32
|
+
return Array.from(
|
33
|
+
this.dropdownElement.querySelectorAll(OPTION_SELECTOR)
|
34
|
+
).filter((opt) => opt.style.display !== "none");
|
35
|
+
}
|
36
|
+
|
30
37
|
openDropdownIfClosed() {
|
31
38
|
if (!this.dropdown.target.classList.contains("open")) {
|
32
39
|
this.dropdown.showElement(this.dropdown.target);
|
@@ -71,7 +78,7 @@ export class PbDropdownKeyboard {
|
|
71
78
|
if (this.searchInput) {
|
72
79
|
setTimeout(() => {
|
73
80
|
if (this.searchInput.value.trim() === "") {
|
74
|
-
this.dropdown.
|
81
|
+
this.dropdown.handleBackspaceClear();
|
75
82
|
}
|
76
83
|
}, 0);
|
77
84
|
}
|
@@ -81,23 +88,43 @@ export class PbDropdownKeyboard {
|
|
81
88
|
}
|
82
89
|
}
|
83
90
|
|
84
|
-
|
91
|
+
moveFocus(direction) {
|
92
|
+
const allOptions = Array.from(
|
93
|
+
this.dropdownElement.querySelectorAll(OPTION_SELECTOR)
|
94
|
+
);
|
95
|
+
const visible = this.getVisibleOptions();
|
96
|
+
if (!visible.length) return;
|
97
|
+
|
85
98
|
if (this.focusedOptionIndex !== -1) {
|
86
|
-
|
99
|
+
allOptions[this.focusedOptionIndex].classList.remove(
|
87
100
|
"pb_dropdown_option_focused"
|
88
101
|
);
|
89
102
|
}
|
90
|
-
|
91
|
-
|
92
|
-
this.
|
93
|
-
|
94
|
-
|
95
|
-
|
103
|
+
|
104
|
+
const prevVisibleIndex =
|
105
|
+
this.focusedOptionIndex === -1
|
106
|
+
? -1
|
107
|
+
: visible.indexOf(allOptions[this.focusedOptionIndex]);
|
108
|
+
|
109
|
+
const nextVisibleIndex =
|
110
|
+
(prevVisibleIndex + direction + visible.length) % visible.length;
|
111
|
+
|
112
|
+
const nextEl = visible[nextVisibleIndex];
|
113
|
+
nextEl.classList.add("pb_dropdown_option_focused");
|
114
|
+
|
115
|
+
this.focusedOptionIndex = allOptions.indexOf(nextEl);
|
96
116
|
}
|
97
117
|
|
118
|
+
|
98
119
|
selectOption() {
|
99
|
-
const
|
100
|
-
|
101
|
-
|
120
|
+
const allOptions = Array.from(
|
121
|
+
this.dropdownElement.querySelectorAll(OPTION_SELECTOR)
|
122
|
+
);
|
123
|
+
if (this.focusedOptionIndex < 0) return;
|
124
|
+
|
125
|
+
const optionEl = allOptions[this.focusedOptionIndex];
|
126
|
+
this.dropdown.handleOptionClick({ target: optionEl });
|
127
|
+
this.dropdown.toggleElement(this.dropdown.target);
|
128
|
+
this.dropdown.updateClearButton();
|
102
129
|
}
|
103
130
|
}
|
@@ -45,27 +45,31 @@ const DropdownOption = (props: DropdownOptionProps) => {
|
|
45
45
|
filterItem,
|
46
46
|
focusedOptionIndex,
|
47
47
|
handleOptionClick,
|
48
|
+
multiSelect,
|
48
49
|
selected,
|
49
50
|
} = useContext(DropdownContext);
|
50
51
|
|
51
|
-
const isItemMatchingFilter = (option: GenericObject) => {
|
52
|
-
const label = typeof option
|
52
|
+
const isItemMatchingFilter = (option: GenericObject | undefined) => {
|
53
|
+
const label = typeof option?.label === 'string' ? option.label.toLowerCase() : option?.label;
|
53
54
|
return String(label).toLowerCase().includes(filterItem.toLowerCase());
|
54
55
|
}
|
55
56
|
|
56
|
-
if
|
57
|
+
// When multiSelect, then if an option is selected, remove from dropdown
|
58
|
+
const isSelected = Array.isArray(selected)
|
59
|
+
? selected.some((item) => item.label === option?.label)
|
60
|
+
: (selected as GenericObject)?.label === option?.label;
|
61
|
+
|
62
|
+
|
63
|
+
if (!isItemMatchingFilter(option) || (multiSelect && isSelected)) {
|
57
64
|
return null;
|
58
65
|
}
|
59
66
|
const isFocused =
|
60
67
|
focusedOptionIndex >= 0 &&
|
61
|
-
filteredOptions[focusedOptionIndex].label === option
|
68
|
+
filteredOptions[focusedOptionIndex].label === option?.label;
|
62
69
|
const focusedClass = isFocused && "focused";
|
63
70
|
|
64
|
-
const selectedClass =
|
65
|
-
|
66
|
-
? "selected"
|
67
|
-
: "list"
|
68
|
-
}`;
|
71
|
+
const selectedClass = isSelected ? "selected" : "list";
|
72
|
+
|
69
73
|
const ariaProps = buildAriaProps(aria);
|
70
74
|
const dataProps = buildDataProps(data);
|
71
75
|
const htmlProps = buildHtmlProps(htmlOptions);
|
@@ -92,14 +96,14 @@ const DropdownOption = (props: DropdownOptionProps) => {
|
|
92
96
|
<ListItem
|
93
97
|
cursor="pointer"
|
94
98
|
dark={dark}
|
95
|
-
data-name={option
|
96
|
-
key={option
|
99
|
+
data-name={option?.value}
|
100
|
+
key={option?.label}
|
97
101
|
padding="none"
|
98
102
|
>
|
99
103
|
{children ?
|
100
104
|
<div className="dropdown_option_wrapper">{children}</div> :
|
101
105
|
<Body dark={dark}
|
102
|
-
text={option
|
106
|
+
text={option?.label}
|
103
107
|
/>
|
104
108
|
}
|
105
109
|
</ListItem>
|