modern-cmdk 1.0.0
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/LICENSE +21 -0
- package/dist/codemod/cli.d.mts +1 -0
- package/dist/codemod/cli.mjs +89836 -0
- package/dist/codemod/cli.mjs.map +1 -0
- package/dist/codemod/transforms/data-attrs.d.mts +11 -0
- package/dist/codemod/transforms/data-attrs.d.mts.map +1 -0
- package/dist/codemod/transforms/data-attrs.mjs +68 -0
- package/dist/codemod/transforms/data-attrs.mjs.map +1 -0
- package/dist/codemod/transforms/forward-ref.d.mts +11 -0
- package/dist/codemod/transforms/forward-ref.d.mts.map +1 -0
- package/dist/codemod/transforms/forward-ref.mjs +53 -0
- package/dist/codemod/transforms/forward-ref.mjs.map +1 -0
- package/dist/codemod/transforms/import-rewrite.d.mts +11 -0
- package/dist/codemod/transforms/import-rewrite.d.mts.map +1 -0
- package/dist/codemod/transforms/import-rewrite.mjs +45 -0
- package/dist/codemod/transforms/import-rewrite.mjs.map +1 -0
- package/dist/codemod/transforms/should-filter.d.mts +10 -0
- package/dist/codemod/transforms/should-filter.d.mts.map +1 -0
- package/dist/codemod/transforms/should-filter.mjs +21 -0
- package/dist/codemod/transforms/should-filter.mjs.map +1 -0
- package/dist/core/index.d.mts +2 -0
- package/dist/core/index.mjs +2 -0
- package/dist/core-Bq0eDvlc.mjs +1217 -0
- package/dist/core-Bq0eDvlc.mjs.map +1 -0
- package/dist/index-Ctz7l29k.d.mts +562 -0
- package/dist/index-Ctz7l29k.d.mts.map +1 -0
- package/dist/react/index.d.mts +358 -0
- package/dist/react/index.d.mts.map +1 -0
- package/dist/react/index.mjs +905 -0
- package/dist/react/index.mjs.map +1 -0
- package/package.json +71 -0
- package/src/react/styles.css +609 -0
|
@@ -0,0 +1,905 @@
|
|
|
1
|
+
import { C as itemId, S as groupId, d as formatShortcut, f as parseShortcut, i as createCommandMachine } from "../core-Bq0eDvlc.mjs";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Component, Suspense, createContext, use, useCallback, useEffect, useId, useInsertionEffect, useMemo, useOptimistic, useRef, useState, useSyncExternalStore, useTransition } from "react";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { Dialog } from "radix-ui";
|
|
6
|
+
//#region src/react/activity.tsx
|
|
7
|
+
const ActivityComponent = "Activity" in React ? React.Activity : null;
|
|
8
|
+
/**
|
|
9
|
+
* Wraps content in React 19.3.0-canary Activity API.
|
|
10
|
+
* When mode="hidden", the component tree is preserved in memory but not rendered.
|
|
11
|
+
* Falls back to conditional rendering if Activity is unavailable.
|
|
12
|
+
*/
|
|
13
|
+
function CommandActivity({ mode, children }) {
|
|
14
|
+
if (ActivityComponent) return /* @__PURE__ */ jsx(ActivityComponent, {
|
|
15
|
+
mode,
|
|
16
|
+
children
|
|
17
|
+
});
|
|
18
|
+
if (mode === "hidden") return null;
|
|
19
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/react/context.ts
|
|
23
|
+
const CommandContext = createContext(null);
|
|
24
|
+
CommandContext.displayName = "CommandContext";
|
|
25
|
+
const CommandGroupContext = createContext(null);
|
|
26
|
+
CommandGroupContext.displayName = "CommandGroupContext";
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/react/async-items.tsx
|
|
29
|
+
/** Inner component that suspends via use() until items resolve */
|
|
30
|
+
function AsyncItemsInner({ items: itemsPromise, children }) {
|
|
31
|
+
const ctx = use(CommandContext);
|
|
32
|
+
if (!ctx) throw new Error("Command.AsyncItems must be used within a <Command> component");
|
|
33
|
+
const items = use(itemsPromise);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
ctx.machine.send({
|
|
36
|
+
type: "ITEMS_LOADED",
|
|
37
|
+
items
|
|
38
|
+
});
|
|
39
|
+
}, [ctx.machine, items]);
|
|
40
|
+
return /* @__PURE__ */ jsx(Fragment, { children: children(items) });
|
|
41
|
+
}
|
|
42
|
+
function CommandAsyncItems({ items, fallback, children }) {
|
|
43
|
+
const stableRef = useRef(items);
|
|
44
|
+
if (stableRef.current !== items) stableRef.current = items;
|
|
45
|
+
return /* @__PURE__ */ jsx(Suspense, {
|
|
46
|
+
fallback,
|
|
47
|
+
children: /* @__PURE__ */ jsx(AsyncItemsInner, {
|
|
48
|
+
items: stableRef.current,
|
|
49
|
+
children
|
|
50
|
+
})
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/react/badge.tsx
|
|
55
|
+
function CommandBadge({ ref, children, ...props }) {
|
|
56
|
+
return /* @__PURE__ */ jsx("span", {
|
|
57
|
+
ref,
|
|
58
|
+
"data-command-badge": "",
|
|
59
|
+
...props,
|
|
60
|
+
children
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/react/hooks/use-command.ts
|
|
65
|
+
function useCommand(machine) {
|
|
66
|
+
const id = useId();
|
|
67
|
+
const [isPending, startTransition] = useTransition();
|
|
68
|
+
const state = useSyncExternalStore(machine.subscribe, machine.getState, machine.getState);
|
|
69
|
+
const filteredIdSet = useMemo(() => new Set(state.filteredIds), [state.filteredIds]);
|
|
70
|
+
const [optimisticActiveId, setOptimisticActiveId] = useOptimistic(state.activeId);
|
|
71
|
+
const updateSearch = useCallback((query) => {
|
|
72
|
+
startTransition(() => {
|
|
73
|
+
machine.send({
|
|
74
|
+
type: "SEARCH_CHANGE",
|
|
75
|
+
query
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}, [machine]);
|
|
79
|
+
return {
|
|
80
|
+
state: optimisticActiveId !== state.activeId ? {
|
|
81
|
+
...state,
|
|
82
|
+
activeId: optimisticActiveId
|
|
83
|
+
} : state,
|
|
84
|
+
isPending,
|
|
85
|
+
updateSearch,
|
|
86
|
+
setOptimisticActiveId,
|
|
87
|
+
filteredIdSet,
|
|
88
|
+
id
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/react/hooks/use-keyboard.ts
|
|
93
|
+
/** Navigation key to machine direction mapping */
|
|
94
|
+
const NAVIGATION_KEYS = {
|
|
95
|
+
ArrowDown: "next",
|
|
96
|
+
ArrowUp: "prev",
|
|
97
|
+
Home: "first",
|
|
98
|
+
End: "last"
|
|
99
|
+
};
|
|
100
|
+
/** Create a keydown handler for command palette keyboard navigation */
|
|
101
|
+
function createKeydownHandler(machine, getState) {
|
|
102
|
+
return (event) => {
|
|
103
|
+
const { key } = event;
|
|
104
|
+
const state = getState();
|
|
105
|
+
const direction = NAVIGATION_KEYS[key];
|
|
106
|
+
if (direction) {
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
machine.send({
|
|
109
|
+
type: "NAVIGATE",
|
|
110
|
+
direction
|
|
111
|
+
});
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
switch (key) {
|
|
115
|
+
case "Enter": {
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
const { activeId } = state;
|
|
118
|
+
if (activeId) machine.send({
|
|
119
|
+
type: "ITEM_SELECT",
|
|
120
|
+
id: activeId
|
|
121
|
+
});
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
case "Backspace":
|
|
125
|
+
if (state.search === "" && state.pageStack.length > 0) {
|
|
126
|
+
event.preventDefault();
|
|
127
|
+
machine.send({ type: "PAGE_POP" });
|
|
128
|
+
}
|
|
129
|
+
break;
|
|
130
|
+
case "Escape":
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
machine.send({ type: "CLOSE" });
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region src/react/dialog.tsx
|
|
139
|
+
function CommandDialog({ children, className, overlayClassName, contentClassName, label = "Command palette", open: controlledOpen, onOpenChange, container, ...machineOptions }) {
|
|
140
|
+
const rootId = useId();
|
|
141
|
+
const listId = `${rootId}-list`;
|
|
142
|
+
const inputId = `${rootId}-input`;
|
|
143
|
+
const machineRef = useRef(null);
|
|
144
|
+
if (machineRef.current === null) machineRef.current = createCommandMachine({
|
|
145
|
+
...machineOptions,
|
|
146
|
+
open: controlledOpen ?? false,
|
|
147
|
+
onOpenChange: (open) => {
|
|
148
|
+
onOpenChange?.(open);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const machine = machineRef.current;
|
|
152
|
+
const { state, isPending, updateSearch, setOptimisticActiveId, filteredIdSet, id } = useCommand(machine);
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
return () => {
|
|
155
|
+
machineRef.current?.[Symbol.dispose]();
|
|
156
|
+
machineRef.current = null;
|
|
157
|
+
};
|
|
158
|
+
}, []);
|
|
159
|
+
const handleKeyDown = useCallback(createKeydownHandler(machine, () => machine.getState()), []);
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
if (!state.open) return;
|
|
162
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
163
|
+
return () => {
|
|
164
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
165
|
+
};
|
|
166
|
+
}, [handleKeyDown, state.open]);
|
|
167
|
+
const prevControlledOpen = useRef(controlledOpen);
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
if (controlledOpen !== void 0 && controlledOpen !== prevControlledOpen.current) {
|
|
170
|
+
prevControlledOpen.current = controlledOpen;
|
|
171
|
+
machine.send({ type: controlledOpen ? "OPEN" : "CLOSE" });
|
|
172
|
+
}
|
|
173
|
+
}, [controlledOpen, machine]);
|
|
174
|
+
const handleRadixOpenChange = useCallback((open) => {
|
|
175
|
+
machine.send({ type: open ? "OPEN" : "CLOSE" });
|
|
176
|
+
}, [machine]);
|
|
177
|
+
const contextValue = useMemo(() => ({
|
|
178
|
+
machine,
|
|
179
|
+
state,
|
|
180
|
+
isPending,
|
|
181
|
+
updateSearch,
|
|
182
|
+
setOptimisticActiveId,
|
|
183
|
+
filteredIdSet,
|
|
184
|
+
rootId: id,
|
|
185
|
+
listId,
|
|
186
|
+
inputId,
|
|
187
|
+
label
|
|
188
|
+
}), [
|
|
189
|
+
machine,
|
|
190
|
+
state,
|
|
191
|
+
isPending,
|
|
192
|
+
updateSearch,
|
|
193
|
+
setOptimisticActiveId,
|
|
194
|
+
filteredIdSet,
|
|
195
|
+
id,
|
|
196
|
+
listId,
|
|
197
|
+
inputId,
|
|
198
|
+
label
|
|
199
|
+
]);
|
|
200
|
+
return /* @__PURE__ */ jsx(Dialog.Root, {
|
|
201
|
+
open: state.open,
|
|
202
|
+
onOpenChange: handleRadixOpenChange,
|
|
203
|
+
children: /* @__PURE__ */ jsxs(Dialog.Portal, {
|
|
204
|
+
container,
|
|
205
|
+
children: [/* @__PURE__ */ jsx(Dialog.Overlay, {
|
|
206
|
+
"data-command-overlay": "",
|
|
207
|
+
"data-state": state.open ? "open" : "closed",
|
|
208
|
+
className: overlayClassName
|
|
209
|
+
}), /* @__PURE__ */ jsxs(Dialog.Content, {
|
|
210
|
+
"data-command-dialog": "",
|
|
211
|
+
"data-state": state.open ? "open" : "closed",
|
|
212
|
+
className,
|
|
213
|
+
"aria-label": label,
|
|
214
|
+
onOpenAutoFocus: (e) => {
|
|
215
|
+
e.preventDefault();
|
|
216
|
+
document.getElementById(inputId)?.focus();
|
|
217
|
+
},
|
|
218
|
+
children: [
|
|
219
|
+
/* @__PURE__ */ jsx(Dialog.Title, {
|
|
220
|
+
className: "sr-only",
|
|
221
|
+
children: label
|
|
222
|
+
}),
|
|
223
|
+
/* @__PURE__ */ jsx(Dialog.Description, {
|
|
224
|
+
className: "sr-only",
|
|
225
|
+
children: "Type a command or search..."
|
|
226
|
+
}),
|
|
227
|
+
/* @__PURE__ */ jsx(CommandContext, {
|
|
228
|
+
value: contextValue,
|
|
229
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
230
|
+
"data-command-dialog-content": "",
|
|
231
|
+
className: contentClassName,
|
|
232
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
233
|
+
"data-command-root": "",
|
|
234
|
+
role: "search",
|
|
235
|
+
"aria-label": label,
|
|
236
|
+
children
|
|
237
|
+
})
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
]
|
|
241
|
+
})]
|
|
242
|
+
})
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/react/empty.tsx
|
|
247
|
+
function CommandEmpty({ ref, children, ...props }) {
|
|
248
|
+
const ctx = use(CommandContext);
|
|
249
|
+
if (!ctx) throw new Error("Command.Empty must be used within a <Command> component");
|
|
250
|
+
if (ctx.state.filteredCount > 0 || ctx.state.loading) return null;
|
|
251
|
+
return /* @__PURE__ */ jsx("div", {
|
|
252
|
+
ref,
|
|
253
|
+
"data-command-empty": "",
|
|
254
|
+
role: "status",
|
|
255
|
+
"aria-live": "polite",
|
|
256
|
+
...props,
|
|
257
|
+
children
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region src/react/hooks/use-register.ts
|
|
262
|
+
/** Register a command item with the machine — auto-deregisters on unmount */
|
|
263
|
+
function useRegisterItem(value, options) {
|
|
264
|
+
const ctx = use(CommandContext);
|
|
265
|
+
if (!ctx) throw new Error("useRegisterItem must be used within a <Command> component");
|
|
266
|
+
const generatedId = useId();
|
|
267
|
+
const id = itemId(options?.forceId ?? generatedId);
|
|
268
|
+
useInsertionEffect(() => {
|
|
269
|
+
const item = {
|
|
270
|
+
id,
|
|
271
|
+
value,
|
|
272
|
+
keywords: options?.keywords,
|
|
273
|
+
groupId: options?.groupId ? groupId(options.groupId) : void 0,
|
|
274
|
+
shortcut: options?.shortcut,
|
|
275
|
+
disabled: options?.disabled,
|
|
276
|
+
onSelect: options?.onSelect,
|
|
277
|
+
data: options?.data
|
|
278
|
+
};
|
|
279
|
+
ctx.machine.send({
|
|
280
|
+
type: "REGISTER_ITEM",
|
|
281
|
+
item
|
|
282
|
+
});
|
|
283
|
+
return () => {
|
|
284
|
+
ctx.machine.send({
|
|
285
|
+
type: "UNREGISTER_ITEM",
|
|
286
|
+
id
|
|
287
|
+
});
|
|
288
|
+
};
|
|
289
|
+
}, [
|
|
290
|
+
ctx.machine,
|
|
291
|
+
id,
|
|
292
|
+
value,
|
|
293
|
+
options?.groupId,
|
|
294
|
+
options?.data,
|
|
295
|
+
options?.disabled,
|
|
296
|
+
options?.keywords,
|
|
297
|
+
options?.onSelect,
|
|
298
|
+
options?.shortcut
|
|
299
|
+
]);
|
|
300
|
+
return id;
|
|
301
|
+
}
|
|
302
|
+
/** Register a command group with the machine — auto-deregisters on unmount */
|
|
303
|
+
function useRegisterGroup(heading, options) {
|
|
304
|
+
const ctx = use(CommandContext);
|
|
305
|
+
if (!ctx) throw new Error("useRegisterGroup must be used within a <Command> component");
|
|
306
|
+
const generatedId = useId();
|
|
307
|
+
const id = groupId(options?.forceId ?? generatedId);
|
|
308
|
+
useInsertionEffect(() => {
|
|
309
|
+
const group = {
|
|
310
|
+
id,
|
|
311
|
+
heading,
|
|
312
|
+
priority: options?.priority
|
|
313
|
+
};
|
|
314
|
+
ctx.machine.send({
|
|
315
|
+
type: "REGISTER_GROUP",
|
|
316
|
+
group
|
|
317
|
+
});
|
|
318
|
+
return () => {
|
|
319
|
+
ctx.machine.send({
|
|
320
|
+
type: "UNREGISTER_GROUP",
|
|
321
|
+
id
|
|
322
|
+
});
|
|
323
|
+
};
|
|
324
|
+
}, [
|
|
325
|
+
ctx.machine,
|
|
326
|
+
id,
|
|
327
|
+
heading,
|
|
328
|
+
options?.priority
|
|
329
|
+
]);
|
|
330
|
+
return id;
|
|
331
|
+
}
|
|
332
|
+
//#endregion
|
|
333
|
+
//#region src/react/group.tsx
|
|
334
|
+
function CommandGroup({ ref, children, heading, priority, forceId, ...props }) {
|
|
335
|
+
const ctx = use(CommandContext);
|
|
336
|
+
if (!ctx) throw new Error("Command.Group must be used within a <Command> component");
|
|
337
|
+
const headingId = useId();
|
|
338
|
+
const groupId = useRegisterGroup(heading, {
|
|
339
|
+
...priority !== void 0 && { priority },
|
|
340
|
+
...forceId !== void 0 && { forceId }
|
|
341
|
+
});
|
|
342
|
+
const groupItems = ctx.state.groupedIds.get(groupId);
|
|
343
|
+
const hasVisibleItems = groupItems !== void 0 && groupItems.length > 0;
|
|
344
|
+
const groupContext = useMemo(() => ({
|
|
345
|
+
groupId,
|
|
346
|
+
headingId
|
|
347
|
+
}), [groupId, headingId]);
|
|
348
|
+
if (!hasVisibleItems) return null;
|
|
349
|
+
return /* @__PURE__ */ jsx(CommandGroupContext, {
|
|
350
|
+
value: groupContext,
|
|
351
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
352
|
+
ref,
|
|
353
|
+
"data-command-group": "",
|
|
354
|
+
role: "group",
|
|
355
|
+
"aria-labelledby": heading ? headingId : void 0,
|
|
356
|
+
...props,
|
|
357
|
+
children: [heading && /* @__PURE__ */ jsx("div", {
|
|
358
|
+
"data-command-group-heading": "",
|
|
359
|
+
id: headingId,
|
|
360
|
+
"aria-hidden": true,
|
|
361
|
+
children: heading
|
|
362
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
363
|
+
"data-command-group-items": "",
|
|
364
|
+
children
|
|
365
|
+
})]
|
|
366
|
+
})
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/react/highlight.tsx
|
|
371
|
+
function CommandHighlight({ text, ranges, highlightClassName }) {
|
|
372
|
+
return useMemo(() => {
|
|
373
|
+
if (ranges.length === 0) return text;
|
|
374
|
+
const sorted = Iterator.from(ranges).toArray().sort((a, b) => a[0] - b[0]);
|
|
375
|
+
const segments = [];
|
|
376
|
+
let lastEnd = 0;
|
|
377
|
+
Iterator.from(sorted).forEach(([start, end], i) => {
|
|
378
|
+
if (start > lastEnd) segments.push(text.slice(lastEnd, start));
|
|
379
|
+
segments.push(/* @__PURE__ */ jsx("mark", {
|
|
380
|
+
"data-command-highlight": "",
|
|
381
|
+
className: highlightClassName,
|
|
382
|
+
children: text.slice(start, end)
|
|
383
|
+
}, i));
|
|
384
|
+
lastEnd = end;
|
|
385
|
+
});
|
|
386
|
+
if (lastEnd < text.length) segments.push(text.slice(lastEnd));
|
|
387
|
+
return /* @__PURE__ */ jsx(Fragment, { children: segments });
|
|
388
|
+
}, [
|
|
389
|
+
text,
|
|
390
|
+
ranges,
|
|
391
|
+
highlightClassName
|
|
392
|
+
]);
|
|
393
|
+
}
|
|
394
|
+
//#endregion
|
|
395
|
+
//#region src/react/input.tsx
|
|
396
|
+
function CommandInput({ ref, placeholder = "Search...", onValueChange, ...props }) {
|
|
397
|
+
const ctx = use(CommandContext);
|
|
398
|
+
if (!ctx) throw new Error("Command.Input must be used within a <Command> component");
|
|
399
|
+
const handleChange = useCallback((event) => {
|
|
400
|
+
const { value } = event.target;
|
|
401
|
+
ctx.updateSearch(value);
|
|
402
|
+
onValueChange?.(value);
|
|
403
|
+
}, [ctx.updateSearch, onValueChange]);
|
|
404
|
+
return /* @__PURE__ */ jsx("input", {
|
|
405
|
+
ref,
|
|
406
|
+
"data-command-input": "",
|
|
407
|
+
type: "text",
|
|
408
|
+
role: "combobox",
|
|
409
|
+
"aria-expanded": ctx.state.filteredCount > 0,
|
|
410
|
+
"aria-controls": ctx.listId,
|
|
411
|
+
"aria-activedescendant": ctx.state.activeId ?? void 0,
|
|
412
|
+
"aria-autocomplete": "list",
|
|
413
|
+
"aria-label": ctx.label,
|
|
414
|
+
id: ctx.inputId,
|
|
415
|
+
autoComplete: "off",
|
|
416
|
+
autoCorrect: "off",
|
|
417
|
+
spellCheck: false,
|
|
418
|
+
placeholder,
|
|
419
|
+
value: ctx.state.search,
|
|
420
|
+
onChange: handleChange,
|
|
421
|
+
...props
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region src/react/item.tsx
|
|
426
|
+
function CommandItem({ ref, children, value, keywords, onSelect, disabled = false, shortcut, forceId, ...props }) {
|
|
427
|
+
const ctx = use(CommandContext);
|
|
428
|
+
if (!ctx) throw new Error("Command.Item must be used within a <Command> component");
|
|
429
|
+
const id = useRegisterItem(value, {
|
|
430
|
+
...keywords !== void 0 && { keywords },
|
|
431
|
+
...shortcut !== void 0 && { shortcut },
|
|
432
|
+
disabled,
|
|
433
|
+
...onSelect !== void 0 && { onSelect },
|
|
434
|
+
...forceId !== void 0 && { forceId }
|
|
435
|
+
});
|
|
436
|
+
const isActive = ctx.state.activeId === id;
|
|
437
|
+
const isFiltered = ctx.filteredIdSet.has(id);
|
|
438
|
+
const handleSelect = useCallback(() => {
|
|
439
|
+
if (!disabled) ctx.machine.send({
|
|
440
|
+
type: "ITEM_SELECT",
|
|
441
|
+
id
|
|
442
|
+
});
|
|
443
|
+
}, [
|
|
444
|
+
ctx.machine,
|
|
445
|
+
id,
|
|
446
|
+
disabled
|
|
447
|
+
]);
|
|
448
|
+
const activeIdRef = useRef(ctx.state.activeId);
|
|
449
|
+
activeIdRef.current = ctx.state.activeId;
|
|
450
|
+
const handlePointerMove = useCallback(() => {
|
|
451
|
+
if (!disabled && activeIdRef.current !== id) {
|
|
452
|
+
ctx.setOptimisticActiveId(id);
|
|
453
|
+
ctx.machine.send({
|
|
454
|
+
type: "ITEM_ACTIVATE",
|
|
455
|
+
id
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
}, [
|
|
459
|
+
ctx.machine,
|
|
460
|
+
ctx.setOptimisticActiveId,
|
|
461
|
+
id,
|
|
462
|
+
disabled
|
|
463
|
+
]);
|
|
464
|
+
if (!isFiltered) return null;
|
|
465
|
+
return /* @__PURE__ */ jsx("div", {
|
|
466
|
+
ref,
|
|
467
|
+
"data-command-item": "",
|
|
468
|
+
"data-active": isActive ? "" : void 0,
|
|
469
|
+
"data-disabled": disabled ? "" : void 0,
|
|
470
|
+
"data-value": value,
|
|
471
|
+
id,
|
|
472
|
+
role: "option",
|
|
473
|
+
"aria-selected": isActive,
|
|
474
|
+
"aria-disabled": disabled || void 0,
|
|
475
|
+
"aria-keyshortcuts": shortcut ?? void 0,
|
|
476
|
+
onClick: handleSelect,
|
|
477
|
+
onPointerMove: handlePointerMove,
|
|
478
|
+
...props,
|
|
479
|
+
children
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/react/hooks/use-virtualizer.ts
|
|
484
|
+
function useVirtualizer(options) {
|
|
485
|
+
const { count, estimateSize, overscan = 8, scrollElement, enabled = true } = options;
|
|
486
|
+
const [scrollOffset, setScrollOffset] = useState(0);
|
|
487
|
+
const [containerHeight, setContainerHeight] = useState(0);
|
|
488
|
+
const measuredSizes = useRef(/* @__PURE__ */ new Map());
|
|
489
|
+
const [measureVersion, setMeasureVersion] = useState(0);
|
|
490
|
+
useEffect(() => {
|
|
491
|
+
if (!scrollElement || !enabled) return;
|
|
492
|
+
const observer = new ResizeObserver((entries) => {
|
|
493
|
+
const lastEntry = entries.at(-1);
|
|
494
|
+
if (lastEntry) setContainerHeight(lastEntry.contentRect.height);
|
|
495
|
+
});
|
|
496
|
+
observer.observe(scrollElement);
|
|
497
|
+
return () => {
|
|
498
|
+
observer.disconnect();
|
|
499
|
+
};
|
|
500
|
+
}, [scrollElement, enabled]);
|
|
501
|
+
useEffect(() => {
|
|
502
|
+
if (!scrollElement || !enabled) return;
|
|
503
|
+
const handleScroll = () => {
|
|
504
|
+
setScrollOffset(scrollElement.scrollTop);
|
|
505
|
+
};
|
|
506
|
+
scrollElement.addEventListener("scroll", handleScroll, { passive: true });
|
|
507
|
+
return () => {
|
|
508
|
+
scrollElement.removeEventListener("scroll", handleScroll);
|
|
509
|
+
};
|
|
510
|
+
}, [scrollElement, enabled]);
|
|
511
|
+
const getItemSize = useCallback((index) => measuredSizes.current.get(index) ?? estimateSize, [estimateSize]);
|
|
512
|
+
const totalSize = useMemo(() => {
|
|
513
|
+
if (!enabled) return 0;
|
|
514
|
+
const sizes = Iterator.from({ [Symbol.iterator]: function* () {
|
|
515
|
+
for (let i = 0; i < count; i++) yield getItemSize(i);
|
|
516
|
+
} }).toArray();
|
|
517
|
+
return Math.sumPrecise(sizes);
|
|
518
|
+
}, [
|
|
519
|
+
enabled,
|
|
520
|
+
count,
|
|
521
|
+
getItemSize,
|
|
522
|
+
measureVersion
|
|
523
|
+
]);
|
|
524
|
+
return {
|
|
525
|
+
virtualItems: useMemo(() => {
|
|
526
|
+
if (!enabled || containerHeight <= 0) return [];
|
|
527
|
+
let offset = 0;
|
|
528
|
+
let startIdx = 0;
|
|
529
|
+
while (startIdx < count && offset + getItemSize(startIdx) < scrollOffset) {
|
|
530
|
+
offset += getItemSize(startIdx);
|
|
531
|
+
startIdx++;
|
|
532
|
+
}
|
|
533
|
+
startIdx = Math.max(0, startIdx - overscan);
|
|
534
|
+
const offsetSizes = Iterator.from({ [Symbol.iterator]: function* () {
|
|
535
|
+
for (let i = 0; i < startIdx; i++) yield getItemSize(i);
|
|
536
|
+
} }).toArray();
|
|
537
|
+
offset = Math.sumPrecise(offsetSizes);
|
|
538
|
+
const items = [];
|
|
539
|
+
let currentOffset = offset;
|
|
540
|
+
const endOffset = scrollOffset + containerHeight;
|
|
541
|
+
for (let i = startIdx; i < count; i++) {
|
|
542
|
+
const size = getItemSize(i);
|
|
543
|
+
items.push({
|
|
544
|
+
index: i,
|
|
545
|
+
start: currentOffset,
|
|
546
|
+
size,
|
|
547
|
+
key: i
|
|
548
|
+
});
|
|
549
|
+
currentOffset += size;
|
|
550
|
+
if (currentOffset > endOffset + overscan * estimateSize) break;
|
|
551
|
+
}
|
|
552
|
+
return items;
|
|
553
|
+
}, [
|
|
554
|
+
enabled,
|
|
555
|
+
containerHeight,
|
|
556
|
+
count,
|
|
557
|
+
scrollOffset,
|
|
558
|
+
overscan,
|
|
559
|
+
estimateSize,
|
|
560
|
+
getItemSize
|
|
561
|
+
]),
|
|
562
|
+
totalSize,
|
|
563
|
+
scrollToIndex: useCallback((index) => {
|
|
564
|
+
if (!scrollElement || !enabled) return;
|
|
565
|
+
const clampedIndex = Math.min(index, count);
|
|
566
|
+
const sizes = Iterator.from({ [Symbol.iterator]: function* () {
|
|
567
|
+
for (let i = 0; i < clampedIndex; i++) yield getItemSize(i);
|
|
568
|
+
} }).toArray();
|
|
569
|
+
const targetOffset = Math.sumPrecise(sizes);
|
|
570
|
+
scrollElement.scrollTo({
|
|
571
|
+
top: targetOffset,
|
|
572
|
+
behavior: "smooth"
|
|
573
|
+
});
|
|
574
|
+
}, [
|
|
575
|
+
scrollElement,
|
|
576
|
+
enabled,
|
|
577
|
+
count,
|
|
578
|
+
getItemSize
|
|
579
|
+
]),
|
|
580
|
+
measureElement: useCallback((element) => {
|
|
581
|
+
if (!element || !enabled) return;
|
|
582
|
+
const index = Number(element.dataset.index);
|
|
583
|
+
if (Number.isNaN(index)) return;
|
|
584
|
+
const measure = () => {
|
|
585
|
+
const height = element.getBoundingClientRect().height;
|
|
586
|
+
if (height > 0 && measuredSizes.current.get(index) !== height) {
|
|
587
|
+
measuredSizes.current.set(index, height);
|
|
588
|
+
setMeasureVersion((v) => v + 1);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
if ("requestIdleCallback" in globalThis) requestIdleCallback(measure);
|
|
592
|
+
else setTimeout(measure, 0);
|
|
593
|
+
}, [enabled])
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
//#endregion
|
|
597
|
+
//#region src/react/list.tsx
|
|
598
|
+
function CommandList({ ref, children, virtualize, estimateSize = 44, overscan = 8, style, ...props }) {
|
|
599
|
+
const ctx = use(CommandContext);
|
|
600
|
+
if (!ctx) throw new Error("Command.List must be used within a <Command> component");
|
|
601
|
+
const innerRef = useRef(null);
|
|
602
|
+
const scrollRef = useRef(null);
|
|
603
|
+
const [height, setHeight] = useState(0);
|
|
604
|
+
const shouldVirtualize = virtualize ?? ctx.state.filteredCount > 100;
|
|
605
|
+
useEffect(() => {
|
|
606
|
+
const element = innerRef.current;
|
|
607
|
+
if (!element) return;
|
|
608
|
+
const observer = new ResizeObserver((entries) => {
|
|
609
|
+
const lastEntry = entries.at(-1);
|
|
610
|
+
if (lastEntry) setHeight(lastEntry.contentRect.height);
|
|
611
|
+
});
|
|
612
|
+
observer.observe(element);
|
|
613
|
+
return () => {
|
|
614
|
+
observer.disconnect();
|
|
615
|
+
};
|
|
616
|
+
}, []);
|
|
617
|
+
const virtualizer = useVirtualizer({
|
|
618
|
+
count: ctx.state.filteredCount,
|
|
619
|
+
estimateSize,
|
|
620
|
+
overscan,
|
|
621
|
+
scrollElement: shouldVirtualize ? scrollRef.current : null,
|
|
622
|
+
enabled: shouldVirtualize
|
|
623
|
+
});
|
|
624
|
+
const prevActiveId = useRef(ctx.state.activeId);
|
|
625
|
+
useEffect(() => {
|
|
626
|
+
if (ctx.state.activeId && ctx.state.activeId !== prevActiveId.current) {
|
|
627
|
+
prevActiveId.current = ctx.state.activeId;
|
|
628
|
+
if (shouldVirtualize) {
|
|
629
|
+
const idx = ctx.state.filteredIds.indexOf(ctx.state.activeId);
|
|
630
|
+
if (idx >= 0) virtualizer.scrollToIndex(idx);
|
|
631
|
+
} else (scrollRef.current?.querySelector(`[id="${CSS.escape(ctx.state.activeId)}"]`))?.scrollIntoView({
|
|
632
|
+
block: "nearest",
|
|
633
|
+
behavior: "smooth"
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}, [
|
|
637
|
+
ctx.state.activeId,
|
|
638
|
+
ctx.state.filteredIds,
|
|
639
|
+
shouldVirtualize,
|
|
640
|
+
virtualizer
|
|
641
|
+
]);
|
|
642
|
+
const mergedStyle = {
|
|
643
|
+
...style,
|
|
644
|
+
"--command-list-height": `${height.toFixed(1)}px`
|
|
645
|
+
};
|
|
646
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
647
|
+
ref: useCallback((el) => {
|
|
648
|
+
scrollRef.current = el;
|
|
649
|
+
if (typeof ref === "function") ref(el);
|
|
650
|
+
else if (ref) ref.current = el;
|
|
651
|
+
}, [ref]),
|
|
652
|
+
"data-command-list": "",
|
|
653
|
+
role: "listbox",
|
|
654
|
+
"aria-label": ctx.label,
|
|
655
|
+
"aria-busy": ctx.state.loading,
|
|
656
|
+
id: ctx.listId,
|
|
657
|
+
style: mergedStyle,
|
|
658
|
+
...props,
|
|
659
|
+
children: [shouldVirtualize ? /* @__PURE__ */ jsxs("div", {
|
|
660
|
+
"data-command-list-virtual": "",
|
|
661
|
+
style: {
|
|
662
|
+
height: `${virtualizer.totalSize}px`,
|
|
663
|
+
position: "relative"
|
|
664
|
+
},
|
|
665
|
+
children: [virtualizer.virtualItems.map((vItem) => /* @__PURE__ */ jsx("div", {
|
|
666
|
+
"data-command-virtual-item": "",
|
|
667
|
+
"data-index": vItem.index,
|
|
668
|
+
ref: virtualizer.measureElement,
|
|
669
|
+
style: {
|
|
670
|
+
position: "absolute",
|
|
671
|
+
top: 0,
|
|
672
|
+
left: 0,
|
|
673
|
+
width: "100%",
|
|
674
|
+
translate: `0 ${vItem.start}px`
|
|
675
|
+
}
|
|
676
|
+
}, vItem.key)), children]
|
|
677
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
678
|
+
ref: innerRef,
|
|
679
|
+
"data-command-list-inner": "",
|
|
680
|
+
children
|
|
681
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
682
|
+
"aria-live": "polite",
|
|
683
|
+
"aria-atomic": true,
|
|
684
|
+
role: "status",
|
|
685
|
+
"data-command-aria-live": "",
|
|
686
|
+
className: "sr-only",
|
|
687
|
+
children: [
|
|
688
|
+
ctx.state.filteredCount,
|
|
689
|
+
" result",
|
|
690
|
+
ctx.state.filteredCount !== 1 ? "s" : "",
|
|
691
|
+
" available."
|
|
692
|
+
]
|
|
693
|
+
})]
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
//#endregion
|
|
697
|
+
//#region src/react/loading.tsx
|
|
698
|
+
function CommandLoading({ ref, children, loading: loadingOverride, ...props }) {
|
|
699
|
+
const ctx = use(CommandContext);
|
|
700
|
+
if (!ctx) throw new Error("Command.Loading must be used within a <Command> component");
|
|
701
|
+
if (!(loadingOverride ?? ctx.state.loading ?? ctx.isPending)) return null;
|
|
702
|
+
return /* @__PURE__ */ jsx("div", {
|
|
703
|
+
ref,
|
|
704
|
+
"data-command-loading": "",
|
|
705
|
+
"aria-busy": true,
|
|
706
|
+
"aria-live": "assertive",
|
|
707
|
+
role: "status",
|
|
708
|
+
...props,
|
|
709
|
+
children
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
//#endregion
|
|
713
|
+
//#region src/react/page.tsx
|
|
714
|
+
function CommandPage({ id, children }) {
|
|
715
|
+
const ctx = use(CommandContext);
|
|
716
|
+
if (!ctx) throw new Error("Command.Page must be used within a <Command> component");
|
|
717
|
+
if (ctx.state.page !== id) return null;
|
|
718
|
+
return /* @__PURE__ */ jsx("div", {
|
|
719
|
+
"data-command-page": "",
|
|
720
|
+
"data-command-page-id": id,
|
|
721
|
+
children
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
//#endregion
|
|
725
|
+
//#region src/react/separator.tsx
|
|
726
|
+
function CommandSeparator({ ref, ...props }) {
|
|
727
|
+
return /* @__PURE__ */ jsx("div", {
|
|
728
|
+
ref,
|
|
729
|
+
"data-command-separator": "",
|
|
730
|
+
role: "separator",
|
|
731
|
+
...props
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region src/react/shortcut.tsx
|
|
736
|
+
function CommandShortcut({ ref, shortcut, children, ...props }) {
|
|
737
|
+
const displayText = useMemo(() => shortcut ? formatShortcut(parseShortcut(shortcut)) : children, [shortcut, children]);
|
|
738
|
+
return /* @__PURE__ */ jsx("kbd", {
|
|
739
|
+
ref,
|
|
740
|
+
"data-command-shortcut": "",
|
|
741
|
+
...props,
|
|
742
|
+
children: displayText
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
//#endregion
|
|
746
|
+
//#region src/react/command.tsx
|
|
747
|
+
function CommandRoot({ children, className, label = "Command palette", ...machineOptions }) {
|
|
748
|
+
const rootId = useId();
|
|
749
|
+
const listId = `${rootId}-list`;
|
|
750
|
+
const inputId = `${rootId}-input`;
|
|
751
|
+
const rootRef = useRef(null);
|
|
752
|
+
const machineRef = useRef(null);
|
|
753
|
+
if (machineRef.current === null) machineRef.current = createCommandMachine(machineOptions);
|
|
754
|
+
const machine = machineRef.current;
|
|
755
|
+
const { state, isPending, updateSearch, setOptimisticActiveId, filteredIdSet, id } = useCommand(machine);
|
|
756
|
+
useEffect(() => {
|
|
757
|
+
return () => {
|
|
758
|
+
machineRef.current?.[Symbol.dispose]();
|
|
759
|
+
machineRef.current = null;
|
|
760
|
+
};
|
|
761
|
+
}, []);
|
|
762
|
+
const handleKeyDown = useCallback(createKeydownHandler(machine, () => machine.getState()), []);
|
|
763
|
+
useEffect(() => {
|
|
764
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
765
|
+
return () => {
|
|
766
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
767
|
+
};
|
|
768
|
+
}, [handleKeyDown]);
|
|
769
|
+
return /* @__PURE__ */ jsx(CommandContext, {
|
|
770
|
+
value: useMemo(() => ({
|
|
771
|
+
machine,
|
|
772
|
+
state,
|
|
773
|
+
isPending,
|
|
774
|
+
updateSearch,
|
|
775
|
+
setOptimisticActiveId,
|
|
776
|
+
filteredIdSet,
|
|
777
|
+
rootId: id,
|
|
778
|
+
listId,
|
|
779
|
+
inputId,
|
|
780
|
+
label
|
|
781
|
+
}), [
|
|
782
|
+
machine,
|
|
783
|
+
state,
|
|
784
|
+
isPending,
|
|
785
|
+
updateSearch,
|
|
786
|
+
setOptimisticActiveId,
|
|
787
|
+
filteredIdSet,
|
|
788
|
+
id,
|
|
789
|
+
listId,
|
|
790
|
+
inputId,
|
|
791
|
+
label
|
|
792
|
+
]),
|
|
793
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
794
|
+
ref: rootRef,
|
|
795
|
+
"data-command-root": "",
|
|
796
|
+
"data-command-state": state.open ? "open" : "closed",
|
|
797
|
+
className,
|
|
798
|
+
role: "search",
|
|
799
|
+
"aria-label": label,
|
|
800
|
+
children
|
|
801
|
+
})
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
/** Compound component namespace */
|
|
805
|
+
const Command = Object.assign(CommandRoot, {
|
|
806
|
+
Input: CommandInput,
|
|
807
|
+
List: CommandList,
|
|
808
|
+
Item: CommandItem,
|
|
809
|
+
Group: CommandGroup,
|
|
810
|
+
Empty: CommandEmpty,
|
|
811
|
+
Loading: CommandLoading,
|
|
812
|
+
Separator: CommandSeparator,
|
|
813
|
+
Dialog: CommandDialog,
|
|
814
|
+
Highlight: CommandHighlight,
|
|
815
|
+
Shortcut: CommandShortcut,
|
|
816
|
+
Badge: CommandBadge,
|
|
817
|
+
Page: CommandPage,
|
|
818
|
+
AsyncItems: CommandAsyncItems,
|
|
819
|
+
Activity: CommandActivity
|
|
820
|
+
});
|
|
821
|
+
//#endregion
|
|
822
|
+
//#region src/react/error-boundary.tsx
|
|
823
|
+
/** Initial state — no error captured */
|
|
824
|
+
const INITIAL_STATE = { error: null };
|
|
825
|
+
var CommandErrorBoundary = class extends Component {
|
|
826
|
+
state = INITIAL_STATE;
|
|
827
|
+
static getDerivedStateFromError(error) {
|
|
828
|
+
return { error };
|
|
829
|
+
}
|
|
830
|
+
componentDidCatch(error, errorInfo) {
|
|
831
|
+
this.props.onError?.(error, errorInfo);
|
|
832
|
+
}
|
|
833
|
+
render() {
|
|
834
|
+
if (this.state.error) {
|
|
835
|
+
const { fallback } = this.props;
|
|
836
|
+
if (typeof fallback === "function") return fallback(this.state.error);
|
|
837
|
+
if (fallback) return fallback;
|
|
838
|
+
return null;
|
|
839
|
+
}
|
|
840
|
+
return this.props.children;
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
//#endregion
|
|
844
|
+
//#region src/react/hooks/use-command-state.ts
|
|
845
|
+
function useCommandState(selector) {
|
|
846
|
+
const ctx = use(CommandContext);
|
|
847
|
+
if (!ctx) throw new Error("useCommandState must be used within a <Command> component");
|
|
848
|
+
const getSnapshot = useCallback(() => selector ? selector(ctx.machine.getState()) : ctx.machine.getState(), [ctx.machine, selector]);
|
|
849
|
+
return useSyncExternalStore(ctx.machine.subscribe, getSnapshot, getSnapshot);
|
|
850
|
+
}
|
|
851
|
+
//#endregion
|
|
852
|
+
//#region src/react/hooks/use-devtools.ts
|
|
853
|
+
/** Branded key for the global devtools instance map */
|
|
854
|
+
const DEVTOOLS_KEY = "__CRIMSON_COMMAND_DEVTOOLS__";
|
|
855
|
+
/**
|
|
856
|
+
* Exposes command palette internals to browser devtools.
|
|
857
|
+
* Only active in development — completely tree-shaken in production builds.
|
|
858
|
+
*
|
|
859
|
+
* @example
|
|
860
|
+
* ```tsx
|
|
861
|
+
* function MyPalette() {
|
|
862
|
+
* useCommandDevtools('main');
|
|
863
|
+
* return <Command>...</Command>;
|
|
864
|
+
* }
|
|
865
|
+
* ```
|
|
866
|
+
*/
|
|
867
|
+
function useCommandDevtools(label = "default") {
|
|
868
|
+
if (!__DEV__) return;
|
|
869
|
+
const ctx = use(CommandContext);
|
|
870
|
+
const stateRef = useRef(null);
|
|
871
|
+
useEffect(() => {
|
|
872
|
+
if (!ctx) return;
|
|
873
|
+
const update = () => {
|
|
874
|
+
const s = ctx.state;
|
|
875
|
+
const devState = {
|
|
876
|
+
registeredItems: s.filteredCount,
|
|
877
|
+
filteredItems: s.filteredIds.length,
|
|
878
|
+
searchQuery: s.search,
|
|
879
|
+
activeId: s.activeId,
|
|
880
|
+
page: s.page,
|
|
881
|
+
pageStack: s.pageStack,
|
|
882
|
+
open: s.open,
|
|
883
|
+
loading: s.loading
|
|
884
|
+
};
|
|
885
|
+
stateRef.current = devState;
|
|
886
|
+
const globals = globalThis;
|
|
887
|
+
if (!globals[DEVTOOLS_KEY]) globals[DEVTOOLS_KEY] = /* @__PURE__ */ new Map();
|
|
888
|
+
globals[DEVTOOLS_KEY].set(label, devState);
|
|
889
|
+
globalThis.dispatchEvent?.(new CustomEvent("crimson-command-devtools", { detail: {
|
|
890
|
+
label,
|
|
891
|
+
state: devState
|
|
892
|
+
} }));
|
|
893
|
+
};
|
|
894
|
+
const unsub = ctx.machine.subscribe(update);
|
|
895
|
+
update();
|
|
896
|
+
return () => {
|
|
897
|
+
unsub();
|
|
898
|
+
globalThis[DEVTOOLS_KEY]?.delete(label);
|
|
899
|
+
};
|
|
900
|
+
}, [ctx, label]);
|
|
901
|
+
}
|
|
902
|
+
//#endregion
|
|
903
|
+
export { Command, CommandActivity, CommandAsyncItems, CommandBadge, CommandDialog, CommandEmpty, CommandErrorBoundary, CommandGroup, CommandHighlight, CommandInput, CommandItem, CommandList, CommandLoading, CommandPage, CommandSeparator, CommandShortcut, createKeydownHandler, useCommand, useCommandDevtools, useCommandState, useRegisterGroup, useRegisterItem, useVirtualizer };
|
|
904
|
+
|
|
905
|
+
//# sourceMappingURL=index.mjs.map
|