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.
- package/dist/assets/jinja/dialog.html.jinja +3 -5
- package/dist/assets/jinja/select.html.jinja +3 -0
- package/dist/assets/js/all.js +13 -39
- package/dist/assets/js/all.min.js +1 -1
- package/dist/assets/js/select.js +12 -4
- package/dist/assets/js/select.min.js +1 -1
- package/dist/assets/js/sidebar.js +1 -36
- package/dist/assets/js/sidebar.min.js +1 -1
- package/dist/assets/nunjucks/select.njk +3 -0
- package/package.json +1 -1
- package/dist/assets/jinja/carousel.html.jinja +0 -111
- package/dist/assets/js/carousel.js +0 -192
- package/dist/assets/js/carousel.min.js +0 -1
- package/dist/assets/nunjucks/carousel.njk +0 -111
|
@@ -83,12 +83,10 @@
|
|
|
83
83
|
</footer>
|
|
84
84
|
{% endif %}
|
|
85
85
|
{% if close_button %}
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
86
|
+
<button type="button" aria-label="Close dialog" onclick="this.closest('dialog').close()">
|
|
87
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
89
88
|
</button>
|
|
90
|
-
</form>
|
|
91
89
|
{% endif %}
|
|
92
90
|
</div>
|
|
93
91
|
</dialog>
|
|
94
|
-
{% endmacro %}
|
|
92
|
+
{% endmacro %}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
@param name {string} [optional] - The name attribute for the hidden input storing the selected value.
|
|
7
7
|
@param multiple {boolean} [optional] [default=false] - Enables multiple selection mode.
|
|
8
8
|
@param placeholder {string} [optional] - Placeholder text shown when no options are selected (multiple mode only).
|
|
9
|
+
@param close_on_select {boolean} [optional] [default=false] - Closes the popover when selecting an option in multiple mode.
|
|
9
10
|
@param main_attrs {object} [optional] - Additional HTML attributes for the main container div.
|
|
10
11
|
@param trigger_attrs {object} [optional] - Additional HTML attributes for the trigger button.
|
|
11
12
|
@param popover_attrs {object} [optional] - Additional HTML attributes for the popover content div.
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
items=[],
|
|
22
23
|
multiple=false,
|
|
23
24
|
placeholder=None,
|
|
25
|
+
close_on_select=false,
|
|
24
26
|
main_attrs={},
|
|
25
27
|
trigger_attrs={},
|
|
26
28
|
popover_attrs={},
|
|
@@ -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 %}
|
package/dist/assets/js/all.js
CHANGED
|
@@ -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
|
-
|
|
867
|
-
|
|
868
|
-
filter.focus();
|
|
870
|
+
if (closeOnSelect) {
|
|
871
|
+
closePopover();
|
|
869
872
|
} else {
|
|
870
|
-
|
|
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))})();
|
package/dist/assets/js/select.js
CHANGED
|
@@ -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
|
-
|
|
362
|
-
|
|
363
|
-
filter.focus();
|
|
365
|
+
if (closeOnSelect) {
|
|
366
|
+
closePopover();
|
|
364
367
|
} else {
|
|
365
|
-
|
|
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(),
|
|
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
|
-
(()=>{
|
|
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,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 %}
|