modern-cmdk 1.2.1 → 1.2.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.
@@ -4,10 +4,10 @@ import { Component, Suspense, createContext, use, useCallback, useEffect, useId,
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
5
  import { Dialog } from "radix-ui";
6
6
  import { createPortal } from "react-dom";
7
- //#region src/react/activity.tsx
7
+ // src/react/activity.tsx
8
8
  const ActivityComponent = "Activity" in React ? React.Activity : null;
9
9
  /**
10
- * Wraps content in React 19.3.0-canary Activity API.
10
+ * Wraps content in React's <Activity> API (React 19.2+).
11
11
  * When mode="hidden", the component tree is preserved in memory but not rendered.
12
12
  * Falls back to conditional rendering if Activity is unavailable.
13
13
  */
@@ -19,8 +19,7 @@ function CommandActivity({ mode, children }) {
19
19
  if (mode === "hidden") return null;
20
20
  return /* @__PURE__ */ jsx(Fragment, { children });
21
21
  }
22
- //#endregion
23
- //#region src/react/context.ts
22
+ // src/react/context.ts
24
23
  const CommandStableContext = createContext(null);
25
24
  CommandStableContext.displayName = "CommandStableContext";
26
25
  const CommandStateContext = createContext(null);
@@ -42,8 +41,7 @@ CommandGroupContext.displayName = "CommandGroupContext";
42
41
  /** Context for the status container rendered outside the listbox — used by Command.Empty */
43
42
  const CommandListStatusContext = createContext(null);
44
43
  CommandListStatusContext.displayName = "CommandListStatusContext";
45
- //#endregion
46
- //#region src/react/async-items.tsx
44
+ // src/react/async-items.tsx
47
45
  /** Inner component that suspends via use() until items resolve */
48
46
  function AsyncItemsInner({ items: itemsPromise, children }) {
49
47
  const stable = useStableContext("Command.AsyncItems");
@@ -68,8 +66,7 @@ function CommandAsyncItems({ items, fallback, children }) {
68
66
  })
69
67
  });
70
68
  }
71
- //#endregion
72
- //#region src/react/badge.tsx
69
+ // src/react/badge.tsx
73
70
  /** Inline badge for categorization or status indicators on command items. */
