basecoat-cli 0.3.10-beta.2 → 0.3.11

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.
@@ -83,12 +83,10 @@
83
83
  </footer>
84
84
  {% endif %}
85
85
  {% if close_button %}
86
- <form method="dialog">
87
- <button aria-label="Close dialog">
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={},
@@ -76,6 +78,7 @@
76
78
  id="{{ id }}"
77
79
  class="select {{ main_attrs.class }}"
78
80
  {% if multiple and placeholder %}data-placeholder="{{ placeholder }}"{% endif %}
81
+ {% if multiple and close_on_select %}data-close-on-select="true"{% endif %}
79
82
  {% for key, value in main_attrs.items() %}
80
83
  {% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
81
84
  {% endfor %}
@@ -529,6 +529,7 @@
529
529
  const isMultiple = listbox.getAttribute('aria-multiselectable') === 'true';
530
530
  const selectedOptions = isMultiple ? new Set() : null;
531
531
  const placeholder = isMultiple ? (selectComponent.dataset.placeholder || '') : null;
532
+ const closeOnSelect = selectComponent.dataset.closeOnSelect === 'true';
532
533
 
533
534
  const getValue = (opt) => opt.dataset.value ?? opt.textContent.trim();
534
535
 
@@ -753,6 +754,9 @@
753
754
  const option = options[activeIndex];
754
755
  if (isMultiple) {
755
756
  toggleMultipleValue(option);
757
+ if (closeOnSelect) {
758
+ closePopover();
759
+ }
756
760
  } else {
757
761
  if (input.value !== getValue(option)) {
758
762
  updateValue(option);
@@ -863,11 +867,15 @@
863
867
 
864
868
  if (isMultiple) {
865
869
  toggleMultipleValue(option);
866
- setActiveOption(options.indexOf(option));
867
- if (filter) {
868
- filter.focus();
870
+ if (closeOnSelect) {
871
+ closePopover();
869
872
  } else {
870
- trigger.focus();
873
+ setActiveOption(options.indexOf(option));
874
+ if (filter) {
875
+ filter.focus();
876
+ } else {
877
+ trigger.focus();
878
+ }
871
879
  }
872
880
  } else {
873
881
  if (input.value !== getValue(option)) {
@@ -937,23 +945,6 @@
937
945
  })();
938
946
 
939
947
  (() => {
940
- // Monkey patching the history API to detect client-side navigation
941
- if (!window.history.__basecoatPatched) {
942
- const originalPushState = window.history.pushState;
943
- window.history.pushState = function(...args) {
944
- originalPushState.apply(this, args);
945
- window.dispatchEvent(new Event('basecoat:locationchange'));
946
- };
947
-
948
- const originalReplaceState = window.history.replaceState;
949
- window.history.replaceState = function(...args) {
950
- originalReplaceState.apply(this, args);
951
- window.dispatchEvent(new Event('basecoat:locationchange'));
952
- };
953
-
954
- window.history.__basecoatPatched = true;
955
- }
956
-
957
948
  const initSidebar = (sidebarComponent) => {
958
949
  const initialOpen = sidebarComponent.dataset.initialOpen !== 'false';
959
950
  const initialMobileOpen = sidebarComponent.dataset.initialMobileOpen === 'true';
@@ -963,20 +954,6 @@
963
954
  ? (window.innerWidth >= breakpoint ? initialOpen : initialMobileOpen)
964
955
  : initialOpen;
965
956
 
966
- const updateCurrentPageLinks = () => {
967
- const currentPath = window.location.pathname.replace(/\/$/, '');
968
- sidebarComponent.querySelectorAll('a').forEach(link => {
969
- if (link.hasAttribute('data-ignore-current')) return;
970
-
971
- const linkPath = new URL(link.href).pathname.replace(/\/$/, '');
972
- if (linkPath === currentPath) {
973
- link.setAttribute('aria-current', 'page');
974
- } else {
975
- link.removeAttribute('aria-current');
976
- }
977
- });
978
- };
979
-
980
957
  const updateState = () => {
981
958
  sidebarComponent.setAttribute('aria-hidden', !open);
982
959
  if (open) {
@@ -1027,11 +1004,7 @@
1027
1004
  }
1028
1005
  });
1029
1006
 
1030
- window.addEventListener('popstate', updateCurrentPageLinks);
1031
- window.addEventListener('basecoat:locationchange', updateCurrentPageLinks);
1032
-
1033
1007
  updateState();
1034
- updateCurrentPageLinks();
1035
1008
  sidebarComponent.dataset.sidebarInitialized = true;
1036
1009
  sidebarComponent.dispatchEvent(new CustomEvent('basecoat:initialized'));
1037
1010
  };
@@ -1040,6 +1013,7 @@
1040
1013
  window.basecoat.register('sidebar', '.sidebar:not([data-sidebar-initialized])', initSidebar);
1041
1014
  }
1042
1015
  })();
1016
+
1043
1017
  (() => {
1044
1018
  const initTabs = (tabsComponent) => {
1045
1019
  const tablist = tabsComponent.querySelector('[role="tablist"]');
@@ -1 +1 @@
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))})();
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"),v=u?new Set:null,f=u?e.dataset.placeholder||"":null,m="true"===e.dataset.closeOnSelect,p=e=>e.dataset.value??e.textContent.trim(),h=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:[];v.clear(),e.forEach((e=>v.add(e)));const i=d.filter((e=>v.has(e)));0===i.length?(n.textContent=f,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(p),r.value=JSON.stringify(a)}else{const e=t;if(!e)return;n.innerHTML=e.innerHTML,a=p(e),r.value=a}d.forEach((e=>{(u?v.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"),h(-1)}},E=e=>{v.has(e)?v.delete(e):v.add(e),w(d.filter((e=>v.has(e))))},A=e=>{if(u){const t=d.find((t=>p(t)===e&&!v.has(t)));if(!t)return;v.add(t),w(d.filter((e=>v.has(e))))}else{const t=d.find((t=>p(t)===e));if(!t)return;r.value!==e&&w(t),g()}},k=e=>{if(!u)return;const t=d.find((t=>p(t)===e&&v.has(t)));t&&(v.delete(t),w(d.filter((e=>v.has(e)))))},y=e=>{if(!u)return;const t=d.find((t=>p(t)===e));t&&E(t)};if(o){const e=()=>{const e=o.value.trim().toLowerCase();h(-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(p)),i=Array.isArray(t)?t.filter((e=>n.has(e))):[],a=[];i.length>0?i.forEach((e=>{const t=d.find((t=>p(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=>p(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),m&&g()):(r.value!==p(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];h(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&&h(e)}})),a.addEventListener("mouseleave",(()=>{const e=a.querySelector('[role="option"][aria-selected="true"]');h(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&&(h(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),m?g():(h(d.indexOf(i)),o?o.focus():t.focus())):(r.value!==p(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=>v.has(e))).map(p):r.value,set:e=>{if(u){const t=Array.isArray(e)?e:null!=e?[e]:[],n=[];t.forEach((e=>{const t=d.find((t=>p(t)===e&&!n.includes(t)));t&&n.push(t)})),w(n)}else{const t=d.find((t=>p(t)===e));t&&(w(t),g())}}}),e.select=A,e.selectByValue=A,u&&(e.deselect=k,e.toggle=y,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)})(),(()=>{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=()=>{e.setAttribute("aria-hidden",!a),a?e.removeAttribute("inert"):e.setAttribute("inert","")},o=e=>{a=e,r()},s=e.id;document.addEventListener("basecoat:sidebar",(e=>{if(!e.detail?.id||e.detail.id===s)switch(e.detail?.action){case"open":o(!0);break;case"close":o(!1);break;default:o(!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 o(!1);(n===e||a&&!a.contains(n))&&(document.activeElement&&document.activeElement.blur(),o(!1))})),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>`:"",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>`:"",f=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||f?`<footer>${v}${f}</footer>`:""}\n </div>\n </div>\n </div>\n `,p=document.createElement("template");return p.innerHTML=m.trim(),p.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))})();
@@ -24,6 +24,7 @@
24
24
  const isMultiple = listbox.getAttribute('aria-multiselectable') === 'true';
25
25
  const selectedOptions = isMultiple ? new Set() : null;
26
26
  const placeholder = isMultiple ? (selectComponent.dataset.placeholder || '') : null;
27
+ const closeOnSelect = selectComponent.dataset.closeOnSelect === 'true';
27
28
 
28
29
  const getValue = (opt) => opt.dataset.value ?? opt.textContent.trim();
29
30
 
@@ -248,6 +249,9 @@
248
249
  const option = options[activeIndex];
249
250
  if (isMultiple) {
250
251
  toggleMultipleValue(option);
252
+ if (closeOnSelect) {
253
+ closePopover();
254
+ }
251
255
  } else {
252
256
  if (input.value !== getValue(option)) {
253
257
  updateValue(option);
@@ -358,11 +362,15 @@
358
362
 
359
363
  if (isMultiple) {
360
364
  toggleMultipleValue(option);
361
- setActiveOption(options.indexOf(option));
362
- if (filter) {
363
- filter.focus();
365
+ if (closeOnSelect) {
366
+ closePopover();
364
367
  } else {
365
- trigger.focus();
368
+ setActiveOption(options.indexOf(option));
369
+ if (filter) {
370
+ filter.focus();
371
+ } else {
372
+ trigger.focus();
373
+ }
366
374
  }
367
375
  } else {
368
376
  if (input.value !== getValue(option)) {
@@ -1 +1 @@
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)})();
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)})();
@@ -1,21 +1,4 @@
1
1
  (() => {
2
- // Monkey patching the history API to detect client-side navigation
3
- if (!window.history.__basecoatPatched) {
4
- const originalPushState = window.history.pushState;
5
- window.history.pushState = function(...args) {
6
- originalPushState.apply(this, args);
7
- window.dispatchEvent(new Event('basecoat:locationchange'));
8
- };
9
-
10
- const originalReplaceState = window.history.replaceState;
11
- window.history.replaceState = function(...args) {
12
- originalReplaceState.apply(this, args);
13
- window.dispatchEvent(new Event('basecoat:locationchange'));
14
- };
15
-
16
- window.history.__basecoatPatched = true;
17
- }
18
-
19
2
  const initSidebar = (sidebarComponent) => {
20
3
  const initialOpen = sidebarComponent.dataset.initialOpen !== 'false';
21
4
  const initialMobileOpen = sidebarComponent.dataset.initialMobileOpen === 'true';
@@ -25,20 +8,6 @@
25
8
  ? (window.innerWidth >= breakpoint ? initialOpen : initialMobileOpen)
26
9
  : initialOpen;
27
10
 
28
- const updateCurrentPageLinks = () => {
29
- const currentPath = window.location.pathname.replace(/\/$/, '');
30
- sidebarComponent.querySelectorAll('a').forEach(link => {
31
- if (link.hasAttribute('data-ignore-current')) return;
32
-
33
- const linkPath = new URL(link.href).pathname.replace(/\/$/, '');
34
- if (linkPath === currentPath) {
35
- link.setAttribute('aria-current', 'page');
36
- } else {
37
- link.removeAttribute('aria-current');
38
- }
39
- });
40
- };
41
-
42
11
  const updateState = () => {
43
12
  sidebarComponent.setAttribute('aria-hidden', !open);
44
13
  if (open) {
@@ -89,11 +58,7 @@
89
58
  }
90
59
  });
91
60
 
92
- window.addEventListener('popstate', updateCurrentPageLinks);
93
- window.addEventListener('basecoat:locationchange', updateCurrentPageLinks);
94
-
95
61
  updateState();
96
- updateCurrentPageLinks();
97
62
  sidebarComponent.dataset.sidebarInitialized = true;
98
63
  sidebarComponent.dispatchEvent(new CustomEvent('basecoat:initialized'));
99
64
  };
@@ -101,4 +66,4 @@
101
66
  if (window.basecoat) {
102
67
  window.basecoat.register('sidebar', '.sidebar:not([data-sidebar-initialized])', initSidebar);
103
68
  }
104
- })();
69
+ })();
@@ -1 +1 @@
1
- (()=>{if(!window.history.__basecoatPatched){const t=window.history.pushState;window.history.pushState=function(...e){t.apply(this,e),window.dispatchEvent(new Event("basecoat:locationchange"))};const e=window.history.replaceState;window.history.replaceState=function(...t){e.apply(this,t),window.dispatchEvent(new Event("basecoat:locationchange"))},window.history.__basecoatPatched=!0}const t=t=>{const e="false"!==t.dataset.initialOpen,a="true"===t.dataset.initialMobileOpen,i=parseInt(t.dataset.breakpoint)||768;let n=i>0?window.innerWidth>=i?e:a:e;const o=()=>{const e=window.location.pathname.replace(/\/$/,"");t.querySelectorAll("a").forEach((t=>{if(t.hasAttribute("data-ignore-current"))return;new URL(t.href).pathname.replace(/\/$/,"")===e?t.setAttribute("aria-current","page"):t.removeAttribute("aria-current")}))},r=()=>{t.setAttribute("aria-hidden",!n),n?t.removeAttribute("inert"):t.setAttribute("inert","")},d=t=>{n=t,r()},s=t.id;document.addEventListener("basecoat:sidebar",(t=>{if(!t.detail?.id||t.detail.id===s)switch(t.detail?.action){case"open":d(!0);break;case"close":d(!1);break;default:d(!n)}})),t.addEventListener("click",(e=>{const a=e.target,n=t.querySelector("nav");if(window.innerWidth<i&&a.closest("a, button")&&!a.closest("[data-keep-mobile-sidebar-open]"))return document.activeElement&&document.activeElement.blur(),void d(!1);(a===t||n&&!n.contains(a))&&(document.activeElement&&document.activeElement.blur(),d(!1))})),window.addEventListener("popstate",o),window.addEventListener("basecoat:locationchange",o),r(),o(),t.dataset.sidebarInitialized=!0,t.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("sidebar",".sidebar:not([data-sidebar-initialized])",t)})();
1
+ (()=>{const e=e=>{const t="false"!==e.dataset.initialOpen,i="true"===e.dataset.initialMobileOpen,a=parseInt(e.dataset.breakpoint)||768;let n=a>0?window.innerWidth>=a?t:i:t;const d=()=>{e.setAttribute("aria-hidden",!n),n?e.removeAttribute("inert"):e.setAttribute("inert","")},s=e=>{n=e,d()},o=e.id;document.addEventListener("basecoat:sidebar",(e=>{if(!e.detail?.id||e.detail.id===o)switch(e.detail?.action){case"open":s(!0);break;case"close":s(!1);break;default:s(!n)}})),e.addEventListener("click",(t=>{const i=t.target,n=e.querySelector("nav");if(window.innerWidth<a&&i.closest("a, button")&&!i.closest("[data-keep-mobile-sidebar-open]"))return document.activeElement&&document.activeElement.blur(),void s(!1);(i===e||n&&!n.contains(i))&&(document.activeElement&&document.activeElement.blur(),s(!1))})),d(),e.dataset.sidebarInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("sidebar",".sidebar:not([data-sidebar-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={},
@@ -76,6 +78,7 @@
76
78
  id="{{ id }}"
77
79
  class="select {{ main_attrs.class }}"
78
80
  {% if multiple and placeholder %}data-placeholder="{{ placeholder }}"{% endif %}
81
+ {% if multiple and close_on_select %}data-close-on-select="true"{% endif %}
79
82
  {% for key, value in main_attrs %}
80
83
  {% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
81
84
  {% endfor %}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basecoat-cli",
3
- "version": "0.3.10-beta.2",
3
+ "version": "0.3.11",
4
4
  "description": "Add Basecoat components to your project",
5
5
  "author": "hunvreus",
6
6
  "license": "MIT",
@@ -1,111 +0,0 @@
1
- {#
2
- Renders a carousel component with navigation controls and optional indicators.
3
-
4
- @param id {string} [optional] - Unique identifier for the carousel component. Auto-generated if not provided.
5
- @param slides {array} - An array of objects representing carousel slides.
6
- Each object should have:
7
- - content {string}: HTML content for the slide.
8
- - attrs {object} [optional]: Additional HTML attributes for the slide item.
9
- @param loop {boolean} [optional] [default=false] - Enable continuous looping.
10
- @param autoplay {number} [optional] [default=0] - Auto-advance delay in milliseconds (0 = disabled).
11
- @param align {string} [optional] [default='start'] - Slide alignment ('start' or 'center').
12
- @param orientation {string} [optional] [default='horizontal'] - Carousel orientation ('horizontal' or 'vertical').
13
- @param show_controls {boolean} [optional] [default=true] - Show previous/next navigation buttons.
14
- @param show_indicators {boolean} [optional] [default=true] - Show slide indicator dots.
15
- @param main_attrs {object} [optional] - Additional HTML attributes for the main container.
16
- @param viewport_attrs {object} [optional] - Additional HTML attributes for the viewport container.
17
- #}
18
- {% macro carousel(
19
- id=None,
20
- slides=[],
21
- loop=false,
22
- autoplay=0,
23
- align='start',
24
- orientation='horizontal',
25
- show_controls=true,
26
- show_indicators=true,
27
- main_attrs={},
28
- viewport_attrs={}
29
- )
30
- %}
31
- {% set id = id or ("carousel-" + (range(100000, 999999) | random | string)) %}
32
- <div
33
- class="carousel {{ main_attrs.class }}"
34
- id="{{ id }}"
35
- data-carousel-loop="{{ 'true' if loop else 'false' }}"
36
- {% if autoplay > 0 %}data-carousel-autoplay="{{ autoplay }}"{% endif %}
37
- data-orientation="{{ orientation }}"
38
- role="region"
39
- aria-roledescription="carousel"
40
- aria-label="Carousel"
41
- tabindex="0"
42
- {% for key, value in main_attrs.items() %}
43
- {% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
44
- {% endfor %}
45
- >
46
- <div
47
- class="carousel-viewport {{ viewport_attrs.class }}"
48
- {% for key, value in viewport_attrs.items() %}
49
- {% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
50
- {% endfor %}
51
- >
52
- <div
53
- class="carousel-slides"
54
- data-orientation="{{ orientation }}"
55
- >
56
- {% for slide in slides %}
57
- <div
58
- class="carousel-item"
59
- role="group"
60
- aria-roledescription="slide"
61
- aria-label="{{ loop.index }} of {{ slides | length }}"
62
- {% if align == 'center' %}data-align="center"{% endif %}
63
- {% if slide.attrs %}
64
- {% for key, value in slide.attrs.items() %}
65
- {{ key }}="{{ value }}"
66
- {% endfor %}
67
- {% endif %}
68
- >
69
- {{ slide.content | safe }}
70
- </div>
71
- {% endfor %}
72
- </div>
73
- </div>
74
-
75
- {% if show_controls %}
76
- <div class="carousel-controls">
77
- <button
78
- type="button"
79
- class="carousel-prev"
80
- aria-label="Previous slide"
81
- >
82
- <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">
83
- <path d="m15 18-6-6 6-6"/>
84
- </svg>
85
- </button>
86
- <button
87
- type="button"
88
- class="carousel-next"
89
- aria-label="Next slide"
90
- >
91
- <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">
92
- <path d="m9 18 6-6-6-6"/>
93
- </svg>
94
- </button>
95
- </div>
96
- {% endif %}
97
-
98
- {% if show_indicators %}
99
- <div class="carousel-indicators" role="tablist" aria-label="Slides">
100
- {% for slide in slides %}
101
- <button
102
- type="button"
103
- role="tab"
104
- aria-label="Slide {{ loop.index }}"
105
- {% if loop.index == 1 %}aria-current="true"{% else %}aria-current="false"{% endif %}
106
- ></button>
107
- {% endfor %}
108
- </div>
109
- {% endif %}
110
- </div>
111
- {% endmacro %}
@@ -1,192 +0,0 @@
1
- (() => {
2
- const initCarousel = (carouselComponent) => {
3
- const slidesContainer = carouselComponent.querySelector('.carousel-slides');
4
- if (!slidesContainer) return;
5
-
6
- const slides = Array.from(carouselComponent.querySelectorAll('.carousel-item'));
7
- const prevButton = carouselComponent.querySelector('.carousel-prev');
8
- const nextButton = carouselComponent.querySelector('.carousel-next');
9
- const indicators = Array.from(carouselComponent.querySelectorAll('.carousel-indicators button'));
10
-
11
- const loop = carouselComponent.dataset.carouselLoop === 'true';
12
- const autoplayDelay = parseInt(carouselComponent.dataset.carouselAutoplay, 10);
13
- const orientation = carouselComponent.dataset.orientation || 'horizontal';
14
-
15
- let currentIndex = 0;
16
- let autoplayInterval = null;
17
-
18
- const getScrollAmount = () => {
19
- if (slides.length === 0) return 0;
20
- const firstSlide = slides[0];
21
- return orientation === 'vertical'
22
- ? firstSlide.offsetHeight + parseInt(getComputedStyle(slidesContainer).gap || 0)
23
- : firstSlide.offsetWidth + parseInt(getComputedStyle(slidesContainer).gap || 0);
24
- };
25
-
26
- const scrollToIndex = (index) => {
27
- const scrollAmount = getScrollAmount();
28
- if (orientation === 'vertical') {
29
- slidesContainer.scrollTo({ top: scrollAmount * index, behavior: 'smooth' });
30
- } else {
31
- slidesContainer.scrollTo({ left: scrollAmount * index, behavior: 'smooth' });
32
- }
33
- currentIndex = index;
34
- updateIndicators();
35
- updateButtonStates();
36
- };
37
-
38
- const updateIndicators = () => {
39
- indicators.forEach((indicator, index) => {
40
- const isActive = index === currentIndex;
41
- indicator.setAttribute('aria-current', isActive ? 'true' : 'false');
42
- indicator.setAttribute('aria-label', `Slide ${index + 1}${isActive ? ' (current)' : ''}`);
43
- });
44
-
45
- slides.forEach((slide, index) => {
46
- slide.setAttribute('aria-hidden', index === currentIndex ? 'false' : 'true');
47
- });
48
- };
49
-
50
- const updateButtonStates = () => {
51
- if (!prevButton || !nextButton) return;
52
-
53
- if (loop) {
54
- prevButton.disabled = false;
55
- nextButton.disabled = false;
56
- } else {
57
- prevButton.disabled = currentIndex === 0;
58
- nextButton.disabled = currentIndex === slides.length - 1;
59
- }
60
- };
61
-
62
- const goToPrevious = () => {
63
- if (currentIndex > 0) {
64
- scrollToIndex(currentIndex - 1);
65
- } else if (loop) {
66
- scrollToIndex(slides.length - 1);
67
- }
68
- };
69
-
70
- const goToNext = () => {
71
- if (currentIndex < slides.length - 1) {
72
- scrollToIndex(currentIndex + 1);
73
- } else if (loop) {
74
- scrollToIndex(0);
75
- }
76
- };
77
-
78
- const startAutoplay = () => {
79
- if (!autoplayDelay || autoplayDelay <= 0) return;
80
-
81
- autoplayInterval = setInterval(() => {
82
- goToNext();
83
- }, autoplayDelay);
84
- };
85
-
86
- const stopAutoplay = () => {
87
- if (autoplayInterval) {
88
- clearInterval(autoplayInterval);
89
- autoplayInterval = null;
90
- }
91
- };
92
-
93
- const detectCurrentSlide = () => {
94
- const scrollPosition = orientation === 'vertical'
95
- ? slidesContainer.scrollTop
96
- : slidesContainer.scrollLeft;
97
- const scrollAmount = getScrollAmount();
98
- const newIndex = Math.round(scrollPosition / scrollAmount);
99
-
100
- if (newIndex !== currentIndex && newIndex >= 0 && newIndex < slides.length) {
101
- currentIndex = newIndex;
102
- updateIndicators();
103
- updateButtonStates();
104
- }
105
- };
106
-
107
- // Previous/Next button handlers
108
- if (prevButton) {
109
- prevButton.addEventListener('click', () => {
110
- stopAutoplay();
111
- goToPrevious();
112
- });
113
- }
114
-
115
- if (nextButton) {
116
- nextButton.addEventListener('click', () => {
117
- stopAutoplay();
118
- goToNext();
119
- });
120
- }
121
-
122
- // Indicator click handlers
123
- indicators.forEach((indicator, index) => {
124
- indicator.addEventListener('click', () => {
125
- stopAutoplay();
126
- scrollToIndex(index);
127
- });
128
- });
129
-
130
- // Keyboard navigation
131
- carouselComponent.addEventListener('keydown', (event) => {
132
- const isVertical = orientation === 'vertical';
133
- const prevKey = isVertical ? 'ArrowUp' : 'ArrowLeft';
134
- const nextKey = isVertical ? 'ArrowDown' : 'ArrowRight';
135
-
136
- switch (event.key) {
137
- case prevKey:
138
- event.preventDefault();
139
- stopAutoplay();
140
- goToPrevious();
141
- break;
142
- case nextKey:
143
- event.preventDefault();
144
- stopAutoplay();
145
- goToNext();
146
- break;
147
- case 'Home':
148
- event.preventDefault();
149
- stopAutoplay();
150
- scrollToIndex(0);
151
- break;
152
- case 'End':
153
- event.preventDefault();
154
- stopAutoplay();
155
- scrollToIndex(slides.length - 1);
156
- break;
157
- }
158
- });
159
-
160
- // Detect scroll position changes (for touch/manual scrolling)
161
- let scrollTimeout;
162
- slidesContainer.addEventListener('scroll', () => {
163
- clearTimeout(scrollTimeout);
164
- scrollTimeout = setTimeout(() => {
165
- detectCurrentSlide();
166
- }, 100);
167
- });
168
-
169
- // Pause autoplay on hover or focus
170
- if (autoplayDelay) {
171
- carouselComponent.addEventListener('mouseenter', stopAutoplay);
172
- carouselComponent.addEventListener('mouseleave', startAutoplay);
173
- carouselComponent.addEventListener('focusin', stopAutoplay);
174
- carouselComponent.addEventListener('focusout', startAutoplay);
175
- }
176
-
177
- // Initialize
178
- updateIndicators();
179
- updateButtonStates();
180
-
181
- if (autoplayDelay) {
182
- startAutoplay();
183
- }
184
-
185
- carouselComponent.dataset.carouselInitialized = true;
186
- carouselComponent.dispatchEvent(new CustomEvent('basecoat:initialized'));
187
- };
188
-
189
- if (window.basecoat) {
190
- window.basecoat.register('carousel', '.carousel:not([data-carousel-initialized])', initCarousel);
191
- }
192
- })();
@@ -1 +0,0 @@
1
- (()=>{const e=e=>{const t=e.querySelector(".carousel-slides");if(!t)return;const r=Array.from(e.querySelectorAll(".carousel-item")),a=e.querySelector(".carousel-prev"),o=e.querySelector(".carousel-next"),l=Array.from(e.querySelectorAll(".carousel-indicators button")),s="true"===e.dataset.carouselLoop,n=parseInt(e.dataset.carouselAutoplay,10),i=e.dataset.orientation||"horizontal";let c=0,d=null;const u=()=>{if(0===r.length)return 0;const e=r[0];return"vertical"===i?e.offsetHeight+parseInt(getComputedStyle(t).gap||0):e.offsetWidth+parseInt(getComputedStyle(t).gap||0)},v=e=>{const r=u();"vertical"===i?t.scrollTo({top:r*e,behavior:"smooth"}):t.scrollTo({left:r*e,behavior:"smooth"}),c=e,f(),h()},f=()=>{l.forEach(((e,t)=>{const r=t===c;e.setAttribute("aria-current",r?"true":"false"),e.setAttribute("aria-label",`Slide ${t+1}${r?" (current)":""}`)})),r.forEach(((e,t)=>{e.setAttribute("aria-hidden",t===c?"false":"true")}))},h=()=>{a&&o&&(s?(a.disabled=!1,o.disabled=!1):(a.disabled=0===c,o.disabled=c===r.length-1))},p=()=>{c>0?v(c-1):s&&v(r.length-1)},b=()=>{c<r.length-1?v(c+1):s&&v(0)},E=()=>{!n||n<=0||(d=setInterval((()=>{b()}),n))},g=()=>{d&&(clearInterval(d),d=null)};let m;a&&a.addEventListener("click",(()=>{g(),p()})),o&&o.addEventListener("click",(()=>{g(),b()})),l.forEach(((e,t)=>{e.addEventListener("click",(()=>{g(),v(t)}))})),e.addEventListener("keydown",(e=>{const t="vertical"===i,a=t?"ArrowUp":"ArrowLeft",o=t?"ArrowDown":"ArrowRight";switch(e.key){case a:e.preventDefault(),g(),p();break;case o:e.preventDefault(),g(),b();break;case"Home":e.preventDefault(),g(),v(0);break;case"End":e.preventDefault(),g(),v(r.length-1)}})),t.addEventListener("scroll",(()=>{clearTimeout(m),m=setTimeout((()=>{(()=>{const e="vertical"===i?t.scrollTop:t.scrollLeft,a=u(),o=Math.round(e/a);o!==c&&o>=0&&o<r.length&&(c=o,f(),h())})()}),100)})),n&&(e.addEventListener("mouseenter",g),e.addEventListener("mouseleave",E),e.addEventListener("focusin",g),e.addEventListener("focusout",E)),f(),h(),n&&E(),e.dataset.carouselInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("carousel",".carousel:not([data-carousel-initialized])",e)})();
@@ -1,111 +0,0 @@
1
- {#
2
- Renders a carousel component with navigation controls and optional indicators.
3
-
4
- @param id {string} [optional] - Unique identifier for the carousel component. Auto-generated if not provided.
5
- @param slides {array} - An array of objects representing carousel slides.
6
- Each object should have:
7
- - content {string}: HTML content for the slide.
8
- - attrs {object} [optional]: Additional HTML attributes for the slide item.
9
- @param loop {boolean} [optional] [default=false] - Enable continuous looping.
10
- @param autoplay {number} [optional] [default=0] - Auto-advance delay in milliseconds (0 = disabled).
11
- @param align {string} [optional] [default='start'] - Slide alignment ('start' or 'center').
12
- @param orientation {string} [optional] [default='horizontal'] - Carousel orientation ('horizontal' or 'vertical').
13
- @param show_controls {boolean} [optional] [default=true] - Show previous/next navigation buttons.
14
- @param show_indicators {boolean} [optional] [default=true] - Show slide indicator dots.
15
- @param main_attrs {object} [optional] - Additional HTML attributes for the main container.
16
- @param viewport_attrs {object} [optional] - Additional HTML attributes for the viewport container.
17
- #}
18
- {% macro carousel(
19
- id=None,
20
- slides=[],
21
- loop=false,
22
- autoplay=0,
23
- align='start',
24
- orientation='horizontal',
25
- show_controls=true,
26
- show_indicators=true,
27
- main_attrs={},
28
- viewport_attrs={}
29
- )
30
- %}
31
- {% set id = id or ("carousel-" + (range(100000, 999999) | random | string)) %}
32
- <div
33
- class="carousel {{ main_attrs.class }}"
34
- id="{{ id }}"
35
- data-carousel-loop="{{ 'true' if loop else 'false' }}"
36
- {% if autoplay > 0 %}data-carousel-autoplay="{{ autoplay }}"{% endif %}
37
- data-orientation="{{ orientation }}"
38
- role="region"
39
- aria-roledescription="carousel"
40
- aria-label="Carousel"
41
- tabindex="0"
42
- {% for key, value in main_attrs %}
43
- {% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
44
- {% endfor %}
45
- >
46
- <div
47
- class="carousel-viewport {{ viewport_attrs.class }}"
48
- {% for key, value in viewport_attrs %}
49
- {% if key != 'class' %}{{ key }}="{{ value }}"{% endif %}
50
- {% endfor %}
51
- >
52
- <div
53
- class="carousel-slides"
54
- data-orientation="{{ orientation }}"
55
- >
56
- {% for slide in slides %}
57
- <div
58
- class="carousel-item"
59
- role="group"
60
- aria-roledescription="slide"
61
- aria-label="{{ loop.index }} of {{ slides | length }}"
62
- {% if align == 'center' %}data-align="center"{% endif %}
63
- {% if slide.attrs %}
64
- {% for key, value in slide.attrs %}
65
- {{ key }}="{{ value }}"
66
- {% endfor %}
67
- {% endif %}
68
- >
69
- {{ slide.content | safe }}
70
- </div>
71
- {% endfor %}
72
- </div>
73
- </div>
74
-
75
- {% if show_controls %}
76
- <div class="carousel-controls">
77
- <button
78
- type="button"
79
- class="carousel-prev"
80
- aria-label="Previous slide"
81
- >
82
- <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">
83
- <path d="m15 18-6-6 6-6"/>
84
- </svg>
85
- </button>
86
- <button
87
- type="button"
88
- class="carousel-next"
89
- aria-label="Next slide"
90
- >
91
- <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">
92
- <path d="m9 18 6-6-6-6"/>
93
- </svg>
94
- </button>
95
- </div>
96
- {% endif %}
97
-
98
- {% if show_indicators %}
99
- <div class="carousel-indicators" role="tablist" aria-label="Slides">
100
- {% for slide in slides %}
101
- <button
102
- type="button"
103
- role="tab"
104
- aria-label="Slide {{ loop.index }}"
105
- {% if loop.index == 1 %}aria-current="true"{% else %}aria-current="false"{% endif %}
106
- ></button>
107
- {% endfor %}
108
- </div>
109
- {% endif %}
110
- </div>
111
- {% endmacro %}