playbook_ui 16.2.0.pre.rc.3 → 16.2.0.pre.rc.4
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/docs/_advanced_table_sort.md +1 -1
- data/app/pb_kits/playbook/pb_checkbox/_checkbox.scss +1 -1
- data/app/pb_kits/playbook/pb_checkbox/_checkbox.tsx +17 -0
- data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +10 -1
- data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +2 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_required_indicator.html.erb +6 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_required_indicator.jsx +17 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_required_indicator.md +3 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +46 -11
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display_rails.html.erb +1 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.html.erb +6 -3
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.jsx +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_label.md +3 -1
- data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +11 -5
- data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +9 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +15 -10
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +4 -0
- data/app/pb_kits/playbook/pb_dropdown/index.js +132 -79
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +16 -0
- data/app/pb_kits/playbook/pb_dropdown/utilities/clickOutsideHelper.tsx +6 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.html.erb +5 -3
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.scss +7 -0
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +638 -549
- 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 +4 -7
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_label.md +3 -0
- data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.test.jsx +4 -4
- data/app/pb_kits/playbook/pb_nav/_item.tsx +5 -3
- data/app/pb_kits/playbook/pb_nav/_nav.scss +82 -3
- data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav_disabled_item.html.erb +24 -0
- data/app/pb_kits/playbook/pb_nav/docs/_collapsible_nav_disabled_item.jsx +87 -0
- data/app/pb_kits/playbook/pb_nav/docs/example.yml +2 -6
- data/app/pb_kits/playbook/pb_nav/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_nav/item.html.erb +1 -1
- data/app/pb_kits/playbook/pb_nav/item.rb +1 -1
- data/app/pb_kits/playbook/pb_nav/navTypes.ts +1 -0
- data/app/pb_kits/playbook/pb_text_input/text_input.html.erb +10 -10
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +29 -1
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +411 -323
- data/app/pb_kits/playbook/pb_typeahead/components/Control.tsx +2 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_required_indicator.html.erb +16 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_required_indicator.jsx +23 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_required_indicator.md +3 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/index.js +22 -21
- data/app/pb_kits/playbook/pb_typeahead/typeahead.html.erb +3 -2
- data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +3 -1
- data/app/pb_kits/playbook/tokens/_colors.scss +3 -0
- data/app/pb_kits/playbook/tokens/_colors_accessible.scss +250 -0
- data/app/pb_kits/playbook/tokens/exports/_colors.module.scss +10 -0
- data/dist/chunks/{_pb_line_graph-CG2X7d4a.js → _pb_line_graph-CC2Ywwix.js} +1 -1
- data/dist/chunks/_typeahead-CmMqokN8.js +1 -0
- data/dist/chunks/{globalProps-B_OY_vR9.js → globalProps-DYr2qrIf.js} +1 -1
- data/dist/chunks/lib-DgqmX9CF.js +29 -0
- data/dist/chunks/vendor.js +2 -2
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +2 -2
- data/dist/reset.css +1 -1
- data/lib/playbook/forms/builder/form_field_builder.rb +1 -1
- data/lib/playbook/forms/builder/typeahead_field.rb +15 -1
- data/lib/playbook/forms/builder.rb +2 -2
- data/lib/playbook/version.rb +1 -1
- metadata +16 -6
- data/dist/chunks/_typeahead-DjDiMPdY.js +0 -1
- data/dist/chunks/lib-9vEH4omL.js +0 -29
|
@@ -4,16 +4,18 @@ import { PbDropdownKeyboard } from "./keyboard_accessibility";
|
|
|
4
4
|
const DROPDOWN_SELECTOR = "[data-pb-dropdown]";
|
|
5
5
|
const TRIGGER_SELECTOR = "[data-dropdown-trigger]";
|
|
6
6
|
const CONTAINER_SELECTOR = "[data-dropdown-container]";
|
|
7
|
-
const DOWN_ARROW_SELECTOR = "
|
|
8
|
-
const UP_ARROW_SELECTOR = "
|
|
7
|
+
const DOWN_ARROW_SELECTOR = "[data-dropdown-open-icon]";
|
|
8
|
+
const UP_ARROW_SELECTOR = "[data-dropdown-close-icon]";
|
|
9
9
|
const OPTION_SELECTOR = "[data-dropdown-option-label]";
|
|
10
10
|
const CUSTOM_DISPLAY_SELECTOR = "[data-dropdown-custom-trigger]";
|
|
11
|
-
const DROPDOWN_TRIGGER_DISPLAY = "
|
|
11
|
+
const DROPDOWN_TRIGGER_DISPLAY = "[data-dropdown-trigger-display]";
|
|
12
12
|
const DROPDOWN_PLACEHOLDER = "[data-dropdown-placeholder]";
|
|
13
|
-
const DROPDOWN_INPUT = "
|
|
13
|
+
const DROPDOWN_INPUT = "[data-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 = "
|
|
16
|
+
const CLEAR_ICON_SELECTOR = "[data-dropdown-clear-icon]";
|
|
17
|
+
const LABEL_SELECTOR = '[data-dropdown="pb-dropdown-label"]';
|
|
18
|
+
|
|
17
19
|
|
|
18
20
|
export default class PbDropdown extends PbEnhancedElement {
|
|
19
21
|
static get selector() {
|
|
@@ -30,14 +32,15 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
30
32
|
connect() {
|
|
31
33
|
// Store instance on element for DatePicker sync
|
|
32
34
|
this.element._pbDropdownInstance = this;
|
|
33
|
-
|
|
35
|
+
|
|
34
36
|
this.keyboardHandler = new PbDropdownKeyboard(this);
|
|
35
37
|
this.isMultiSelect = this.element.dataset.pbDropdownMultiSelect === "true";
|
|
36
38
|
this.formPillProps = this.element.dataset.formPillProps
|
|
37
39
|
? JSON.parse(this.element.dataset.formPillProps)
|
|
38
40
|
: {};
|
|
39
41
|
const baseInput = this.element.querySelector(DROPDOWN_INPUT);
|
|
40
|
-
this.wasOriginallyRequired =
|
|
42
|
+
this.wasOriginallyRequired =
|
|
43
|
+
baseInput && baseInput.hasAttribute("required");
|
|
41
44
|
this.setDefaultValue();
|
|
42
45
|
this.bindEventListeners();
|
|
43
46
|
this.bindSearchInput();
|
|
@@ -75,15 +78,24 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
75
78
|
bindEventListeners() {
|
|
76
79
|
const customTrigger =
|
|
77
80
|
this.element.querySelector(CUSTOM_DISPLAY_SELECTOR) || this.element;
|
|
78
|
-
customTrigger.addEventListener("click", () =>
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
customTrigger.addEventListener("click", (e) => {
|
|
82
|
+
const label = e.target.closest(LABEL_SELECTOR);
|
|
83
|
+
if (label && label.htmlFor) {
|
|
84
|
+
const trigger = this.element.querySelector(
|
|
85
|
+
`#${CSS.escape(label.htmlFor)}`,
|
|
86
|
+
);
|
|
87
|
+
if (trigger) {
|
|
88
|
+
trigger.focus();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
this.toggleElement(this.target);
|
|
92
|
+
});
|
|
81
93
|
|
|
82
94
|
this.target.addEventListener("click", this.handleOptionClick.bind(this));
|
|
83
95
|
document.addEventListener(
|
|
84
96
|
"click",
|
|
85
97
|
this.handleDocumentClick.bind(this),
|
|
86
|
-
true
|
|
98
|
+
true,
|
|
87
99
|
);
|
|
88
100
|
}
|
|
89
101
|
|
|
@@ -92,7 +104,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
92
104
|
if (!this.searchBar) return;
|
|
93
105
|
|
|
94
106
|
this.searchBar.addEventListener("input", (e) =>
|
|
95
|
-
this.handleSearch(e.target.value)
|
|
107
|
+
this.handleSearch(e.target.value),
|
|
96
108
|
);
|
|
97
109
|
}
|
|
98
110
|
|
|
@@ -107,7 +119,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
107
119
|
|
|
108
120
|
// Live filter
|
|
109
121
|
this.searchInput.addEventListener("input", (e) =>
|
|
110
|
-
this.handleSearch(e.target.value)
|
|
122
|
+
this.handleSearch(e.target.value),
|
|
111
123
|
);
|
|
112
124
|
}
|
|
113
125
|
|
|
@@ -161,28 +173,31 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
161
173
|
|
|
162
174
|
handleSearch(term = "") {
|
|
163
175
|
const lcTerm = term.toLowerCase();
|
|
164
|
-
let hasMatch = false
|
|
176
|
+
let hasMatch = false;
|
|
165
177
|
this.element.querySelectorAll(OPTION_SELECTOR).forEach((opt) => {
|
|
166
178
|
//make it so that if the option is selected, it will not show up in the search results
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
if (
|
|
180
|
+
this.isMultiSelect &&
|
|
181
|
+
this.selectedOptions.has(opt.dataset.dropdownOptionLabel)
|
|
182
|
+
) {
|
|
183
|
+
opt.style.display = "none";
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
171
186
|
const label = JSON.parse(opt.dataset.dropdownOptionLabel)
|
|
172
187
|
.label.toString()
|
|
173
188
|
.toLowerCase();
|
|
174
189
|
|
|
175
|
-
|
|
190
|
+
// hide or show option
|
|
176
191
|
const match = label.includes(lcTerm);
|
|
177
192
|
opt.style.display = match ? "" : "none";
|
|
178
|
-
if (match) hasMatch = true
|
|
193
|
+
if (match) hasMatch = true;
|
|
179
194
|
});
|
|
180
195
|
|
|
181
196
|
this.adjustDropdownHeight();
|
|
182
197
|
|
|
183
|
-
this.removeNoOptionsMessage()
|
|
198
|
+
this.removeNoOptionsMessage();
|
|
184
199
|
if (!hasMatch) {
|
|
185
|
-
this.showNoOptionsMessage()
|
|
200
|
+
this.showNoOptionsMessage();
|
|
186
201
|
}
|
|
187
202
|
}
|
|
188
203
|
|
|
@@ -190,7 +205,8 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
190
205
|
if (this.element.querySelector(".dropdown_no_options")) return;
|
|
191
206
|
|
|
192
207
|
const noOptionElement = document.createElement("div");
|
|
193
|
-
noOptionElement.className =
|
|
208
|
+
noOptionElement.className =
|
|
209
|
+
"pb_body_kit_light dropdown_no_options pb_item_kit p_xs display_flex justify_content_center";
|
|
194
210
|
noOptionElement.textContent = "no option";
|
|
195
211
|
|
|
196
212
|
this.target.appendChild(noOptionElement);
|
|
@@ -241,6 +257,8 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
241
257
|
}
|
|
242
258
|
|
|
243
259
|
isClickOutside(event) {
|
|
260
|
+
const label = event.target.closest(LABEL_SELECTOR);
|
|
261
|
+
if (label && this.element.contains(label)) return false;
|
|
244
262
|
const customTrigger = this.element.querySelector(CUSTOM_DISPLAY_SELECTOR);
|
|
245
263
|
if (customTrigger) {
|
|
246
264
|
return !customTrigger.contains(event.target);
|
|
@@ -271,8 +289,8 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
271
289
|
? JSON.parse(
|
|
272
290
|
this.element.querySelector(
|
|
273
291
|
OPTION_SELECTOR +
|
|
274
|
-
`[data-dropdown-option-label*='"id":"${hiddenInput.value}"']
|
|
275
|
-
).dataset.dropdownOptionLabel
|
|
292
|
+
`[data-dropdown-option-label*='"id":"${hiddenInput.value}"']`,
|
|
293
|
+
).dataset.dropdownOptionLabel,
|
|
276
294
|
)
|
|
277
295
|
: null;
|
|
278
296
|
}
|
|
@@ -281,14 +299,14 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
281
299
|
new CustomEvent("pb:dropdown:selected", {
|
|
282
300
|
detail,
|
|
283
301
|
bubbles: true,
|
|
284
|
-
})
|
|
302
|
+
}),
|
|
285
303
|
);
|
|
286
304
|
}
|
|
287
305
|
|
|
288
306
|
onOptionSelected(value, selectedOption) {
|
|
289
307
|
const triggerElement = this.element.querySelector(DROPDOWN_TRIGGER_DISPLAY);
|
|
290
308
|
const customDisplayElement = this.element.querySelector(
|
|
291
|
-
|
|
309
|
+
'[data-dropdown-trigger-custom-display]',
|
|
292
310
|
);
|
|
293
311
|
|
|
294
312
|
if (triggerElement) {
|
|
@@ -296,36 +314,46 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
296
314
|
const selectedLabel = JSON.parse(value).label;
|
|
297
315
|
triggerElement.textContent = selectedLabel;
|
|
298
316
|
this.emitSelectionChange();
|
|
299
|
-
|
|
317
|
+
|
|
300
318
|
// Handle quickpick variant: populate start/end date hidden inputs
|
|
301
319
|
const optionData = JSON.parse(value);
|
|
302
320
|
const startDateId = this.element.dataset.startDateId;
|
|
303
321
|
const endDateId = this.element.dataset.endDateId;
|
|
304
322
|
const controlsStartId = this.element.dataset.controlsStartId;
|
|
305
323
|
const controlsEndId = this.element.dataset.controlsEndId;
|
|
306
|
-
|
|
324
|
+
|
|
307
325
|
if (optionData.formatted_start_date && optionData.formatted_end_date) {
|
|
308
326
|
// Populate date inputs when option has date fields
|
|
309
327
|
if (startDateId) {
|
|
310
328
|
const startDateInput = document.getElementById(startDateId);
|
|
311
|
-
if (startDateInput)
|
|
329
|
+
if (startDateInput)
|
|
330
|
+
startDateInput.value = optionData.formatted_start_date;
|
|
312
331
|
}
|
|
313
|
-
|
|
332
|
+
|
|
314
333
|
if (endDateId) {
|
|
315
334
|
const endDateInput = document.getElementById(endDateId);
|
|
316
|
-
if (endDateInput)
|
|
335
|
+
if (endDateInput)
|
|
336
|
+
endDateInput.value = optionData.formatted_end_date;
|
|
317
337
|
}
|
|
318
|
-
|
|
338
|
+
|
|
319
339
|
// Sync with DatePickers if controlsStartId/controlsEndId are present
|
|
320
340
|
if (controlsStartId) {
|
|
321
|
-
const startPicker = document.querySelector(
|
|
341
|
+
const startPicker = document.querySelector(
|
|
342
|
+
`#${controlsStartId}`,
|
|
343
|
+
)?._flatpickr;
|
|
322
344
|
if (startPicker) {
|
|
323
|
-
startPicker.setDate(
|
|
345
|
+
startPicker.setDate(
|
|
346
|
+
optionData.formatted_start_date,
|
|
347
|
+
true,
|
|
348
|
+
"m/d/Y",
|
|
349
|
+
);
|
|
324
350
|
}
|
|
325
351
|
}
|
|
326
|
-
|
|
352
|
+
|
|
327
353
|
if (controlsEndId) {
|
|
328
|
-
const endPicker = document.querySelector(
|
|
354
|
+
const endPicker = document.querySelector(
|
|
355
|
+
`#${controlsEndId}`,
|
|
356
|
+
)?._flatpickr;
|
|
329
357
|
if (endPicker) {
|
|
330
358
|
endPicker.setDate(optionData.formatted_end_date, true, "m/d/Y");
|
|
331
359
|
}
|
|
@@ -336,22 +364,26 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
336
364
|
const startDateInput = document.getElementById(startDateId);
|
|
337
365
|
if (startDateInput) startDateInput.value = "";
|
|
338
366
|
}
|
|
339
|
-
|
|
367
|
+
|
|
340
368
|
if (endDateId) {
|
|
341
369
|
const endDateInput = document.getElementById(endDateId);
|
|
342
370
|
if (endDateInput) endDateInput.value = "";
|
|
343
371
|
}
|
|
344
|
-
|
|
372
|
+
|
|
345
373
|
// Clear DatePickers as well
|
|
346
374
|
if (controlsStartId) {
|
|
347
|
-
const startPicker = document.querySelector(
|
|
375
|
+
const startPicker = document.querySelector(
|
|
376
|
+
`#${controlsStartId}`,
|
|
377
|
+
)?._flatpickr;
|
|
348
378
|
if (startPicker) {
|
|
349
379
|
startPicker.clear();
|
|
350
380
|
}
|
|
351
381
|
}
|
|
352
|
-
|
|
382
|
+
|
|
353
383
|
if (controlsEndId) {
|
|
354
|
-
const endPicker = document.querySelector(
|
|
384
|
+
const endPicker = document.querySelector(
|
|
385
|
+
`#${controlsEndId}`,
|
|
386
|
+
)?._flatpickr;
|
|
355
387
|
if (endPicker) {
|
|
356
388
|
endPicker.clear();
|
|
357
389
|
}
|
|
@@ -391,7 +423,9 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
391
423
|
this.adjustDropdownHeight();
|
|
392
424
|
}
|
|
393
425
|
});
|
|
394
|
-
this.element.querySelector(DROPDOWN_INPUT).value = Array.from(
|
|
426
|
+
this.element.querySelector(DROPDOWN_INPUT).value = Array.from(
|
|
427
|
+
this.selectedOptions,
|
|
428
|
+
)
|
|
395
429
|
.map((opt) => JSON.parse(opt).id)
|
|
396
430
|
.join(",");
|
|
397
431
|
} else {
|
|
@@ -437,7 +471,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
437
471
|
this.keyboardHandler.focusedOptionIndex = -1;
|
|
438
472
|
const options = this.element.querySelectorAll(OPTION_SELECTOR);
|
|
439
473
|
options.forEach((option) =>
|
|
440
|
-
option.classList.remove("pb_dropdown_option_focused")
|
|
474
|
+
option.classList.remove("pb_dropdown_option_focused"),
|
|
441
475
|
);
|
|
442
476
|
}
|
|
443
477
|
}
|
|
@@ -472,7 +506,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
472
506
|
hiddenInput.closest(".dropdown_wrapper").classList.add("error");
|
|
473
507
|
}
|
|
474
508
|
},
|
|
475
|
-
true
|
|
509
|
+
true,
|
|
476
510
|
);
|
|
477
511
|
}
|
|
478
512
|
|
|
@@ -482,7 +516,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
482
516
|
const dropdownWrapperElement = input.closest(".dropdown_wrapper");
|
|
483
517
|
dropdownWrapperElement.classList.remove("error");
|
|
484
518
|
const errorLabelElement = dropdownWrapperElement.querySelector(
|
|
485
|
-
".pb_body_kit_negative"
|
|
519
|
+
".pb_body_kit_negative",
|
|
486
520
|
);
|
|
487
521
|
if (errorLabelElement) {
|
|
488
522
|
errorLabelElement.remove();
|
|
@@ -490,13 +524,13 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
490
524
|
return;
|
|
491
525
|
}
|
|
492
526
|
}
|
|
493
|
-
|
|
527
|
+
|
|
494
528
|
if (input.checkValidity()) {
|
|
495
529
|
const dropdownWrapperElement = input.closest(".dropdown_wrapper");
|
|
496
530
|
dropdownWrapperElement.classList.remove("error");
|
|
497
531
|
|
|
498
532
|
const errorLabelElement = dropdownWrapperElement.querySelector(
|
|
499
|
-
".pb_body_kit_negative"
|
|
533
|
+
".pb_body_kit_negative",
|
|
500
534
|
);
|
|
501
535
|
if (errorLabelElement) {
|
|
502
536
|
errorLabelElement.remove();
|
|
@@ -507,7 +541,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
507
541
|
setDefaultValue() {
|
|
508
542
|
const hiddenInput = this.element.querySelector(DROPDOWN_INPUT);
|
|
509
543
|
const optionEls = Array.from(
|
|
510
|
-
this.element.querySelectorAll(OPTION_SELECTOR)
|
|
544
|
+
this.element.querySelectorAll(OPTION_SELECTOR),
|
|
511
545
|
);
|
|
512
546
|
const defaultValue = hiddenInput.dataset.defaultValue || "";
|
|
513
547
|
if (!defaultValue) return;
|
|
@@ -553,44 +587,53 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
553
587
|
selectedOption.classList.add("pb_dropdown_option_selected");
|
|
554
588
|
const optionData = JSON.parse(selectedOption.dataset.dropdownOptionLabel);
|
|
555
589
|
this.setTriggerElementText(optionData.label);
|
|
556
|
-
|
|
590
|
+
|
|
557
591
|
// Handle quickpick variant: populate start/end date hidden inputs and sync DatePickers
|
|
558
592
|
if (optionData.formatted_start_date && optionData.formatted_end_date) {
|
|
559
593
|
const startDateId = this.element.dataset.startDateId;
|
|
560
594
|
const endDateId = this.element.dataset.endDateId;
|
|
561
595
|
const controlsStartId = this.element.dataset.controlsStartId;
|
|
562
596
|
const controlsEndId = this.element.dataset.controlsEndId;
|
|
563
|
-
|
|
597
|
+
|
|
564
598
|
if (startDateId) {
|
|
565
599
|
const startDateInput = document.getElementById(startDateId);
|
|
566
|
-
if (startDateInput)
|
|
600
|
+
if (startDateInput)
|
|
601
|
+
startDateInput.value = optionData.formatted_start_date;
|
|
567
602
|
}
|
|
568
|
-
|
|
603
|
+
|
|
569
604
|
if (endDateId) {
|
|
570
605
|
const endDateInput = document.getElementById(endDateId);
|
|
571
606
|
if (endDateInput) endDateInput.value = optionData.formatted_end_date;
|
|
572
607
|
}
|
|
573
|
-
|
|
608
|
+
|
|
574
609
|
// Sync with DatePickers - retry with delays to ensure DatePickers are initialized
|
|
575
610
|
const syncDatePickers = () => {
|
|
576
611
|
if (controlsStartId) {
|
|
577
|
-
const startPicker = document.querySelector(
|
|
612
|
+
const startPicker = document.querySelector(
|
|
613
|
+
`#${controlsStartId}`,
|
|
614
|
+
)?._flatpickr;
|
|
578
615
|
if (startPicker) {
|
|
579
|
-
startPicker.setDate(
|
|
616
|
+
startPicker.setDate(
|
|
617
|
+
optionData.formatted_start_date,
|
|
618
|
+
true,
|
|
619
|
+
"m/d/Y",
|
|
620
|
+
);
|
|
580
621
|
}
|
|
581
622
|
}
|
|
582
|
-
|
|
623
|
+
|
|
583
624
|
if (controlsEndId) {
|
|
584
|
-
const endPicker = document.querySelector(
|
|
625
|
+
const endPicker = document.querySelector(
|
|
626
|
+
`#${controlsEndId}`,
|
|
627
|
+
)?._flatpickr;
|
|
585
628
|
if (endPicker) {
|
|
586
629
|
endPicker.setDate(optionData.formatted_end_date, true, "m/d/Y");
|
|
587
630
|
}
|
|
588
631
|
}
|
|
589
632
|
};
|
|
590
|
-
|
|
633
|
+
|
|
591
634
|
// Try immediately
|
|
592
635
|
syncDatePickers();
|
|
593
|
-
|
|
636
|
+
|
|
594
637
|
// Retry after short delay in case DatePickers aren't ready yet
|
|
595
638
|
setTimeout(syncDatePickers, 100);
|
|
596
639
|
setTimeout(syncDatePickers, 300);
|
|
@@ -651,9 +694,9 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
651
694
|
updatePills() {
|
|
652
695
|
if (!this.isMultiSelect) return;
|
|
653
696
|
|
|
654
|
-
const wrapper = this.element.querySelector(
|
|
697
|
+
const wrapper = this.element.querySelector('[data-dropdown-pills-wrapper]');
|
|
655
698
|
const placeholder = this.element.querySelector(
|
|
656
|
-
|
|
699
|
+
'[data-dropdown-trigger-display-multi-select]',
|
|
657
700
|
);
|
|
658
701
|
if (!wrapper) return;
|
|
659
702
|
|
|
@@ -671,7 +714,12 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
671
714
|
// Create a form pill for each selected option
|
|
672
715
|
const pill = document.createElement("div");
|
|
673
716
|
const color = this.formPillProps.color || "primary";
|
|
674
|
-
pill.classList.add(
|
|
717
|
+
pill.classList.add(
|
|
718
|
+
"pb_form_pill_kit",
|
|
719
|
+
`pb_form_pill_${color}`,
|
|
720
|
+
"pb_form_pill_none",
|
|
721
|
+
"mr_xs",
|
|
722
|
+
);
|
|
675
723
|
if (this.formPillProps.size === "small") {
|
|
676
724
|
pill.classList.add("pb_form_pill_small");
|
|
677
725
|
}
|
|
@@ -696,8 +744,8 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
696
744
|
|
|
697
745
|
const optEl = this.element.querySelector(
|
|
698
746
|
`${OPTION_SELECTOR}[data-dropdown-option-label*='"id":${JSON.stringify(
|
|
699
|
-
id
|
|
700
|
-
)}']
|
|
747
|
+
id,
|
|
748
|
+
)}']`,
|
|
701
749
|
);
|
|
702
750
|
if (optEl) {
|
|
703
751
|
optEl.style.display = "";
|
|
@@ -726,18 +774,18 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
726
774
|
}
|
|
727
775
|
}
|
|
728
776
|
const customDisplay = this.element.querySelector(
|
|
729
|
-
|
|
777
|
+
'[data-dropdown-trigger-custom-display]',
|
|
730
778
|
);
|
|
731
779
|
if (customDisplay) {
|
|
732
780
|
customDisplay.style.display = "none";
|
|
733
781
|
}
|
|
734
|
-
|
|
782
|
+
|
|
735
783
|
// Clear quickpick hidden inputs
|
|
736
784
|
const startDateId = this.element.dataset.startDateId;
|
|
737
785
|
const endDateId = this.element.dataset.endDateId;
|
|
738
786
|
const controlsStartId = this.element.dataset.controlsStartId;
|
|
739
787
|
const controlsEndId = this.element.dataset.controlsEndId;
|
|
740
|
-
|
|
788
|
+
|
|
741
789
|
if (startDateId) {
|
|
742
790
|
const startDateInput = document.getElementById(startDateId);
|
|
743
791
|
if (startDateInput) startDateInput.value = "";
|
|
@@ -746,22 +794,24 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
746
794
|
const endDateInput = document.getElementById(endDateId);
|
|
747
795
|
if (endDateInput) endDateInput.value = "";
|
|
748
796
|
}
|
|
749
|
-
|
|
797
|
+
|
|
750
798
|
// Clear linked DatePickers if controlsStartId/controlsEndId are present
|
|
751
799
|
if (controlsStartId) {
|
|
752
|
-
const startPicker = document.querySelector(
|
|
800
|
+
const startPicker = document.querySelector(
|
|
801
|
+
`#${controlsStartId}`,
|
|
802
|
+
)?._flatpickr;
|
|
753
803
|
if (startPicker) {
|
|
754
804
|
startPicker.clear();
|
|
755
805
|
}
|
|
756
806
|
}
|
|
757
|
-
|
|
807
|
+
|
|
758
808
|
if (controlsEndId) {
|
|
759
809
|
const endPicker = document.querySelector(`#${controlsEndId}`)?._flatpickr;
|
|
760
810
|
if (endPicker) {
|
|
761
811
|
endPicker.clear();
|
|
762
812
|
}
|
|
763
813
|
}
|
|
764
|
-
|
|
814
|
+
|
|
765
815
|
this.resetDropdownValue();
|
|
766
816
|
this.updatePills();
|
|
767
817
|
this.updateClearButton();
|
|
@@ -772,21 +822,24 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
772
822
|
// Method for DatePicker sync - only clears the dropdown, not the DatePickers
|
|
773
823
|
clearSelected() {
|
|
774
824
|
// Only clear if this is a single-select quickpick variant
|
|
775
|
-
if (
|
|
825
|
+
if (
|
|
826
|
+
this.element.dataset.pbDropdownVariant !== "quickpick" ||
|
|
827
|
+
this.isMultiSelect
|
|
828
|
+
) {
|
|
776
829
|
return;
|
|
777
830
|
}
|
|
778
|
-
|
|
831
|
+
|
|
779
832
|
const customDisplay = this.element.querySelector(
|
|
780
|
-
|
|
833
|
+
'[data-dropdown-trigger-custom-display]',
|
|
781
834
|
);
|
|
782
835
|
if (customDisplay) {
|
|
783
836
|
customDisplay.style.display = "none";
|
|
784
837
|
}
|
|
785
|
-
|
|
838
|
+
|
|
786
839
|
// Clear quickpick hidden inputs only (not the DatePickers)
|
|
787
840
|
const startDateId = this.element.dataset.startDateId;
|
|
788
841
|
const endDateId = this.element.dataset.endDateId;
|
|
789
|
-
|
|
842
|
+
|
|
790
843
|
if (startDateId) {
|
|
791
844
|
const startDateInput = document.getElementById(startDateId);
|
|
792
845
|
if (startDateInput) startDateInput.value = "";
|
|
@@ -795,7 +848,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
795
848
|
const endDateInput = document.getElementById(endDateId);
|
|
796
849
|
if (endDateInput) endDateInput.value = "";
|
|
797
850
|
}
|
|
798
|
-
|
|
851
|
+
|
|
799
852
|
this.resetDropdownValue();
|
|
800
853
|
this.updateClearButton();
|
|
801
854
|
this.emitSelectionChange();
|
|
@@ -822,7 +875,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
822
875
|
inp.dataset.generated = "true";
|
|
823
876
|
baseInput.insertAdjacentElement("afterend", inp);
|
|
824
877
|
});
|
|
825
|
-
|
|
878
|
+
|
|
826
879
|
// For multi-select, remove required from base input when there are selections
|
|
827
880
|
// The generated inputs handle the form submission with actual values
|
|
828
881
|
// Restore required attribute when there are no selections (if it was originally required)
|
|
@@ -45,6 +45,8 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
45
45
|
const {
|
|
46
46
|
autocomplete,
|
|
47
47
|
clearable,
|
|
48
|
+
error,
|
|
49
|
+
errorId,
|
|
48
50
|
filterItem,
|
|
49
51
|
handleBackspace,
|
|
50
52
|
handleChange,
|
|
@@ -53,8 +55,10 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
53
55
|
inputWrapperRef,
|
|
54
56
|
isDropDownClosed,
|
|
55
57
|
isInputFocused,
|
|
58
|
+
label: contextLabel,
|
|
56
59
|
multiSelect,
|
|
57
60
|
selected,
|
|
61
|
+
selectId,
|
|
58
62
|
setIsInputFocused,
|
|
59
63
|
toggleDropdown,
|
|
60
64
|
} = useContext(DropdownContext);
|
|
@@ -104,6 +108,10 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
104
108
|
? placeholder
|
|
105
109
|
: "Select...";
|
|
106
110
|
|
|
111
|
+
const triggerAriaLabel = contextLabel
|
|
112
|
+
? (children ? contextLabel : `${contextLabel}, ${defaultDisplayPlaceholder}`)
|
|
113
|
+
: undefined;
|
|
114
|
+
|
|
107
115
|
return (
|
|
108
116
|
<div {...ariaProps}
|
|
109
117
|
{...dataProps}
|
|
@@ -114,6 +122,10 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
114
122
|
{
|
|
115
123
|
children ? (
|
|
116
124
|
<div
|
|
125
|
+
aria-describedby={errorId}
|
|
126
|
+
aria-invalid={!!error}
|
|
127
|
+
aria-label={triggerAriaLabel}
|
|
128
|
+
id={selectId}
|
|
117
129
|
onClick={() => toggleDropdown()}
|
|
118
130
|
onKeyDown= {handleKeyDown}
|
|
119
131
|
ref={inputWrapperRef}
|
|
@@ -130,6 +142,10 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
130
142
|
className={triggerWrapperClasses}
|
|
131
143
|
cursor={`${autocomplete ? "text" : "pointer"}`}
|
|
132
144
|
htmlOptions={{
|
|
145
|
+
"aria-describedby": errorId,
|
|
146
|
+
"aria-invalid": !!error,
|
|
147
|
+
"aria-label": triggerAriaLabel,
|
|
148
|
+
id: selectId,
|
|
133
149
|
onClick: () => handleWrapperClick(),
|
|
134
150
|
onKeyDown: handleKeyDown,
|
|
135
151
|
tabIndex: "0",
|
|
@@ -25,6 +25,12 @@ export const handleClickOutside =
|
|
|
25
25
|
) {
|
|
26
26
|
shouldClose = false;
|
|
27
27
|
}
|
|
28
|
+
// Target dropdown container to open dropdown
|
|
29
|
+
if (
|
|
30
|
+
targetElement.getAttribute("data-dropdown") === "pb-dropdown-label"
|
|
31
|
+
) {
|
|
32
|
+
shouldClose = false;
|
|
33
|
+
}
|
|
28
34
|
targetElement = targetElement.parentElement as HTMLElement;
|
|
29
35
|
}
|
|
30
36
|
if (
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
<%= pb_form_with(scope: :example, url: "", method: :get, validate: true) do |form| %>
|
|
2
|
+
<%= form.typeahead :example_typeahead_field, props: { label: true, required: true, required_indicator: true } %>
|
|
2
3
|
<%= form.text_field :example_text_field, props: { label: true, required: true, required_indicator: true } %>
|
|
3
4
|
<%= form.text_field :example_text_field_2, props: { label: "Text Field Custom Label", required: true, required_indicator: true } %>
|
|
4
|
-
<%= form.
|
|
5
|
-
<%= form.text_area :example_text_area_2, props: { label: "Textarea Custom Label", required: true, required_indicator: true } %>
|
|
5
|
+
<%= form.phone_number_field :example_phone_number_field, props: { label: true, required: true, required_indicator: true } %>
|
|
6
6
|
<%= form.email_field :example_email_field, props: { label: true, required: true, required_indicator: true } %>
|
|
7
7
|
<%= form.number_field :example_number_field, props: { label: true, required: true, required_indicator: true } %>
|
|
8
8
|
<%= form.search_field :example_search_field, props: { label: true, required: true, required_indicator: true } %>
|
|
9
9
|
<%= form.password_field :example_password_field, props: { label: true, required: true, required_indicator: true } %>
|
|
10
10
|
<%= form.url_field :example_url_field, props: { label: true, required: true, required_indicator: true } %>
|
|
11
|
-
<%= form.
|
|
11
|
+
<%= form.text_area :example_text_area, props: { label: true, required: true, required_indicator: true } %>
|
|
12
|
+
<%= form.text_area :example_text_area_2, props: { label: "Textarea Custom Label", required: true, required_indicator: true } %>
|
|
13
|
+
<%# <%= form.check_box :example_checkbox, props: { label: true, text: "Checkbox Label", required: true, required_indicator: true } %>
|
|
12
14
|
<%= form.time_picker :example_time_picker_required_indicator, props: { label: true, required: true, required_indicator: true } %>
|
|
13
15
|
|
|
14
16
|
<%= form.actions do |action| %>
|
|
@@ -39,6 +39,13 @@
|
|
|
39
39
|
display: flex;
|
|
40
40
|
align-items: center;
|
|
41
41
|
justify-content: space-between;
|
|
42
|
+
@include transition_default;
|
|
43
|
+
|
|
44
|
+
&:focus-within {
|
|
45
|
+
border-color: $primary;
|
|
46
|
+
background-color: $focus_input_light;
|
|
47
|
+
}
|
|
48
|
+
|
|
42
49
|
.input_inner_container {
|
|
43
50
|
width: 100%;
|
|
44
51
|
}
|