74
71
  function CommandBadge({ ref, children, ...props }) {
75
72
  return /* @__PURE__ */ jsx("span", {
@@ -79,8 +76,7 @@ function CommandBadge({ ref, children, ...props }) {
79
76
  children
80
77
  });
81
78
  }
82
- //#endregion
83
- //#region src/core/utils/string-wellformed.ts
79
+ // src/core/utils/string-wellformed.ts
84
80
  /**
85
81
  * Regex matching lone surrogates (unpaired high or low surrogates).
86
82
  * A lone high surrogate (U+D800–U+DBFF) not followed by a low surrogate,
@@ -97,84 +93,7 @@ const REPLACEMENT_CHAR = "�";
97
93
  function ensureWellFormed(str) {
98
94
  return str.replace(LONE_SURROGATE_RE, REPLACEMENT_CHAR);
99
95
  }
100
- //#endregion
101
- //#region src/core/keyboard/parser.ts
102
- const isMac = typeof navigator !== "undefined" && (navigator.userAgentData?.platform === "macOS" || /Mac|iPod|iPhone|iPad/.test(navigator.platform));
103
- /** Modifier aliases — cross-platform Mod resolution */
104
- const MODIFIER_MAP = {
105
- mod: isMac ? "meta" : "ctrl",
106
- meta: "meta",
107
- cmd: "meta",
108
- command: "meta",
109
- ctrl: "ctrl",
110
- control: "ctrl",
111
- shift: "shift",
112
- alt: "alt",
113
- option: "alt",
114
- opt: "alt"
115
- };
116
- /**
117
- * Parse a shortcut string like "Mod+Shift+K" into a structured ParsedShortcut.
118
- * Ensures valid Unicode input via ensureWellFormed helper.
119
- */
120
- function parseShortcut(shortcut) {
121
- const safeShortcut = ensureWellFormed(shortcut);
122
- const parts = safeShortcut.split("+").map((p) => p.trim().toLowerCase());
123
- let meta = false;
124
- let ctrl = false;
125
- let shift = false;
126
- let alt = false;
127
- let key = "";
128
- for (const part of parts) {
129
- const modifier = MODIFIER_MAP[part];
130
- if (modifier) switch (modifier) {
131
- case "meta":
132
- meta = true;
133
- break;
134
- case "ctrl":
135
- ctrl = true;
136
- break;
137
- case "shift":
138
- shift = true;
139
- break;
140
- case "alt":
141
- alt = true;
142
- break;
143
- }
144
- else key = part;
145
- }
146
- const modifiers = [];
147
- if (meta) modifiers.push("meta");
148
- if (ctrl) modifiers.push("ctrl");
149
- if (shift) modifiers.push("shift");
150
- if (alt) modifiers.push("alt");
151
- modifiers.push(key);
152
- return {
153
- key,
154
- meta,
155
- ctrl,
156
- shift,
157
- alt,
158
- raw: safeShortcut,
159
- normalized: modifiers.join("+")
160
- };
161
- }
162
- /**
163
- * Formats a ParsedShortcut for display using platform-appropriate symbols.
164
- * On macOS: renders glyphs (⌘, ⇧, ⌥, ⌃). On other platforms: text labels joined by "+".
165
- */
166
- function formatShortcut(parsed) {
167
- const parts = [];
168
- if (parsed.meta) parts.push(isMac ? "⌘" : "Ctrl");
169
- if (parsed.ctrl && !(!isMac && parsed.meta)) parts.push(isMac ? "⌃" : "Ctrl");
170
- if (parsed.shift) parts.push(isMac ? "⇧" : "Shift");
171
- if (parsed.alt) parts.push(isMac ? "⌥" : "Alt");
172
- const displayKey = parsed.key.length === 1 ? parsed.key.toUpperCase() : parsed.key.charAt(0).toUpperCase() + parsed.key.slice(1);
173
- parts.push(displayKey);
174
- return isMac ? parts.join("") : parts.join("+");
175
- }
176
- //#endregion
177
- //#region src/core/types.ts
96
+ // src/core/types.ts
178
97
  /** Create a branded {@link ItemId} from a plain string. Ensures well-formed Unicode. */
179
98
  function itemId(id) {
180
99
  return ensureWellFormed(id);
@@ -206,8 +125,7 @@ function createInitialState(options) {
206
125
  lastUpdated: Date.now()
207
126
  };
208
127
  }
209
- //#endregion
210
- //#region src/core/frecency/memory-storage.ts
128
+ // src/core/frecency/memory-storage.ts
211
129
  /**
212
130
  * In-memory implementation of FrecencyStorage using a Map.
213
131
  * Data does not persist across page reloads. Suitable for ephemeral
@@ -229,8 +147,7 @@ var MemoryFrecencyStorage = class {
229
147
  this.#store.clear();
230
148
  }
231
149
  };
232
- //#endregion
233
- //#region src/core/frecency/index.ts
150
+ // src/core/frecency/index.ts
234
151
  /** Shared empty bonus map — avoids allocation when no frecency records exist */
235
152
  const EMPTY_BONUS_MAP = /* @__PURE__ */ new Map();
236
153
  /** Pre-computed bucket boundaries in hours — avoids Duration.total() per call */
@@ -332,8 +249,7 @@ var FrecencyEngine = class {
332
249
  this.#storage[Symbol.dispose]();
333
250
  }
334
251
  };
