basecoat-cli 0.3.10-beta.1 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/jinja/dialog.html.jinja +3 -5
- package/dist/assets/jinja/select.html.jinja +18 -23
- package/dist/assets/js/all.js +150 -141
- package/dist/assets/js/all.min.js +1 -1
- package/dist/assets/js/select.js +150 -141
- package/dist/assets/js/select.min.js +1 -1
- package/dist/assets/nunjucks/select.njk +19 -24
- package/package.json +1 -1
|
@@ -83,12 +83,10 @@
|
|
|
83
83
|
</footer>
|
|
84
84
|
{% endif %}
|
|
85
85
|
{% if close_button %}
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
86
|
+
<button type="button" aria-label="Close dialog" onclick="this.closest('dialog').close()">
|
|
87
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
89
88
|
</button>
|
|
90
|
-
</form>
|
|
91
89
|
{% endif %}
|
|
92
90
|
</div>
|
|
93
91
|
</dialog>
|
|
94
|
-
{% endmacro %}
|
|
92
|
+
{% endmacro %}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
@param name {string} [optional] - The name attribute for the hidden input storing the selected value.
|
|
7
7
|
@param multiple {boolean} [optional] [default=false] - Enables multiple selection mode.
|
|
8
8
|
@param placeholder {string} [optional] - Placeholder text shown when no options are selected (multiple mode only).
|
|
9
|
+
@param close_on_select {boolean} [optional] [default=false] - Closes the popover when selecting an option in multiple mode.
|
|
9
10
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
10
11
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
|
|
11
12
|
@param popover_attrs {object} [optional] - Additional HTML attributes for the popover content div.
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
items=[],
|
|
22
23
|
multiple=false,
|
|
23
24
|
placeholder=None,
|
|
25
|
+
close_on_select=false,
|
|
24
26
|
main_attrs={},
|
|
25
27
|
trigger_attrs={},
|
|
26
28
|
popover_attrs={},
|
|
@@ -31,7 +33,13 @@
|
|
|
31
33
|
) %}
|
|
32
34
|
{% set id = id or ("select-" + (range(100000, 999999) | random | string)) %}
|
|
33
35
|
|
|
34
|
-
{%
|
|
36
|
+
{% if selected is defined and selected is iterable and selected is not string %}
|
|
37
|
+
{% set selectedArray = selected %}
|
|
38
|
+
{% elif selected is defined %}
|
|
39
|
+
{% set selectedArray = [selected] %}
|
|
40
|
+
{% else %}
|
|
41
|
+
{% set selectedArray = [] %}
|
|
42
|
+
{% endif %}
|
|
35
43
|
{% set first_option = namespace(item=None) %}
|
|
36
44
|
{% set selected_options = namespace(items=[]) %}
|
|
37
45
|
|
|
@@ -70,6 +78,7 @@
|
|
|
70
78
|
id="{{ id }}"
|
|
71
79
|
class="select {{ main_attrs.class }}"
|
|
72
80
|
{% if multiple and placeholder %}data-placeholder="{{ placeholder }}"{% endif %}
|
|
81
|
+
{% if multiple and close_on_select %}data-close-on-select="true"{% endif %}
|
|
73
82
|
{% for key, value in main_attrs.items() %}
|
|
74
83
|
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
75
84
|
{% endfor %}
|
|
@@ -135,28 +144,14 @@
|
|
|
135
144
|
{% endif %}
|
|
136
145
|
</div>
|
|
137
146
|
</div>
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
{% if loop.index0 > 0 %}id="{{ id }}-value-{{ loop.index0 }}"{% endif %}
|
|
145
|
-
{% for key, value in input_attrs.items() %}
|
|
146
|
-
{% if key != 'name' and key != 'value' %}{{ key }}="{{ value }}"{% endif %}
|
|
147
|
-
{% endfor %}
|
|
148
|
-
>
|
|
147
|
+
<input
|
|
148
|
+
type="hidden"
|
|
149
|
+
name="{{ name or id ~ '-value' }}"
|
|
150
|
+
value="{% if multiple %}{{ selectedArray | tojson }}{% else %}{{ (default_option.value if default_option) or '' }}{% endif %}"
|
|
151
|
+
{% for key, value in input_attrs.items() %}
|
|
152
|
+
{% if key != 'name' and key != 'value' %}{{ key }}="{{ value }}"{% endif %}
|
|
149
153
|
{% endfor %}
|
|
150
|
-
|
|
151
|
-
<input
|
|
152
|
-
type="hidden"
|
|
153
|
-
name="{{ name or id ~ '-value' }}"
|
|
154
|
-
value="{{ (default_option.value if default_option) or '' }}"
|
|
155
|
-
{% for key, value in input_attrs.items() %}
|
|
156
|
-
{% if key != 'name' and key != 'value' %}{{ key }}="{{ value }}"{% endif %}
|
|
157
|
-
{% endfor %}
|
|
158
|
-
>
|
|
159
|
-
{% endif %}
|
|
154
|
+
>
|
|
160
155
|
</div>
|
|
161
156
|
{% endmacro %}
|
|
162
157
|
|
|
@@ -189,7 +184,7 @@
|
|
|
189
184
|
<div
|
|
190
185
|
id="{{ item_id }}"
|
|
191
186
|
role="option"
|
|
192
|
-
data-value="{{ item.value }}"
|
|
187
|
+
{% if item.value is defined and item.value is not none %}data-value="{{ item.value }}"{% endif %}
|
|
193
188
|
{% if item.value in selectedArray %}aria-selected="true"{% endif %}
|
|
194
189
|
{% if item.attrs %}
|
|
195
190
|
{% for key, value in item.attrs.items() %}
|
package/dist/assets/js/all.js
CHANGED
|
@@ -527,20 +527,19 @@
|
|
|
527
527
|
let visibleOptions = [...options];
|
|
528
528
|
let activeIndex = -1;
|
|
529
529
|
const isMultiple = listbox.getAttribute('aria-multiselectable') === 'true';
|
|
530
|
-
|
|
531
|
-
|
|
530
|
+
const selectedOptions = isMultiple ? new Set() : null;
|
|
531
|
+
const placeholder = isMultiple ? (selectComponent.dataset.placeholder || '') : null;
|
|
532
|
+
const closeOnSelect = selectComponent.dataset.closeOnSelect === 'true';
|
|
532
533
|
|
|
533
|
-
|
|
534
|
-
placeholder = selectComponent.dataset.placeholder || '';
|
|
535
|
-
}
|
|
534
|
+
const getValue = (opt) => opt.dataset.value ?? opt.textContent.trim();
|
|
536
535
|
|
|
537
536
|
const setActiveOption = (index) => {
|
|
538
537
|
if (activeIndex > -1 && options[activeIndex]) {
|
|
539
538
|
options[activeIndex].classList.remove('active');
|
|
540
539
|
}
|
|
541
|
-
|
|
540
|
+
|
|
542
541
|
activeIndex = index;
|
|
543
|
-
|
|
542
|
+
|
|
544
543
|
if (activeIndex > -1) {
|
|
545
544
|
const activeOption = options[activeIndex];
|
|
546
545
|
activeOption.classList.add('active');
|
|
@@ -559,70 +558,43 @@
|
|
|
559
558
|
return parseFloat(style.transitionDuration) > 0 || parseFloat(style.transitionDelay) > 0;
|
|
560
559
|
};
|
|
561
560
|
|
|
562
|
-
const syncMultipleInputs = () => {
|
|
563
|
-
if (!isMultiple) return;
|
|
564
|
-
const values = Array.from(selectedValues);
|
|
565
|
-
const inputs = Array.from(selectComponent.querySelectorAll(':scope > input[type="hidden"]'));
|
|
566
|
-
inputs.slice(1).forEach(inp => inp.remove());
|
|
567
|
-
|
|
568
|
-
if (values.length === 0) {
|
|
569
|
-
input.value = '';
|
|
570
|
-
} else {
|
|
571
|
-
input.value = values[0];
|
|
572
|
-
let insertAfter = input;
|
|
573
|
-
for (let i = 1; i < values.length; i++) {
|
|
574
|
-
const clone = input.cloneNode(true);
|
|
575
|
-
clone.removeAttribute('id');
|
|
576
|
-
clone.value = values[i];
|
|
577
|
-
insertAfter.after(clone);
|
|
578
|
-
insertAfter = clone;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
const updateMultipleLabel = () => {
|
|
584
|
-
if (!isMultiple) return;
|
|
585
|
-
const selected = options.filter(opt => selectedValues.has(opt.dataset.value));
|
|
586
|
-
if (selected.length === 0) {
|
|
587
|
-
selectedLabel.textContent = placeholder;
|
|
588
|
-
selectedLabel.classList.add('text-muted-foreground');
|
|
589
|
-
} else {
|
|
590
|
-
selectedLabel.textContent = selected.map(opt => opt.dataset.label || opt.textContent.trim()).join(', ');
|
|
591
|
-
selectedLabel.classList.remove('text-muted-foreground');
|
|
592
|
-
}
|
|
593
|
-
};
|
|
594
|
-
|
|
595
561
|
const updateValue = (optionOrOptions, triggerEvent = true) => {
|
|
596
562
|
let value;
|
|
597
563
|
|
|
598
564
|
if (isMultiple) {
|
|
599
565
|
const opts = Array.isArray(optionOrOptions) ? optionOrOptions : [];
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
566
|
+
selectedOptions.clear();
|
|
567
|
+
opts.forEach(opt => selectedOptions.add(opt));
|
|
568
|
+
|
|
569
|
+
// Get selected options in DOM order
|
|
570
|
+
const selected = options.filter(opt => selectedOptions.has(opt));
|
|
571
|
+
if (selected.length === 0) {
|
|
572
|
+
selectedLabel.textContent = placeholder;
|
|
573
|
+
selectedLabel.classList.add('text-muted-foreground');
|
|
574
|
+
} else {
|
|
575
|
+
selectedLabel.textContent = selected.map(opt => opt.dataset.label || opt.textContent.trim()).join(', ');
|
|
576
|
+
selectedLabel.classList.remove('text-muted-foreground');
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
value = selected.map(getValue);
|
|
580
|
+
input.value = JSON.stringify(value);
|
|
611
581
|
} else {
|
|
612
582
|
const option = optionOrOptions;
|
|
613
583
|
if (!option) return;
|
|
614
584
|
selectedLabel.innerHTML = option.innerHTML;
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
if (opt === option) {
|
|
618
|
-
opt.setAttribute('aria-selected', 'true');
|
|
619
|
-
} else {
|
|
620
|
-
opt.removeAttribute('aria-selected');
|
|
621
|
-
}
|
|
622
|
-
});
|
|
623
|
-
value = option.dataset.value;
|
|
585
|
+
value = getValue(option);
|
|
586
|
+
input.value = value;
|
|
624
587
|
}
|
|
625
588
|
|
|
589
|
+
options.forEach(opt => {
|
|
590
|
+
const isSelected = isMultiple ? selectedOptions.has(opt) : opt === optionOrOptions;
|
|
591
|
+
if (isSelected) {
|
|
592
|
+
opt.setAttribute('aria-selected', 'true');
|
|
593
|
+
} else {
|
|
594
|
+
opt.removeAttribute('aria-selected');
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
|
|
626
598
|
if (triggerEvent) {
|
|
627
599
|
selectComponent.dispatchEvent(new CustomEvent('change', {
|
|
628
600
|
detail: { value },
|
|
@@ -631,85 +603,73 @@
|
|
|
631
603
|
}
|
|
632
604
|
};
|
|
633
605
|
|
|
634
|
-
const toggleMultipleValue = (value, triggerEvent = true) => {
|
|
635
|
-
if (!isMultiple || value == null) return;
|
|
636
|
-
|
|
637
|
-
const newValues = new Set(selectedValues);
|
|
638
|
-
if (newValues.has(value)) {
|
|
639
|
-
newValues.delete(value);
|
|
640
|
-
} else {
|
|
641
|
-
newValues.add(value);
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
const selectedOptions = options.filter(opt => newValues.has(opt.dataset.value));
|
|
645
|
-
updateValue(selectedOptions, triggerEvent);
|
|
646
|
-
};
|
|
647
|
-
|
|
648
606
|
const closePopover = (focusOnTrigger = true) => {
|
|
649
607
|
if (popover.getAttribute('aria-hidden') === 'true') return;
|
|
650
|
-
|
|
608
|
+
|
|
651
609
|
if (filter) {
|
|
652
610
|
const resetFilter = () => {
|
|
653
611
|
filter.value = '';
|
|
654
612
|
visibleOptions = [...options];
|
|
655
613
|
allOptions.forEach(opt => opt.setAttribute('aria-hidden', 'false'));
|
|
656
614
|
};
|
|
657
|
-
|
|
615
|
+
|
|
658
616
|
if (hasTransition()) {
|
|
659
617
|
popover.addEventListener('transitionend', resetFilter, { once: true });
|
|
660
618
|
} else {
|
|
661
619
|
resetFilter();
|
|
662
620
|
}
|
|
663
621
|
}
|
|
664
|
-
|
|
622
|
+
|
|
665
623
|
if (focusOnTrigger) trigger.focus();
|
|
666
624
|
popover.setAttribute('aria-hidden', 'true');
|
|
667
625
|
trigger.setAttribute('aria-expanded', 'false');
|
|
668
626
|
setActiveOption(-1);
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
const selectOption = (option) => {
|
|
672
|
-
if (!option) return;
|
|
673
|
-
|
|
674
|
-
const oldValue = input.value;
|
|
675
|
-
const newValue = option.dataset.value;
|
|
627
|
+
};
|
|
676
628
|
|
|
677
|
-
|
|
678
|
-
|
|
629
|
+
const toggleMultipleValue = (option) => {
|
|
630
|
+
if (selectedOptions.has(option)) {
|
|
631
|
+
selectedOptions.delete(option);
|
|
632
|
+
} else {
|
|
633
|
+
selectedOptions.add(option);
|
|
679
634
|
}
|
|
680
|
-
|
|
681
|
-
closePopover();
|
|
635
|
+
updateValue(options.filter(opt => selectedOptions.has(opt)));
|
|
682
636
|
};
|
|
683
637
|
|
|
684
|
-
const
|
|
685
|
-
const option = options.find(opt => opt.dataset.value === value);
|
|
638
|
+
const select = (value) => {
|
|
686
639
|
if (isMultiple) {
|
|
687
|
-
|
|
688
|
-
if (option
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
const selectedOptions = options.filter(opt => newValues.has(opt.dataset.value));
|
|
692
|
-
updateValue(selectedOptions);
|
|
693
|
-
}
|
|
640
|
+
const option = options.find(opt => getValue(opt) === value && !selectedOptions.has(opt));
|
|
641
|
+
if (!option) return;
|
|
642
|
+
selectedOptions.add(option);
|
|
643
|
+
updateValue(options.filter(opt => selectedOptions.has(opt)));
|
|
694
644
|
} else {
|
|
695
|
-
|
|
645
|
+
const option = options.find(opt => getValue(opt) === value);
|
|
646
|
+
if (!option) return;
|
|
647
|
+
if (input.value !== value) {
|
|
648
|
+
updateValue(option);
|
|
649
|
+
}
|
|
650
|
+
closePopover();
|
|
696
651
|
}
|
|
697
652
|
};
|
|
698
653
|
|
|
699
|
-
const
|
|
654
|
+
const deselect = (value) => {
|
|
700
655
|
if (!isMultiple) return;
|
|
701
|
-
|
|
656
|
+
const option = options.find(opt => getValue(opt) === value && selectedOptions.has(opt));
|
|
657
|
+
if (!option) return;
|
|
658
|
+
selectedOptions.delete(option);
|
|
659
|
+
updateValue(options.filter(opt => selectedOptions.has(opt)));
|
|
702
660
|
};
|
|
703
661
|
|
|
704
|
-
const
|
|
662
|
+
const toggle = (value) => {
|
|
705
663
|
if (!isMultiple) return;
|
|
706
|
-
|
|
664
|
+
const option = options.find(opt => getValue(opt) === value);
|
|
665
|
+
if (!option) return;
|
|
666
|
+
toggleMultipleValue(option);
|
|
707
667
|
};
|
|
708
668
|
|
|
709
669
|
if (filter) {
|
|
710
670
|
const filterOptions = () => {
|
|
711
671
|
const searchTerm = filter.value.trim().toLowerCase();
|
|
712
|
-
|
|
672
|
+
|
|
713
673
|
setActiveOption(-1);
|
|
714
674
|
|
|
715
675
|
visibleOptions = [];
|
|
@@ -735,35 +695,36 @@
|
|
|
735
695
|
}
|
|
736
696
|
});
|
|
737
697
|
};
|
|
738
|
-
|
|
698
|
+
|
|
739
699
|
filter.addEventListener('input', filterOptions);
|
|
740
700
|
}
|
|
741
701
|
|
|
702
|
+
// Initialization
|
|
742
703
|
if (isMultiple) {
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
.map(
|
|
747
|
-
.filter(v =>
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
if (!initialOption) {
|
|
761
|
-
initialOption = options.find(opt => opt.dataset.value !== undefined) ?? options[0];
|
|
762
|
-
}
|
|
704
|
+
const ariaSelected = options.filter(opt => opt.getAttribute('aria-selected') === 'true');
|
|
705
|
+
try {
|
|
706
|
+
const parsed = JSON.parse(input.value || '[]');
|
|
707
|
+
const validValues = new Set(options.map(getValue));
|
|
708
|
+
const initialValues = Array.isArray(parsed) ? parsed.filter(v => validValues.has(v)) : [];
|
|
709
|
+
|
|
710
|
+
const initialOptions = [];
|
|
711
|
+
if (initialValues.length > 0) {
|
|
712
|
+
// Match values to options in order, allowing duplicates
|
|
713
|
+
initialValues.forEach(val => {
|
|
714
|
+
const opt = options.find(o => getValue(o) === val && !initialOptions.includes(o));
|
|
715
|
+
if (opt) initialOptions.push(opt);
|
|
716
|
+
});
|
|
717
|
+
} else {
|
|
718
|
+
initialOptions.push(...ariaSelected);
|
|
719
|
+
}
|
|
763
720
|
|
|
764
|
-
|
|
765
|
-
|
|
721
|
+
updateValue(initialOptions, false);
|
|
722
|
+
} catch (e) {
|
|
723
|
+
updateValue(ariaSelected, false);
|
|
766
724
|
}
|
|
725
|
+
} else {
|
|
726
|
+
const initialOption = options.find(opt => getValue(opt) === input.value) || options[0];
|
|
727
|
+
if (initialOption) updateValue(initialOption, false);
|
|
767
728
|
}
|
|
768
729
|
|
|
769
730
|
const handleKeyNavigation = (event) => {
|
|
@@ -780,20 +741,27 @@
|
|
|
780
741
|
}
|
|
781
742
|
return;
|
|
782
743
|
}
|
|
783
|
-
|
|
744
|
+
|
|
784
745
|
event.preventDefault();
|
|
785
746
|
|
|
786
747
|
if (event.key === 'Escape') {
|
|
787
748
|
closePopover();
|
|
788
749
|
return;
|
|
789
750
|
}
|
|
790
|
-
|
|
751
|
+
|
|
791
752
|
if (event.key === 'Enter') {
|
|
792
753
|
if (activeIndex > -1) {
|
|
754
|
+
const option = options[activeIndex];
|
|
793
755
|
if (isMultiple) {
|
|
794
|
-
toggleMultipleValue(
|
|
756
|
+
toggleMultipleValue(option);
|
|
757
|
+
if (closeOnSelect) {
|
|
758
|
+
closePopover();
|
|
759
|
+
}
|
|
795
760
|
} else {
|
|
796
|
-
|
|
761
|
+
if (input.value !== getValue(option)) {
|
|
762
|
+
updateValue(option);
|
|
763
|
+
}
|
|
764
|
+
closePopover();
|
|
797
765
|
}
|
|
798
766
|
}
|
|
799
767
|
return;
|
|
@@ -860,7 +828,7 @@
|
|
|
860
828
|
document.dispatchEvent(new CustomEvent('basecoat:popover', {
|
|
861
829
|
detail: { source: selectComponent }
|
|
862
830
|
}));
|
|
863
|
-
|
|
831
|
+
|
|
864
832
|
if (filter) {
|
|
865
833
|
if (hasTransition()) {
|
|
866
834
|
popover.addEventListener('transitionend', () => {
|
|
@@ -873,7 +841,7 @@
|
|
|
873
841
|
|
|
874
842
|
popover.setAttribute('aria-hidden', 'false');
|
|
875
843
|
trigger.setAttribute('aria-expanded', 'true');
|
|
876
|
-
|
|
844
|
+
|
|
877
845
|
const selectedOption = listbox.querySelector('[role="option"][aria-selected="true"]');
|
|
878
846
|
if (selectedOption) {
|
|
879
847
|
setActiveOption(options.indexOf(selectedOption));
|
|
@@ -892,18 +860,28 @@
|
|
|
892
860
|
|
|
893
861
|
listbox.addEventListener('click', (event) => {
|
|
894
862
|
const clickedOption = event.target.closest('[role="option"]');
|
|
895
|
-
if (clickedOption)
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
863
|
+
if (!clickedOption) return;
|
|
864
|
+
|
|
865
|
+
const option = options.find(opt => opt === clickedOption);
|
|
866
|
+
if (!option) return;
|
|
867
|
+
|
|
868
|
+
if (isMultiple) {
|
|
869
|
+
toggleMultipleValue(option);
|
|
870
|
+
if (closeOnSelect) {
|
|
871
|
+
closePopover();
|
|
872
|
+
} else {
|
|
873
|
+
setActiveOption(options.indexOf(option));
|
|
899
874
|
if (filter) {
|
|
900
875
|
filter.focus();
|
|
901
876
|
} else {
|
|
902
877
|
trigger.focus();
|
|
903
878
|
}
|
|
904
|
-
} else {
|
|
905
|
-
selectOption(clickedOption);
|
|
906
879
|
}
|
|
880
|
+
} else {
|
|
881
|
+
if (input.value !== getValue(option)) {
|
|
882
|
+
updateValue(option);
|
|
883
|
+
}
|
|
884
|
+
closePopover();
|
|
907
885
|
}
|
|
908
886
|
});
|
|
909
887
|
|
|
@@ -921,10 +899,41 @@
|
|
|
921
899
|
|
|
922
900
|
popover.setAttribute('aria-hidden', 'true');
|
|
923
901
|
|
|
924
|
-
|
|
902
|
+
// Public API
|
|
903
|
+
Object.defineProperty(selectComponent, 'value', {
|
|
904
|
+
get: () => {
|
|
905
|
+
if (isMultiple) {
|
|
906
|
+
return options.filter(opt => selectedOptions.has(opt)).map(getValue);
|
|
907
|
+
} else {
|
|
908
|
+
return input.value;
|
|
909
|
+
}
|
|
910
|
+
},
|
|
911
|
+
set: (val) => {
|
|
912
|
+
if (isMultiple) {
|
|
913
|
+
const values = Array.isArray(val) ? val : (val != null ? [val] : []);
|
|
914
|
+
const opts = [];
|
|
915
|
+
values.forEach(v => {
|
|
916
|
+
const opt = options.find(o => getValue(o) === v && !opts.includes(o));
|
|
917
|
+
if (opt) opts.push(opt);
|
|
918
|
+
});
|
|
919
|
+
updateValue(opts);
|
|
920
|
+
} else {
|
|
921
|
+
const option = options.find(opt => getValue(opt) === val);
|
|
922
|
+
if (option) {
|
|
923
|
+
updateValue(option);
|
|
924
|
+
closePopover();
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
selectComponent.select = select;
|
|
931
|
+
selectComponent.selectByValue = select; // Backward compatibility alias
|
|
925
932
|
if (isMultiple) {
|
|
926
|
-
selectComponent.
|
|
927
|
-
selectComponent.
|
|
933
|
+
selectComponent.deselect = deselect;
|
|
934
|
+
selectComponent.toggle = toggle;
|
|
935
|
+
selectComponent.selectAll = () => updateValue(options);
|
|
936
|
+
selectComponent.selectNone = () => updateValue([]);
|
|
928
937
|
}
|
|
929
938
|
selectComponent.dataset.selectInitialized = true;
|
|
930
939
|
selectComponent.dispatchEvent(new CustomEvent('basecoat:initialized'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{const e={};let t=null;const n=()=>{Object.entries(e).forEach((([e,{selector:t,init:n}])=>{document.querySelectorAll(t).forEach(n)}))},a=t=>{t.nodeType===Node.ELEMENT_NODE&&Object.entries(e).forEach((([e,{selector:n,init:a}])=>{t.matches(n)&&a(t),t.querySelectorAll(n).forEach(a)}))},i=()=>{t||(t=new MutationObserver((e=>{e.forEach((e=>{e.addedNodes.forEach(a)}))})),t.observe(document.body,{childList:!0,subtree:!0}))};window.basecoat={register:(t,n,a)=>{e[t]={selector:n,init:a}},init:t=>{const n=e[t];if(!n)return void console.warn(`Component '${t}' not found in registry`);const a=`data-${t}-initialized`;document.querySelectorAll(`[${a}]`).forEach((e=>{e.removeAttribute(a)})),document.querySelectorAll(n.selector).forEach(n.init)},initAll:()=>{Object.entries(e).forEach((([e,{selector:t}])=>{const n=`data-${e}-initialized`;document.querySelectorAll(`[${n}]`).forEach((e=>{e.removeAttribute(n)}))})),n()},start:i,stop:()=>{t&&(t.disconnect(),t=null)}},document.addEventListener("DOMContentLoaded",(()=>{n(),i()}))})(),(()=>{const e=e=>{const t=e.querySelector("header input"),n=e.querySelector('[role="menu"]');if(!t||!n){const a=[];return t||a.push("input"),n||a.push("menu"),void console.error(`Command component initialization failed. Missing element(s): ${a.join(", ")}`,e)}const a=Array.from(n.querySelectorAll('[role="menuitem"]')),i=a.filter((e=>!e.hasAttribute("disabled")&&"true"!==e.getAttribute("aria-disabled")));let r=[...i],o=-1;const s=e=>{if(o>-1&&i[o]&&i[o].classList.remove("active"),o=e,o>-1){const e=i[o];e.classList.add("active"),e.id?t.setAttribute("aria-activedescendant",e.id):t.removeAttribute("aria-activedescendant")}else t.removeAttribute("aria-activedescendant")};t.addEventListener("input",(()=>{const e=t.value.trim().toLowerCase();s(-1),r=[],a.forEach((t=>{if(t.hasAttribute("data-force"))return t.setAttribute("aria-hidden","false"),void(i.includes(t)&&r.push(t));const n=(t.dataset.filter||t.textContent).trim().toLowerCase(),a=(t.dataset.keywords||"").toLowerCase().split(/[\s,]+/).filter(Boolean).some((t=>t.includes(e))),o=n.includes(e)||a;t.setAttribute("aria-hidden",String(!o)),o&&i.includes(t)&&r.push(t)})),r.length>0&&(s(i.indexOf(r[0])),r[0].scrollIntoView({block:"nearest"}))}));n.addEventListener("mousemove",(e=>{const t=e.target.closest('[role="menuitem"]');if(t&&r.includes(t)){const e=i.indexOf(t);e!==o&&s(e)}})),n.addEventListener("click",(t=>{const n=t.target.closest('[role="menuitem"]');if(n&&r.includes(n)){const t=e.closest("dialog.command-dialog");t&&!n.hasAttribute("data-keep-command-open")&&t.close()}})),t.addEventListener("keydown",(e=>{if(!["ArrowDown","ArrowUp","Enter","Home","End"].includes(e.key))return;if("Enter"===e.key)return e.preventDefault(),void(o>-1&&i[o]?.click());if(0===r.length)return;e.preventDefault();const t=o>-1?r.indexOf(i[o]):-1;let n=t;switch(e.key){case"ArrowDown":t<r.length-1&&(n=t+1);break;case"ArrowUp":t>0?n=t-1:-1===t&&(n=0);break;case"Home":n=0;break;case"End":n=r.length-1}if(n!==t){const e=r[n];s(i.indexOf(e)),e.scrollIntoView({block:"nearest",behavior:"smooth"})}})),r.length>0&&(s(i.indexOf(r[0])),r[0].scrollIntoView({block:"nearest"})),e.dataset.commandInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("command",".command:not([data-command-initialized])",e)})(),(()=>{const e=e=>{const t=e.querySelector(":scope > button"),n=e.querySelector(":scope > [data-popover]"),a=n.querySelector('[role="menu"]');if(!t||!a||!n){const i=[];return t||i.push("trigger"),a||i.push("menu"),n||i.push("popover"),void console.error(`Dropdown menu initialisation failed. Missing element(s): ${i.join(", ")}`,e)}let i=[],r=-1;const o=(e=!0)=>{"false"!==t.getAttribute("aria-expanded")&&(t.setAttribute("aria-expanded","false"),t.removeAttribute("aria-activedescendant"),n.setAttribute("aria-hidden","true"),e&&t.focus(),d(-1))},s=(r=!1)=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}})),t.setAttribute("aria-expanded","true"),n.setAttribute("aria-hidden","false"),i=Array.from(a.querySelectorAll('[role^="menuitem"]')).filter((e=>!e.hasAttribute("disabled")&&"true"!==e.getAttribute("aria-disabled"))),i.length>0&&r&&("first"===r?d(0):"last"===r&&d(i.length-1))},d=e=>{if(r>-1&&i[r]&&i[r].classList.remove("active"),r=e,r>-1&&i[r]){const e=i[r];e.classList.add("active"),t.setAttribute("aria-activedescendant",e.id)}else t.removeAttribute("aria-activedescendant")};t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?o():s(!1)})),e.addEventListener("keydown",(e=>{const n="true"===t.getAttribute("aria-expanded");if("Escape"===e.key)return void(n&&o());if(!n)return void(["Enter"," "].includes(e.key)?(e.preventDefault(),s(!1)):"ArrowDown"===e.key?(e.preventDefault(),s("first")):"ArrowUp"===e.key&&(e.preventDefault(),s("last")));if(0===i.length)return;let a=r;switch(e.key){case"ArrowDown":e.preventDefault(),a=-1===r?0:Math.min(r+1,i.length-1);break;case"ArrowUp":e.preventDefault(),a=-1===r?i.length-1:Math.max(r-1,0);break;case"Home":e.preventDefault(),a=0;break;case"End":e.preventDefault(),a=i.length-1;break;case"Enter":case" ":return e.preventDefault(),i[r]?.click(),void o()}a!==r&&d(a)})),a.addEventListener("mousemove",(e=>{const t=e.target.closest('[role^="menuitem"]');if(t&&i.includes(t)){const e=i.indexOf(t);e!==r&&d(e)}})),a.addEventListener("mouseleave",(()=>{d(-1)})),a.addEventListener("click",(e=>{e.target.closest('[role^="menuitem"]')&&o()})),document.addEventListener("click",(t=>{e.contains(t.target)||o()})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&o(!1)})),e.dataset.dropdownMenuInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("dropdown-menu",".dropdown-menu:not([data-dropdown-menu-initialized])",e)})(),(()=>{const e=e=>{const t=e.querySelector(":scope > button"),n=e.querySelector(":scope > [data-popover]");if(!t||!n){const a=[];return t||a.push("trigger"),n||a.push("content"),void console.error(`Popover initialisation failed. Missing element(s): ${a.join(", ")}`,e)}const a=(e=!0)=>{"false"!==t.getAttribute("aria-expanded")&&(t.setAttribute("aria-expanded","false"),n.setAttribute("aria-hidden","true"),e&&t.focus())};t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?a():(()=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}}));const a=n.querySelector("[autofocus]");a&&n.addEventListener("transitionend",(()=>{a.focus()}),{once:!0}),t.setAttribute("aria-expanded","true"),n.setAttribute("aria-hidden","false")})()})),e.addEventListener("keydown",(e=>{"Escape"===e.key&&a()})),document.addEventListener("click",(t=>{e.contains(t.target)||a()})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&a(!1)})),e.dataset.popoverInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("popover",".popover:not([data-popover-initialized])",e)})(),(()=>{const e=e=>{const t=e.querySelector(":scope > button"),n=t.querySelector(":scope > span"),a=e.querySelector(":scope > [data-popover]"),i=a?a.querySelector('[role="listbox"]'):null,r=e.querySelector(':scope > input[type="hidden"]'),o=e.querySelector('header input[type="text"]');if(!(t&&a&&i&&r)){const n=[];return t||n.push("trigger"),a||n.push("popover"),i||n.push("listbox"),r||n.push("input"),void console.error(`Select component initialisation failed. Missing element(s): ${n.join(", ")}`,e)}const s=Array.from(i.querySelectorAll('[role="option"]')),d=s.filter((e=>"true"!==e.getAttribute("aria-disabled")));let c=[...d],l=-1;const u="true"===i.getAttribute("aria-multiselectable");let v=u?new Set:null,p=null;u&&(p=e.dataset.placeholder||"");const m=e=>{if(l>-1&&d[l]&&d[l].classList.remove("active"),l=e,l>-1){const e=d[l];e.classList.add("active"),e.id?t.setAttribute("aria-activedescendant",e.id):t.removeAttribute("aria-activedescendant")}else t.removeAttribute("aria-activedescendant")},f=()=>{const e=getComputedStyle(a);return parseFloat(e.transitionDuration)>0||parseFloat(e.transitionDelay)>0},h=(t,a=!0)=>{let i;if(u){const a=Array.isArray(t)?t:[];v=new Set(a.map((e=>e.dataset.value))),d.forEach((e=>{v.has(e.dataset.value)?e.setAttribute("aria-selected","true"):e.removeAttribute("aria-selected")})),(()=>{if(!u)return;const e=d.filter((e=>v.has(e.dataset.value)));0===e.length?(n.textContent=p,n.classList.add("text-muted-foreground")):(n.textContent=e.map((e=>e.dataset.label||e.textContent.trim())).join(", "),n.classList.remove("text-muted-foreground"))})(),(()=>{if(!u)return;const t=Array.from(v);if(Array.from(e.querySelectorAll(':scope > input[type="hidden"]')).slice(1).forEach((e=>e.remove())),0===t.length)r.value="";else{r.value=t[0];let e=r;for(let n=1;n<t.length;n++){const a=r.cloneNode(!0);a.removeAttribute("id"),a.value=t[n],e.after(a),e=a}}})(),i=Array.from(v)}else{const e=t;if(!e)return;n.innerHTML=e.innerHTML,r.value=e.dataset.value,d.forEach((t=>{t===e?t.setAttribute("aria-selected","true"):t.removeAttribute("aria-selected")})),i=e.dataset.value}a&&e.dispatchEvent(new CustomEvent("change",{detail:{value:i},bubbles:!0}))},b=(e,t=!0)=>{if(!u||null==e)return;const n=new Set(v);n.has(e)?n.delete(e):n.add(e);const a=d.filter((e=>n.has(e.dataset.value)));h(a,t)},w=(e=!0)=>{if("true"!==a.getAttribute("aria-hidden")){if(o){const e=()=>{o.value="",c=[...d],s.forEach((e=>e.setAttribute("aria-hidden","false")))};f()?a.addEventListener("transitionend",e,{once:!0}):e()}e&&t.focus(),a.setAttribute("aria-hidden","true"),t.setAttribute("aria-expanded","false"),m(-1)}},g=e=>{if(!e)return;const t=r.value,n=e.dataset.value;null!=n&&n!==t&&h(e),w()},E=()=>{u&&h(d.filter((e=>null!=e.dataset.value)))},A=()=>{u&&h([])};if(o){const e=()=>{const e=o.value.trim().toLowerCase();m(-1),c=[],s.forEach((t=>{if(t.hasAttribute("data-force"))return t.setAttribute("aria-hidden","false"),void(d.includes(t)&&c.push(t));const n=(t.dataset.filter||t.textContent).trim().toLowerCase(),a=(t.dataset.keywords||"").toLowerCase().split(/[\s,]+/).filter(Boolean).some((t=>t.includes(e))),i=n.includes(e)||a;t.setAttribute("aria-hidden",String(!i)),i&&d.includes(t)&&c.push(t)}))};o.addEventListener("input",e)}if(u){const t=new Set(d.map((e=>e.dataset.value)).filter((e=>null!=e))),n=Array.from(e.querySelectorAll(':scope > input[type="hidden"]')).map((e=>e.value)).filter((e=>null!=e&&t.has(e)));let a;a=n.length>0?d.filter((e=>n.includes(e.dataset.value))):d.filter((e=>"true"===e.getAttribute("aria-selected"))),h(a,!1)}else{let e=d.find((e=>e.dataset.value===r.value));e||(e=d.find((e=>void 0!==e.dataset.value))??d[0]),e&&h(e,!1)}const y=e=>{const n="false"===a.getAttribute("aria-hidden");if(!["ArrowDown","ArrowUp","Enter","Home","End","Escape"].includes(e.key))return;if(!n)return void("Enter"!==e.key&&"Escape"!==e.key&&(e.preventDefault(),t.click()));if(e.preventDefault(),"Escape"===e.key)return void w();if("Enter"===e.key)return void(l>-1&&(u?b(d[l].dataset.value):g(d[l])));if(0===c.length)return;const i=l>-1?c.indexOf(d[l]):-1;let r=i;switch(e.key){case"ArrowDown":i<c.length-1&&(r=i+1);break;case"ArrowUp":i>0?r=i-1:-1===i&&(r=0);break;case"Home":r=0;break;case"End":r=c.length-1}if(r!==i){const e=c[r];m(d.indexOf(e)),e.scrollIntoView({block:"nearest",behavior:"smooth"})}};i.addEventListener("mousemove",(e=>{const t=e.target.closest('[role="option"]');if(t&&c.includes(t)){const e=d.indexOf(t);e!==l&&m(e)}})),i.addEventListener("mouseleave",(()=>{const e=i.querySelector('[role="option"][aria-selected="true"]');m(e?d.indexOf(e):-1)})),t.addEventListener("keydown",y),o&&o.addEventListener("keydown",y);t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?w():(()=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}})),o&&(f()?a.addEventListener("transitionend",(()=>{o.focus()}),{once:!0}):o.focus()),a.setAttribute("aria-hidden","false"),t.setAttribute("aria-expanded","true");const n=i.querySelector('[role="option"][aria-selected="true"]');n&&(m(d.indexOf(n)),n.scrollIntoView({block:"nearest"}))})()})),i.addEventListener("click",(e=>{const n=e.target.closest('[role="option"]');n&&(u?(b(n.dataset.value),m(d.indexOf(n)),o?o.focus():t.focus()):g(n))})),document.addEventListener("click",(t=>{e.contains(t.target)||w(!1)})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&w(!1)})),a.setAttribute("aria-hidden","true"),e.selectByValue=e=>{const t=d.find((t=>t.dataset.value===e));if(u){if(null!=e&&v.has(e))return;if(t&&null!=e){const t=new Set(v);t.add(e);const n=d.filter((e=>t.has(e.dataset.value)));h(n)}}else g(t)},u&&(e.selectAll=E,e.selectNone=A),e.dataset.selectInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("select","div.select:not([data-select-initialized])",e)})(),(()=>{if(!window.history.__basecoatPatched){const e=window.history.pushState;window.history.pushState=function(...t){e.apply(this,t),window.dispatchEvent(new Event("basecoat:locationchange"))};const t=window.history.replaceState;window.history.replaceState=function(...e){t.apply(this,e),window.dispatchEvent(new Event("basecoat:locationchange"))},window.history.__basecoatPatched=!0}const e=e=>{const t="false"!==e.dataset.initialOpen,n="true"===e.dataset.initialMobileOpen,a=parseInt(e.dataset.breakpoint)||768;let i=a>0?window.innerWidth>=a?t:n:t;const r=()=>{const t=window.location.pathname.replace(/\/$/,"");e.querySelectorAll("a").forEach((e=>{if(e.hasAttribute("data-ignore-current"))return;new URL(e.href).pathname.replace(/\/$/,"")===t?e.setAttribute("aria-current","page"):e.removeAttribute("aria-current")}))},o=()=>{e.setAttribute("aria-hidden",!i),i?e.removeAttribute("inert"):e.setAttribute("inert","")},s=e=>{i=e,o()},d=e.id;document.addEventListener("basecoat:sidebar",(e=>{if(!e.detail?.id||e.detail.id===d)switch(e.detail?.action){case"open":s(!0);break;case"close":s(!1);break;default:s(!i)}})),e.addEventListener("click",(t=>{const n=t.target,i=e.querySelector("nav");if(window.innerWidth<a&&n.closest("a, button")&&!n.closest("[data-keep-mobile-sidebar-open]"))return document.activeElement&&document.activeElement.blur(),void s(!1);(n===e||i&&!i.contains(n))&&(document.activeElement&&document.activeElement.blur(),s(!1))})),window.addEventListener("popstate",r),window.addEventListener("basecoat:locationchange",r),o(),r(),e.dataset.sidebarInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("sidebar",".sidebar:not([data-sidebar-initialized])",e)})(),(()=>{const e=e=>{const t=e.querySelector('[role="tablist"]');if(!t)return;const n=Array.from(t.querySelectorAll('[role="tab"]')),a=n.map((e=>document.getElementById(e.getAttribute("aria-controls")))).filter(Boolean),i=e=>{n.forEach(((e,t)=>{e.setAttribute("aria-selected","false"),e.setAttribute("tabindex","-1"),a[t]&&(a[t].hidden=!0)})),e.setAttribute("aria-selected","true"),e.setAttribute("tabindex","0");const t=document.getElementById(e.getAttribute("aria-controls"));t&&(t.hidden=!1)};t.addEventListener("click",(e=>{const t=e.target.closest('[role="tab"]');t&&i(t)})),t.addEventListener("keydown",(e=>{const t=e.target;if(!n.includes(t))return;let a;const r=n.indexOf(t);switch(e.key){case"ArrowRight":a=n[(r+1)%n.length];break;case"ArrowLeft":a=n[(r-1+n.length)%n.length];break;case"Home":a=n[0];break;case"End":a=n[n.length-1];break;default:return}e.preventDefault(),i(a),a.focus()})),e.dataset.tabsInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("tabs",".tabs:not([data-tabs-initialized])",e)})(),(()=>{let e;const t=new WeakMap;let n=!1;const a={success:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>',error:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>',info:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',warning:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>'};function i(e){if(e.dataset.toastInitialized)return;const a=parseInt(e.dataset.duration),i=-1!==a?a||("error"===e.dataset.category?5e3:3e3):-1,r={remainingTime:i,timeoutId:null,startTime:null};-1!==i&&(n?r.timeoutId=null:(r.startTime=Date.now(),r.timeoutId=setTimeout((()=>s(e)),i))),t.set(e,r),e.dataset.toastInitialized="true"}function r(){n||(n=!0,e.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((e=>{if(!t.has(e))return;const n=t.get(e);n.timeoutId&&(clearTimeout(n.timeoutId),n.timeoutId=null,n.remainingTime-=Date.now()-n.startTime)})))}function o(){n&&(n=!1,e.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((e=>{if(!t.has(e))return;const n=t.get(e);-1===n.remainingTime||n.timeoutId||(n.remainingTime>0?(n.startTime=Date.now(),n.timeoutId=setTimeout((()=>s(e)),n.remainingTime)):s(e))})))}function s(e){if(!t.has(e))return;const n=t.get(e);clearTimeout(n.timeoutId),t.delete(e),e.contains(document.activeElement)&&document.activeElement.blur(),e.setAttribute("aria-hidden","true"),e.addEventListener("transitionend",(()=>e.remove()),{once:!0})}document.addEventListener("basecoat:toast",(t=>{if(!e)return void console.error("Cannot create toast: toaster container not found on page.");const n=function(e){const{category:t="info",title:n,description:i,action:r,cancel:o,duration:s,icon:d}=e,c=d||t&&a[t]||"",l=n?`<h2>${n}</h2>`:"",u=i?`<p>${i}</p>`:"",v=r?.href?`<a href="${r.href}" class="btn" data-toast-action>${r.label}</a>`:r?.onclick?`<button type="button" class="btn" data-toast-action onclick="${r.onclick}">${r.label}</button>`:"",p=o?`<button type="button" class="btn-outline h-6 text-xs px-2.5 rounded-sm" data-toast-cancel onclick="${o?.onclick}">${o.label}</button>`:"",m=`\n <div\n class="toast"\n role="${"error"===t?"alert":"status"}"\n aria-atomic="true"\n ${t?`data-category="${t}"`:""}\n ${void 0!==s?`data-duration="${s}"`:""}\n >\n <div class="toast-content">\n ${c}\n <section>\n ${l}\n ${u}\n </section>\n ${v||p?`<footer>${v}${p}</footer>`:""}\n </div>\n </div>\n </div>\n `,f=document.createElement("template");return f.innerHTML=m.trim(),f.content.firstChild}(t.detail?.config||{});e.appendChild(n)})),window.basecoat&&(window.basecoat.register("toaster","#toaster:not([data-toaster-initialized])",(function(t){t.dataset.toasterInitialized||(e=t,e.addEventListener("mouseenter",r),e.addEventListener("mouseleave",o),e.addEventListener("click",(e=>{const t=e.target.closest(".toast footer a"),n=e.target.closest(".toast footer button");(t||n)&&s(e.target.closest(".toast"))})),e.querySelectorAll(".toast:not([data-toast-initialized])").forEach(i),e.dataset.toasterInitialized="true",e.dispatchEvent(new CustomEvent("basecoat:initialized")))})),window.basecoat.register("toast",".toast:not([data-toast-initialized])",i))})();
|
|
1
|
+
(()=>{const e={};let t=null;const n=()=>{Object.entries(e).forEach((([e,{selector:t,init:n}])=>{document.querySelectorAll(t).forEach(n)}))},i=t=>{t.nodeType===Node.ELEMENT_NODE&&Object.entries(e).forEach((([e,{selector:n,init:i}])=>{t.matches(n)&&i(t),t.querySelectorAll(n).forEach(i)}))},a=()=>{t||(t=new MutationObserver((e=>{e.forEach((e=>{e.addedNodes.forEach(i)}))})),t.observe(document.body,{childList:!0,subtree:!0}))};window.basecoat={register:(t,n,i)=>{e[t]={selector:n,init:i}},init:t=>{const n=e[t];if(!n)return void console.warn(`Component '${t}' not found in registry`);const i=`data-${t}-initialized`;document.querySelectorAll(`[${i}]`).forEach((e=>{e.removeAttribute(i)})),document.querySelectorAll(n.selector).forEach(n.init)},initAll:()=>{Object.entries(e).forEach((([e,{selector:t}])=>{const n=`data-${e}-initialized`;document.querySelectorAll(`[${n}]`).forEach((e=>{e.removeAttribute(n)}))})),n()},start:a,stop:()=>{t&&(t.disconnect(),t=null)}},document.addEventListener("DOMContentLoaded",(()=>{n(),a()}))})(),(()=>{const e=e=>{const t=e.querySelector("header input"),n=e.querySelector('[role="menu"]');if(!t||!n){const i=[];return t||i.push("input"),n||i.push("menu"),void console.error(`Command component initialization failed. Missing element(s): ${i.join(", ")}`,e)}const i=Array.from(n.querySelectorAll('[role="menuitem"]')),a=i.filter((e=>!e.hasAttribute("disabled")&&"true"!==e.getAttribute("aria-disabled")));let r=[...a],o=-1;const s=e=>{if(o>-1&&a[o]&&a[o].classList.remove("active"),o=e,o>-1){const e=a[o];e.classList.add("active"),e.id?t.setAttribute("aria-activedescendant",e.id):t.removeAttribute("aria-activedescendant")}else t.removeAttribute("aria-activedescendant")};t.addEventListener("input",(()=>{const e=t.value.trim().toLowerCase();s(-1),r=[],i.forEach((t=>{if(t.hasAttribute("data-force"))return t.setAttribute("aria-hidden","false"),void(a.includes(t)&&r.push(t));const n=(t.dataset.filter||t.textContent).trim().toLowerCase(),i=(t.dataset.keywords||"").toLowerCase().split(/[\s,]+/).filter(Boolean).some((t=>t.includes(e))),o=n.includes(e)||i;t.setAttribute("aria-hidden",String(!o)),o&&a.includes(t)&&r.push(t)})),r.length>0&&(s(a.indexOf(r[0])),r[0].scrollIntoView({block:"nearest"}))}));n.addEventListener("mousemove",(e=>{const t=e.target.closest('[role="menuitem"]');if(t&&r.includes(t)){const e=a.indexOf(t);e!==o&&s(e)}})),n.addEventListener("click",(t=>{const n=t.target.closest('[role="menuitem"]');if(n&&r.includes(n)){const t=e.closest("dialog.command-dialog");t&&!n.hasAttribute("data-keep-command-open")&&t.close()}})),t.addEventListener("keydown",(e=>{if(!["ArrowDown","ArrowUp","Enter","Home","End"].includes(e.key))return;if("Enter"===e.key)return e.preventDefault(),void(o>-1&&a[o]?.click());if(0===r.length)return;e.preventDefault();const t=o>-1?r.indexOf(a[o]):-1;let n=t;switch(e.key){case"ArrowDown":t<r.length-1&&(n=t+1);break;case"ArrowUp":t>0?n=t-1:-1===t&&(n=0);break;case"Home":n=0;break;case"End":n=r.length-1}if(n!==t){const e=r[n];s(a.indexOf(e)),e.scrollIntoView({block:"nearest",behavior:"smooth"})}})),r.length>0&&(s(a.indexOf(r[0])),r[0].scrollIntoView({block:"nearest"})),e.dataset.commandInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("command",".command:not([data-command-initialized])",e)})(),(()=>{const e=e=>{const t=e.querySelector(":scope > button"),n=e.querySelector(":scope > [data-popover]"),i=n.querySelector('[role="menu"]');if(!t||!i||!n){const a=[];return t||a.push("trigger"),i||a.push("menu"),n||a.push("popover"),void console.error(`Dropdown menu initialisation failed. Missing element(s): ${a.join(", ")}`,e)}let a=[],r=-1;const o=(e=!0)=>{"false"!==t.getAttribute("aria-expanded")&&(t.setAttribute("aria-expanded","false"),t.removeAttribute("aria-activedescendant"),n.setAttribute("aria-hidden","true"),e&&t.focus(),d(-1))},s=(r=!1)=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}})),t.setAttribute("aria-expanded","true"),n.setAttribute("aria-hidden","false"),a=Array.from(i.querySelectorAll('[role^="menuitem"]')).filter((e=>!e.hasAttribute("disabled")&&"true"!==e.getAttribute("aria-disabled"))),a.length>0&&r&&("first"===r?d(0):"last"===r&&d(a.length-1))},d=e=>{if(r>-1&&a[r]&&a[r].classList.remove("active"),r=e,r>-1&&a[r]){const e=a[r];e.classList.add("active"),t.setAttribute("aria-activedescendant",e.id)}else t.removeAttribute("aria-activedescendant")};t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?o():s(!1)})),e.addEventListener("keydown",(e=>{const n="true"===t.getAttribute("aria-expanded");if("Escape"===e.key)return void(n&&o());if(!n)return void(["Enter"," "].includes(e.key)?(e.preventDefault(),s(!1)):"ArrowDown"===e.key?(e.preventDefault(),s("first")):"ArrowUp"===e.key&&(e.preventDefault(),s("last")));if(0===a.length)return;let i=r;switch(e.key){case"ArrowDown":e.preventDefault(),i=-1===r?0:Math.min(r+1,a.length-1);break;case"ArrowUp":e.preventDefault(),i=-1===r?a.length-1:Math.max(r-1,0);break;case"Home":e.preventDefault(),i=0;break;case"End":e.preventDefault(),i=a.length-1;break;case"Enter":case" ":return e.preventDefault(),a[r]?.click(),void o()}i!==r&&d(i)})),i.addEventListener("mousemove",(e=>{const t=e.target.closest('[role^="menuitem"]');if(t&&a.includes(t)){const e=a.indexOf(t);e!==r&&d(e)}})),i.addEventListener("mouseleave",(()=>{d(-1)})),i.addEventListener("click",(e=>{e.target.closest('[role^="menuitem"]')&&o()})),document.addEventListener("click",(t=>{e.contains(t.target)||o()})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&o(!1)})),e.dataset.dropdownMenuInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("dropdown-menu",".dropdown-menu:not([data-dropdown-menu-initialized])",e)})(),(()=>{const e=e=>{const t=e.querySelector(":scope > button"),n=e.querySelector(":scope > [data-popover]");if(!t||!n){const i=[];return t||i.push("trigger"),n||i.push("content"),void console.error(`Popover initialisation failed. Missing element(s): ${i.join(", ")}`,e)}const i=(e=!0)=>{"false"!==t.getAttribute("aria-expanded")&&(t.setAttribute("aria-expanded","false"),n.setAttribute("aria-hidden","true"),e&&t.focus())};t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?i():(()=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}}));const i=n.querySelector("[autofocus]");i&&n.addEventListener("transitionend",(()=>{i.focus()}),{once:!0}),t.setAttribute("aria-expanded","true"),n.setAttribute("aria-hidden","false")})()})),e.addEventListener("keydown",(e=>{"Escape"===e.key&&i()})),document.addEventListener("click",(t=>{e.contains(t.target)||i()})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&i(!1)})),e.dataset.popoverInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("popover",".popover:not([data-popover-initialized])",e)})(),(()=>{const e=e=>{const t=e.querySelector(":scope > button"),n=t.querySelector(":scope > span"),i=e.querySelector(":scope > [data-popover]"),a=i?i.querySelector('[role="listbox"]'):null,r=e.querySelector(':scope > input[type="hidden"]'),o=e.querySelector('header input[type="text"]');if(!(t&&i&&a&&r)){const n=[];return t||n.push("trigger"),i||n.push("popover"),a||n.push("listbox"),r||n.push("input"),void console.error(`Select component initialisation failed. Missing element(s): ${n.join(", ")}`,e)}const s=Array.from(a.querySelectorAll('[role="option"]')),d=s.filter((e=>"true"!==e.getAttribute("aria-disabled")));let c=[...d],l=-1;const u="true"===a.getAttribute("aria-multiselectable"),p=u?new Set:null,v=u?e.dataset.placeholder||"":null,h="true"===e.dataset.closeOnSelect,f=e=>e.dataset.value??e.textContent.trim(),m=e=>{if(l>-1&&d[l]&&d[l].classList.remove("active"),l=e,l>-1){const e=d[l];e.classList.add("active"),e.id?t.setAttribute("aria-activedescendant",e.id):t.removeAttribute("aria-activedescendant")}else t.removeAttribute("aria-activedescendant")},b=()=>{const e=getComputedStyle(i);return parseFloat(e.transitionDuration)>0||parseFloat(e.transitionDelay)>0},w=(t,i=!0)=>{let a;if(u){const e=Array.isArray(t)?t:[];p.clear(),e.forEach((e=>p.add(e)));const i=d.filter((e=>p.has(e)));0===i.length?(n.textContent=v,n.classList.add("text-muted-foreground")):(n.textContent=i.map((e=>e.dataset.label||e.textContent.trim())).join(", "),n.classList.remove("text-muted-foreground")),a=i.map(f),r.value=JSON.stringify(a)}else{const e=t;if(!e)return;n.innerHTML=e.innerHTML,a=f(e),r.value=a}d.forEach((e=>{(u?p.has(e):e===t)?e.setAttribute("aria-selected","true"):e.removeAttribute("aria-selected")})),i&&e.dispatchEvent(new CustomEvent("change",{detail:{value:a},bubbles:!0}))},g=(e=!0)=>{if("true"!==i.getAttribute("aria-hidden")){if(o){const e=()=>{o.value="",c=[...d],s.forEach((e=>e.setAttribute("aria-hidden","false")))};b()?i.addEventListener("transitionend",e,{once:!0}):e()}e&&t.focus(),i.setAttribute("aria-hidden","true"),t.setAttribute("aria-expanded","false"),m(-1)}},E=e=>{p.has(e)?p.delete(e):p.add(e),w(d.filter((e=>p.has(e))))},A=e=>{if(u){const t=d.find((t=>f(t)===e&&!p.has(t)));if(!t)return;p.add(t),w(d.filter((e=>p.has(e))))}else{const t=d.find((t=>f(t)===e));if(!t)return;r.value!==e&&w(t),g()}},y=e=>{if(!u)return;const t=d.find((t=>f(t)===e&&p.has(t)));t&&(p.delete(t),w(d.filter((e=>p.has(e)))))},k=e=>{if(!u)return;const t=d.find((t=>f(t)===e));t&&E(t)};if(o){const e=()=>{const e=o.value.trim().toLowerCase();m(-1),c=[],s.forEach((t=>{if(t.hasAttribute("data-force"))return t.setAttribute("aria-hidden","false"),void(d.includes(t)&&c.push(t));const n=(t.dataset.filter||t.textContent).trim().toLowerCase(),i=(t.dataset.keywords||"").toLowerCase().split(/[\s,]+/).filter(Boolean).some((t=>t.includes(e))),a=n.includes(e)||i;t.setAttribute("aria-hidden",String(!a)),a&&d.includes(t)&&c.push(t)}))};o.addEventListener("input",e)}if(u){const e=d.filter((e=>"true"===e.getAttribute("aria-selected")));try{const t=JSON.parse(r.value||"[]"),n=new Set(d.map(f)),i=Array.isArray(t)?t.filter((e=>n.has(e))):[],a=[];i.length>0?i.forEach((e=>{const t=d.find((t=>f(t)===e&&!a.includes(t)));t&&a.push(t)})):a.push(...e),w(a,!1)}catch(t){w(e,!1)}}else{const e=d.find((e=>f(e)===r.value))||d[0];e&&w(e,!1)}const L=e=>{const n="false"===i.getAttribute("aria-hidden");if(!["ArrowDown","ArrowUp","Enter","Home","End","Escape"].includes(e.key))return;if(!n)return void("Enter"!==e.key&&"Escape"!==e.key&&(e.preventDefault(),t.click()));if(e.preventDefault(),"Escape"===e.key)return void g();if("Enter"===e.key){if(l>-1){const e=d[l];u?(E(e),h&&g()):(r.value!==f(e)&&w(e),g())}return}if(0===c.length)return;const a=l>-1?c.indexOf(d[l]):-1;let o=a;switch(e.key){case"ArrowDown":a<c.length-1&&(o=a+1);break;case"ArrowUp":a>0?o=a-1:-1===a&&(o=0);break;case"Home":o=0;break;case"End":o=c.length-1}if(o!==a){const e=c[o];m(d.indexOf(e)),e.scrollIntoView({block:"nearest",behavior:"smooth"})}};a.addEventListener("mousemove",(e=>{const t=e.target.closest('[role="option"]');if(t&&c.includes(t)){const e=d.indexOf(t);e!==l&&m(e)}})),a.addEventListener("mouseleave",(()=>{const e=a.querySelector('[role="option"][aria-selected="true"]');m(e?d.indexOf(e):-1)})),t.addEventListener("keydown",L),o&&o.addEventListener("keydown",L);t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?g():(()=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}})),o&&(b()?i.addEventListener("transitionend",(()=>{o.focus()}),{once:!0}):o.focus()),i.setAttribute("aria-hidden","false"),t.setAttribute("aria-expanded","true");const n=a.querySelector('[role="option"][aria-selected="true"]');n&&(m(d.indexOf(n)),n.scrollIntoView({block:"nearest"}))})()})),a.addEventListener("click",(e=>{const n=e.target.closest('[role="option"]');if(!n)return;const i=d.find((e=>e===n));i&&(u?(E(i),h?g():(m(d.indexOf(i)),o?o.focus():t.focus())):(r.value!==f(i)&&w(i),g()))})),document.addEventListener("click",(t=>{e.contains(t.target)||g(!1)})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&g(!1)})),i.setAttribute("aria-hidden","true"),Object.defineProperty(e,"value",{get:()=>u?d.filter((e=>p.has(e))).map(f):r.value,set:e=>{if(u){const t=Array.isArray(e)?e:null!=e?[e]:[],n=[];t.forEach((e=>{const t=d.find((t=>f(t)===e&&!n.includes(t)));t&&n.push(t)})),w(n)}else{const t=d.find((t=>f(t)===e));t&&(w(t),g())}}}),e.select=A,e.selectByValue=A,u&&(e.deselect=y,e.toggle=k,e.selectAll=()=>w(d),e.selectNone=()=>w([])),e.dataset.selectInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("select","div.select:not([data-select-initialized])",e)})(),(()=>{if(!window.history.__basecoatPatched){const e=window.history.pushState;window.history.pushState=function(...t){e.apply(this,t),window.dispatchEvent(new Event("basecoat:locationchange"))};const t=window.history.replaceState;window.history.replaceState=function(...e){t.apply(this,e),window.dispatchEvent(new Event("basecoat:locationchange"))},window.history.__basecoatPatched=!0}const e=e=>{const t="false"!==e.dataset.initialOpen,n="true"===e.dataset.initialMobileOpen,i=parseInt(e.dataset.breakpoint)||768;let a=i>0?window.innerWidth>=i?t:n:t;const r=()=>{const t=window.location.pathname.replace(/\/$/,"");e.querySelectorAll("a").forEach((e=>{if(e.hasAttribute("data-ignore-current"))return;new URL(e.href).pathname.replace(/\/$/,"")===t?e.setAttribute("aria-current","page"):e.removeAttribute("aria-current")}))},o=()=>{e.setAttribute("aria-hidden",!a),a?e.removeAttribute("inert"):e.setAttribute("inert","")},s=e=>{a=e,o()},d=e.id;document.addEventListener("basecoat:sidebar",(e=>{if(!e.detail?.id||e.detail.id===d)switch(e.detail?.action){case"open":s(!0);break;case"close":s(!1);break;default:s(!a)}})),e.addEventListener("click",(t=>{const n=t.target,a=e.querySelector("nav");if(window.innerWidth<i&&n.closest("a, button")&&!n.closest("[data-keep-mobile-sidebar-open]"))return document.activeElement&&document.activeElement.blur(),void s(!1);(n===e||a&&!a.contains(n))&&(document.activeElement&&document.activeElement.blur(),s(!1))})),window.addEventListener("popstate",r),window.addEventListener("basecoat:locationchange",r),o(),r(),e.dataset.sidebarInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("sidebar",".sidebar:not([data-sidebar-initialized])",e)})(),(()=>{const e=e=>{const t=e.querySelector('[role="tablist"]');if(!t)return;const n=Array.from(t.querySelectorAll('[role="tab"]')),i=n.map((e=>document.getElementById(e.getAttribute("aria-controls")))).filter(Boolean),a=e=>{n.forEach(((e,t)=>{e.setAttribute("aria-selected","false"),e.setAttribute("tabindex","-1"),i[t]&&(i[t].hidden=!0)})),e.setAttribute("aria-selected","true"),e.setAttribute("tabindex","0");const t=document.getElementById(e.getAttribute("aria-controls"));t&&(t.hidden=!1)};t.addEventListener("click",(e=>{const t=e.target.closest('[role="tab"]');t&&a(t)})),t.addEventListener("keydown",(e=>{const t=e.target;if(!n.includes(t))return;let i;const r=n.indexOf(t);switch(e.key){case"ArrowRight":i=n[(r+1)%n.length];break;case"ArrowLeft":i=n[(r-1+n.length)%n.length];break;case"Home":i=n[0];break;case"End":i=n[n.length-1];break;default:return}e.preventDefault(),a(i),i.focus()})),e.dataset.tabsInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("tabs",".tabs:not([data-tabs-initialized])",e)})(),(()=>{let e;const t=new WeakMap;let n=!1;const i={success:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>',error:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>',info:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>',warning:'<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>'};function a(e){if(e.dataset.toastInitialized)return;const i=parseInt(e.dataset.duration),a=-1!==i?i||("error"===e.dataset.category?5e3:3e3):-1,r={remainingTime:a,timeoutId:null,startTime:null};-1!==a&&(n?r.timeoutId=null:(r.startTime=Date.now(),r.timeoutId=setTimeout((()=>s(e)),a))),t.set(e,r),e.dataset.toastInitialized="true"}function r(){n||(n=!0,e.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((e=>{if(!t.has(e))return;const n=t.get(e);n.timeoutId&&(clearTimeout(n.timeoutId),n.timeoutId=null,n.remainingTime-=Date.now()-n.startTime)})))}function o(){n&&(n=!1,e.querySelectorAll('.toast:not([aria-hidden="true"])').forEach((e=>{if(!t.has(e))return;const n=t.get(e);-1===n.remainingTime||n.timeoutId||(n.remainingTime>0?(n.startTime=Date.now(),n.timeoutId=setTimeout((()=>s(e)),n.remainingTime)):s(e))})))}function s(e){if(!t.has(e))return;const n=t.get(e);clearTimeout(n.timeoutId),t.delete(e),e.contains(document.activeElement)&&document.activeElement.blur(),e.setAttribute("aria-hidden","true"),e.addEventListener("transitionend",(()=>e.remove()),{once:!0})}document.addEventListener("basecoat:toast",(t=>{if(!e)return void console.error("Cannot create toast: toaster container not found on page.");const n=function(e){const{category:t="info",title:n,description:a,action:r,cancel:o,duration:s,icon:d}=e,c=d||t&&i[t]||"",l=n?`<h2>${n}</h2>`:"",u=a?`<p>${a}</p>`:"",p=r?.href?`<a href="${r.href}" class="btn" data-toast-action>${r.label}</a>`:r?.onclick?`<button type="button" class="btn" data-toast-action onclick="${r.onclick}">${r.label}</button>`:"",v=o?`<button type="button" class="btn-outline h-6 text-xs px-2.5 rounded-sm" data-toast-cancel onclick="${o?.onclick}">${o.label}</button>`:"",h=`\n <div\n class="toast"\n role="${"error"===t?"alert":"status"}"\n aria-atomic="true"\n ${t?`data-category="${t}"`:""}\n ${void 0!==s?`data-duration="${s}"`:""}\n >\n <div class="toast-content">\n ${c}\n <section>\n ${l}\n ${u}\n </section>\n ${p||v?`<footer>${p}${v}</footer>`:""}\n </div>\n </div>\n </div>\n `,f=document.createElement("template");return f.innerHTML=h.trim(),f.content.firstChild}(t.detail?.config||{});e.appendChild(n)})),window.basecoat&&(window.basecoat.register("toaster","#toaster:not([data-toaster-initialized])",(function(t){t.dataset.toasterInitialized||(e=t,e.addEventListener("mouseenter",r),e.addEventListener("mouseleave",o),e.addEventListener("click",(e=>{const t=e.target.closest(".toast footer a"),n=e.target.closest(".toast footer button");(t||n)&&s(e.target.closest(".toast"))})),e.querySelectorAll(".toast:not([data-toast-initialized])").forEach(a),e.dataset.toasterInitialized="true",e.dispatchEvent(new CustomEvent("basecoat:initialized")))})),window.basecoat.register("toast",".toast:not([data-toast-initialized])",a))})();
|
package/dist/assets/js/select.js
CHANGED
|
@@ -22,20 +22,19 @@
|
|
|
22
22
|
let visibleOptions = [...options];
|
|
23
23
|
let activeIndex = -1;
|
|
24
24
|
const isMultiple = listbox.getAttribute('aria-multiselectable') === 'true';
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const selectedOptions = isMultiple ? new Set() : null;
|
|
26
|
+
const placeholder = isMultiple ? (selectComponent.dataset.placeholder || '') : null;
|
|
27
|
+
const closeOnSelect = selectComponent.dataset.closeOnSelect === 'true';
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
placeholder = selectComponent.dataset.placeholder || '';
|
|
30
|
-
}
|
|
29
|
+
const getValue = (opt) => opt.dataset.value ?? opt.textContent.trim();
|
|
31
30
|
|
|
32
31
|
const setActiveOption = (index) => {
|
|
33
32
|
if (activeIndex > -1 && options[activeIndex]) {
|
|
34
33
|
options[activeIndex].classList.remove('active');
|
|
35
34
|
}
|
|
36
|
-
|
|
35
|
+
|
|
37
36
|
activeIndex = index;
|
|
38
|
-
|
|
37
|
+
|
|
39
38
|
if (activeIndex > -1) {
|
|
40
39
|
const activeOption = options[activeIndex];
|
|
41
40
|
activeOption.classList.add('active');
|
|
@@ -54,70 +53,43 @@
|
|
|
54
53
|
return parseFloat(style.transitionDuration) > 0 || parseFloat(style.transitionDelay) > 0;
|
|
55
54
|
};
|
|
56
55
|
|
|
57
|
-
const syncMultipleInputs = () => {
|
|
58
|
-
if (!isMultiple) return;
|
|
59
|
-
const values = Array.from(selectedValues);
|
|
60
|
-
const inputs = Array.from(selectComponent.querySelectorAll(':scope > input[type="hidden"]'));
|
|
61
|
-
inputs.slice(1).forEach(inp => inp.remove());
|
|
62
|
-
|
|
63
|
-
if (values.length === 0) {
|
|
64
|
-
input.value = '';
|
|
65
|
-
} else {
|
|
66
|
-
input.value = values[0];
|
|
67
|
-
let insertAfter = input;
|
|
68
|
-
for (let i = 1; i < values.length; i++) {
|
|
69
|
-
const clone = input.cloneNode(true);
|
|
70
|
-
clone.removeAttribute('id');
|
|
71
|
-
clone.value = values[i];
|
|
72
|
-
insertAfter.after(clone);
|
|
73
|
-
insertAfter = clone;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const updateMultipleLabel = () => {
|
|
79
|
-
if (!isMultiple) return;
|
|
80
|
-
const selected = options.filter(opt => selectedValues.has(opt.dataset.value));
|
|
81
|
-
if (selected.length === 0) {
|
|
82
|
-
selectedLabel.textContent = placeholder;
|
|
83
|
-
selectedLabel.classList.add('text-muted-foreground');
|
|
84
|
-
} else {
|
|
85
|
-
selectedLabel.textContent = selected.map(opt => opt.dataset.label || opt.textContent.trim()).join(', ');
|
|
86
|
-
selectedLabel.classList.remove('text-muted-foreground');
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
56
|
const updateValue = (optionOrOptions, triggerEvent = true) => {
|
|
91
57
|
let value;
|
|
92
58
|
|
|
93
59
|
if (isMultiple) {
|
|
94
60
|
const opts = Array.isArray(optionOrOptions) ? optionOrOptions : [];
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
61
|
+
selectedOptions.clear();
|
|
62
|
+
opts.forEach(opt => selectedOptions.add(opt));
|
|
63
|
+
|
|
64
|
+
// Get selected options in DOM order
|
|
65
|
+
const selected = options.filter(opt => selectedOptions.has(opt));
|
|
66
|
+
if (selected.length === 0) {
|
|
67
|
+
selectedLabel.textContent = placeholder;
|
|
68
|
+
selectedLabel.classList.add('text-muted-foreground');
|
|
69
|
+
} else {
|
|
70
|
+
selectedLabel.textContent = selected.map(opt => opt.dataset.label || opt.textContent.trim()).join(', ');
|
|
71
|
+
selectedLabel.classList.remove('text-muted-foreground');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
value = selected.map(getValue);
|
|
75
|
+
input.value = JSON.stringify(value);
|
|
106
76
|
} else {
|
|
107
77
|
const option = optionOrOptions;
|
|
108
78
|
if (!option) return;
|
|
109
79
|
selectedLabel.innerHTML = option.innerHTML;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (opt === option) {
|
|
113
|
-
opt.setAttribute('aria-selected', 'true');
|
|
114
|
-
} else {
|
|
115
|
-
opt.removeAttribute('aria-selected');
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
value = option.dataset.value;
|
|
80
|
+
value = getValue(option);
|
|
81
|
+
input.value = value;
|
|
119
82
|
}
|
|
120
83
|
|
|
84
|
+
options.forEach(opt => {
|
|
85
|
+
const isSelected = isMultiple ? selectedOptions.has(opt) : opt === optionOrOptions;
|
|
86
|
+
if (isSelected) {
|
|
87
|
+
opt.setAttribute('aria-selected', 'true');
|
|
88
|
+
} else {
|
|
89
|
+
opt.removeAttribute('aria-selected');
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
121
93
|
if (triggerEvent) {
|
|
122
94
|
selectComponent.dispatchEvent(new CustomEvent('change', {
|
|
123
95
|
detail: { value },
|
|
@@ -126,85 +98,73 @@
|
|
|
126
98
|
}
|
|
127
99
|
};
|
|
128
100
|
|
|
129
|
-
const toggleMultipleValue = (value, triggerEvent = true) => {
|
|
130
|
-
if (!isMultiple || value == null) return;
|
|
131
|
-
|
|
132
|
-
const newValues = new Set(selectedValues);
|
|
133
|
-
if (newValues.has(value)) {
|
|
134
|
-
newValues.delete(value);
|
|
135
|
-
} else {
|
|
136
|
-
newValues.add(value);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const selectedOptions = options.filter(opt => newValues.has(opt.dataset.value));
|
|
140
|
-
updateValue(selectedOptions, triggerEvent);
|
|
141
|
-
};
|
|
142
|
-
|
|
143
101
|
const closePopover = (focusOnTrigger = true) => {
|
|
144
102
|
if (popover.getAttribute('aria-hidden') === 'true') return;
|
|
145
|
-
|
|
103
|
+
|
|
146
104
|
if (filter) {
|
|
147
105
|
const resetFilter = () => {
|
|
148
106
|
filter.value = '';
|
|
149
107
|
visibleOptions = [...options];
|
|
150
108
|
allOptions.forEach(opt => opt.setAttribute('aria-hidden', 'false'));
|
|
151
109
|
};
|
|
152
|
-
|
|
110
|
+
|
|
153
111
|
if (hasTransition()) {
|
|
154
112
|
popover.addEventListener('transitionend', resetFilter, { once: true });
|
|
155
113
|
} else {
|
|
156
114
|
resetFilter();
|
|
157
115
|
}
|
|
158
116
|
}
|
|
159
|
-
|
|
117
|
+
|
|
160
118
|
if (focusOnTrigger) trigger.focus();
|
|
161
119
|
popover.setAttribute('aria-hidden', 'true');
|
|
162
120
|
trigger.setAttribute('aria-expanded', 'false');
|
|
163
121
|
setActiveOption(-1);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const selectOption = (option) => {
|
|
167
|
-
if (!option) return;
|
|
168
|
-
|
|
169
|
-
const oldValue = input.value;
|
|
170
|
-
const newValue = option.dataset.value;
|
|
122
|
+
};
|
|
171
123
|
|
|
172
|
-
|
|
173
|
-
|
|
124
|
+
const toggleMultipleValue = (option) => {
|
|
125
|
+
if (selectedOptions.has(option)) {
|
|
126
|
+
selectedOptions.delete(option);
|
|
127
|
+
} else {
|
|
128
|
+
selectedOptions.add(option);
|
|
174
129
|
}
|
|
175
|
-
|
|
176
|
-
closePopover();
|
|
130
|
+
updateValue(options.filter(opt => selectedOptions.has(opt)));
|
|
177
131
|
};
|
|
178
132
|
|
|
179
|
-
const
|
|
180
|
-
const option = options.find(opt => opt.dataset.value === value);
|
|
133
|
+
const select = (value) => {
|
|
181
134
|
if (isMultiple) {
|
|
182
|
-
|
|
183
|
-
if (option
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const selectedOptions = options.filter(opt => newValues.has(opt.dataset.value));
|
|
187
|
-
updateValue(selectedOptions);
|
|
188
|
-
}
|
|
135
|
+
const option = options.find(opt => getValue(opt) === value && !selectedOptions.has(opt));
|
|
136
|
+
if (!option) return;
|
|
137
|
+
selectedOptions.add(option);
|
|
138
|
+
updateValue(options.filter(opt => selectedOptions.has(opt)));
|
|
189
139
|
} else {
|
|
190
|
-
|
|
140
|
+
const option = options.find(opt => getValue(opt) === value);
|
|
141
|
+
if (!option) return;
|
|
142
|
+
if (input.value !== value) {
|
|
143
|
+
updateValue(option);
|
|
144
|
+
}
|
|
145
|
+
closePopover();
|
|
191
146
|
}
|
|
192
147
|
};
|
|
193
148
|
|
|
194
|
-
const
|
|
149
|
+
const deselect = (value) => {
|
|
195
150
|
if (!isMultiple) return;
|
|
196
|
-
|
|
151
|
+
const option = options.find(opt => getValue(opt) === value && selectedOptions.has(opt));
|
|
152
|
+
if (!option) return;
|
|
153
|
+
selectedOptions.delete(option);
|
|
154
|
+
updateValue(options.filter(opt => selectedOptions.has(opt)));
|
|
197
155
|
};
|
|
198
156
|
|
|
199
|
-
const
|
|
157
|
+
const toggle = (value) => {
|
|
200
158
|
if (!isMultiple) return;
|
|
201
|
-
|
|
159
|
+
const option = options.find(opt => getValue(opt) === value);
|
|
160
|
+
if (!option) return;
|
|
161
|
+
toggleMultipleValue(option);
|
|
202
162
|
};
|
|
203
163
|
|
|
204
164
|
if (filter) {
|
|
205
165
|
const filterOptions = () => {
|
|
206
166
|
const searchTerm = filter.value.trim().toLowerCase();
|
|
207
|
-
|
|
167
|
+
|
|
208
168
|
setActiveOption(-1);
|
|
209
169
|
|
|
210
170
|
visibleOptions = [];
|
|
@@ -230,35 +190,36 @@
|
|
|
230
190
|
}
|
|
231
191
|
});
|
|
232
192
|
};
|
|
233
|
-
|
|
193
|
+
|
|
234
194
|
filter.addEventListener('input', filterOptions);
|
|
235
195
|
}
|
|
236
196
|
|
|
197
|
+
// Initialization
|
|
237
198
|
if (isMultiple) {
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
.map(
|
|
242
|
-
.filter(v =>
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if (!initialOption) {
|
|
256
|
-
initialOption = options.find(opt => opt.dataset.value !== undefined) ?? options[0];
|
|
257
|
-
}
|
|
199
|
+
const ariaSelected = options.filter(opt => opt.getAttribute('aria-selected') === 'true');
|
|
200
|
+
try {
|
|
201
|
+
const parsed = JSON.parse(input.value || '[]');
|
|
202
|
+
const validValues = new Set(options.map(getValue));
|
|
203
|
+
const initialValues = Array.isArray(parsed) ? parsed.filter(v => validValues.has(v)) : [];
|
|
204
|
+
|
|
205
|
+
const initialOptions = [];
|
|
206
|
+
if (initialValues.length > 0) {
|
|
207
|
+
// Match values to options in order, allowing duplicates
|
|
208
|
+
initialValues.forEach(val => {
|
|
209
|
+
const opt = options.find(o => getValue(o) === val && !initialOptions.includes(o));
|
|
210
|
+
if (opt) initialOptions.push(opt);
|
|
211
|
+
});
|
|
212
|
+
} else {
|
|
213
|
+
initialOptions.push(...ariaSelected);
|
|
214
|
+
}
|
|
258
215
|
|
|
259
|
-
|
|
260
|
-
|
|
216
|
+
updateValue(initialOptions, false);
|
|
217
|
+
} catch (e) {
|
|
218
|
+
updateValue(ariaSelected, false);
|
|
261
219
|
}
|
|
220
|
+
} else {
|
|
221
|
+
const initialOption = options.find(opt => getValue(opt) === input.value) || options[0];
|
|
222
|
+
if (initialOption) updateValue(initialOption, false);
|
|
262
223
|
}
|
|
263
224
|
|
|
264
225
|
const handleKeyNavigation = (event) => {
|
|
@@ -275,20 +236,27 @@
|
|
|
275
236
|
}
|
|
276
237
|
return;
|
|
277
238
|
}
|
|
278
|
-
|
|
239
|
+
|
|
279
240
|
event.preventDefault();
|
|
280
241
|
|
|
281
242
|
if (event.key === 'Escape') {
|
|
282
243
|
closePopover();
|
|
283
244
|
return;
|
|
284
245
|
}
|
|
285
|
-
|
|
246
|
+
|
|
286
247
|
if (event.key === 'Enter') {
|
|
287
248
|
if (activeIndex > -1) {
|
|
249
|
+
const option = options[activeIndex];
|
|
288
250
|
if (isMultiple) {
|
|
289
|
-
toggleMultipleValue(
|
|
251
|
+
toggleMultipleValue(option);
|
|
252
|
+
if (closeOnSelect) {
|
|
253
|
+
closePopover();
|
|
254
|
+
}
|
|
290
255
|
} else {
|
|
291
|
-
|
|
256
|
+
if (input.value !== getValue(option)) {
|
|
257
|
+
updateValue(option);
|
|
258
|
+
}
|
|
259
|
+
closePopover();
|
|
292
260
|
}
|
|
293
261
|
}
|
|
294
262
|
return;
|
|
@@ -355,7 +323,7 @@
|
|
|
355
323
|
document.dispatchEvent(new CustomEvent('basecoat:popover', {
|
|
356
324
|
detail: { source: selectComponent }
|
|
357
325
|
}));
|
|
358
|
-
|
|
326
|
+
|
|
359
327
|
if (filter) {
|
|
360
328
|
if (hasTransition()) {
|
|
361
329
|
popover.addEventListener('transitionend', () => {
|
|
@@ -368,7 +336,7 @@
|
|
|
368
336
|
|
|
369
337
|
popover.setAttribute('aria-hidden', 'false');
|
|
370
338
|
trigger.setAttribute('aria-expanded', 'true');
|
|
371
|
-
|
|
339
|
+
|
|
372
340
|
const selectedOption = listbox.querySelector('[role="option"][aria-selected="true"]');
|
|
373
341
|
if (selectedOption) {
|
|
374
342
|
setActiveOption(options.indexOf(selectedOption));
|
|
@@ -387,18 +355,28 @@
|
|
|
387
355
|
|
|
388
356
|
listbox.addEventListener('click', (event) => {
|
|
389
357
|
const clickedOption = event.target.closest('[role="option"]');
|
|
390
|
-
if (clickedOption)
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
358
|
+
if (!clickedOption) return;
|
|
359
|
+
|
|
360
|
+
const option = options.find(opt => opt === clickedOption);
|
|
361
|
+
if (!option) return;
|
|
362
|
+
|
|
363
|
+
if (isMultiple) {
|
|
364
|
+
toggleMultipleValue(option);
|
|
365
|
+
if (closeOnSelect) {
|
|
366
|
+
closePopover();
|
|
367
|
+
} else {
|
|
368
|
+
setActiveOption(options.indexOf(option));
|
|
394
369
|
if (filter) {
|
|
395
370
|
filter.focus();
|
|
396
371
|
} else {
|
|
397
372
|
trigger.focus();
|
|
398
373
|
}
|
|
399
|
-
} else {
|
|
400
|
-
selectOption(clickedOption);
|
|
401
374
|
}
|
|
375
|
+
} else {
|
|
376
|
+
if (input.value !== getValue(option)) {
|
|
377
|
+
updateValue(option);
|
|
378
|
+
}
|
|
379
|
+
closePopover();
|
|
402
380
|
}
|
|
403
381
|
});
|
|
404
382
|
|
|
@@ -416,10 +394,41 @@
|
|
|
416
394
|
|
|
417
395
|
popover.setAttribute('aria-hidden', 'true');
|
|
418
396
|
|
|
419
|
-
|
|
397
|
+
// Public API
|
|
398
|
+
Object.defineProperty(selectComponent, 'value', {
|
|
399
|
+
get: () => {
|
|
400
|
+
if (isMultiple) {
|
|
401
|
+
return options.filter(opt => selectedOptions.has(opt)).map(getValue);
|
|
402
|
+
} else {
|
|
403
|
+
return input.value;
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
set: (val) => {
|
|
407
|
+
if (isMultiple) {
|
|
408
|
+
const values = Array.isArray(val) ? val : (val != null ? [val] : []);
|
|
409
|
+
const opts = [];
|
|
410
|
+
values.forEach(v => {
|
|
411
|
+
const opt = options.find(o => getValue(o) === v && !opts.includes(o));
|
|
412
|
+
if (opt) opts.push(opt);
|
|
413
|
+
});
|
|
414
|
+
updateValue(opts);
|
|
415
|
+
} else {
|
|
416
|
+
const option = options.find(opt => getValue(opt) === val);
|
|
417
|
+
if (option) {
|
|
418
|
+
updateValue(option);
|
|
419
|
+
closePopover();
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
selectComponent.select = select;
|
|
426
|
+
selectComponent.selectByValue = select; // Backward compatibility alias
|
|
420
427
|
if (isMultiple) {
|
|
421
|
-
selectComponent.
|
|
422
|
-
selectComponent.
|
|
428
|
+
selectComponent.deselect = deselect;
|
|
429
|
+
selectComponent.toggle = toggle;
|
|
430
|
+
selectComponent.selectAll = () => updateValue(options);
|
|
431
|
+
selectComponent.selectNone = () => updateValue([]);
|
|
423
432
|
}
|
|
424
433
|
selectComponent.dataset.selectInitialized = true;
|
|
425
434
|
selectComponent.dispatchEvent(new CustomEvent('basecoat:initialized'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{const e=e=>{const t=e.querySelector(":scope > button"),
|
|
1
|
+
(()=>{const e=e=>{const t=e.querySelector(":scope > button"),r=t.querySelector(":scope > span"),n=e.querySelector(":scope > [data-popover]"),i=n?n.querySelector('[role="listbox"]'):null,a=e.querySelector(':scope > input[type="hidden"]'),s=e.querySelector('header input[type="text"]');if(!(t&&n&&i&&a)){const r=[];return t||r.push("trigger"),n||r.push("popover"),i||r.push("listbox"),a||r.push("input"),void console.error(`Select component initialisation failed. Missing element(s): ${r.join(", ")}`,e)}const o=Array.from(i.querySelectorAll('[role="option"]')),c=o.filter((e=>"true"!==e.getAttribute("aria-disabled")));let l=[...c],d=-1;const u="true"===i.getAttribute("aria-multiselectable"),f=u?new Set:null,p=u?e.dataset.placeholder||"":null,v="true"===e.dataset.closeOnSelect,h=e=>e.dataset.value??e.textContent.trim(),b=e=>{if(d>-1&&c[d]&&c[d].classList.remove("active"),d=e,d>-1){const e=c[d];e.classList.add("active"),e.id?t.setAttribute("aria-activedescendant",e.id):t.removeAttribute("aria-activedescendant")}else t.removeAttribute("aria-activedescendant")},m=()=>{const e=getComputedStyle(n);return parseFloat(e.transitionDuration)>0||parseFloat(e.transitionDelay)>0},y=(t,n=!0)=>{let i;if(u){const e=Array.isArray(t)?t:[];f.clear(),e.forEach((e=>f.add(e)));const n=c.filter((e=>f.has(e)));0===n.length?(r.textContent=p,r.classList.add("text-muted-foreground")):(r.textContent=n.map((e=>e.dataset.label||e.textContent.trim())).join(", "),r.classList.remove("text-muted-foreground")),i=n.map(h),a.value=JSON.stringify(i)}else{const e=t;if(!e)return;r.innerHTML=e.innerHTML,i=h(e),a.value=i}c.forEach((e=>{(u?f.has(e):e===t)?e.setAttribute("aria-selected","true"):e.removeAttribute("aria-selected")})),n&&e.dispatchEvent(new CustomEvent("change",{detail:{value:i},bubbles:!0}))},A=(e=!0)=>{if("true"!==n.getAttribute("aria-hidden")){if(s){const e=()=>{s.value="",l=[...c],o.forEach((e=>e.setAttribute("aria-hidden","false")))};m()?n.addEventListener("transitionend",e,{once:!0}):e()}e&&t.focus(),n.setAttribute("aria-hidden","true"),t.setAttribute("aria-expanded","false"),b(-1)}},E=e=>{f.has(e)?f.delete(e):f.add(e),y(c.filter((e=>f.has(e))))},g=e=>{if(u){const t=c.find((t=>h(t)===e&&!f.has(t)));if(!t)return;f.add(t),y(c.filter((e=>f.has(e))))}else{const t=c.find((t=>h(t)===e));if(!t)return;a.value!==e&&y(t),A()}},w=e=>{if(!u)return;const t=c.find((t=>h(t)===e&&f.has(t)));t&&(f.delete(t),y(c.filter((e=>f.has(e)))))},L=e=>{if(!u)return;const t=c.find((t=>h(t)===e));t&&E(t)};if(s){const e=()=>{const e=s.value.trim().toLowerCase();b(-1),l=[],o.forEach((t=>{if(t.hasAttribute("data-force"))return t.setAttribute("aria-hidden","false"),void(c.includes(t)&&l.push(t));const r=(t.dataset.filter||t.textContent).trim().toLowerCase(),n=(t.dataset.keywords||"").toLowerCase().split(/[\s,]+/).filter(Boolean).some((t=>t.includes(e))),i=r.includes(e)||n;t.setAttribute("aria-hidden",String(!i)),i&&c.includes(t)&&l.push(t)}))};s.addEventListener("input",e)}if(u){const e=c.filter((e=>"true"===e.getAttribute("aria-selected")));try{const t=JSON.parse(a.value||"[]"),r=new Set(c.map(h)),n=Array.isArray(t)?t.filter((e=>r.has(e))):[],i=[];n.length>0?n.forEach((e=>{const t=c.find((t=>h(t)===e&&!i.includes(t)));t&&i.push(t)})):i.push(...e),y(i,!1)}catch(t){y(e,!1)}}else{const e=c.find((e=>h(e)===a.value))||c[0];e&&y(e,!1)}const x=e=>{const r="false"===n.getAttribute("aria-hidden");if(!["ArrowDown","ArrowUp","Enter","Home","End","Escape"].includes(e.key))return;if(!r)return void("Enter"!==e.key&&"Escape"!==e.key&&(e.preventDefault(),t.click()));if(e.preventDefault(),"Escape"===e.key)return void A();if("Enter"===e.key){if(d>-1){const e=c[d];u?(E(e),v&&A()):(a.value!==h(e)&&y(e),A())}return}if(0===l.length)return;const i=d>-1?l.indexOf(c[d]):-1;let s=i;switch(e.key){case"ArrowDown":i<l.length-1&&(s=i+1);break;case"ArrowUp":i>0?s=i-1:-1===i&&(s=0);break;case"Home":s=0;break;case"End":s=l.length-1}if(s!==i){const e=l[s];b(c.indexOf(e)),e.scrollIntoView({block:"nearest",behavior:"smooth"})}};i.addEventListener("mousemove",(e=>{const t=e.target.closest('[role="option"]');if(t&&l.includes(t)){const e=c.indexOf(t);e!==d&&b(e)}})),i.addEventListener("mouseleave",(()=>{const e=i.querySelector('[role="option"][aria-selected="true"]');b(e?c.indexOf(e):-1)})),t.addEventListener("keydown",x),s&&s.addEventListener("keydown",x);t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?A():(()=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}})),s&&(m()?n.addEventListener("transitionend",(()=>{s.focus()}),{once:!0}):s.focus()),n.setAttribute("aria-hidden","false"),t.setAttribute("aria-expanded","true");const r=i.querySelector('[role="option"][aria-selected="true"]');r&&(b(c.indexOf(r)),r.scrollIntoView({block:"nearest"}))})()})),i.addEventListener("click",(e=>{const r=e.target.closest('[role="option"]');if(!r)return;const n=c.find((e=>e===r));n&&(u?(E(n),v?A():(b(c.indexOf(n)),s?s.focus():t.focus())):(a.value!==h(n)&&y(n),A()))})),document.addEventListener("click",(t=>{e.contains(t.target)||A(!1)})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&A(!1)})),n.setAttribute("aria-hidden","true"),Object.defineProperty(e,"value",{get:()=>u?c.filter((e=>f.has(e))).map(h):a.value,set:e=>{if(u){const t=Array.isArray(e)?e:null!=e?[e]:[],r=[];t.forEach((e=>{const t=c.find((t=>h(t)===e&&!r.includes(t)));t&&r.push(t)})),y(r)}else{const t=c.find((t=>h(t)===e));t&&(y(t),A())}}}),e.select=g,e.selectByValue=g,u&&(e.deselect=w,e.toggle=L,e.selectAll=()=>y(c),e.selectNone=()=>y([])),e.dataset.selectInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("select","div.select:not([data-select-initialized])",e)})();
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
@param name {string} [optional] - The name attribute for the hidden input storing the selected value.
|
|
7
7
|
@param multiple {boolean} [optional] [default=false] - Enables multiple selection mode.
|
|
8
8
|
@param placeholder {string} [optional] - Placeholder text shown when no options are selected (multiple mode only).
|
|
9
|
+
@param close_on_select {boolean} [optional] [default=false] - Closes the popover when selecting an option in multiple mode.
|
|
9
10
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
10
11
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
|
|
11
12
|
@param popover_attrs {object} [optional] - Additional HTML attributes for the popover content div.
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
items=None,
|
|
22
23
|
multiple=false,
|
|
23
24
|
placeholder=None,
|
|
25
|
+
close_on_select=false,
|
|
24
26
|
main_attrs={},
|
|
25
27
|
trigger_attrs={},
|
|
26
28
|
popover_attrs={},
|
|
@@ -31,7 +33,13 @@
|
|
|
31
33
|
) %}
|
|
32
34
|
{% set id = id or ("select-" + (range(100000, 999999) | random | string)) %}
|
|
33
35
|
|
|
34
|
-
{%
|
|
36
|
+
{% if selected is defined and selected is iterable and selected is not string %}
|
|
37
|
+
{% set selectedArray = selected %}
|
|
38
|
+
{% elif selected is defined %}
|
|
39
|
+
{% set selectedArray = [selected] %}
|
|
40
|
+
{% else %}
|
|
41
|
+
{% set selectedArray = [] %}
|
|
42
|
+
{% endif %}
|
|
35
43
|
{% set first_option = [] %}
|
|
36
44
|
{% set selected_options = [] %}
|
|
37
45
|
|
|
@@ -70,6 +78,7 @@
|
|
|
70
78
|
id="{{ id }}"
|
|
71
79
|
class="select {{ main_attrs.class }}"
|
|
72
80
|
{% if multiple and placeholder %}data-placeholder="{{ placeholder }}"{% endif %}
|
|
81
|
+
{% if multiple and close_on_select %}data-close-on-select="true"{% endif %}
|
|
73
82
|
{% for key, value in main_attrs %}
|
|
74
83
|
{% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
|
|
75
84
|
{% endfor %}
|
|
@@ -135,28 +144,14 @@
|
|
|
135
144
|
{% endif %}
|
|
136
145
|
</div>
|
|
137
146
|
</div>
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
{% if loop.index0 > 0 %}id="{{ id }}-value-{{ loop.index0 }}"{% endif %}
|
|
145
|
-
{% for key, value in input_attrs %}
|
|
146
|
-
{% if key != 'name' and key != 'value' %}{{ key }}="{{ value }}"{% endif %}
|
|
147
|
-
{% endfor %}
|
|
148
|
-
>
|
|
147
|
+
<input
|
|
148
|
+
type="hidden"
|
|
149
|
+
name="{{ name or id ~ '-value' }}"
|
|
150
|
+
value="{% if multiple %}{{ selectedArray | dump }}{% else %}{{ (default_option.value if default_option) or '' }}{% endif %}"
|
|
151
|
+
{% for key, value in input_attrs %}
|
|
152
|
+
{% if key != 'name' and key != 'value' %}{{ key }}="{{ value }}"{% endif %}
|
|
149
153
|
{% endfor %}
|
|
150
|
-
|
|
151
|
-
<input
|
|
152
|
-
type="hidden"
|
|
153
|
-
name="{{ name or id ~ '-value' }}"
|
|
154
|
-
value="{{ (default_option.value if default_option) or '' }}"
|
|
155
|
-
{% for key, value in input_attrs %}
|
|
156
|
-
{% if key != 'name' and key != 'value' %}{{ key }}="{{ value }}"{% endif %}
|
|
157
|
-
{% endfor %}
|
|
158
|
-
>
|
|
159
|
-
{% endif %}
|
|
154
|
+
>
|
|
160
155
|
</div>
|
|
161
156
|
{% endmacro %}
|
|
162
157
|
|
|
@@ -189,7 +184,7 @@
|
|
|
189
184
|
<div
|
|
190
185
|
id="{{ item_id }}"
|
|
191
186
|
role="option"
|
|
192
|
-
data-value="{{ item.value }}"
|
|
187
|
+
{% if item.value is defined and item.value is not none %}data-value="{{ item.value }}"{% endif %}
|
|
193
188
|
{% if item.value in selectedArray %}aria-selected="true"{% endif %}
|
|
194
189
|
{% if item.attrs %}
|
|
195
190
|
{% for key, value in item.attrs %}
|
|
@@ -201,4 +196,4 @@
|
|
|
201
196
|
</div>
|
|
202
197
|
{% endif %}
|
|
203
198
|
{% endfor %}
|
|
204
|
-
{% endmacro %}
|
|
199
|
+
{% endmacro %}
|