basecoat-cli 0.3.10-beta.1 → 0.3.10-beta.2

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.
@@ -31,7 +31,13 @@
31
31
  ) %}
32
32
  {% set id = id or ("select-" + (range(100000, 999999) | random | string)) %}
33
33
 
34
- {% set selectedArray = ((selected if (selected is iterable and selected is not string) else [selected]) if selected else []) %}
34
+ {% if selected is defined and selected is iterable and selected is not string %}
35
+ {% set selectedArray = selected %}
36
+ {% elif selected is defined %}
37
+ {% set selectedArray = [selected] %}
38
+ {% else %}
39
+ {% set selectedArray = [] %}
40
+ {% endif %}
35
41
  {% set first_option = namespace(item=None) %}
36
42
  {% set selected_options = namespace(items=[]) %}
37
43
 
@@ -135,28 +141,14 @@
135
141
  {% endif %}
136
142
  </div>
137
143
  </div>
138
- {% if multiple and selectedArray %}
139
- {% for val in selectedArray %}
140
- <input
141
- type="hidden"
142
- name="{{ name or id ~ '-value' }}"
143
- value="{{ val }}"
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
- >
144
+ <input
145
+ type="hidden"
146
+ name="{{ name or id ~ '-value' }}"
147
+ value="{% if multiple %}{{ selectedArray | tojson }}{% else %}{{ (default_option.value if default_option) or '' }}{% endif %}"
148
+ {% for key, value in input_attrs.items() %}
149
+ {% if key != 'name' and key != 'value' %}{{ key }}="{{ value }}"{% endif %}
149
150
  {% endfor %}
150
- {% else %}
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 %}
151
+ >
160
152
  </div>
161
153
  {% endmacro %}
162
154
 
@@ -189,7 +181,7 @@
189
181
  <div
190
182
  id="{{ item_id }}"
191
183
  role="option"
192
- data-value="{{ item.value }}"
184
+ {% if item.value is defined and item.value is not none %}data-value="{{ item.value }}"{% endif %}
193
185
  {% if item.value in selectedArray %}aria-selected="true"{% endif %}
194
186
  {% if item.attrs %}
195
187
  {% for key, value in item.attrs.items() %}
@@ -527,20 +527,18 @@
527
527
  let visibleOptions = [...options];
528
528
  let activeIndex = -1;
529
529
  const isMultiple = listbox.getAttribute('aria-multiselectable') === 'true';
530
- let selectedValues = isMultiple ? new Set() : null;
531
- let placeholder = null;
530
+ const selectedOptions = isMultiple ? new Set() : null;
531
+ const placeholder = isMultiple ? (selectComponent.dataset.placeholder || '') : null;
532
532
 
533
- if (isMultiple) {
534
- placeholder = selectComponent.dataset.placeholder || '';
535
- }
533
+ const getValue = (opt) => opt.dataset.value ?? opt.textContent.trim();
536
534
 