335
- //#endregion
336
- //#region src/core/utils/group-by.ts
252
+ // src/core/utils/group-by.ts
337
253
  /**
338
254
  * Groups items from an iterable into a Map keyed by the result of `keyFn`.
339
255
  * Cross-browser replacement for `Map.groupBy()`.
@@ -348,8 +264,7 @@ function mapGroupBy(items, keyFn) {
348
264
  }
349
265
  return map;
350
266
  }
351
- //#endregion
352
- //#region src/core/keyboard/matcher.ts
267
+ // src/core/keyboard/matcher.ts
353
268
  /**
354
269
  * Tests whether a KeyboardEvent exactly matches a ParsedShortcut,
355
270
  * comparing all four modifier keys (meta, ctrl, shift, alt) and the primary key.
@@ -370,8 +285,80 @@ function detectConflicts(shortcuts) {
370
285
  const grouped = mapGroupBy(shortcuts, (s) => s.normalized);
371
286
  return new Map(grouped.entries().filter(([, group]) => group.length > 1));
372
287
  }
373
- //#endregion
374
- //#region src/core/keyboard/index.ts
288
+ // src/core/keyboard/parser.ts
289
+ const isMac = typeof navigator !== "undefined" && (navigator.userAgentData?.platform === "macOS" || /Mac|iPod|iPhone|iPad/.test(navigator.platform));
290
+ /** Modifier aliases — cross-platform Mod resolution */
291
+ const MODIFIER_MAP = {
292
+ mod: isMac ? "meta" : "ctrl",
293
+ meta: "meta",
294
+ cmd: "meta",
295
+ command: "meta",
296
+ ctrl: "ctrl",
297
+ control: "ctrl",
298
+ shift: "shift",
299
+ alt: "alt",
300
+ option: "alt",
301
+ opt: "alt"
302
+ };
303
+ /**
304
+ * Parse a shortcut string like "Mod+Shift+K" into a structured ParsedShortcut.
305
+ * Ensures valid Unicode input via ensureWellFormed helper.
306
+ */
307
+ function parseShortcut(shortcut) {
308
+ const safeShortcut = ensureWellFormed(shortcut);
309
+ const parts = safeShortcut.split("+").map((p) => p.trim().toLowerCase());
310
+ let meta = false;
311
+ let ctrl = false;
312
+ let shift = false;
313
+ let alt = false;
314
+ let key = "";
315
+ for (const part of parts) {
316
+ const modifier = MODIFIER_MAP[part];
317
+ if (modifier) switch (modifier) {
318
+ case "meta":
319
+ meta = true;
320
+ break;
321
+ case "ctrl":
322
+ ctrl = true;
323
+ break;
324
+ case "shift":
325
+ shift = true;
326
+ break;
327
+ case "alt": alt = true;
328
+ }
329
+ else key = part;
330
+ }
331
+ const modifiers = [];
332
+ if (meta) modifiers.push("meta");
333
+ if (ctrl) modifiers.push("ctrl");
334
+ if (shift) modifiers.push("shift");
335
+ if (alt) modifiers.push("alt");
336
+ modifiers.push(key);
337
+ return {
338
+ key,
339
+ meta,
340
+ ctrl,
341
+ shift,
342
+ alt,
343
+ raw: safeShortcut,
344
+ normalized: modifiers.join("+")
345
+ };
346
+ }
347
+ /**
348
+ * Formats a ParsedShortcut for display using platform-appropriate symbols.
349
+ * On macOS: renders glyphs (⌘, ⇧, ⌥, ⌃). On other platforms: text labels joined by "+".
350
+ */
351
+ function formatShortcut(parsed) {
352
+ const parts = [];
353
+ if (parsed.meta) parts.push(isMac ? "⌘" : "Ctrl");
354
+ if (parsed.ctrl && !(!isMac && parsed.meta)) parts.push(isMac ? "⌃" : "Ctrl");
355
+ if (parsed.shift) parts.push(isMac ? "⇧" : "Shift");
356
+ if (parsed.alt) parts.push(isMac ? "⌥" : "Alt");
357
+ const displayKey = parsed.key.length === 1 ? parsed.key.toUpperCase() : parsed.key.charAt(0).toUpperCase() + parsed.key.slice(1);
358
+ parts.push(displayKey);
359
+ return isMac ? parts.join("") : parts.join("+");
360
+ }
361
+ // src/core/keyboard/index.ts
375
362
  /**
376
363
  * Manages keyboard shortcut bindings with global keydown listening.
377
364
  * Supports `using` for automatic cleanup of both individual bindings and the
@@ -442,8 +429,7 @@ var KeyboardShortcutRegistry = class {
442
429
  this.#bindings.clear();
443
430
  }
444
431
  };
445
- //#endregion
446
- //#region src/core/utils/set-ops.ts
432
+ // src/core/utils/set-ops.ts
447
433
  /** Returns a new Set containing elements present in both `a` and `b`. */
