@data-slot/command 0.2.125
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/README.md +222 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +42 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +1 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# @data-slot/command
|
|
2
|
+
|
|
3
|
+
Headless command palette component for vanilla JavaScript. Accessible, unstyled, tiny.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @data-slot/command
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<div data-slot="command" data-label="Command Menu">
|
|
15
|
+
<div data-slot="command-input-wrapper">
|
|
16
|
+
<input data-slot="command-input" placeholder="Type a command..." />
|
|
17
|
+
</div>
|
|
18
|
+
<div data-slot="command-list">
|
|
19
|
+
<div data-slot="command-empty" hidden>No results.</div>
|
|
20
|
+
|
|
21
|
+
<div data-slot="command-group">
|
|
22
|
+
<div data-slot="command-group-heading">Actions</div>
|
|
23
|
+
<div data-slot="command-item">Open Project</div>
|
|
24
|
+
<div data-slot="command-item">Invite Teammate</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div data-slot="command-separator"></div>
|
|
28
|
+
|
|
29
|
+
<div data-slot="command-item" data-value="settings">
|
|
30
|
+
Settings
|
|
31
|
+
<span data-slot="command-shortcut">⌘,</span>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<script type="module">
|
|
37
|
+
import { create } from "@data-slot/command";
|
|
38
|
+
|
|
39
|
+
const controllers = create();
|
|
40
|
+
</script>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## API
|
|
44
|
+
|
|
45
|
+
### `create(scope?)`
|
|
46
|
+
|
|
47
|
+
Auto-discover and bind all command palettes in a scope (defaults to `document`).
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { create } from "@data-slot/command";
|
|
51
|
+
|
|
52
|
+
const controllers = create();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### `createCommand(root, options?)`
|
|
56
|
+
|
|
57
|
+
Create a controller for a specific element.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { createCommand } from "@data-slot/command";
|
|
61
|
+
|
|
62
|
+
const command = createCommand(element, {
|
|
63
|
+
defaultSearch: "set",
|
|
64
|
+
onSelect: (value) => console.log("Selected:", value),
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Slots
|
|
69
|
+
|
|
70
|
+
| Slot | Description |
|
|
71
|
+
|------|-------------|
|
|
72
|
+
| `command` | Root container |
|
|
73
|
+
| `command-input` | Search input |
|
|
74
|
+
| `command-input-wrapper` | Optional wrapper around the input for styling |
|
|
75
|
+
| `command-list` | Listbox container for items and groups |
|
|
76
|
+
| `command-empty` | Empty state shown when there are no ranked matches |
|
|
77
|
+
| `command-group` | Group of related items |
|
|
78
|
+
| `command-group-heading` | Optional label for a group |
|
|
79
|
+
| `command-item` | Selectable command item |
|
|
80
|
+
| `command-shortcut` | Optional shortcut hint inside an item |
|
|
81
|
+
| `command-separator` | Visual divider between sections |
|
|
82
|
+
|
|
83
|
+
## Item and Group Attributes
|
|
84
|
+
|
|
85
|
+
| Attribute | Applies To | Description |
|
|
86
|
+
|-----------|------------|-------------|
|
|
87
|
+
| `data-value` | `command-item`, `command-group` | Explicit value. If omitted on an item, value is inferred from `data-label` or text content |
|
|
88
|
+
| `data-label` | `command-item` | Alternate text source for value inference |
|
|
89
|
+
| `data-keywords` | `command-item` | Comma-separated aliases used during filtering |
|
|
90
|
+
| `data-disabled` / `disabled` | `command-item` | Prevents navigation and selection |
|
|
91
|
+
| `data-force-mount` | `command-item`, `command-group` | Keeps the node rendered during filtering |
|
|
92
|
+
| `data-always-render` | `command-separator` | Keeps the separator visible while searching |
|
|
93
|
+
|
|
94
|
+
`command-shortcut` text is ignored when inferring an item value, so shadcn-style shortcut hints do not affect search matches.
|
|
95
|
+
|
|
96
|
+
## Options
|
|
97
|
+
|
|
98
|
+
Options can be passed via JavaScript or data attributes on the root element. JavaScript options take precedence.
|
|
99
|
+
|
|
100
|
+
| Option | Data Attribute | Type | Default | Description |
|
|
101
|
+
|--------|----------------|------|---------|-------------|
|
|
102
|
+
| `label` | `data-label` | `string` | `"Command Menu"` | Accessible label announced for the search input |
|
|
103
|
+
| `defaultValue` | `data-default-value` | `string` | `null` | Initial active item value |
|
|
104
|
+
| `defaultSearch` | `data-default-search` | `string` | `""` | Initial search text |
|
|
105
|
+
| `shouldFilter` | `data-should-filter` | `boolean` | `true` | Disable built-in filtering and sorting |
|
|
106
|
+
| `loop` | `data-loop` | `boolean` | `false` | Wrap arrow-key navigation |
|
|
107
|
+
| `disablePointerSelection` | `data-disable-pointer-selection` | `boolean` | `false` | Disable hover-driven selection |
|
|
108
|
+
| `vimBindings` | `data-vim-bindings` | `boolean` | `true` | Enable `Ctrl+J/K/N/P` shortcuts |
|
|
109
|
+
| `filter` | - | `(value, search, keywords?) => number` | `commandScore` | Custom ranking function |
|
|
110
|
+
| `onValueChange` | - | `(value: string \| null) => void` | - | Called when the active item changes |
|
|
111
|
+
| `onSearchChange` | - | `(search: string) => void` | - | Called when the search query changes |
|
|
112
|
+
| `onSelect` | - | `(value: string) => void` | - | Called on click or Enter selection |
|
|
113
|
+
|
|
114
|
+
## Controller
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
interface CommandController {
|
|
118
|
+
readonly value: string | null;
|
|
119
|
+
readonly search: string;
|
|
120
|
+
select(value: string | null): void;
|
|
121
|
+
setSearch(search: string): void;
|
|
122
|
+
destroy(): void;
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Events
|
|
127
|
+
|
|
128
|
+
### Outbound Events
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
root.addEventListener("command:change", (event) => {
|
|
132
|
+
console.log("Active item:", event.detail.value);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
root.addEventListener("command:search-change", (event) => {
|
|
136
|
+
console.log("Search:", event.detail.search);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
root.addEventListener("command:select", (event) => {
|
|
140
|
+
console.log("Selected:", event.detail.value);
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Inbound Event
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
root.dispatchEvent(
|
|
148
|
+
new CustomEvent("command:set", {
|
|
149
|
+
detail: {
|
|
150
|
+
search: "set",
|
|
151
|
+
value: "settings",
|
|
152
|
+
},
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Keyboard Navigation
|
|
158
|
+
|
|
159
|
+
| Key | Action |
|
|
160
|
+
|-----|--------|
|
|
161
|
+
| `ArrowDown` / `ArrowUp` | Move to the next or previous enabled item |
|
|
162
|
+
| `Home` / `End` | Jump to the first or last enabled item |
|
|
163
|
+
| `Alt+ArrowDown` / `Alt+ArrowUp` | Jump between groups |
|
|
164
|
+
| `Ctrl+J` / `Ctrl+N` | Next item |
|
|
165
|
+
| `Ctrl+K` / `Ctrl+P` | Previous item |
|
|
166
|
+
| `Enter` | Trigger `command:select` for the active item |
|
|
167
|
+
|
|
168
|
+
Arrow navigation is handled on the command root like cmdk. Selecting from the input or a focused command root keeps keyboard flow intact, but clicking non-interactive palette chrome does not auto-focus the input.
|
|
169
|
+
|
|
170
|
+
## Dialog Composition
|
|
171
|
+
|
|
172
|
+
Use `@data-slot/dialog` when you want modal presentation:
|
|
173
|
+
|
|
174
|
+
```html
|
|
175
|
+
<div data-slot="dialog">
|
|
176
|
+
<button data-slot="dialog-trigger">Open Command Palette</button>
|
|
177
|
+
<div data-slot="dialog-overlay" hidden></div>
|
|
178
|
+
<div data-slot="dialog-content" hidden>
|
|
179
|
+
<h2 data-slot="dialog-title">Command Palette</h2>
|
|
180
|
+
<p data-slot="dialog-description">Search for a command to run.</p>
|
|
181
|
+
|
|
182
|
+
<div data-slot="command" data-label="Global Command Palette">
|
|
183
|
+
<input data-slot="command-input" placeholder="Search commands..." />
|
|
184
|
+
<div data-slot="command-list">
|
|
185
|
+
<div data-slot="command-empty" hidden>No results.</div>
|
|
186
|
+
<div data-slot="command-item">New Issue</div>
|
|
187
|
+
<div data-slot="command-item">Open Settings</div>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<script type="module">
|
|
194
|
+
import { createDialog } from "@data-slot/dialog";
|
|
195
|
+
import { createCommand } from "@data-slot/command";
|
|
196
|
+
|
|
197
|
+
document.querySelectorAll('[data-slot="dialog"]').forEach((el) => createDialog(el));
|
|
198
|
+
document.querySelectorAll('[data-slot="command"]').forEach((el) => createCommand(el));
|
|
199
|
+
</script>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Styling
|
|
203
|
+
|
|
204
|
+
```css
|
|
205
|
+
[data-slot="command-item"][data-selected] {
|
|
206
|
+
background: #f1f1f1;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
[data-slot="command-item"][aria-disabled="true"] {
|
|
210
|
+
opacity: 0.5;
|
|
211
|
+
pointer-events: none;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
[data-slot="command-list"] {
|
|
215
|
+
height: var(--command-list-height);
|
|
216
|
+
transition: height 150ms ease;
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
|
|
222
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@data-slot/core`);const t=.1,n=.999,r=/[\\/_+.#"@\[\(\{&]/,i=/[\\/_+.#"@\[\(\{&]/g,a=/[\s-]/,o=/[\s-]/g;function s(e,c,l,u,d,f,p){if(f===c.length)return d===e.length?1:.99;let m=`${d},${f}`,h=p[m];if(h!==void 0)return h;let g=u.charAt(f),_=l.indexOf(g,d),v=0;for(;_>=0;){let m=s(e,c,l,u,_+1,f+1,p);if(m>v){if(_===d)m*=1;else if(r.test(e.charAt(_-1))){m*=.8;let t=e.slice(d,_-1).match(i);t&&d>0&&(m*=n**+t.length)}else if(a.test(e.charAt(_-1))){m*=.9;let t=e.slice(d,_-1).match(o);t&&d>0&&(m*=n**+t.length)}else m*=.17,d>0&&(m*=n**+(_-d));e.charAt(_)!==c.charAt(f)&&(m*=.9999)}if(m<t&&l.charAt(_-1)===u.charAt(f+1)||u.charAt(f+1)===u.charAt(f)&&l.charAt(_-1)!==u.charAt(f)){let n=s(e,c,l,u,_+1,f+2,p);n*t>m&&(m=n*t)}m>v&&(v=m),_=l.indexOf(g,_+1)}return p[m]=v,v}function c(e){return e.toLowerCase().replace(o,` `)}function l(e,t,n=[]){let r=n.length>0?`${e} ${n.join(` `)}`:e;return s(r,t,c(r),c(t),0,0,{})}const u=`@data-slot/command`,d=`[data-slot="command-item"]`,f=`[data-slot="command-group"]`,p=`[data-slot="command-separator"]`,m=Symbol(`data-slot.command.authored-value`),h=Symbol(`data-slot.command.inferred-value`),g=[`data-slot`,`data-value`,`data-label`,`data-keywords`,`data-disabled`,`disabled`,`data-force-mount`,`data-always-render`],_=[`input:not([type="hidden"])`,`textarea`,`select`,`button`,`a[href]`,`summary`,`audio[controls]`,`video[controls]`,`[contenteditable=""]`,`[contenteditable="true"]`,`[contenteditable="plaintext-only"]`,`[tabindex]:not([tabindex="-1"])`].join(`, `),v=(e,t,n)=>t.trim()?l(e,t,n??[]):1,y=e=>e==null?null:e.trim(),ee=e=>e?e.split(/[,\n]/).map(e=>e.trim()).filter(Boolean):[],te=(e,t)=>Array.from(e.children).filter(e=>e instanceof HTMLElement&&e.getAttribute(`data-slot`)===t),b=(e,t)=>{let n=e;for(;n&&n.parentElement&&n.parentElement!==t;)n=n.parentElement;return n?.parentElement===t?n:null},x=(e,t,n)=>Array.from(e.querySelectorAll(t)).filter(e=>e.closest(`[data-slot="command"]`)===n),S=e=>Array.from(e.children).filter(e=>e instanceof HTMLElement),ne=e=>{let t=e=>{if(e.nodeType===Node.TEXT_NODE)return e.textContent??``;if(!(e instanceof HTMLElement)||e.getAttribute(`data-slot`)===`command-shortcut`)return``;let n=``;for(let r of e.childNodes)n+=t(r);return n};return t(e).replace(/\s+/g,` `).trim()},re=e=>e.hasAttribute(`disabled`)||e.hasAttribute(`data-disabled`)||e.getAttribute(`aria-disabled`)===`true`,ie=(e,t)=>{let n=e,r=e.hasAttribute(`data-value`);if(n[m]===void 0&&(n[m]=r),r?n[m]||y(e.getAttribute(`data-value`))!==n[h]&&(n[m]=!0):n[m]=!1,n[m])return{authored:!0,value:y(e.getAttribute(`data-value`))};let i=t();return n[h]=i,i===null?e.removeAttribute(`data-value`):e.setAttribute(`data-value`,i),{authored:!1,value:i}};function C(t,n={}){let r=(0,e.reuseRootBinding)(t,u,`[@data-slot/command] createCommand() called more than once for the same root. Returning the existing controller. Destroy it before rebinding with new options.`);if(r)return r;let i=t,a=(0,e.getPart)(t,`command-input`),o=(0,e.getPart)(t,`command-list`),s=(0,e.getPart)(o??t,`command-empty`);if(!a||!o)throw Error(`Command requires command-input and command-list slots`);let c=n.label??(0,e.getDataString)(i,`label`)??`Command Menu`,l=n.shouldFilter??(0,e.getDataBool)(i,`shouldFilter`)??!0,m=n.loop??(0,e.getDataBool)(i,`loop`)??!1,h=n.disablePointerSelection??(0,e.getDataBool)(i,`disablePointerSelection`)??!1,C=n.vimBindings??(0,e.getDataBool)(i,`vimBindings`)??!0,w=n.filter??v,ae=n.onValueChange,oe=n.onSearchChange,se=n.onSelect,T=y(n.defaultValue??(0,e.getDataString)(i,`defaultValue`)),E=n.defaultSearch??(0,e.getDataString)(i,`defaultSearch`)??``,D=[],O=[],k=new Map,A=new Map,j=0,M=[],N=null,P=null,F=!1,I=!1,ce=!1,L=[],R=new Map,z=!1,le=(0,e.ensureId)(a,`command-input`),ue=(0,e.ensureId)(o,`command-list`);i.hasAttribute(`tabindex`)||(i.tabIndex=-1,ce=!0),a.setAttribute(`role`,`combobox`),a.setAttribute(`aria-autocomplete`,`list`),a.setAttribute(`aria-expanded`,`true`),a.setAttribute(`aria-controls`,ue),a.setAttribute(`autocomplete`,`off`),a.setAttribute(`autocorrect`,`off`),a.spellcheck=!1,o.setAttribute(`role`,`listbox`),o.tabIndex=-1;let B=document.querySelector(`label[for="${CSS.escape(le)}"]`);if(B){let t=(0,e.ensureId)(B,`command-label`),n=a.getAttribute(`aria-labelledby`);a.setAttribute(`aria-labelledby`,n?`${n} ${t}`:t),o.setAttribute(`aria-labelledby`,t)}else !a.hasAttribute(`aria-label`)&&!a.hasAttribute(`aria-labelledby`)&&(a.setAttribute(`aria-label`,c),o.setAttribute(`aria-label`,`Suggestions`));let de=()=>{document.activeElement!==a&&a.focus({preventScroll:!0})},V=e=>{if(!(e instanceof HTMLElement)||!i.contains(e))return null;let t=e.closest(_);return t instanceof HTMLElement&&i.contains(t)?t:null},fe=e=>{N?.disconnect();try{return e()}finally{Q()}},H=()=>{o.style.setProperty(`--command-list-height`,`${o.scrollHeight.toFixed(1)}px`)},pe=()=>{if(typeof ResizeObserver>`u`){H();return}P||=new ResizeObserver(()=>{H()}),P.disconnect(),P.observe(o);for(let e of x(o,`${d}, ${f}, ${p}, [data-slot="command-empty"]`,i))P.observe(e);H()},U=(e,t)=>{let n=e.filter(e=>t.includes(e));for(let e of t){if(n.includes(e))continue;let r=t.indexOf(e),i=!1;for(let a=r-1;a>=0;--a){let r=t[a];if(!r)continue;let o=n.indexOf(r);if(o!==-1){n.splice(o+1,0,e),i=!0;break}}if(!i){for(let a=r+1;a<t.length;a+=1){let r=t[a];if(!r)continue;let o=n.indexOf(r);if(o!==-1){n.splice(o,0,e),i=!0;break}}i||n.push(e)}}return n},me=()=>{L=S(o),R=new Map(O.map(e=>[e.el,S(e.el)]))},he=()=>{let e=S(o);L=L.length===0?e:U(L,e);let t=new Map;for(let e of O){let n=S(e.el),r=R.get(e.el)??[];t.set(e.el,r.length===0?n:U(r,n))}R=t},W=(e,t)=>{let n=S(e),r=new Set;for(let n of t)n.parentElement!==e||r.has(n)||(r.add(n),e.appendChild(n));for(let t of n)r.has(t)||t.parentElement!==e||e.appendChild(t)},ge=e=>new Map(e.map((e,t)=>[e,t])),_e=()=>{for(let e of O){let t=R.get(e.el)?.filter(t=>t.parentElement===e.el)??[];W(e.el,t)}W(o,L.filter(e=>e.parentElement===o))},G=()=>T===null?null:x(o,d,i).find(e=>{let t=k.get(e);return t?.value===T&&!e.hidden&&!(t.group?.el.hidden??!1)})??null,ve=()=>{for(let t of D){let n=t.value===T&&T!==null;(0,e.setAria)(t.el,`selected`,n),n?t.el.setAttribute(`data-selected`,``):t.el.removeAttribute(`data-selected`)}let t=G();t?(a.setAttribute(`aria-activedescendant`,t.id),o.setAttribute(`aria-activedescendant`,t.id)):(a.removeAttribute(`aria-activedescendant`),o.removeAttribute(`aria-activedescendant`))},ye=()=>{T===null?i.removeAttribute(`data-value`):i.setAttribute(`data-value`,T),E?i.setAttribute(`data-search`,E):i.removeAttribute(`data-search`)},be=()=>x(o,d,i).map(e=>k.get(e)??null).filter(e=>e!==null&&!e.el.hidden&&!(e.group?.el.hidden??!1)),K=()=>be().filter(e=>!e.disabled),xe=(t,n,r)=>{!r||t===n||((0,e.emit)(i,`command:change`,{value:n}),ae?.(n))},q=(e,t=!0)=>{let n=y(e),r=T;return T=n,ve(),ye(),(document.activeElement===a||document.activeElement===i)&&de(),xe(r,T,t),r!==T},Se=()=>{D=[],O=[],k=new Map,A=new Map;for(let t of x(o,f,i)){let n=te(t,`command-group-heading`)[0]??null,r={el:t,heading:n,value:ie(t,()=>y(n?.textContent)??(0,e.ensureId)(t,`command-group`)).value??(0,e.ensureId)(t,`command-group`),forceMount:(0,e.getDataBool)(t,`forceMount`)??!1,maxRank:0};if(A.set(t,r),O.push(r),t.setAttribute(`role`,`group`),n){let r=(0,e.ensureId)(n,`command-group-heading`);t.setAttribute(`aria-labelledby`,r)}else t.removeAttribute(`aria-labelledby`)}for(let t of x(o,d,i)){let n=t.closest(f),r=n instanceof HTMLElement&&n.closest(`[data-slot="command"]`)===i?A.get(n)??null:null,a={el:t,value:ie(t,()=>y(t.getAttribute(`data-label`))??y(ne(t))).value,keywords:ee(t.getAttribute(`data-keywords`)??void 0),disabled:re(t),forceMount:(0,e.getDataBool)(t,`forceMount`)??!1,rank:0,group:r};k.set(t,a),D.push(a),(0,e.ensureId)(t,`command-item`),t.setAttribute(`role`,`option`),a.disabled?t.setAttribute(`aria-disabled`,`true`):t.removeAttribute(`aria-disabled`)}},Ce=()=>{let t=E.length>0;j=0;for(let e of O)e.maxRank=0;for(let e of D){e.rank=l&&t&&e.value!==null?w(e.value,E,e.keywords):1,l&&t&&e.rank>0&&(j+=1);let n=!t||!l||e.forceMount||e.group?.forceMount||e.rank>0;e.el.hidden=!n,e.group&&e.rank>e.group.maxRank&&(e.group.maxRank=e.rank)}(!l||!t)&&(j=D.length);for(let e of O){let n=!t||!l||e.forceMount||D.some(t=>t.group===e&&t.rank>0);e.el.hidden=!n}for(let n of x(o,p,i)){let r=(0,e.getDataBool)(n,`alwaysRender`)??!1;n.hidden=t&&!r,n.setAttribute(`role`,`separator`)}s&&(s.hidden=j>0)},we=()=>{if(!l||!E)return;let e=L.filter(e=>e.parentElement===o),t=ge(e),n=new Map,r=new Map;for(let e of D){if(e.group!==null)continue;let t=b(e.el,o);t&&(n.set(t,Math.max(n.get(t)??0,e.rank)),e.el.hidden||r.set(t,Math.max(r.get(t)??0,e.rank)))}let i=new Set([...n.keys(),...O.map(e=>e.el)]),a=[...Array.from(r,([e,t])=>({el:e,rank:t})),...O.filter(e=>!e.el.hidden).map(e=>({el:e.el,rank:e.maxRank}))].sort((e,n)=>n.rank===e.rank?(t.get(e.el)??2**53-1)-(t.get(n.el)??2**53-1):n.rank-e.rank),s=new Set(a.map(e=>e.el)),c=e.filter(e=>i.has(e)&&!s.has(e)),u=[...a.map(e=>e.el),...c],d=0;W(o,e.map(e=>i.has(e)?u[d++]??e:e));for(let e of O){let t=R.get(e.el)?.filter(t=>t.parentElement===e.el)??[],n=ge(t),r=new Set,i=new Map;for(let t of D){if(t.group!==e)continue;let n=b(t.el,e.el);n&&(r.add(n),t.el.hidden||i.set(n,Math.max(i.get(n)??0,t.rank)))}let a=Array.from(i,([e,t])=>({el:e,rank:t})).sort((e,t)=>t.rank===e.rank?(n.get(e.el)??2**53-1)-(n.get(t.el)??2**53-1):t.rank-e.rank),o=new Set(a.map(e=>e.el)),s=t.filter(e=>r.has(e)&&!o.has(e)),c=[...a.map(e=>e.el),...s],l=0,u=t.map(e=>r.has(e)?c[l++]??e:e);W(e.el,u)}},J=()=>{fe(()=>{Se(),l&&E?(he(),Ce(),we(),z=!0):(z&&_e(),me(),Ce(),z=!1),ve(),ye()}),Q(),pe()},Te=(e=!0)=>{q(K()[0]?.value??null,e)},Y=(t,n=!0,r=!0)=>{E!==t&&(E=t,a.value=t,J(),r&&Te(n),n&&((0,e.emit)(i,`command:search-change`,{search:E}),oe?.(E)))},Ee=t=>{t.value===null||t.disabled||(q(t.value,!0),(0,e.emit)(i,`command:select`,{value:t.value}),se?.(t.value))},De=e=>{let t=k.get(e)??null;return t||(J(),t=k.get(e)??null,t)},X=e=>{let t=K()[e];t&&q(t.value,!0)},Z=e=>{let t=K();if(t.length===0)return;let n=t.findIndex(e=>e.value===T),r=t[n+e];m&&(r=n+e<0?t[t.length-1]:n+e===t.length?t[0]:t[n+e]),r&&q(r.value,!0)},Oe=e=>{let t=G()?.closest(f);for(;t;){let n=e>0?t.nextElementSibling:t.previousElementSibling,r=null;for(;n;){if(n instanceof HTMLElement&&n.getAttribute(`data-slot`)===`command-group`&&!n.hidden){r=n;break}n=e>0?n.nextElementSibling:n.previousElementSibling}if(!r)break;let a=x(r,d,i).map(e=>k.get(e)??null).find(e=>e!==null&&!e.disabled&&!e.el.hidden);if(a){q(a.value,!0);return}t=r}Z(e)},ke=e=>{if(e.defaultPrevented)return;let t=V(e.target);if(t&&t!==a)return;let n=e.key.toLowerCase();if(e.isComposing||e.keyCode===229)return;let r=()=>{e.preventDefault(),e.metaKey?X(K().length-1):e.altKey?Oe(1):Z(1)},i=()=>{e.preventDefault(),e.metaKey?X(0):e.altKey?Oe(-1):Z(-1)};switch(n){case`arrowdown`:r();break;case`arrowup`:i();break;case`home`:e.preventDefault(),X(0);break;case`end`:e.preventDefault(),X(K().length-1);break;case`enter`:{let t=G(),n=t?k.get(t):null;if(!n||n.value===null)return;e.preventDefault(),Ee(n);break}case`j`:case`n`:C&&e.ctrlKey&&r();break;case`k`:case`p`:C&&e.ctrlKey&&i();break}},Ae=()=>{F||I||(F=!0,queueMicrotask(()=>{if(F=!1,I)return;let e=G();J();let t=e?k.get(e)??null:null;if(t&&t.value!==null&&!t.disabled&&!t.el.hidden&&!(t.group?.el.hidden??!1)){q(t.value,!0);return}if(T!==null){let e=K().find(e=>e.value===T)??null;if(e){q(e.value,!0);return}}q(K()[0]?.value??null,!0)}))},Q=()=>{N&&N.observe(o,{subtree:!0,childList:!0,characterData:!0,attributes:!0,attributeFilter:[...g]})};typeof MutationObserver<`u`&&(N=new MutationObserver(()=>{Ae()}),Q()),a.value=E,J(),(E||T===null)&&Te(!1),M.push((0,e.on)(a,`input`,()=>{Y(a.value,!0,!0)})),M.push((0,e.on)(i,`keydown`,e=>{ke(e)})),M.push((0,e.on)(o,`pointermove`,e=>{if(h)return;let t=e.target,n=t instanceof HTMLElement?t.closest(d):null;if(!(n instanceof HTMLElement))return;let r=De(n);!r||r.disabled||n.hidden||r.group?.el.hidden||q(r.value,!0)})),M.push((0,e.on)(o,`click`,e=>{let t=e.target,n=V(t),r=t instanceof HTMLElement?t.closest(d):null;if(n&&n!==r||!(r instanceof HTMLElement))return;let i=De(r);!i||i.disabled||i.value===null||r.hidden||i.group?.el.hidden||Ee(i)})),M.push((0,e.on)(i,`command:set`,e=>{let t=e.detail;t&&(t.search!==void 0&&Y(String(t.search),!0,t.value===void 0),t.value!==void 0&&q(t.value,!0))}));let $={get value(){return T},get search(){return E},select(e){q(e,!0)},setSearch(e){Y(e,!0,!0)},destroy(){I=!0,N?.disconnect(),P?.disconnect(),M.forEach(e=>e()),M=[],ce&&i.removeAttribute(`tabindex`),(0,e.clearRootBinding)(i,u,$)}};return(0,e.setRootBinding)(i,u,$),$}function w(t=document){let n=[];for(let r of(0,e.getRoots)(t,`command`))(0,e.hasRootBinding)(r,u)||n.push(C(r));return n}exports.create=w,exports.createCommand=C;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
type CommandFilter = (value: string, search: string, keywords?: string[]) => number;
|
|
3
|
+
interface CommandOptions {
|
|
4
|
+
/** Accessible label announced for the command input */
|
|
5
|
+
label?: string;
|
|
6
|
+
/** Initial active item value */
|
|
7
|
+
defaultValue?: string;
|
|
8
|
+
/** Initial search input value */
|
|
9
|
+
defaultSearch?: string;
|
|
10
|
+
/** Called whenever the active item value changes */
|
|
11
|
+
onValueChange?: (value: string | null) => void;
|
|
12
|
+
/** Called whenever the search query changes */
|
|
13
|
+
onSearchChange?: (search: string) => void;
|
|
14
|
+
/** Called when an item is selected via click or Enter */
|
|
15
|
+
onSelect?: (value: string) => void;
|
|
16
|
+
/** Disable built-in filtering and sorting */
|
|
17
|
+
shouldFilter?: boolean;
|
|
18
|
+
/** Custom ranking function. Return 0 to hide the item. */
|
|
19
|
+
filter?: CommandFilter;
|
|
20
|
+
/** Wrap arrow-key navigation */
|
|
21
|
+
loop?: boolean;
|
|
22
|
+
/** Disable pointer-move selection */
|
|
23
|
+
disablePointerSelection?: boolean;
|
|
24
|
+
/** Enable ctrl+j/k/n/p shortcuts @default true */
|
|
25
|
+
vimBindings?: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface CommandController {
|
|
28
|
+
/** Current active item value */
|
|
29
|
+
readonly value: string | null;
|
|
30
|
+
/** Current search query */
|
|
31
|
+
readonly search: string;
|
|
32
|
+
/** Set the active item value programmatically */
|
|
33
|
+
select(value: string | null): void;
|
|
34
|
+
/** Set the search query programmatically */
|
|
35
|
+
setSearch(search: string): void;
|
|
36
|
+
/** Cleanup all event listeners and observers */
|
|
37
|
+
destroy(): void;
|
|
38
|
+
}
|
|
39
|
+
declare function createCommand(root: Element, options?: CommandOptions): CommandController;
|
|
40
|
+
declare function create(scope?: ParentNode): CommandController[];
|
|
41
|
+
//#endregion
|
|
42
|
+
export { CommandController, CommandFilter, CommandOptions, create, createCommand };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
type CommandFilter = (value: string, search: string, keywords?: string[]) => number;
|
|
3
|
+
interface CommandOptions {
|
|
4
|
+
/** Accessible label announced for the command input */
|
|
5
|
+
label?: string;
|
|
6
|
+
/** Initial active item value */
|
|
7
|
+
defaultValue?: string;
|
|
8
|
+
/** Initial search input value */
|
|
9
|
+
defaultSearch?: string;
|
|
10
|
+
/** Called whenever the active item value changes */
|
|
11
|
+
onValueChange?: (value: string | null) => void;
|
|
12
|
+
/** Called whenever the search query changes */
|
|
13
|
+
onSearchChange?: (search: string) => void;
|
|
14
|
+
/** Called when an item is selected via click or Enter */
|
|
15
|
+
onSelect?: (value: string) => void;
|
|
16
|
+
/** Disable built-in filtering and sorting */
|
|
17
|
+
shouldFilter?: boolean;
|
|
18
|
+
/** Custom ranking function. Return 0 to hide the item. */
|
|
19
|
+
filter?: CommandFilter;
|
|
20
|
+
/** Wrap arrow-key navigation */
|
|
21
|
+
loop?: boolean;
|
|
22
|
+
/** Disable pointer-move selection */
|
|
23
|
+
disablePointerSelection?: boolean;
|
|
24
|
+
/** Enable ctrl+j/k/n/p shortcuts @default true */
|
|
25
|
+
vimBindings?: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface CommandController {
|
|
28
|
+
/** Current active item value */
|
|
29
|
+
readonly value: string | null;
|
|
30
|
+
/** Current search query */
|
|
31
|
+
readonly search: string;
|
|
32
|
+
/** Set the active item value programmatically */
|
|
33
|
+
select(value: string | null): void;
|
|
34
|
+
/** Set the search query programmatically */
|
|
35
|
+
setSearch(search: string): void;
|
|
36
|
+
/** Cleanup all event listeners and observers */
|
|
37
|
+
destroy(): void;
|
|
38
|
+
}
|
|
39
|
+
declare function createCommand(root: Element, options?: CommandOptions): CommandController;
|
|
40
|
+
declare function create(scope?: ParentNode): CommandController[];
|
|
41
|
+
//#endregion
|
|
42
|
+
export { CommandController, CommandFilter, CommandOptions, create, createCommand };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{clearRootBinding as e,emit as t,ensureId as n,getDataBool as r,getDataString as i,getPart as a,getRoots as o,hasRootBinding as s,on as c,reuseRootBinding as l,setAria as u,setRootBinding as d}from"@data-slot/core";const f=.1,p=.999,m=/[\\/_+.#"@\[\(\{&]/,h=/[\\/_+.#"@\[\(\{&]/g,g=/[\s-]/,_=/[\s-]/g;function v(e,t,n,r,i,a,o){if(a===t.length)return i===e.length?1:.99;let s=`${i},${a}`,c=o[s];if(c!==void 0)return c;let l=r.charAt(a),u=n.indexOf(l,i),d=0;for(;u>=0;){let s=v(e,t,n,r,u+1,a+1,o);if(s>d){if(u===i)s*=1;else if(m.test(e.charAt(u-1))){s*=.8;let t=e.slice(i,u-1).match(h);t&&i>0&&(s*=p**+t.length)}else if(g.test(e.charAt(u-1))){s*=.9;let t=e.slice(i,u-1).match(_);t&&i>0&&(s*=p**+t.length)}else s*=.17,i>0&&(s*=p**+(u-i));e.charAt(u)!==t.charAt(a)&&(s*=.9999)}if(s<f&&n.charAt(u-1)===r.charAt(a+1)||r.charAt(a+1)===r.charAt(a)&&n.charAt(u-1)!==r.charAt(a)){let i=v(e,t,n,r,u+1,a+2,o);i*f>s&&(s=i*f)}s>d&&(d=s),u=n.indexOf(l,u+1)}return o[s]=d,d}function y(e){return e.toLowerCase().replace(_,` `)}function ee(e,t,n=[]){let r=n.length>0?`${e} ${n.join(` `)}`:e;return v(r,t,y(r),y(t),0,0,{})}const b=`@data-slot/command`,x=`[data-slot="command-item"]`,S=`[data-slot="command-group"]`,te=`[data-slot="command-separator"]`,C=Symbol(`data-slot.command.authored-value`),w=Symbol(`data-slot.command.inferred-value`),ne=[`data-slot`,`data-value`,`data-label`,`data-keywords`,`data-disabled`,`disabled`,`data-force-mount`,`data-always-render`],re=[`input:not([type="hidden"])`,`textarea`,`select`,`button`,`a[href]`,`summary`,`audio[controls]`,`video[controls]`,`[contenteditable=""]`,`[contenteditable="true"]`,`[contenteditable="plaintext-only"]`,`[tabindex]:not([tabindex="-1"])`].join(`, `),ie=(e,t,n)=>t.trim()?ee(e,t,n??[]):1,T=e=>e==null?null:e.trim(),ae=e=>e?e.split(/[,\n]/).map(e=>e.trim()).filter(Boolean):[],oe=(e,t)=>Array.from(e.children).filter(e=>e instanceof HTMLElement&&e.getAttribute(`data-slot`)===t),se=(e,t)=>{let n=e;for(;n&&n.parentElement&&n.parentElement!==t;)n=n.parentElement;return n?.parentElement===t?n:null},E=(e,t,n)=>Array.from(e.querySelectorAll(t)).filter(e=>e.closest(`[data-slot="command"]`)===n),D=e=>Array.from(e.children).filter(e=>e instanceof HTMLElement),ce=e=>{let t=e=>{if(e.nodeType===Node.TEXT_NODE)return e.textContent??``;if(!(e instanceof HTMLElement)||e.getAttribute(`data-slot`)===`command-shortcut`)return``;let n=``;for(let r of e.childNodes)n+=t(r);return n};return t(e).replace(/\s+/g,` `).trim()},le=e=>e.hasAttribute(`disabled`)||e.hasAttribute(`data-disabled`)||e.getAttribute(`aria-disabled`)===`true`,ue=(e,t)=>{let n=e,r=e.hasAttribute(`data-value`);if(n[C]===void 0&&(n[C]=r),r?n[C]||T(e.getAttribute(`data-value`))!==n[w]&&(n[C]=!0):n[C]=!1,n[C])return{authored:!0,value:T(e.getAttribute(`data-value`))};let i=t();return n[w]=i,i===null?e.removeAttribute(`data-value`):e.setAttribute(`data-value`,i),{authored:!1,value:i}};function O(o,s={}){let f=l(o,b,`[@data-slot/command] createCommand() called more than once for the same root. Returning the existing controller. Destroy it before rebinding with new options.`);if(f)return f;let p=o,m=a(o,`command-input`),h=a(o,`command-list`),g=a(h??o,`command-empty`);if(!m||!h)throw Error(`Command requires command-input and command-list slots`);let _=s.label??i(p,`label`)??`Command Menu`,v=s.shouldFilter??r(p,`shouldFilter`)??!0,y=s.loop??r(p,`loop`)??!1,ee=s.disablePointerSelection??r(p,`disablePointerSelection`)??!1,C=s.vimBindings??r(p,`vimBindings`)??!0,w=s.filter??ie,O=s.onValueChange,de=s.onSearchChange,fe=s.onSelect,k=T(s.defaultValue??i(p,`defaultValue`)),A=s.defaultSearch??i(p,`defaultSearch`)??``,j=[],M=[],N=new Map,P=new Map,F=0,I=[],L=null,R=null,z=!1,B=!1,pe=!1,V=[],H=new Map,U=!1,me=n(m,`command-input`),he=n(h,`command-list`);p.hasAttribute(`tabindex`)||(p.tabIndex=-1,pe=!0),m.setAttribute(`role`,`combobox`),m.setAttribute(`aria-autocomplete`,`list`),m.setAttribute(`aria-expanded`,`true`),m.setAttribute(`aria-controls`,he),m.setAttribute(`autocomplete`,`off`),m.setAttribute(`autocorrect`,`off`),m.spellcheck=!1,h.setAttribute(`role`,`listbox`),h.tabIndex=-1;let ge=document.querySelector(`label[for="${CSS.escape(me)}"]`);if(ge){let e=n(ge,`command-label`),t=m.getAttribute(`aria-labelledby`);m.setAttribute(`aria-labelledby`,t?`${t} ${e}`:e),h.setAttribute(`aria-labelledby`,e)}else !m.hasAttribute(`aria-label`)&&!m.hasAttribute(`aria-labelledby`)&&(m.setAttribute(`aria-label`,_),h.setAttribute(`aria-label`,`Suggestions`));let _e=()=>{document.activeElement!==m&&m.focus({preventScroll:!0})},ve=e=>{if(!(e instanceof HTMLElement)||!p.contains(e))return null;let t=e.closest(re);return t instanceof HTMLElement&&p.contains(t)?t:null},ye=e=>{L?.disconnect();try{return e()}finally{$()}},W=()=>{h.style.setProperty(`--command-list-height`,`${h.scrollHeight.toFixed(1)}px`)},be=()=>{if(typeof ResizeObserver>`u`){W();return}R||=new ResizeObserver(()=>{W()}),R.disconnect(),R.observe(h);for(let e of E(h,`${x}, ${S}, ${te}, [data-slot="command-empty"]`,p))R.observe(e);W()},xe=(e,t)=>{let n=e.filter(e=>t.includes(e));for(let e of t){if(n.includes(e))continue;let r=t.indexOf(e),i=!1;for(let a=r-1;a>=0;--a){let r=t[a];if(!r)continue;let o=n.indexOf(r);if(o!==-1){n.splice(o+1,0,e),i=!0;break}}if(!i){for(let a=r+1;a<t.length;a+=1){let r=t[a];if(!r)continue;let o=n.indexOf(r);if(o!==-1){n.splice(o,0,e),i=!0;break}}i||n.push(e)}}return n},Se=()=>{V=D(h),H=new Map(M.map(e=>[e.el,D(e.el)]))},Ce=()=>{let e=D(h);V=V.length===0?e:xe(V,e);let t=new Map;for(let e of M){let n=D(e.el),r=H.get(e.el)??[];t.set(e.el,r.length===0?n:xe(r,n))}H=t},G=(e,t)=>{let n=D(e),r=new Set;for(let n of t)n.parentElement!==e||r.has(n)||(r.add(n),e.appendChild(n));for(let t of n)r.has(t)||t.parentElement!==e||e.appendChild(t)},we=e=>new Map(e.map((e,t)=>[e,t])),Te=()=>{for(let e of M){let t=H.get(e.el)?.filter(t=>t.parentElement===e.el)??[];G(e.el,t)}G(h,V.filter(e=>e.parentElement===h))},K=()=>k===null?null:E(h,x,p).find(e=>{let t=N.get(e);return t?.value===k&&!e.hidden&&!(t.group?.el.hidden??!1)})??null,Ee=()=>{for(let e of j){let t=e.value===k&&k!==null;u(e.el,`selected`,t),t?e.el.setAttribute(`data-selected`,``):e.el.removeAttribute(`data-selected`)}let e=K();e?(m.setAttribute(`aria-activedescendant`,e.id),h.setAttribute(`aria-activedescendant`,e.id)):(m.removeAttribute(`aria-activedescendant`),h.removeAttribute(`aria-activedescendant`))},De=()=>{k===null?p.removeAttribute(`data-value`):p.setAttribute(`data-value`,k),A?p.setAttribute(`data-search`,A):p.removeAttribute(`data-search`)},Oe=()=>E(h,x,p).map(e=>N.get(e)??null).filter(e=>e!==null&&!e.el.hidden&&!(e.group?.el.hidden??!1)),q=()=>Oe().filter(e=>!e.disabled),ke=(e,n,r)=>{!r||e===n||(t(p,`command:change`,{value:n}),O?.(n))},J=(e,t=!0)=>{let n=T(e),r=k;return k=n,Ee(),De(),(document.activeElement===m||document.activeElement===p)&&_e(),ke(r,k,t),r!==k},Ae=()=>{j=[],M=[],N=new Map,P=new Map;for(let e of E(h,S,p)){let t=oe(e,`command-group-heading`)[0]??null,i={el:e,heading:t,value:ue(e,()=>T(t?.textContent)??n(e,`command-group`)).value??n(e,`command-group`),forceMount:r(e,`forceMount`)??!1,maxRank:0};if(P.set(e,i),M.push(i),e.setAttribute(`role`,`group`),t){let r=n(t,`command-group-heading`);e.setAttribute(`aria-labelledby`,r)}else e.removeAttribute(`aria-labelledby`)}for(let e of E(h,x,p)){let t=e.closest(S),i=t instanceof HTMLElement&&t.closest(`[data-slot="command"]`)===p?P.get(t)??null:null,a={el:e,value:ue(e,()=>T(e.getAttribute(`data-label`))??T(ce(e))).value,keywords:ae(e.getAttribute(`data-keywords`)??void 0),disabled:le(e),forceMount:r(e,`forceMount`)??!1,rank:0,group:i};N.set(e,a),j.push(a),n(e,`command-item`),e.setAttribute(`role`,`option`),a.disabled?e.setAttribute(`aria-disabled`,`true`):e.removeAttribute(`aria-disabled`)}},je=()=>{let e=A.length>0;F=0;for(let e of M)e.maxRank=0;for(let t of j){t.rank=v&&e&&t.value!==null?w(t.value,A,t.keywords):1,v&&e&&t.rank>0&&(F+=1);let n=!e||!v||t.forceMount||t.group?.forceMount||t.rank>0;t.el.hidden=!n,t.group&&t.rank>t.group.maxRank&&(t.group.maxRank=t.rank)}(!v||!e)&&(F=j.length);for(let t of M){let n=!e||!v||t.forceMount||j.some(e=>e.group===t&&e.rank>0);t.el.hidden=!n}for(let t of E(h,te,p)){let n=r(t,`alwaysRender`)??!1;t.hidden=e&&!n,t.setAttribute(`role`,`separator`)}g&&(g.hidden=F>0)},Me=()=>{if(!v||!A)return;let e=V.filter(e=>e.parentElement===h),t=we(e),n=new Map,r=new Map;for(let e of j){if(e.group!==null)continue;let t=se(e.el,h);t&&(n.set(t,Math.max(n.get(t)??0,e.rank)),e.el.hidden||r.set(t,Math.max(r.get(t)??0,e.rank)))}let i=new Set([...n.keys(),...M.map(e=>e.el)]),a=[...Array.from(r,([e,t])=>({el:e,rank:t})),...M.filter(e=>!e.el.hidden).map(e=>({el:e.el,rank:e.maxRank}))].sort((e,n)=>n.rank===e.rank?(t.get(e.el)??2**53-1)-(t.get(n.el)??2**53-1):n.rank-e.rank),o=new Set(a.map(e=>e.el)),s=e.filter(e=>i.has(e)&&!o.has(e)),c=[...a.map(e=>e.el),...s],l=0;G(h,e.map(e=>i.has(e)?c[l++]??e:e));for(let e of M){let t=H.get(e.el)?.filter(t=>t.parentElement===e.el)??[],n=we(t),r=new Set,i=new Map;for(let t of j){if(t.group!==e)continue;let n=se(t.el,e.el);n&&(r.add(n),t.el.hidden||i.set(n,Math.max(i.get(n)??0,t.rank)))}let a=Array.from(i,([e,t])=>({el:e,rank:t})).sort((e,t)=>t.rank===e.rank?(n.get(e.el)??2**53-1)-(n.get(t.el)??2**53-1):t.rank-e.rank),o=new Set(a.map(e=>e.el)),s=t.filter(e=>r.has(e)&&!o.has(e)),c=[...a.map(e=>e.el),...s],l=0,u=t.map(e=>r.has(e)?c[l++]??e:e);G(e.el,u)}},Y=()=>{ye(()=>{Ae(),v&&A?(Ce(),je(),Me(),U=!0):(U&&Te(),Se(),je(),U=!1),Ee(),De()}),$(),be()},Ne=(e=!0)=>{J(q()[0]?.value??null,e)},X=(e,n=!0,r=!0)=>{A!==e&&(A=e,m.value=e,Y(),r&&Ne(n),n&&(t(p,`command:search-change`,{search:A}),de?.(A)))},Pe=e=>{e.value===null||e.disabled||(J(e.value,!0),t(p,`command:select`,{value:e.value}),fe?.(e.value))},Fe=e=>{let t=N.get(e)??null;return t||(Y(),t=N.get(e)??null,t)},Z=e=>{let t=q()[e];t&&J(t.value,!0)},Q=e=>{let t=q();if(t.length===0)return;let n=t.findIndex(e=>e.value===k),r=t[n+e];y&&(r=n+e<0?t[t.length-1]:n+e===t.length?t[0]:t[n+e]),r&&J(r.value,!0)},Ie=e=>{let t=K()?.closest(S);for(;t;){let n=e>0?t.nextElementSibling:t.previousElementSibling,r=null;for(;n;){if(n instanceof HTMLElement&&n.getAttribute(`data-slot`)===`command-group`&&!n.hidden){r=n;break}n=e>0?n.nextElementSibling:n.previousElementSibling}if(!r)break;let i=E(r,x,p).map(e=>N.get(e)??null).find(e=>e!==null&&!e.disabled&&!e.el.hidden);if(i){J(i.value,!0);return}t=r}Q(e)},Le=e=>{if(e.defaultPrevented)return;let t=ve(e.target);if(t&&t!==m)return;let n=e.key.toLowerCase();if(e.isComposing||e.keyCode===229)return;let r=()=>{e.preventDefault(),e.metaKey?Z(q().length-1):e.altKey?Ie(1):Q(1)},i=()=>{e.preventDefault(),e.metaKey?Z(0):e.altKey?Ie(-1):Q(-1)};switch(n){case`arrowdown`:r();break;case`arrowup`:i();break;case`home`:e.preventDefault(),Z(0);break;case`end`:e.preventDefault(),Z(q().length-1);break;case`enter`:{let t=K(),n=t?N.get(t):null;if(!n||n.value===null)return;e.preventDefault(),Pe(n);break}case`j`:case`n`:C&&e.ctrlKey&&r();break;case`k`:case`p`:C&&e.ctrlKey&&i();break}},Re=()=>{z||B||(z=!0,queueMicrotask(()=>{if(z=!1,B)return;let e=K();Y();let t=e?N.get(e)??null:null;if(t&&t.value!==null&&!t.disabled&&!t.el.hidden&&!(t.group?.el.hidden??!1)){J(t.value,!0);return}if(k!==null){let e=q().find(e=>e.value===k)??null;if(e){J(e.value,!0);return}}J(q()[0]?.value??null,!0)}))},$=()=>{L&&L.observe(h,{subtree:!0,childList:!0,characterData:!0,attributes:!0,attributeFilter:[...ne]})};typeof MutationObserver<`u`&&(L=new MutationObserver(()=>{Re()}),$()),m.value=A,Y(),(A||k===null)&&Ne(!1),I.push(c(m,`input`,()=>{X(m.value,!0,!0)})),I.push(c(p,`keydown`,e=>{Le(e)})),I.push(c(h,`pointermove`,e=>{if(ee)return;let t=e.target,n=t instanceof HTMLElement?t.closest(x):null;if(!(n instanceof HTMLElement))return;let r=Fe(n);!r||r.disabled||n.hidden||r.group?.el.hidden||J(r.value,!0)})),I.push(c(h,`click`,e=>{let t=e.target,n=ve(t),r=t instanceof HTMLElement?t.closest(x):null;if(n&&n!==r||!(r instanceof HTMLElement))return;let i=Fe(r);!i||i.disabled||i.value===null||r.hidden||i.group?.el.hidden||Pe(i)})),I.push(c(p,`command:set`,e=>{let t=e.detail;t&&(t.search!==void 0&&X(String(t.search),!0,t.value===void 0),t.value!==void 0&&J(t.value,!0))}));let ze={get value(){return k},get search(){return A},select(e){J(e,!0)},setSearch(e){X(e,!0,!0)},destroy(){B=!0,L?.disconnect(),R?.disconnect(),I.forEach(e=>e()),I=[],pe&&p.removeAttribute(`tabindex`),e(p,b,ze)}};return d(p,b,ze),ze}function de(e=document){let t=[];for(let n of o(e,`command`))s(n,b)||t.push(O(n));return t}export{de as create,O as createCommand};
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@data-slot/command",
|
|
3
|
+
"version": "0.2.125",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsdown"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/bejamas/data-slot.git",
|
|
26
|
+
"directory": "packages/command"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"headless",
|
|
30
|
+
"ui",
|
|
31
|
+
"command",
|
|
32
|
+
"command-palette",
|
|
33
|
+
"cmdk",
|
|
34
|
+
"vanilla",
|
|
35
|
+
"data-slot"
|
|
36
|
+
],
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@data-slot/core": "workspace:*"
|
|
40
|
+
}
|
|
41
|
+
}
|