basecoat-css 0.3.2 → 0.3.3

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.
@@ -0,0 +1,148 @@
1
+ (() => {
2
+ const initCommand = (container) => {
3
+ const input = container.querySelector('header input');
4
+ const menu = container.querySelector('[role="menu"]');
5
+
6
+ if (!input || !menu) {
7
+ const missing = [];
8
+ if (!input) missing.push('input');
9
+ if (!menu) missing.push('menu');
10
+ console.error(`Command component initialization failed. Missing element(s): ${missing.join(', ')}`, container);
11
+ return;
12
+ }
13
+
14
+ const allMenuItems = Array.from(menu.querySelectorAll('[role="menuitem"]'));
15
+ const menuItems = allMenuItems.filter(item =>
16
+ !item.hasAttribute('disabled') &&
17
+ item.getAttribute('aria-disabled') !== 'true'
18
+ );
19
+ let visibleMenuItems = [...menuItems];
20
+ let activeIndex = -1;
21
+
22
+ const setActiveItem = (index) => {
23
+ if (activeIndex > -1 && menuItems[activeIndex]) {
24
+ menuItems[activeIndex].classList.remove('active');
25
+ }
26
+
27
+ activeIndex = index;
28
+
29
+ if (activeIndex > -1) {
30
+ const activeItem = menuItems[activeIndex];
31
+ activeItem.classList.add('active');
32
+ if (activeItem.id) {
33
+ input.setAttribute('aria-activedescendant', activeItem.id);
34
+ } else {
35
+ input.removeAttribute('aria-activedescendant');
36
+ }
37
+ } else {
38
+ input.removeAttribute('aria-activedescendant');
39
+ }
40
+ };
41
+
42
+ const filterMenuItems = () => {
43
+ const searchTerm = input.value.trim().toLowerCase();
44
+
45
+ setActiveItem(-1);
46
+
47
+ visibleMenuItems = [];
48
+ allMenuItems.forEach(item => {
49
+ const itemText = (item.dataset.label || item.textContent).trim().toLowerCase();
50
+ const keywords = (item.dataset.keywords || '').toLowerCase();
51
+ const matches = itemText.includes(searchTerm) || keywords.includes(searchTerm);
52
+ item.setAttribute('aria-hidden', String(!matches));
53
+ if (matches && menuItems.includes(item)) {
54
+ visibleMenuItems.push(item);
55
+ }
56
+ });
57
+
58
+ if (visibleMenuItems.length > 0) {
59
+ setActiveItem(menuItems.indexOf(visibleMenuItems[0]));
60
+ visibleMenuItems[0].scrollIntoView({ block: 'nearest' });
61
+ }
62
+ };
63
+
64
+ input.addEventListener('input', filterMenuItems);
65
+
66
+ const handleKeyNavigation = (event) => {
67
+ if (!['ArrowDown', 'ArrowUp', 'Enter', 'Home', 'End'].includes(event.key)) {
68
+ return;
69
+ }
70
+
71
+ if (event.key === 'Enter') {
72
+ event.preventDefault();
73
+ if (activeIndex > -1) {
74
+ menuItems[activeIndex]?.click();
75
+ }
76
+ return;
77
+ }
78
+
79
+ if (visibleMenuItems.length === 0) return;
80
+
81
+ event.preventDefault();
82
+
83
+ const currentVisibleIndex = activeIndex > -1 ? visibleMenuItems.indexOf(menuItems[activeIndex]) : -1;
84
+ let nextVisibleIndex = currentVisibleIndex;
85
+
86
+ switch (event.key) {
87
+ case 'ArrowDown':
88
+ if (currentVisibleIndex < visibleMenuItems.length - 1) {
89
+ nextVisibleIndex = currentVisibleIndex + 1;
90
+ }
91
+ break;
92
+ case 'ArrowUp':
93
+ if (currentVisibleIndex > 0) {
94
+ nextVisibleIndex = currentVisibleIndex - 1;
95
+ } else if (currentVisibleIndex === -1) {
96
+ nextVisibleIndex = 0;
97
+ }
98
+ break;
99
+ case 'Home':
100
+ nextVisibleIndex = 0;
101
+ break;
102
+ case 'End':
103
+ nextVisibleIndex = visibleMenuItems.length - 1;
104
+ break;
105
+ }
106
+
107
+ if (nextVisibleIndex !== currentVisibleIndex) {
108
+ const newActiveItem = visibleMenuItems[nextVisibleIndex];
109
+ setActiveItem(menuItems.indexOf(newActiveItem));
110
+ newActiveItem.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
111
+ }
112
+ };
113
+
114
+ menu.addEventListener('mousemove', (event) => {
115
+ const menuItem = event.target.closest('[role="menuitem"]');
116
+ if (menuItem && visibleMenuItems.includes(menuItem)) {
117
+ const index = menuItems.indexOf(menuItem);
118
+ if (index !== activeIndex) {
119
+ setActiveItem(index);
120
+ }
121
+ }
122
+ });
123
+
124
+ menu.addEventListener('click', (event) => {
125
+ const clickedItem = event.target.closest('[role="menuitem"]');
126
+ if (clickedItem && visibleMenuItems.includes(clickedItem)) {
127
+ const dialog = container.closest('dialog.command-dialog');
128
+ if (dialog && !clickedItem.hasAttribute('data-keep-command-open')) {
129
+ dialog.close();
130
+ }
131
+ }
132
+ });
133
+
134
+ input.addEventListener('keydown', handleKeyNavigation);
135
+
136
+ if (visibleMenuItems.length > 0) {
137
+ setActiveItem(menuItems.indexOf(visibleMenuItems[0]));
138
+ visibleMenuItems[0].scrollIntoView({ block: 'nearest' });
139
+ }
140
+
141
+ container.dataset.commandInitialized = true;
142
+ container.dispatchEvent(new CustomEvent('basecoat:initialized'));
143
+ };
144
+
145
+ if (window.basecoat) {
146
+ window.basecoat.register('command', '.command:not([data-command-initialized])', initCommand);
147
+ }
148
+ })();
@@ -0,0 +1 @@
1
+ (()=>{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"]')),o=i.filter((e=>!e.hasAttribute("disabled")&&"true"!==e.getAttribute("aria-disabled")));let a=[...o],r=-1;const s=e=>{if(r>-1&&o[r]&&o[r].classList.remove("active"),r=e,r>-1){const e=o[r];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),a=[],i.forEach((t=>{const n=(t.dataset.label||t.textContent).trim().toLowerCase(),i=(t.dataset.keywords||"").toLowerCase(),r=n.includes(e)||i.includes(e);t.setAttribute("aria-hidden",String(!r)),r&&o.includes(t)&&a.push(t)})),a.length>0&&(s(o.indexOf(a[0])),a[0].scrollIntoView({block:"nearest"}))}));n.addEventListener("mousemove",(e=>{const t=e.target.closest('[role="menuitem"]');if(t&&a.includes(t)){const e=o.indexOf(t);e!==r&&s(e)}})),n.addEventListener("click",(t=>{const n=t.target.closest('[role="menuitem"]');if(n&&a.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(r>-1&&o[r]?.click());if(0===a.length)return;e.preventDefault();const t=r>-1?a.indexOf(o[r]):-1;let n=t;switch(e.key){case"ArrowDown":t<a.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=a.length-1}if(n!==t){const e=a[n];s(o.indexOf(e)),e.scrollIntoView({block:"nearest",behavior:"smooth"})}})),a.length>0&&(s(o.indexOf(a[0])),a[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)})();
package/dist/js/select.js CHANGED
@@ -16,7 +16,8 @@
16
16
  return;
17
17
  }
18
18
 
19
- const options = Array.from(listbox.querySelectorAll('[role="option"]'));
19
+ const allOptions = Array.from(listbox.querySelectorAll('[role="option"]'));
20
+ const options = allOptions.filter(opt => opt.getAttribute('aria-disabled') !== 'true');
20
21
  let visibleOptions = [...options];
21
22
  let activeIndex = -1;
22
23
 
@@ -69,7 +70,7 @@
69
70
  const resetFilter = () => {
70
71
  filter.value = '';
71
72
  visibleOptions = [...options];
72
- options.forEach(opt => opt.setAttribute('aria-hidden', 'false'));
73
+ allOptions.forEach(opt => opt.setAttribute('aria-hidden', 'false'));
73
74
  };
74
75
 
75
76
  if (hasTransition()) {
@@ -110,11 +111,11 @@
110
111
  setActiveOption(-1);
111
112
 
112
113
  visibleOptions = [];
113
- options.forEach(option => {
114
+ allOptions.forEach(option => {
114
115
  const optionText = (option.dataset.label || option.textContent).trim().toLowerCase();
115
116
  const matches = optionText.includes(searchTerm);
116
117
  option.setAttribute('aria-hidden', String(!matches));
117
- if (matches) {
118
+ if (matches && options.includes(option)) {
118
119
  visibleOptions.push(option);
119
120
  }
120
121
  });
@@ -1 +1 @@
1
- (()=>{const e=e=>{const t=e.querySelector(":scope > button"),a=t.querySelector(":scope > span"),n=e.querySelector(":scope > [data-popover]"),i=n.querySelector('[role="listbox"]'),r=e.querySelector(':scope > input[type="hidden"]'),o=e.querySelector('header input[type="text"]');if(!(t&&n&&i&&r)){const a=[];return t||a.push("trigger"),n||a.push("popover"),i||a.push("listbox"),r||a.push("input"),void console.error(`Select component initialisation failed. Missing element(s): ${a.join(", ")}`,e)}const s=Array.from(i.querySelectorAll('[role="option"]'));let d=[...s],c=-1;const l=e=>{if(c>-1&&s[c]&&s[c].classList.remove("active"),c=e,c>-1){const e=s[c];e.classList.add("active"),e.id?t.setAttribute("aria-activedescendant",e.id):t.removeAttribute("aria-activedescendant")}else t.removeAttribute("aria-activedescendant")},u=()=>{const e=getComputedStyle(n);return parseFloat(e.transitionDuration)>0||parseFloat(e.transitionDelay)>0},v=(t,n=!0)=>{if(t&&(a.innerHTML=t.dataset.label||t.innerHTML,r.value=t.dataset.value,i.querySelector('[role="option"][aria-selected="true"]')?.removeAttribute("aria-selected"),t.setAttribute("aria-selected","true"),n)){const a=new CustomEvent("change",{detail:{value:t.dataset.value},bubbles:!0});e.dispatchEvent(a)}},p=(e=!0)=>{if("true"!==n.getAttribute("aria-hidden")){if(o){const e=()=>{o.value="",d=[...s],s.forEach((e=>e.setAttribute("aria-hidden","false")))};u()?n.addEventListener("transitionend",e,{once:!0}):e()}e&&t.focus(),n.setAttribute("aria-hidden","true"),t.setAttribute("aria-expanded","false"),l(-1)}},f=e=>{if(!e)return;const t=r.value,a=e.dataset.value;null!=a&&a!==t&&v(e),p()};if(o){const e=()=>{const e=o.value.trim().toLowerCase();l(-1),d=[],s.forEach((t=>{const a=(t.dataset.label||t.textContent).trim().toLowerCase().includes(e);t.setAttribute("aria-hidden",String(!a)),a&&d.push(t)}))};o.addEventListener("input",e)}let b=s.find((e=>e.dataset.value===r.value));b||(b=s.find((e=>void 0!==e.dataset.value))??s[0]),v(b,!1);const E=e=>{const a="false"===n.getAttribute("aria-hidden");if(!["ArrowDown","ArrowUp","Enter","Home","End","Escape"].includes(e.key))return;if(!a)return void("Enter"!==e.key&&"Escape"!==e.key&&(e.preventDefault(),t.click()));if(e.preventDefault(),"Escape"===e.key)return void p();if("Enter"===e.key)return void(c>-1&&f(s[c]));if(0===d.length)return;const i=c>-1?d.indexOf(s[c]):-1;let r=i;switch(e.key){case"ArrowDown":i<d.length-1&&(r=i+1);break;case"ArrowUp":i>0?r=i-1:-1===i&&(r=0);break;case"Home":r=0;break;case"End":r=d.length-1}if(r!==i){const e=d[r];l(s.indexOf(e)),e.scrollIntoView({block:"nearest",behavior:"smooth"})}};i.addEventListener("mousemove",(e=>{const t=e.target.closest('[role="option"]');if(t&&d.includes(t)){const e=s.indexOf(t);e!==c&&l(e)}})),i.addEventListener("mouseleave",(()=>{const e=i.querySelector('[role="option"][aria-selected="true"]');l(e?s.indexOf(e):-1)})),t.addEventListener("keydown",E),o&&o.addEventListener("keydown",E);t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?p():(()=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}})),o&&(u()?n.addEventListener("transitionend",(()=>{o.focus()}),{once:!0}):o.focus()),n.setAttribute("aria-hidden","false"),t.setAttribute("aria-expanded","true");const a=i.querySelector('[role="option"][aria-selected="true"]');a&&(l(s.indexOf(a)),a.scrollIntoView({block:"nearest"}))})()})),i.addEventListener("click",(e=>{const t=e.target.closest('[role="option"]');t&&f(t)})),document.addEventListener("click",(t=>{e.contains(t.target)||p(!1)})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&p(!1)})),n.setAttribute("aria-hidden","true"),e.selectByValue=e=>{const t=s.find((t=>t.dataset.value===e));f(t)},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"),a=t.querySelector(":scope > span"),i=e.querySelector(":scope > [data-popover]"),n=i.querySelector('[role="listbox"]'),r=e.querySelector(':scope > input[type="hidden"]'),o=e.querySelector('header input[type="text"]');if(!(t&&i&&n&&r)){const a=[];return t||a.push("trigger"),i||a.push("popover"),n||a.push("listbox"),r||a.push("input"),void console.error(`Select component initialisation failed. Missing element(s): ${a.join(", ")}`,e)}const s=Array.from(n.querySelectorAll('[role="option"]')),d=s.filter((e=>"true"!==e.getAttribute("aria-disabled")));let c=[...d],l=-1;const u=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")},v=()=>{const e=getComputedStyle(i);return parseFloat(e.transitionDuration)>0||parseFloat(e.transitionDelay)>0},p=(t,i=!0)=>{if(t&&(a.innerHTML=t.dataset.label||t.innerHTML,r.value=t.dataset.value,n.querySelector('[role="option"][aria-selected="true"]')?.removeAttribute("aria-selected"),t.setAttribute("aria-selected","true"),i)){const a=new CustomEvent("change",{detail:{value:t.dataset.value},bubbles:!0});e.dispatchEvent(a)}},b=(e=!0)=>{if("true"!==i.getAttribute("aria-hidden")){if(o){const e=()=>{o.value="",c=[...d],s.forEach((e=>e.setAttribute("aria-hidden","false")))};v()?i.addEventListener("transitionend",e,{once:!0}):e()}e&&t.focus(),i.setAttribute("aria-hidden","true"),t.setAttribute("aria-expanded","false"),u(-1)}},f=e=>{if(!e)return;const t=r.value,a=e.dataset.value;null!=a&&a!==t&&p(e),b()};if(o){const e=()=>{const e=o.value.trim().toLowerCase();u(-1),c=[],s.forEach((t=>{const a=(t.dataset.label||t.textContent).trim().toLowerCase().includes(e);t.setAttribute("aria-hidden",String(!a)),a&&d.includes(t)&&c.push(t)}))};o.addEventListener("input",e)}let E=d.find((e=>e.dataset.value===r.value));E||(E=d.find((e=>void 0!==e.dataset.value))??d[0]),p(E,!1);const h=e=>{const a="false"===i.getAttribute("aria-hidden");if(!["ArrowDown","ArrowUp","Enter","Home","End","Escape"].includes(e.key))return;if(!a)return void("Enter"!==e.key&&"Escape"!==e.key&&(e.preventDefault(),t.click()));if(e.preventDefault(),"Escape"===e.key)return void b();if("Enter"===e.key)return void(l>-1&&f(d[l]));if(0===c.length)return;const n=l>-1?c.indexOf(d[l]):-1;let r=n;switch(e.key){case"ArrowDown":n<c.length-1&&(r=n+1);break;case"ArrowUp":n>0?r=n-1:-1===n&&(r=0);break;case"Home":r=0;break;case"End":r=c.length-1}if(r!==n){const e=c[r];u(d.indexOf(e)),e.scrollIntoView({block:"nearest",behavior:"smooth"})}};n.addEventListener("mousemove",(e=>{const t=e.target.closest('[role="option"]');if(t&&c.includes(t)){const e=d.indexOf(t);e!==l&&u(e)}})),n.addEventListener("mouseleave",(()=>{const e=n.querySelector('[role="option"][aria-selected="true"]');u(e?d.indexOf(e):-1)})),t.addEventListener("keydown",h),o&&o.addEventListener("keydown",h);t.addEventListener("click",(()=>{"true"===t.getAttribute("aria-expanded")?b():(()=>{document.dispatchEvent(new CustomEvent("basecoat:popover",{detail:{source:e}})),o&&(v()?i.addEventListener("transitionend",(()=>{o.focus()}),{once:!0}):o.focus()),i.setAttribute("aria-hidden","false"),t.setAttribute("aria-expanded","true");const a=n.querySelector('[role="option"][aria-selected="true"]');a&&(u(d.indexOf(a)),a.scrollIntoView({block:"nearest"}))})()})),n.addEventListener("click",(e=>{const t=e.target.closest('[role="option"]');t&&f(t)})),document.addEventListener("click",(t=>{e.contains(t.target)||b(!1)})),document.addEventListener("basecoat:popover",(t=>{t.detail.source!==e&&b(!1)})),i.setAttribute("aria-hidden","true"),e.selectByValue=e=>{const t=d.find((t=>t.dataset.value===e));f(t)},e.dataset.selectInitialized=!0,e.dispatchEvent(new CustomEvent("basecoat:initialized"))};window.basecoat&&window.basecoat.register("select","div.select:not([data-select-initialized])",e)})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basecoat-css",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Tailwind CSS for Basecoat components",
5
5
  "author": {
6
6
  "name": "hunvreus",
@@ -26,8 +26,7 @@
26
26
  "css",
27
27
  "html",
28
28
  "jinja",
29
- "nunjucks",
30
- "alpinejs"
29
+ "nunjucks"
31
30
  ],
32
31
  "repository": {
33
32
  "type": "git",
@@ -43,6 +42,8 @@
43
42
  "./css": "./dist/basecoat.css",
44
43
  "./all": "./dist/js/all.js",
45
44
  "./all.min": "./dist/js/all.min.js",
45
+ "./command": "./dist/js/command.js",
46
+ "./command.min": "./dist/js/command.min.js",
46
47
  "./dropdown-menu": "./dist/js/dropdown-menu.js",
47
48
  "./dropdown-menu.min": "./dist/js/dropdown-menu.min.js",
48
49
  "./popover": "./dist/js/popover.js",