448
434
  function setIntersection(a, b) {
449
435
  const result = /* @__PURE__ */ new Set();
@@ -486,8 +472,7 @@ function setSymmetricDifference(a, b) {
486
472
  else result.add(item);
487
473
  return result;
488
474
  }
489
- //#endregion
490
- //#region src/core/registry.ts
475
+ // src/core/registry.ts
491
476
  /**
492
477
  * Manages registration and lookup of command items and groups.
493
478
  * Uses set operation helpers (union/intersection/difference) for efficient ID operations.
@@ -648,8 +633,23 @@ var CommandRegistry = class {
648
633
  this.clear();
649
634
  }
650
635
  };
651
- //#endregion
652
- //#region src/core/search/default-scorer.ts
636
+ // src/core/utils/env.ts
637
+ /**
638
+ * `true` unless `process.env.NODE_ENV` is `'production'`.
639
+ *
640
+ * Consumer bundlers (Vite, webpack, Next, esbuild) replace `process.env.NODE_ENV` statically,
641
+ * so the dev-only branches guarded by this flag fold away in production builds. A browser
642
+ * running the unbundled module throws a ReferenceError on the bare `process` reference;
643
+ * the catch turns that into the production value (`false`), so dev-only code stays off.
644
+ */
645
+ const isDev = (() => {
646
+ try {
647
+ return process.env.NODE_ENV !== "production";
648
+ } catch {
649
+ return false;
650
+ }
651
+ })();
652
+ // src/core/search/default-scorer.ts
653
653
  function isWordSeparator(code) {
654
654
  return code === 32 || code === 9 || code === 45 || code === 95 || code === 46 || code === 47 || code === 92;
655
655
  }
@@ -771,11 +771,9 @@ function scoreFuzzy(query, qLen, lowerTarget, tLen) {
771
771
  matches
772
772
  };
773
773
  }
774
- //#endregion
775
- //#region src/core/search/index.ts
776
- const __DEV__$1 = globalThis.process ? globalThis.process.env.NODE_ENV !== "production" : false;
774
+ // src/core/search/index.ts
777
775
  let leakRegistry;