537
535
  const setActiveOption = (index) => {
538
536
  if (activeIndex > -1 && options[activeIndex]) {
539
537
  options[activeIndex].classList.remove('active');
540
538
  }
541
-
539
+
542
540
  activeIndex = index;
543
-
541
+
544
542
  if (activeIndex > -1) {
545
543
  const activeOption = options[activeIndex];
546
544
  activeOption.classList.add('active');
@@ -559,70 +557,43 @@
559
557
  return parseFloat(style.transitionDuration) > 0 || parseFloat(style.transitionDelay) > 0;
560
558
  };
561
559
 
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
560
  const updateValue = (optionOrOptions, triggerEvent = true) => {
596
561
  let value;
597
562
 
598
563
  if (isMultiple) {
599
564
  const opts = Array.isArray(optionOrOptions) ? optionOrOptions : [];
600
- selectedValues = new Set(opts.map(opt => opt.dataset.value));
601
- options.forEach(opt => {
602
- if (selectedValues.has(opt.dataset.value)) {
603
- opt.setAttribute('aria-selected', 'true');
604
- } else {
605
- opt.removeAttribute('aria-selected');
606
- }
607
- });
608
- updateMultipleLabel();
609
- syncMultipleInputs();
610
- value = Array.from(selectedValues);
565
+ selectedOptions.clear();
566
+ opts.forEach(opt => selectedOptions.add(opt));
567
+
568
+ // Get selected options in DOM order
569
+ const selected = options.filter(opt => selectedOptions.has(opt));
570
+ if (selected.length === 0) {
571
+ selectedLabel.textContent = placeholder;
572
+ selectedLabel.classList.add('text-muted-foreground');
573
+ } else {
574
+ selectedLabel.textContent = selected.map(opt => opt.dataset.label || opt.textContent.trim()).join(', ');
575
+ selectedLabel.classList.remove('text-muted-foreground');
576
+ }
577
+
578
+ value = selected.map(getValue);
579
+ input.value = JSON.stringify(value);
611
580
  } else {
612
581
  const option = optionOrOptions;
613
582
  if (!option) return;
614
583
  selectedLabel.innerHTML = option.innerHTML;
615
- input.value = option.dataset.value;
616
- options.forEach(opt => {
617
- if (opt === option) {
618
- opt.setAttribute('aria-selected', 'true');
619
- } else {
620
- opt.removeAttribute('aria-selected');
621
- }
622
- });
623
- value = option.dataset.value;
584
+ value = getValue(option);
585
+ input.value = value;
624
586
  }
625
587
 
588
+ options.forEach(opt => {
589
+ const isSelected = isMultiple ? selectedOptions.has(opt) : opt === optionOrOptions;
590
+ if (isSelected) {
591
+ opt.setAttribute('aria-selected', 'true');
592
+ } else {
593
+ opt.removeAttribute('aria-selected');
594
+ }
595
+ });
596
+
626
597
  if (triggerEvent) {
627
598
  selectComponent.dispatchEvent(new CustomEvent('change', {
628
599
  detail: { value },
@@ -631,85 +602,73 @@
631
602
  }
632
603
  };
633
604
 
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
605
  const closePopover = (focusOnTrigger = true) => {
649
606
  if (popover.getAttribute('aria-hidden') === 'true') return;
650
-
607
+
651
608
  if (filter) {
652
609
  const resetFilter = () => {
653
610
  filter.value = '';
654
611
  visibleOptions = [...options];
655
612
  allOptions.forEach(opt => opt.setAttribute('aria-hidden', 'false'));
656
613
  };
657
-
614
+
658
615
  if (hasTransition()) {
659
616
  popover.addEventListener('transitionend', resetFilter, { once: true });
660
617
  } else {
661
618
  resetFilter();
662
619
  }
663
620
  }
664
-
621
+
665
622
  if (focusOnTrigger) trigger.focus();
666
623
  popover.setAttribute('aria-hidden', 'true');
667
624
  trigger.setAttribute('aria-expanded', 'false');
668
625
  setActiveOption(-1);
669
- }
670
-
671
- const selectOption = (option) => {
672
- if (!option) return;
673
-
674
- const oldValue = input.value;
675
- const newValue = option.dataset.value;
626
+ };
676
627
 
677
- if (newValue != null && newValue !== oldValue) {
678
- updateValue(option);
628
+ const toggleMultipleValue = (option) => {
629
+ if (selectedOptions.has(option)) {
630
+ selectedOptions.delete(option);
631
+ } else {
632
+ selectedOptions.add(option);
679
633
  }
680
-
681
- closePopover();
634
+ updateValue(options.filter(opt => selectedOptions.has(opt)));
682
635
  };
683
636
 
684
- const selectByValue = (value) => {
685
- const option = options.find(opt => opt.dataset.value === value);
637
+ const select = (value) => {
686
638
  if (isMultiple) {
687
- if (value != null && selectedValues.has(value)) return;
688
- if (option && value != null) {
689
- const newValues = new Set(selectedValues);
690
- newValues.add(value);
691
- const selectedOptions = options.filter(opt => newValues.has(opt.dataset.value));
692
- updateValue(selectedOptions);
693
- }
639
+ const option = options.find(opt => getValue(opt) === value && !selectedOptions.has(opt));
640
+ if (!option) return;
641
+ selectedOptions.add(option);
642
+ updateValue(options.filter(opt => selectedOptions.has(opt)));
694
643
  } else {
695
- selectOption(option);
644
+ const option = options.find(opt => getValue(opt) === value);
645
+ if (!option) return;
646
+ if (input.value !== value) {
647
+ updateValue(option);
648
+ }
649
+ closePopover();
696
650
  }
697
651
  };
698
652
 
699
- const selectAll = () => {
653
+ const deselect = (value) => {
700
654
  if (!isMultiple) return;
701
- updateValue(options.filter(opt => opt.dataset.value != null));
655
+ const option = options.find(opt => getValue(opt) === value && selectedOptions.has(opt));
656
+ if (!option) return;
657
+ selectedOptions.delete(option);
658
+ updateValue(options.filter(opt => selectedOptions.has(opt)));
702
659
  };
703
660
 
704
- const selectNone = () => {
661
+ const toggle = (value) => {
705
662
  if (!isMultiple) return;
706
- updateValue([]);
663
+ const option = options.find(opt => getValue(opt) === value);
664
+ if (!option) return;
665
+ toggleMultipleValue(option);
707
666
  };
708
667
 
709
668
  if (filter) {
710
669
  const filterOptions = () => {
711
670
  const searchTerm = filter.value.trim().toLowerCase();
712
-
671
+
713
672
  setActiveOption(-1);
714
673
 
715
674
  visibleOptions = [];
@@ -735,35 +694,36 @@
735
694
  }
736
695
  });
737
696
  };
738
-
697
+
739
698
  filter.addEventListener('input', filterOptions);
740
699
  }
741
700
 
701
+ // Initialization
742
702
  if (isMultiple) {
743
- const validValues = new Set(options.map(opt => opt.dataset.value).filter(v => v != null));
744
- const inputs = Array.from(selectComponent.querySelectorAll(':scope > input[type="hidden"]'));
745
- const initialValues = inputs
746
- .map(inp => inp.value)
747
- .filter(v => v != null && validValues.has(v));
748
-
749
- let initialOptions;
750
- if (initialValues.length > 0) {
751
- initialOptions = options.filter(opt => initialValues.includes(opt.dataset.value));
752
- } else {
753
- initialOptions = options.filter(opt => opt.getAttribute('aria-selected') === 'true');
754
- }
755
-
756
- updateValue(initialOptions, false);
757
- } else {
758
- let initialOption = options.find(opt => opt.dataset.value === input.value);
759
-
760
- if (!initialOption) {
761
- initialOption = options.find(opt => opt.dataset.value !== undefined) ?? options[0];
762
- }
703
+ const ariaSelected = options.filter(opt => opt.getAttribute('aria-selected') === 'true');
704
+ try {
705
+ const parsed = JSON.parse(input.value || '[]');
706
+ const validValues = new Set(options.map(getValue));
707
+ const initialValues = Array.isArray(parsed) ? parsed.filter(v => validValues.has(v)) : [];
708
+
709
+ const initialOptions = [];
710
+ if (initialValues.length > 0) {
711
+ // Match values to options in order, allowing duplicates
712
+ initialValues.forEach(val => {
713
+ const opt = options.find(o => getValue(o) === val && !initialOptions.includes(o));
714
+ if (opt) initialOptions.push(opt);
715
+ });
716
+ } else {
717
+ initialOptions.push(...ariaSelected);
718
+ }
763
719
 
764
- if (initialOption) {
765
- updateValue(initialOption, false);
720
+ updateValue(initialOptions, false);
721
+ } catch (e) {
722
+ updateValue(ariaSelected, false);
766
723
  }
724
+ } else {
725
+ const initialOption = options.find(opt => getValue(opt) === input.value) || options[0];
726
+ if (initialOption) updateValue(initialOption, false);
767
727
  }
768
728
 
769
729
  const handleKeyNavigation = (event) => {
@@ -780,20 +740,24 @@
780
740
  }
781
741
  return;
782
742
  }
783
-
743
+
784
744
  event.preventDefault();
785
745
 
786
746
  if (event.key === 'Escape') {
787
747
  closePopover();
788
748
  return;
789
749
  }
790
-
750
+
791
751
  if (event.key === 'Enter') {
792
752
  if (activeIndex > -1) {
753
+ const option = options[activeIndex];
793
754
  if (isMultiple) {
794
- toggleMultipleValue(options[activeIndex].dataset.value);
755
+ toggleMultipleValue(option);
795
756
  } else {
796
- selectOption(options[activeIndex]);
757
+ if (input.value !== getValue(option)) {
758
+ updateValue(option);
759
+ }
760
+ closePopover();
797
761
  }
798
762
  }
799
763
  return;
@@ -860,7 +824,7 @@
860
824
  document.dispatchEvent(new CustomEvent('basecoat:popover', {
861
825
  detail: { source: selectComponent }
862
826
  }));
863
-
827
+
864
828
  if (filter) {
865
829
  if (hasTransition()) {
866
830
  popover.addEventListener('transitionend', () => {
@@ -873,7 +837,7 @@
873
837
 
874
838
  popover.setAttribute('aria-hidden', 'false');
875
839
  trigger.setAttribute('aria-expanded', 'true');
876
-
840
+
877
841
  const selectedOption = listbox.querySelector('[role="option"][aria-selected="true"]');
878
842
  if (selectedOption) {
879
843
  setActiveOption(options.indexOf(selectedOption));
@@ -892,18 +856,24 @@
892
856
 
893
857
  listbox.addEventListener('click', (event) => {
894
858
  const clickedOption = event.target.closest('[role="option"]');
895
- if (clickedOption) {
896
- if (isMultiple) {
897
- toggleMultipleValue(clickedOption.dataset.value);
898
- setActiveOption(options.indexOf(clickedOption));
899
- if (filter) {
900
- filter.focus();
901
- } else {
902
- trigger.focus();
903
- }
859
+ if (!clickedOption) return;
860
+
861
+ const option = options.find(opt => opt === clickedOption);
862
+ if (!option) return;
863
+
864
+ if (isMultiple) {
865
+ toggleMultipleValue(option);
866
+ setActiveOption(options.indexOf(option));
867
+ if (filter) {
868
+ filter.focus();
904
869
  } else {
905
- selectOption(clickedOption);
870
+ trigger.focus();
906
871
  }
872
+ } else {
873
+ if (input.value !== getValue(option)) {
874
+ updateValue(option);
875
+ }
876
+ closePopover();
907
877
  }
908
878
  });
909
879
 
@@ -921,10 +891,41 @@
921
891
 
922
892
  popover.setAttribute('aria-hidden', 'true');
923
893
 
924
- selectComponent.selectByValue = selectByValue;
894
+ // Public API
895
+ Object.defineProperty(selectComponent, 'value', {
896
+ get: () => {
897
+ if (isMultiple) {
898
+ return options.filter(opt => selectedOptions.has(opt)).map(getValue);
899
+ } else {
900
+ return input.value;
901
+ }
902
+ },
903
+ set: (val) => {
904
+ if (isMultiple) {
905
+ const values = Array.isArray(val) ? val : (val != null ? [val] : []);
906
+ const opts = [];
907
+ values.forEach(v => {
908
+ const opt = options.find(o => getValue(o) === v && !opts.includes(o));
909
+ if (opt) opts.push(opt);
910
+ });
911
+ updateValue(opts);
912
+ } else {
913
+ const option = options.find(opt => getValue(opt) === val);
914
+ if (option) {
915
+ updateValue(option);
916
+ closePopover();
917
+ }
918
+ }
919
+ }
920
+ });
921
+
922
+ selectComponent.select = select;
923
+ selectComponent.selectByValue = select; // Backward compatibility alias
925
924
  if (isMultiple) {
926
- selectComponent.selectAll = selectAll;
927
- selectComponent.selectNone = selectNone;
925
+ selectComponent.deselect = deselect;
926
+ selectComponent.toggle = toggle;
927
+ selectComponent.selectAll = () => updateValue(options);
928
+ selectComponent.selectNone = () => updateValue([]);
928
929
  }
929
930
  selectComponent.dataset.selectInitialized = true;
930
931
  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=e=>e.dataset.value??e.textContent.trim(),f=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")},m=()=>{const e=getComputedStyle(i);return parseFloat(e.transitionDuration)>0||parseFloat(e.transitionDelay)>0},b=(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(h),r.value=JSON.stringify(a)}else{const e=t;if(!e)return;n.innerHTML=e.innerHTML,a=h(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}))},w=(e=!0)=>{if("true"!==i.getAttribute("aria-hidden")){if(o){const e=()=>{o.value="",c=[...d],s.forEach((e=>e.setAttribute("aria-hidden","false")))};m()?i.addEventListener("transitionend",e,{once:!0}):e()}e&&t.focus(),i.setAttribute("aria-hidden","true"),t.setAttribute("aria-expanded","false"),f(-1)}},g=e=>{p.has(e)?p.delete(e):p.add(e),b(d.filter((e=>p.has(e))))},E=e=>{if(u){const t=d.find((t=>h(t)===e&&!p.has(t)));if(!t)return;p.add(t),b(d.filter((e=>p.has(e))))}else{const t=d.find((t=>h(t)===e));if(!t)return;r.value!==e&&b(t),w()}},A=e=>{if(!u)return;const t=d.find((t=>h(t)===e&&p.has(t)));t&&(p.delete(t),b(d.filter((e=>p.has(e)))))},y=e=>{if(!u)return;const t=d.find((t=>h(t)===e));t&&g(t)};if(o){const e=()=>{const e=o.value.trim().toLowerCase();f(-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(h)),i=Array.isArray(t)?t.filter((e=>n.has(e))):[],a=[];i.length>0?i.forEach((e=>{const t=d.find((t=>h(t)===e&&!a.includes(t)));t&&a.push(t)})):a.push(...e),b(a,!1)}catch(t){b(e,!1)}}else{const e=d.find((e=>h(e)===r.value))||d[0];e&&b(e,!1)}const k=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 w();if("Enter"===e.key){if(l>-1){const e=d[l];u?g(e):(r.value!==h(e)&&b(e),w())}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];f(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&&f(e)}})),a.addEventListener("mouseleave",(()=>{const e=a.querySelector('[role="option"][aria-selected="true"]');f(e?d.indexOf(e):-1)})),t.addEventListener("keydown",k),o&&o.addEventListener("keydown",k);t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?w():(()=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}})),o&&(m()?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&&(f(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?(g(i),f(d.indexOf(i)),o?o.focus():t.focus()):(r.value!==h(i)&&b(i),w()))})),document.addEventListener("click",(t=>{e.contains(t.target)||w(!1)})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&w(!1)})),i.setAttribute("aria-hidden","true"),Object.defineProperty(e,"value",{get:()=>u?d.filter((e=>p.has(e))).map(h):r.value,set:e=>{if(u){const t=Array.isArray(e)?e:null!=e?[e]:[],n=[];t.forEach((e=>{const t=d.find((t=>h(t)===e&&!n.includes(t)));t&&n.push(t)})),b(n)}else{const t=d.find((t=>h(t)===e));t&&(b(t),w())}}}),e.select=E,e.selectByValue=E,u&&(e.deselect=A,e.toggle=y,e.selectAll=()=>b(d),e.selectNone=()=>b([])),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))})();
@@ -22,20 +22,18 @@
22
22
  let visibleOptions = [...options];
23
23
  let activeIndex = -1;
24
24
  const isMultiple = listbox.getAttribute('aria-multiselectable') === 'true';
25
- let selectedValues = isMultiple ? new Set() : null;
26
- let placeholder = null;
25
+ const selectedOptions = isMultiple ? new Set() : null;
26
+ const placeholder = isMultiple ? (selectComponent.dataset.placeholder || '') : null;
27
27
 
28
- if (isMultiple) {
29
- placeholder = selectComponent.dataset.placeholder || '';
30
- }
28
+ const getValue = (opt) => opt.dataset.value ?? opt.textContent.trim();
31
29
 
32
30
  const setActiveOption = (index) => {
33
31
  if (activeIndex > -1 && options[activeIndex]) {
34
32
  options[activeIndex].classList.remove('active');
35
33
  }
36
-
34
+
37
35
  activeIndex = index;
38
-
36
+
39
37
  if (activeIndex > -1) {
40
38
  const activeOption = options[activeIndex];
41
39
  activeOption.classList.add('active');
@@ -54,70 +52,43 @@
54
52
  return parseFloat(style.transitionDuration) > 0 || parseFloat(style.transitionDelay) > 0;
55
53
  };
56
54
 
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
55
  const updateValue = (optionOrOptions, triggerEvent = true) => {
91
56
  let value;
92
57
 
93
58
  if (isMultiple) {
94
59
  const opts = Array.isArray(optionOrOptions) ? optionOrOptions : [];
95
- selectedValues = new Set(opts.map(opt => opt.dataset.value));
96
- options.forEach(opt => {
97
- if (selectedValues.has(opt.dataset.value)) {
98
- opt.setAttribute('aria-selected', 'true');
99
- } else {
100
- opt.removeAttribute('aria-selected');
101
- }
102
- });
103
- updateMultipleLabel();
104
- syncMultipleInputs();
105
- value = Array.from(selectedValues);
60
+ selectedOptions.clear();
61
+ opts.forEach(opt => selectedOptions.add(opt));
62
+
63
+ // Get selected options in DOM order
64
+ const selected = options.filter(opt => selectedOptions.has(opt));
65
+ if (selected.length === 0) {
66
+ selectedLabel.textContent = placeholder;
67
+ selectedLabel.classList.add('text-muted-foreground');
68
+ } else {
69
+ selectedLabel.textContent = selected.map(opt => opt.dataset.label || opt.textContent.trim()).join(', ');
70
+ selectedLabel.classList.remove('text-muted-foreground');
71
+ }
72
+
73
+ value = selected.map(getValue);
74
+ input.value = JSON.stringify(value);
106
75
  } else {
107
76
  const option = optionOrOptions;
108
77
  if (!option) return;
109
78
  selectedLabel.innerHTML = option.innerHTML;
110
- input.value = option.dataset.value;
111
- options.forEach(opt => {
112
- if (opt === option) {
113
- opt.setAttribute('aria-selected', 'true');
114
- } else {
115
- opt.removeAttribute('aria-selected');
116
- }
117
- });
118
- value = option.dataset.value;
79
+ value = getValue(option);
80
+ input.value = value;
119
81
  }
120
82
 
83
+ options.forEach(opt => {
84
+ const isSelected = isMultiple ? selectedOptions.has(opt) : opt === optionOrOptions;
85
+ if (isSelected) {
86
+ opt.setAttribute('aria-selected', 'true');
87
+ } else {
88
+ opt.removeAttribute('aria-selected');
89
+ }
90
+ });
91
+
121
92
  if (triggerEvent) {
122
93
  selectComponent.dispatchEvent(new CustomEvent('change', {
123
94
  detail: { value },
@@ -126,85 +97,73 @@
126
97
  }
127
98
  };
128
99
 
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
100
  const closePopover = (focusOnTrigger = true) => {
144
101
  if (popover.getAttribute('aria-hidden') === 'true') return;
145
-
102
+
146
103
  if (filter) {
147
104
  const resetFilter = () => {
148
105
  filter.value = '';
149
106
  visibleOptions = [...options];
150
107
  allOptions.forEach(opt => opt.setAttribute('aria-hidden', 'false'));
151
108
  };
152
-
109
+
153
110
  if (hasTransition()) {
154
111
  popover.addEventListener('transitionend', resetFilter, { once: true });
155
112
  } else {
156
113
  resetFilter();
157
114
  }
158
115
  }
159
-
116
+
160
117
  if (focusOnTrigger) trigger.focus();
161
118
  popover.setAttribute('aria-hidden', 'true');
162
119
  trigger.setAttribute('aria-expanded', 'false');
163
120
  setActiveOption(-1);
164
- }
165
-
166
- const selectOption = (option) => {
167
- if (!option) return;
168
-
169
- const oldValue = input.value;
170
- const newValue = option.dataset.value;
121
+ };
171
122
 
172
- if (newValue != null && newValue !== oldValue) {
173
- updateValue(option);
123
+ const toggleMultipleValue = (option) => {
124
+ if (selectedOptions.has(option)) {
125
+ selectedOptions.delete(option);
126
+ } else {
127
+ selectedOptions.add(option);
174
128
  }
175
-
176
- closePopover();
129
+ updateValue(options.filter(opt => selectedOptions.has(opt)));
177
130
  };
178
131
 
179
- const selectByValue = (value) => {
180
- const option = options.find(opt => opt.dataset.value === value);
132
+ const select = (value) => {
181
133
  if (isMultiple) {
182
- if (value != null && selectedValues.has(value)) return;
183
- if (option && value != null) {
184
- const newValues = new Set(selectedValues);
185
- newValues.add(value);
186
- const selectedOptions = options.filter(opt => newValues.has(opt.dataset.value));
187
- updateValue(selectedOptions);
188
- }
134
+ const option = options.find(opt => getValue(opt) === value && !selectedOptions.has(opt));
135
+ if (!option) return;
136
+ selectedOptions.add(option);
137
+ updateValue(options.filter(opt => selectedOptions.has(opt)));
189
138
  } else {
190
- selectOption(option);
139
+ const option = options.find(opt => getValue(opt) === value);
140
+ if (!option) return;
141
+ if (input.value !== value) {
142
+ updateValue(option);
143
+ }
144
+ closePopover();
191
145
  }
192
146
  };
193
147
 
194
- const selectAll = () => {
148
+ const deselect = (value) => {
195
149
  if (!isMultiple) return;
196
- updateValue(options.filter(opt => opt.dataset.value != null));
150
+ const option = options.find(opt => getValue(opt) === value && selectedOptions.has(opt));
151
+ if (!option) return;
152
+ selectedOptions.delete(option);
153
+ updateValue(options.filter(opt => selectedOptions.has(opt)));
197
154
  };
198
155
 
199
- const selectNone = () => {
156
+ const toggle = (value) => {
200
157
  if (!isMultiple) return;
201
- updateValue([]);
158
+ const option = options.find(opt => getValue(opt) === value);
159
+ if (!option) return;
160
+ toggleMultipleValue(option);
202
161
  };
203
162
 
204
163
  if (filter) {
205
164
  const filterOptions = () => {
206
165
  const searchTerm = filter.value.trim().toLowerCase();
207
-
166
+
208
167
  setActiveOption(-1);
209
168
 
210
169
  visibleOptions = [];
@@ -230,35 +189,36 @@
230
189
  }
231
190
  });
232
191
  };
233
-
192
+
234
193
  filter.addEventListener('input', filterOptions);
235
194
  }
236
195
 
196
+ // Initialization
237
197
  if (isMultiple) {
238
- const validValues = new Set(options.map(opt => opt.dataset.value).filter(v => v != null));
239
- const inputs = Array.from(selectComponent.querySelectorAll(':scope > input[type="hidden"]'));
240
- const initialValues = inputs
241
- .map(inp => inp.value)
242
- .filter(v => v != null && validValues.has(v));
243
-
244
- let initialOptions;
245
- if (initialValues.length > 0) {
246
- initialOptions = options.filter(opt => initialValues.includes(opt.dataset.value));
247
- } else {
248
- initialOptions = options.filter(opt => opt.getAttribute('aria-selected') === 'true');
249
- }
250
-
251
- updateValue(initialOptions, false);
252
- } else {
253
- let initialOption = options.find(opt => opt.dataset.value === input.value);
254
-
255
- if (!initialOption) {
256
- initialOption = options.find(opt => opt.dataset.value !== undefined) ?? options[0];
257
- }
198
+ const ariaSelected = options.filter(opt => opt.getAttribute('aria-selected') === 'true');
199
+ try {
200
+ const parsed = JSON.parse(input.value || '[]');
201
+ const validValues = new Set(options.map(getValue));
202
+ const initialValues = Array.isArray(parsed) ? parsed.filter(v => validValues.has(v)) : [];
203
+
204
+ const initialOptions = [];
205
+ if (initialValues.length > 0) {
206
+ // Match values to options in order, allowing duplicates
207
+ initialValues.forEach(val => {
208
+ const opt = options.find(o => getValue(o) === val && !initialOptions.includes(o));
209
+ if (opt) initialOptions.push(opt);
210
+ });
211
+ } else {
212
+ initialOptions.push(...ariaSelected);
213
+ }
258
214
 
259
- if (initialOption) {
260
- updateValue(initialOption, false);
215
+ updateValue(initialOptions, false);
216
+ } catch (e) {
217
+ updateValue(ariaSelected, false);
261
218
  }
219
+ } else {
220
+ const initialOption = options.find(opt => getValue(opt) === input.value) || options[0];
221
+ if (initialOption) updateValue(initialOption, false);
262
222
  }
263
223
 
264
224
  const handleKeyNavigation = (event) => {
@@ -275,20 +235,24 @@
275
235
  }
276
236
  return;
277
237
  }
278
-
238
+
279
239
  event.preventDefault();
280
240
 
281
241
  if (event.key === 'Escape') {
282
242
  closePopover();
283
243
  return;
284
244
  }
285
-
245
+
286
246
  if (event.key === 'Enter') {
287
247
  if (activeIndex > -1) {
248
+ const option = options[activeIndex];
288
249
  if (isMultiple) {
289
- toggleMultipleValue(options[activeIndex].dataset.value);
250
+ toggleMultipleValue(option);
290
251
  } else {
291
- selectOption(options[activeIndex]);
252
+ if (input.value !== getValue(option)) {
253
+ updateValue(option);
254
+ }
255
+ closePopover();
292
256
  }
293
257
  }
294
258
  return;
@@ -355,7 +319,7 @@
355
319
  document.dispatchEvent(new CustomEvent('basecoat:popover', {
356
320
  detail: { source: selectComponent }
357
321
  }));
358
-
322
+
359
323
  if (filter) {
360
324
  if (hasTransition()) {
361
325
  popover.addEventListener('transitionend', () => {
@@ -368,7 +332,7 @@
368
332
 
369
333
  popover.setAttribute('aria-hidden', 'false');
370
334
  trigger.setAttribute('aria-expanded', 'true');
371
-
335
+
372
336
  const selectedOption = listbox.querySelector('[role="option"][aria-selected="true"]');
373
337
  if (selectedOption) {
374
338
  setActiveOption(options.indexOf(selectedOption));
@@ -387,18 +351,24 @@
387
351
 
388
352
  listbox.addEventListener('click', (event) => {
389
353
  const clickedOption = event.target.closest('[role="option"]');
390
- if (clickedOption) {
391
- if (isMultiple) {
392
- toggleMultipleValue(clickedOption.dataset.value);
393
- setActiveOption(options.indexOf(clickedOption));
394
- if (filter) {
395
- filter.focus();
396
- } else {
397
- trigger.focus();
398
- }
354
+ if (!clickedOption) return;
355
+
356
+ const option = options.find(opt => opt === clickedOption);
357
+ if (!option) return;
358
+
359
+ if (isMultiple) {
360
+ toggleMultipleValue(option);
361
+ setActiveOption(options.indexOf(option));
362
+ if (filter) {
363
+ filter.focus();
399
364
  } else {
400
- selectOption(clickedOption);
365
+ trigger.focus();
401
366
  }
367
+ } else {
368
+ if (input.value !== getValue(option)) {
369
+ updateValue(option);
370
+ }
371
+ closePopover();
402
372
  }
403
373
  });
404
374
 
@@ -416,10 +386,41 @@
416
386
 
417
387
  popover.setAttribute('aria-hidden', 'true');
418
388
 
419
- selectComponent.selectByValue = selectByValue;
389
+ // Public API
390
+ Object.defineProperty(selectComponent, 'value', {
391
+ get: () => {
392
+ if (isMultiple) {
393
+ return options.filter(opt => selectedOptions.has(opt)).map(getValue);
394
+ } else {
395
+ return input.value;
396
+ }
397
+ },
398
+ set: (val) => {
399
+ if (isMultiple) {
400
+ const values = Array.isArray(val) ? val : (val != null ? [val] : []);
401
+ const opts = [];
402
+ values.forEach(v => {
403
+ const opt = options.find(o => getValue(o) === v && !opts.includes(o));
404
+ if (opt) opts.push(opt);
405
+ });
406
+ updateValue(opts);
407
+ } else {
408
+ const option = options.find(opt => getValue(opt) === val);
409
+ if (option) {
410
+ updateValue(option);
411
+ closePopover();
412
+ }
413
+ }
414
+ }
415
+ });
416
+
417
+ selectComponent.select = select;
418
+ selectComponent.selectByValue = select; // Backward compatibility alias
420
419
  if (isMultiple) {
421
- selectComponent.selectAll = selectAll;
422
- selectComponent.selectNone = selectNone;
420
+ selectComponent.deselect = deselect;
421
+ selectComponent.toggle = toggle;
422
+ selectComponent.selectAll = () => updateValue(options);
423
+ selectComponent.selectNone = () => updateValue([]);
423
424
  }
424
425
  selectComponent.dataset.selectInitialized = true;
425
426
  selectComponent.dispatchEvent(new CustomEvent('basecoat:initialized'));
@@ -1 +1 @@
1
- (()=>{const e=e=>{const t=e.querySelector(":scope > button"),a=t.querySelector(":scope > span"),r=e.querySelector(":scope > [data-popover]"),n=r?r.querySelector('[role="listbox"]'):null,i=e.querySelector(':scope > input[type="hidden"]'),s=e.querySelector('header input[type="text"]');if(!(t&&r&&n&&i)){const a=[];return t||a.push("trigger"),r||a.push("popover"),n||a.push("listbox"),i||a.push("input"),void console.error(`Select component initialisation failed. Missing element(s): ${a.join(", ")}`,e)}const o=Array.from(n.querySelectorAll('[role="option"]')),l=o.filter((e=>"true"!==e.getAttribute("aria-disabled")));let d=[...l],u=-1;const c="true"===n.getAttribute("aria-multiselectable");let f=c?new Set:null,v=null;c&&(v=e.dataset.placeholder||"");const p=e=>{if(u>-1&&l[u]&&l[u].classList.remove("active"),u=e,u>-1){const e=l[u];e.classList.add("active"),e.id?t.setAttribute("aria-activedescendant",e.id):t.removeAttribute("aria-activedescendant")}else t.removeAttribute("aria-activedescendant")},h=()=>{const e=getComputedStyle(r);return parseFloat(e.transitionDuration)>0||parseFloat(e.transitionDelay)>0},b=(t,r=!0)=>{let n;if(c){const r=Array.isArray(t)?t:[];f=new Set(r.map((e=>e.dataset.value))),l.forEach((e=>{f.has(e.dataset.value)?e.setAttribute("aria-selected","true"):e.removeAttribute("aria-selected")})),(()=>{if(!c)return;const e=l.filter((e=>f.has(e.dataset.value)));0===e.length?(a.textContent=v,a.classList.add("text-muted-foreground")):(a.textContent=e.map((e=>e.dataset.label||e.textContent.trim())).join(", "),a.classList.remove("text-muted-foreground"))})(),(()=>{if(!c)return;const t=Array.from(f);if(Array.from(e.querySelectorAll(':scope > input[type="hidden"]')).slice(1).forEach((e=>e.remove())),0===t.length)i.value="";else{i.value=t[0];let e=i;for(let a=1;a<t.length;a++){const r=i.cloneNode(!0);r.removeAttribute("id"),r.value=t[a],e.after(r),e=r}}})(),n=Array.from(f)}else{const e=t;if(!e)return;a.innerHTML=e.innerHTML,i.value=e.dataset.value,l.forEach((t=>{t===e?t.setAttribute("aria-selected","true"):t.removeAttribute("aria-selected")})),n=e.dataset.value}r&&e.dispatchEvent(new CustomEvent("change",{detail:{value:n},bubbles:!0}))},m=(e,t=!0)=>{if(!c||null==e)return;const a=new Set(f);a.has(e)?a.delete(e):a.add(e);const r=l.filter((e=>a.has(e.dataset.value)));b(r,t)},A=(e=!0)=>{if("true"!==r.getAttribute("aria-hidden")){if(s){const e=()=>{s.value="",d=[...l],o.forEach((e=>e.setAttribute("aria-hidden","false")))};h()?r.addEventListener("transitionend",e,{once:!0}):e()}e&&t.focus(),r.setAttribute("aria-hidden","true"),t.setAttribute("aria-expanded","false"),p(-1)}},y=e=>{if(!e)return;const t=i.value,a=e.dataset.value;null!=a&&a!==t&&b(e),A()},E=()=>{c&&b(l.filter((e=>null!=e.dataset.value)))},w=()=>{c&&b([])};if(s){const e=()=>{const e=s.value.trim().toLowerCase();p(-1),d=[],o.forEach((t=>{if(t.hasAttribute("data-force"))return t.setAttribute("aria-hidden","false"),void(l.includes(t)&&d.push(t));const a=(t.dataset.filter||t.textContent).trim().toLowerCase(),r=(t.dataset.keywords||"").toLowerCase().split(/[\s,]+/).filter(Boolean).some((t=>t.includes(e))),n=a.includes(e)||r;t.setAttribute("aria-hidden",String(!n)),n&&l.includes(t)&&d.push(t)}))};s.addEventListener("input",e)}if(c){const t=new Set(l.map((e=>e.dataset.value)).filter((e=>null!=e))),a=Array.from(e.querySelectorAll(':scope > input[type="hidden"]')).map((e=>e.value)).filter((e=>null!=e&&t.has(e)));let r;r=a.length>0?l.filter((e=>a.includes(e.dataset.value))):l.filter((e=>"true"===e.getAttribute("aria-selected"))),b(r,!1)}else{let e=l.find((e=>e.dataset.value===i.value));e||(e=l.find((e=>void 0!==e.dataset.value))??l[0]),e&&b(e,!1)}const g=e=>{const a="false"===r.getAttribute("aria-hidden");if(!["ArrowDown","ArrowUp","Enter","Home","End","Escape"].includes(e.key))return;if(!a)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)return void(u>-1&&(c?m(l[u].dataset.value):y(l[u])));if(0===d.length)return;const n=u>-1?d.indexOf(l[u]):-1;let i=n;switch(e.key){case"ArrowDown":n<d.length-1&&(i=n+1);break;case"ArrowUp":n>0?i=n-1:-1===n&&(i=0);break;case"Home":i=0;break;case"End":i=d.length-1}if(i!==n){const e=d[i];p(l.indexOf(e)),e.scrollIntoView({block:"nearest",behavior:"smooth"})}};n.addEventListener("mousemove",(e=>{const t=e.target.closest('[role="option"]');if(t&&d.includes(t)){const e=l.indexOf(t);e!==u&&p(e)}})),n.addEventListener("mouseleave",(()=>{const e=n.querySelector('[role="option"][aria-selected="true"]');p(e?l.indexOf(e):-1)})),t.addEventListener("keydown",g),s&&s.addEventListener("keydown",g);t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?A():(()=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}})),s&&(h()?r.addEventListener("transitionend",(()=>{s.focus()}),{once:!0}):s.focus()),r.setAttribute("aria-hidden","false"),t.setAttribute("aria-expanded","true");const a=n.querySelector('[role="option"][aria-selected="true"]');a&&(p(l.indexOf(a)),a.scrollIntoView({block:"nearest"}))})()})),n.addEventListener("click",(e=>{const a=e.target.closest('[role="option"]');a&&(c?(m(a.dataset.value),p(l.indexOf(a)),s?s.focus():t.focus()):y(a))})),document.addEventListener("click",(t=>{e.contains(t.target)||A(!1)})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&A(!1)})),r.setAttribute("aria-hidden","true"),e.selectByValue=e=>{const t=l.find((t=>t.dataset.value===e));if(c){if(null!=e&&f.has(e))return;if(t&&null!=e){const t=new Set(f);t.add(e);const a=l.filter((e=>t.has(e.dataset.value)));b(a)}}else y(t)},c&&(e.selectAll=E,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)})();
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=e=>e.dataset.value??e.textContent.trim(),h=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")},b=()=>{const e=getComputedStyle(n);return parseFloat(e.transitionDuration)>0||parseFloat(e.transitionDelay)>0},m=(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(v),a.value=JSON.stringify(i)}else{const e=t;if(!e)return;r.innerHTML=e.innerHTML,i=v(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}))},y=(e=!0)=>{if("true"!==n.getAttribute("aria-hidden")){if(s){const e=()=>{s.value="",l=[...c],o.forEach((e=>e.setAttribute("aria-hidden","false")))};b()?n.addEventListener("transitionend",e,{once:!0}):e()}e&&t.focus(),n.setAttribute("aria-hidden","true"),t.setAttribute("aria-expanded","false"),h(-1)}},A=e=>{f.has(e)?f.delete(e):f.add(e),m(c.filter((e=>f.has(e))))},E=e=>{if(u){const t=c.find((t=>v(t)===e&&!f.has(t)));if(!t)return;f.add(t),m(c.filter((e=>f.has(e))))}else{const t=c.find((t=>v(t)===e));if(!t)return;a.value!==e&&m(t),y()}},g=e=>{if(!u)return;const t=c.find((t=>v(t)===e&&f.has(t)));t&&(f.delete(t),m(c.filter((e=>f.has(e)))))},w=e=>{if(!u)return;const t=c.find((t=>v(t)===e));t&&A(t)};if(s){const e=()=>{const e=s.value.trim().toLowerCase();h(-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(v)),n=Array.isArray(t)?t.filter((e=>r.has(e))):[],i=[];n.length>0?n.forEach((e=>{const t=c.find((t=>v(t)===e&&!i.includes(t)));t&&i.push(t)})):i.push(...e),m(i,!1)}catch(t){m(e,!1)}}else{const e=c.find((e=>v(e)===a.value))||c[0];e&&m(e,!1)}const L=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 y();if("Enter"===e.key){if(d>-1){const e=c[d];u?A(e):(a.value!==v(e)&&m(e),y())}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];h(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&&h(e)}})),i.addEventListener("mouseleave",(()=>{const e=i.querySelector('[role="option"][aria-selected="true"]');h(e?c.indexOf(e):-1)})),t.addEventListener("keydown",L),s&&s.addEventListener("keydown",L);t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?y():(()=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}})),s&&(b()?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&&(h(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?(A(n),h(c.indexOf(n)),s?s.focus():t.focus()):(a.value!==v(n)&&m(n),y()))})),document.addEventListener("click",(t=>{e.contains(t.target)||y(!1)})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&y(!1)})),n.setAttribute("aria-hidden","true"),Object.defineProperty(e,"value",{get:()=>u?c.filter((e=>f.has(e))).map(v):a.value,set:e=>{if(u){const t=Array.isArray(e)?e:null!=e?[e]:[],r=[];t.forEach((e=>{const t=c.find((t=>v(t)===e&&!r.includes(t)));t&&r.push(t)})),m(r)}else{const t=c.find((t=>v(t)===e));t&&(m(t),y())}}}),e.select=E,e.selectByValue=E,u&&(e.deselect=g,e.toggle=w,e.selectAll=()=>m(c),e.selectNone=()=>m([])),e.dataset.selectInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("select","div.select:not([data-select-initialized])",e)})();
@@ -31,7 +31,13 @@
31
31
  ) %}
32
32
  {% set id = id or ("select-" + (range(100000, 999999) | random | string)) %}
33
33
 
34
- {% set selectedArray = ((selected if (selected is iterable and selected is not string) else [selected]) if selected else []) %}
34
+ {% if selected is defined and selected is iterable and selected is not string %}
35
+ {% set selectedArray = selected %}
36
+ {% elif selected is defined %}
37
+ {% set selectedArray = [selected] %}
38
+ {% else %}
39
+ {% set selectedArray = [] %}
40
+ {% endif %}
35
41
  {% set first_option = [] %}
36
42
  {% set selected_options = [] %}
37
43
 
@@ -135,28 +141,14 @@
135
141
  {% endif %}
136
142
  </div>
137
143
  </div>
138
- {% if multiple and selectedArray %}
139
- {% for val in selectedArray %}
140
- <input
141
- type="hidden"
142
- name="{{ name or id ~ '-value' }}"
143
- value="{{ val }}"
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
- >
144
+ <input
145
+ type="hidden"
146
+ name="{{ name or id ~ '-value' }}"
147
+ value="{% if multiple %}{{ selectedArray | dump }}{% else %}{{ (default_option.value if default_option) or '' }}{% endif %}"
148
+ {% for key, value in input_attrs %}
149
+ {% if key != 'name' and key != 'value' %}{{ key }}="{{ value }}"{% endif %}
149
150
  {% endfor %}
150
- {% else %}
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 %}
151
+ >
160
152
  </div>
161
153
  {% endmacro %}
162
154
 
@@ -189,7 +181,7 @@
189
181
  <div
190
182
  id="{{ item_id }}"
191
183
  role="option"
192
- data-value="{{ item.value }}"
184
+ {% if item.value is defined and item.value is not none %}data-value="{{ item.value }}"{% endif %}
193
185
  {% if item.value in selectedArray %}aria-selected="true"{% endif %}
194
186
  {% if item.attrs %}
195
187
  {% for key, value in item.attrs %}
@@ -201,4 +193,4 @@
201
193
  </div>
202
194
  {% endif %}
203
195
  {% endfor %}
204
- {% endmacro %}
196
+ {% endmacro %}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basecoat-cli",
3
- "version": "0.3.10-beta.1",
3
+ "version": "0.3.10-beta.2",
4
4
  "description": "Add Basecoat components to your project",
5
5
  "author": "hunvreus",
6
6
  "license": "MIT",