778
- if (__DEV__$1) leakRegistry = new FinalizationRegistry((label) => {
776
+ if (isDev && typeof window !== "undefined") leakRegistry = new FinalizationRegistry((label) => {
779
777
  console.warn(`[modern-cmdk] ${label} was garbage collected without being disposed. Use \`using\` or call [Symbol.dispose]() to prevent leaks.`);
780
778
  });
781
779
  /**
@@ -791,7 +789,7 @@ function createSearchEngine(options) {
791
789
  let previousQuery = "";
792
790
  let previousResults = /* @__PURE__ */ new Set();
793
791
  const sentinel = {};
794
- if (__DEV__$1 && leakRegistry) leakRegistry.register(sentinel, "SearchEngine", sentinel);
792
+ if (leakRegistry) leakRegistry.register(sentinel, "SearchEngine", sentinel);
795
793
  return {
796
794
  index(items) {
797
795
  for (const item of items) indexedEntries.set(item.id, {
@@ -841,12 +839,11 @@ function createSearchEngine(options) {
841
839
  [Symbol.dispose]() {
842
840
  indexedEntries.clear();
843
841
  previousResults.clear();
844
- if (__DEV__$1 && leakRegistry) leakRegistry.unregister(sentinel);
842
+ if (leakRegistry) leakRegistry.unregister(sentinel);
845
843
  }
846
844
  };
847
845
  }
848
- //#endregion
849
- //#region src/core/utils/event-emitter.ts
846
+ // src/core/utils/event-emitter.ts
850
847
  /**
851
848
  * Type-safe event emitter with strong references and Disposable subscriptions.
852
849
  * Returns Disposable from `on()` for automatic unsubscription via `using`.
@@ -889,8 +886,7 @@ var TypedEmitter = class {
889
886
  this.#listeners.clear();
890
887
  }
891
888
  };
892
- //#endregion
893
- //#region src/core/utils/scheduler.ts
889
+ // src/core/utils/scheduler.ts
894
890
  /** Whether we're in a browser environment with rAF available */
895
891
  const hasRAF = typeof requestAnimationFrame === "function";
896
892
  /** Feature detection for cutting-edge scheduling APIs */
@@ -951,8 +947,7 @@ function createScheduler() {
951
947
  }
952
948
  };
953
949
  }
954
- //#endregion
955
- //#region src/core/machine.ts
950
+ // src/core/machine.ts
956
951
  /**
957
952
  * Creates a headless command palette state machine with search, frecency,
958
953
  * and keyboard shortcut support. Implements Disposable for `using` cleanup.
@@ -1059,9 +1054,10 @@ function createCommandMachine(options = {}) {
1059
1054
  const loop = options.loop ?? true;
1060
1055
  const currentIdx = activeId ? filteredIdIndex.get(activeId) ?? -1 : -1;
1061
1056
  let newIdx;
1062
- if (direction === "next") if (currentIdx === -1 || currentIdx >= filteredIds.length - 1) newIdx = loop ? 0 : filteredIds.length - 1;
1063
- else newIdx = currentIdx + 1;
1064
- else if (currentIdx <= 0) newIdx = loop ? filteredIds.length - 1 : 0;
1057
+ if (direction === "next") {
1058
+ if (currentIdx === -1 || currentIdx >= filteredIds.length - 1) newIdx = loop ? 0 : filteredIds.length - 1;
1059
+ else newIdx = currentIdx + 1;
1060
+ } else if (currentIdx <= 0) newIdx = loop ? filteredIds.length - 1 : 0;
1065
1061
  else newIdx = currentIdx - 1;
1066
1062
  const newActiveId = filteredIds[newIdx] ?? null;
1067
1063
  if (newActiveId !== activeId) {
@@ -1177,7 +1173,6 @@ function createCommandMachine(options = {}) {
1177
1173
  case "UNREGISTER_GROUP":
1178
1174
  registry.unregisterGroup(event.id);
1179
1175
  refilter(state.search);
1180
- break;
1181
1176
  }
1182
1177
  }
1183
1178
  return {
@@ -1218,8 +1213,7 @@ function createCommandMachine(options = {}) {
1218
1213
  }
1219
1214
  };
1220
1215
  }
1221
- //#endregion
1222
- //#region src/react/hooks/use-command.ts
1216
+ // src/react/hooks/use-command.ts
1223
1217
  /** Core hook that binds a CommandMachine to React via useSyncExternalStore, useTransition, and useOptimistic. */
1224
1218
  function useCommand(machine) {
1225
1219
  const id = useId();
@@ -1252,8 +1246,7 @@ function useCommand(machine) {
1252
1246
  id
1253
1247
  };
1254
1248
  }
1255
- //#endregion
1256
- //#region src/react/hooks/use-keyboard.ts
1249
+ // src/react/hooks/use-keyboard.ts
1257
1250
  /** Navigation key to machine direction mapping */
1258
1251
  const NAVIGATION_KEYS = {
1259
1252
  ArrowDown: "next",
@@ -1294,12 +1287,10 @@ function createKeydownHandler(machine, getState) {
1294
1287
  case "Escape":
1295
1288
  event.preventDefault();
1296
1289
  machine.send({ type: "CLOSE" });
1297
- break;
1298
1290
  }
1299
1291
  };
1300
1292
  }
1301
- //#endregion
1302
- //#region src/react/hooks/use-command-setup.ts
1293
+ // src/react/hooks/use-command-setup.ts
1303
1294
  /**
1304
1295
  * Shared setup for Command and Command.Dialog — creates machine once,
1305
1296
  * subscribes via useSyncExternalStore, memoizes context values, and
@@ -1359,8 +1350,7 @@ function useCommandSetup(machineFactory, label) {
1359
1350
  ])
1360
1351
  };
1361
1352
  }
1362
- //#endregion
1363
- //#region src/react/dialog.tsx
1353
+ // src/react/dialog.tsx
1364
1354
  /** Dialog variant that wraps the command palette in a Radix UI Dialog with focus trap and overlay. */
1365
1355
  function CommandDialog({ children, className, overlayClassName, contentClassName, label = "Command palette", description = "Type a command or search...", open: controlledOpen, onOpenChange, container, ...machineOptions }) {
1366
1356
  const onOpenChangeRef = useRef(onOpenChange);
@@ -1434,8 +1424,7 @@ function CommandDialog({ children, className, overlayClassName, contentClassName
1434
1424
  })
1435
1425
  });
1436
1426
  }
1437
- //#endregion
1438
- //#region src/react/empty.tsx
1427
+ // src/react/empty.tsx
1439
1428
  /** Rendered when no items match the current search query. */
1440
1429
  function CommandEmpty({ ref, children, ...props }) {
1441
1430
  const stateCtx = useStateContext("Command.Empty");
@@ -1452,8 +1441,7 @@ function CommandEmpty({ ref, children, ...props }) {
1452
1441
  if (statusContainerRef?.current) return createPortal(content, statusContainerRef.current);
1453
1442
  return content;
1454
1443
  }
1455
- //#endregion
1456
- //#region src/react/hooks/use-register.ts
1444
+ // src/react/hooks/use-register.ts
1457
1445
  /** Register a command item with the machine — auto-deregisters on unmount */
1458
1446
  function useRegisterItem(value, options) {
1459
1447
  const stable = useStableContext("useRegisterItem");
@@ -1525,8 +1513,7 @@ function useRegisterGroup(heading, options) {
1525
1513
  ]);
1526
1514
  return id;
1527
1515
  }
1528
- //#endregion
1529
- //#region src/react/group.tsx
1516
+ // src/react/group.tsx
1530
1517
  /** Module-level constant — avoids allocating a new object on every render of hidden groups */
1531
1518
  const HIDDEN_STYLE = { display: "none" };
1532
1519
  /** Visual grouping container with an optional heading that hides when no items match. */
@@ -1570,8 +1557,7 @@ function CommandGroup({ ref, children, heading, priority, forceId, ...props }) {
1570
1557
  })
1571
1558
  });
1572
1559
  }
1573
- //#endregion
1574
- //#region src/react/highlight.tsx
1560
+ // src/react/highlight.tsx
1575
1561
  /** Renders search match highlighting by splitting text at scored match ranges. */
1576
1562
  function CommandHighlight({ text, ranges, highlightClassName }) {
1577
1563
  return useMemo(() => {
@@ -1596,8 +1582,7 @@ function CommandHighlight({ text, ranges, highlightClassName }) {
1596
1582
  highlightClassName
1597
1583
  ]);
1598
1584
  }
1599
- //#endregion
1600
- //#region src/react/input.tsx
1585
+ // src/react/input.tsx
1601
1586
  /** Combobox input that drives the command palette search state. */
1602
1587
  function CommandInput({ ref, placeholder = "Search...", onValueChange, ...props }) {
1603
1588
  const stable = useStableContext("Command.Input");
@@ -1627,8 +1612,7 @@ function CommandInput({ ref, placeholder = "Search...", onValueChange, ...props
1627
1612
  ...props
1628
1613
  });
1629
1614
  }
1630
- //#endregion
1631
- //#region src/react/item.tsx
1615
+ // src/react/item.tsx
1632
1616
  /** Individual selectable item in the command list with keyboard and pointer activation. */
1633
1617
  function CommandItem({ ref, children, value, keywords, onSelect, disabled = false, shortcut, forceId, ...props }) {
1634
1618
  const stable = useStableContext("Command.Item");
@@ -1698,8 +1682,7 @@ function CommandItem({ ref, children, value, keywords, onSelect, disabled = fals
1698
1682
  children
1699
1683
  });
1700
1684
  }
1701
- //#endregion
1702
- //#region src/react/hooks/use-virtualizer.ts
1685
+ // src/react/hooks/use-virtualizer.ts
1703
1686
  /** Lightweight virtualizer for large item lists using ResizeObserver and scroll tracking. */
1704
1687
  function useVirtualizer(options) {
1705
1688
  const { count, estimateSize, overscan = 8, scrollElement, enabled = true } = options;
@@ -1803,8 +1786,7 @@ function useVirtualizer(options) {
1803
1786
  }, [enabled])
1804
1787
  };
1805
1788
  }
1806
- //#endregion
1807
- //#region src/react/list.tsx
1789
+ // src/react/list.tsx
1808
1790
  /** Scrollable list container with auto-virtualization and aria-live announcements. */
1809
1791
  function CommandList({ ref, children, virtualize, estimateSize = 44, overscan = 8, announceResults, style, ...props }) {
1810
1792
  const stable = useStableContext("Command.List");
@@ -1944,8 +1926,7 @@ function CommandList({ ref, children, virtualize, estimateSize = 44, overscan =
1944
1926
  ]
1945
1927
  });
1946
1928
  }
1947
- //#endregion
1948
- //#region src/react/loading.tsx
1929
+ // src/react/loading.tsx
1949
1930
  /** Shown during async operations, with configurable loading state override. */
1950
1931
  function CommandLoading({ ref, children, loading: loadingOverride, ...props }) {
1951
1932
  const stateCtx = useStateContext("Command.Loading");
@@ -1960,8 +1941,7 @@ function CommandLoading({ ref, children, loading: loadingOverride, ...props }) {
1960
1941
  children
1961
1942
  });
1962
1943
  }
1963
- //#endregion
1964
- //#region src/react/page.tsx
1944
+ // src/react/page.tsx
1965
1945
  /** Page navigation container that only renders when its ID matches the active page. */
1966
1946
  function CommandPage({ id, children }) {
1967
1947
  if (useStateContext("Command.Page").state.page !== id) return null;
@@ -1971,8 +1951,7 @@ function CommandPage({ id, children }) {
1971
1951
  children
1972
1952
  });
1973
1953
  }
1974
- //#endregion
1975
- //#region src/react/separator.tsx
1954
+ // src/react/separator.tsx
1976
1955
  /** Visual divider between items or groups, rendered as a presentational element. */
1977
1956
  function CommandSeparator({ ref, ...props }) {
1978
1957
  return /* @__PURE__ */ jsx("div", {
@@ -1982,8 +1961,7 @@ function CommandSeparator({ ref, ...props }) {
1982
1961
  ...props
1983
1962
  });
1984
1963
  }
1985
- //#endregion
1986
- //#region src/react/shortcut.tsx
1964
+ // src/react/shortcut.tsx
1987
1965
  /** Keyboard shortcut display with platform-aware formatting (e.g., Cmd vs Ctrl). */
1988
1966
  function CommandShortcut({ ref, shortcut, children, ...props }) {
1989
1967
  const formattedShortcut = useMemo(() => shortcut ? formatShortcut(parseShortcut(shortcut)) : null, [shortcut]);
@@ -1994,8 +1972,7 @@ function CommandShortcut({ ref, shortcut, children, ...props }) {
1994
1972
  children: formattedShortcut ?? children
1995
1973
  });
1996
1974
  }
1997
- //#endregion
1998
- //#region src/react/command.tsx
1975
+ // src/react/command.tsx
1999
1976
  /** Root compound component that provides the command state machine context to all children. */
2000
1977
  function CommandRoot({ children, className, label = "Command palette", ...machineOptions }) {
2001
1978
  const rootRef = useRef(null);
@@ -2044,8 +2021,7 @@ const Command = Object.assign(CommandRoot, {
2044
2021
  AsyncItems: CommandAsyncItems,
2045
2022
  Activity: CommandActivity
2046
2023
  });
2047
- //#endregion
2048
- //#region src/react/error-boundary.tsx
2024
+ // src/react/error-boundary.tsx
2049
2025
  /** Initial state — no error captured */
2050
2026
  const INITIAL_STATE = { error: null };
2051
2027
  /** Error boundary for graceful failure recovery in command subtrees. */
@@ -2067,8 +2043,7 @@ var CommandErrorBoundary = class extends Component {
2067
2043
  return this.props.children;
2068
2044
  }
2069
2045
  };
2070
- //#endregion
2071
- //#region src/react/hooks/use-command-state.ts
2046
+ // src/react/hooks/use-command-state.ts
2072
2047
  function useCommandState(selector) {
2073
2048
  const stable = useStableContext("useCommandState");
2074
2049
  const selectorRef = useRef(selector);
@@ -2076,19 +2051,20 @@ function useCommandState(selector) {
2076
2051
  const getSnapshot = useCallback(() => selectorRef.current ? selectorRef.current(stable.machine.getState()) : stable.machine.getState(), [stable.machine]);
2077
2052
  return useSyncExternalStore(stable.machine.subscribe, getSnapshot, getSnapshot);
2078
2053
  }
2079
- //#endregion
2080
- //#region src/react/hooks/use-devtools.ts
2054
+ // src/react/hooks/use-devtools.ts
2081
2055
  /** Branded key for the global devtools instance map */
2082
2056
  const DEVTOOLS_KEY = "__CRIMSON_COMMAND_DEVTOOLS__";
2083
2057
  /**
2084
2058
  * Exposes command palette internals to browser devtools.
2085
- * Only active in development — completely tree-shaken in production builds.
2059
+ * Development only: the effect is gated on `process.env.NODE_ENV` and returns early in
2060
+ * production builds (the hook itself still ships). Call it from a component rendered inside
2061
+ * `<Command>`: outside one there is no machine to inspect and the hook does nothing.
2086
2062
  *
2087
2063
  * @example
2088
2064
  * ```tsx
2089
- * function MyPalette() {
2065
+ * function DevtoolsBridge() {
2090
2066
  * useCommandDevtools('main');
2091
- * return <Command>...</Command>;
2067
+ * return null;
2092
2068
  * }
2093
2069
  * ```
2094
2070
  */
@@ -2097,7 +2073,7 @@ function useCommandDevtools(label = "default") {
2097
2073
  const stateCtx = use(CommandStateContext);
2098
2074
  const stateRef = useRef(null);
2099
2075
  useEffect(() => {
2100
- if (!__DEV__) return;
2076
+ if (!isDev) return;
2101
2077
  if (!stable || !stateCtx) return;
2102
2078
  const update = () => {
2103
2079
  const s = stateCtx.state;
@@ -2132,5 +2108,4 @@ function useCommandDevtools(label = "default") {
2132
2108
  label
2133
2109
  ]);
2134
2110
  }
2135
- //#endregion
2136
2111
  export { Command, CommandActivity, CommandAsyncItems, CommandBadge, CommandDialog, CommandEmpty, CommandErrorBoundary, CommandGroup, CommandHighlight, CommandInput, CommandItem, CommandList, CommandLoading, CommandPage, CommandSeparator, CommandShortcut, CommandStableContext, CommandStateContext, createKeydownHandler, useCommand, useCommandDevtools, useCommandState, useRegisterGroup, useRegisterItem, useVirtualizer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modern-cmdk",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "type": "module",
5
5
  "description": "The definitive command palette engine for the modern web",
6
6
  "license": "MIT",
@@ -57,13 +57,13 @@
57
57
  }
58
58
  },
59
59
  "dependencies": {
60
- "idb-keyval": "6.2.5"
60
+ "idb-keyval": "6.3.0"
61
61
  },
62
62
  "devDependencies": {
63
- "globby": "16.2.0",
64
- "jscodeshift": "17.3.0",
65
- "radix-ui": "1.6.0",
66
- "@types/jscodeshift": "^17.3.0"
63
+ "globby": "16.2.4",
64
+ "jscodeshift": "17.4.0",
65
+ "radix-ui": "1.8.2-rc.1791984254107",
66
+ "@types/jscodeshift": "17.3.0"
67
67
  },
68
68
  "keywords": [
69
69
  "command-palette",
@@ -80,8 +80,8 @@
80
80
  "directory": "packages/modern-cmdk"
81
81
  },
82
82
  "scripts": {
83
- "build": "tsdown --config tsdown.config.ts && node -e \"const fs=require('fs');fs.cpSync('src/react/styles.css','dist/react/styles.css')\"",
84
- "dev": "tsdown src/core/index.ts src/react/index.ts --format esm --dts --watch",
83
+ "build": "tsdown",
84
+ "dev": "tsdown --watch",
85
85
  "typecheck": "tsc --noEmit"
86
86
  }
87
87
  }