modern-cmdk 1.2.1 → 1.2.2

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.
@@ -1,6 +1,5 @@
1
1
 
2
2
  import { Component, ComponentPropsWithRef, Context, ErrorInfo, ReactNode } from "react";
3
-
4
3
  //#region src/react/activity.d.ts
5
4
  /** Activity mode — maps directly to React's Activity API */
6
5
  type ActivityMode = "visible" | "hidden";
@@ -11,14 +10,11 @@ interface CommandActivityProps {
11
10
  readonly children: ReactNode;
12
11
  }
13
12
  /**
14
- * Wraps content in React 19.3.0-canary Activity API.
15
- * When mode="hidden", the component tree is preserved in memory but not rendered.
16
- * Falls back to conditional rendering if Activity is unavailable.
17
- */
18
- declare function CommandActivity({
19
- mode,
20
- children
21
- }: CommandActivityProps): ReactNode;
13
+ * Wraps content in React 19.3.0-canary Activity API.
14
+ * When mode="hidden", the component tree is preserved in memory but not rendered.
15
+ * Falls back to conditional rendering if Activity is unavailable.
16
+ */
17
+ export declare function CommandActivity({ mode, children }: CommandActivityProps): ReactNode;
22
18
  //#endregion
23
19
  //#region src/core/search/types.d.ts
24
20
  /** Result of scoring a single item against a query */
@@ -44,31 +40,31 @@ interface SearchEngine extends Disposable {
44
40
  //#endregion
45
41
  //#region src/core/types.d.ts
46
42
  /**
47
- * Branded type for command item IDs.
48
- * Prevents accidental mixing with plain strings at the type level.
49
- *
50
- * @example
51
- * ```ts
52
- * const id = itemId('copy');
53
- * // id has type ItemId, not string — catches type errors at compile time
54
- * ```
55
- */
43
+ * Branded type for command item IDs.
44
+ * Prevents accidental mixing with plain strings at the type level.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const id = itemId('copy');
49
+ * // id has type ItemId, not string — catches type errors at compile time
50
+ * ```
51
+ */
56
52
  declare const __itemIdBrand: unique symbol;
57
53
  type ItemId = string & {
58
54
  readonly [__itemIdBrand]: never;
59
55
  };
60
56
  /**
61
- * Branded type for group IDs.
62
- * Prevents accidental mixing with plain strings or ItemId at the type level.
63
- */
57
+ * Branded type for group IDs.
58
+ * Prevents accidental mixing with plain strings or ItemId at the type level.
59
+ */
64
60
  declare const __groupIdBrand: unique symbol;
65
61
  type GroupId = string & {
66
62
  readonly [__groupIdBrand]: never;
67
63
  };
68
64
  /**
69
- * A registered command item in the palette.
70
- * All fields are readonly — state machine creates new items on update.
71
- */
65
+ * A registered command item in the palette.
66
+ * All fields are readonly — state machine creates new items on update.
67
+ */
72
68
  interface CommandItem$1 {
73
69
  /** Unique identifier (branded type) */
74
70
  readonly id: ItemId;
@@ -88,9 +84,9 @@ interface CommandItem$1 {
88
84
  readonly data?: Readonly<Record<string, unknown>> | undefined;
89
85
  }
90
86
  /**
91
- * A command group for categorizing items.
92
- * Groups are rendered with headings and sorted by priority.
93
- */
87
+ * A command group for categorizing items.
88
+ * Groups are rendered with headings and sorted by priority.
89
+ */
94
90
  interface CommandGroup$1 {
95
91
  /** Unique identifier (branded type) */
96
92
  readonly id: GroupId;
@@ -100,10 +96,10 @@ interface CommandGroup$1 {
100
96
  readonly priority?: number | undefined;
101
97
  }
102
98
  /**
103
- * Immutable state snapshot of the command palette.
104
- * Consumed by React via `useSyncExternalStore` — each mutation
105
- * produces a new object reference for efficient re-render detection.
106
- */
99
+ * Immutable state snapshot of the command palette.
100
+ * Consumed by React via `useSyncExternalStore` — each mutation
101
+ * produces a new object reference for efficient re-render detection.
102
+ */
107
103
  interface CommandState {
108
104
  /** Current search query string */
109
105
  readonly search: string;
@@ -228,9 +224,9 @@ interface CommandMachineOptions {
228
224
  //#endregion
229
225
  //#region src/core/keyboard/parser.d.ts
230
226
  /**
231
- * Structured representation of a keyboard shortcut after parsing.
232
- * The `normalized` field provides a deterministic string for dedup and comparison.
233
- */
227
+ * Structured representation of a keyboard shortcut after parsing.
228
+ * The `normalized` field provides a deterministic string for dedup and comparison.
229
+ */
234
230
  interface ParsedShortcut {
235
231
  readonly key: string;
236
232
  readonly meta: boolean;
@@ -248,10 +244,10 @@ interface ShortcutBinding {
248
244
  readonly handler: () => void;
249
245
  }
250
246
  /**
251
- * Manages keyboard shortcut bindings with global keydown listening.
252
- * Supports `using` for automatic cleanup of both individual bindings and the
253
- * global document listener. Detects conflicts via Map.groupBy (ES2026).
254
- */
247
+ * Manages keyboard shortcut bindings with global keydown listening.
248
+ * Supports `using` for automatic cleanup of both individual bindings and the
249
+ * global document listener. Detects conflicts via Map.groupBy (ES2026).
250
+ */
255
251
  declare class KeyboardShortcutRegistry implements Disposable {
256
252
  #private;
257
253
  constructor(options?: {
@@ -274,10 +270,10 @@ declare class KeyboardShortcutRegistry implements Disposable {
274
270
  //#endregion
275
271
  //#region src/core/registry.d.ts
276
272
  /**
277
- * Manages registration and lookup of command items and groups.
278
- * Uses set operation helpers (union/intersection/difference) for efficient ID operations.
279
- * All registration methods return Disposable for automatic cleanup via `using`.
280
- */
273
+ * Manages registration and lookup of command items and groups.
274
+ * Uses set operation helpers (union/intersection/difference) for efficient ID operations.
275
+ * All registration methods return Disposable for automatic cleanup via `using`.
276
+ */
281
277
  declare class CommandRegistry implements Disposable {
282
278
  #private;
283
279
  /** Register an item — returns Disposable for `using` auto-deregister */
@@ -355,20 +351,12 @@ interface CommandAsyncItemsProps {
355
351
  readonly children: (items: readonly CommandItem$1[]) => ReactNode;
356
352
  }
357
353
  /** Suspense-based async item loader that resolves a promise of items using React 19 `use()`. */
358
- declare function CommandAsyncItems({
359
- items,
360
- fallback,
361
- children
362
- }: CommandAsyncItemsProps): ReactNode;
354
+ export declare function CommandAsyncItems({ items, fallback, children }: CommandAsyncItemsProps): ReactNode;
363
355
  //#endregion
364
356
  //#region src/react/badge.d.ts
365
357
  interface CommandBadgeProps extends ComponentPropsWithRef<"span"> {}
366
358
  /** Inline badge for categorization or status indicators on command items. */
367
- declare function CommandBadge({
368
- ref,
369
- children,
370
- ...props
371
- }: CommandBadgeProps): ReactNode;
359
+ export declare function CommandBadge({ ref, children, ...props }: CommandBadgeProps): ReactNode;
372
360
  //#endregion
373
361
  //#region src/react/dialog.d.ts
374
362
  interface CommandDialogProps extends CommandMachineOptions {
@@ -385,27 +373,12 @@ interface CommandDialogProps extends CommandMachineOptions {
385
373
  readonly container?: HTMLElement | null;
386
374
  }
387
375
  /** Dialog variant that wraps the command palette in a Radix UI Dialog with focus trap and overlay. */
388
- declare function CommandDialog({
389
- children,
390
- className,
391
- overlayClassName,
392
- contentClassName,
393
- label,
394
- description,
395
- open: controlledOpen,
396
- onOpenChange,
397
- container,
398
- ...machineOptions
399
- }: CommandDialogProps): ReactNode;
376
+ export declare function CommandDialog({ children, className, overlayClassName, contentClassName, label, description, open: controlledOpen, onOpenChange, container, ...machineOptions }: CommandDialogProps): ReactNode;
400
377
  //#endregion
401
378
  //#region src/react/empty.d.ts
402
379
  interface CommandEmptyProps extends ComponentPropsWithRef<"div"> {}
403
380
  /** Rendered when no items match the current search query. */
404
- declare function CommandEmpty({
405
- ref,
406
- children,
407
- ...props
408
- }: CommandEmptyProps): ReactNode;
381
+ export declare function CommandEmpty({ ref, children, ...props }: CommandEmptyProps): ReactNode;
409
382
  //#endregion
410
383
  //#region src/react/group.d.ts
411
384
  interface CommandGroupProps extends ComponentPropsWithRef<"div"> {
@@ -417,14 +390,7 @@ interface CommandGroupProps extends ComponentPropsWithRef<"div"> {
417
390
  readonly forceId?: string;
418
391
  }
419
392
  /** Visual grouping container with an optional heading that hides when no items match. */
420
- declare function CommandGroup({
421
- ref,
422
- children,
423
- heading,
424
- priority,
425
- forceId,
426
- ...props
427
- }: CommandGroupProps): ReactNode;
393
+ export declare function CommandGroup({ ref, children, heading, priority, forceId, ...props }: CommandGroupProps): ReactNode;
428
394
  //#endregion
429
395
  //#region src/react/highlight.d.ts
430
396
  interface CommandHighlightProps {
@@ -436,23 +402,14 @@ interface CommandHighlightProps {
436
402
  readonly highlightClassName?: string;
437
403
  }
438
404
  /** Renders search match highlighting by splitting text at scored match ranges. */
439
- declare function CommandHighlight({
440
- text,
441
- ranges,
442
- highlightClassName
443
- }: CommandHighlightProps): ReactNode;
405
+ export declare function CommandHighlight({ text, ranges, highlightClassName }: CommandHighlightProps): ReactNode;
444
406
  //#endregion
445
407
  //#region src/react/input.d.ts
446
408
  interface CommandInputProps extends Omit<ComponentPropsWithRef<"input">, "value" | "onChange" | "type" | "role"> {
447
409
  readonly onValueChange?: (value: string) => void;
448
410
  }
449
411
  /** Combobox input that drives the command palette search state. */
450
- declare function CommandInput({
451
- ref,
452
- placeholder,
453
- onValueChange,
454
- ...props
455
- }: CommandInputProps): ReactNode;
412
+ export declare function CommandInput({ ref, placeholder, onValueChange, ...props }: CommandInputProps): ReactNode;
456
413
  //#endregion
457
414
  //#region src/react/item.d.ts
458
415
  interface CommandItemProps extends Omit<ComponentPropsWithRef<"div">, "onSelect" | "value"> {
@@ -464,17 +421,7 @@ interface CommandItemProps extends Omit<ComponentPropsWithRef<"div">, "onSelect"
464
421
  readonly forceId?: string;
465
422
  }
466
423
  /** Individual selectable item in the command list with keyboard and pointer activation. */
467
- declare function CommandItem({
468
- ref,
469
- children,
470
- value,
471
- keywords,
472
- onSelect,
473
- disabled,
474
- shortcut,
475
- forceId,
476
- ...props
477
- }: CommandItemProps): ReactNode;
424
+ export declare function CommandItem({ ref, children, value, keywords, onSelect, disabled, shortcut, forceId, ...props }: CommandItemProps): ReactNode;
478
425
  //#endregion
479
426
  //#region src/react/list.d.ts
480
427
  interface CommandListProps extends ComponentPropsWithRef<"div"> {
@@ -488,16 +435,7 @@ interface CommandListProps extends ComponentPropsWithRef<"div"> {
488
435
  readonly announceResults?: (count: number) => string;
489
436
  }
490
437
  /** Scrollable list container with auto-virtualization and aria-live announcements. */
491
- declare function CommandList({
492
- ref,
493
- children,
494
- virtualize,
495
- estimateSize,
496
- overscan,
497
- announceResults,
498
- style,
499
- ...props
500
- }: CommandListProps): ReactNode;
438
+ export declare function CommandList({ ref, children, virtualize, estimateSize, overscan, announceResults, style, ...props }: CommandListProps): ReactNode;
501
439
  //#endregion
502
440
  //#region src/react/loading.d.ts
503
441
  interface CommandLoadingProps extends ComponentPropsWithRef<"div"> {
@@ -505,12 +443,7 @@ interface CommandLoadingProps extends ComponentPropsWithRef<"div"> {
505
443
  readonly loading?: boolean;
506
444
  }
507
445
  /** Shown during async operations, with configurable loading state override. */
508
- declare function CommandLoading({
509
- ref,
510
- children,
511
- loading: loadingOverride,
512
- ...props
513
- }: CommandLoadingProps): ReactNode;
446
+ export declare function CommandLoading({ ref, children, loading: loadingOverride, ...props }: CommandLoadingProps): ReactNode;
514
447
  //#endregion
515
448
  //#region src/react/page.d.ts
516
449
  /** Branded page identifier */
@@ -523,18 +456,12 @@ interface CommandPageProps {
523
456
  readonly children?: ReactNode;
524
457
  }
525
458
  /** Page navigation container that only renders when its ID matches the active page. */
526
- declare function CommandPage({
527
- id,
528
- children
529
- }: CommandPageProps): ReactNode;
459
+ export declare function CommandPage({ id, children }: CommandPageProps): ReactNode;
530
460
  //#endregion
531
461
  //#region src/react/separator.d.ts
532
462
  interface CommandSeparatorProps extends ComponentPropsWithRef<"div"> {}
533
463
  /** Visual divider between items or groups, rendered as a presentational element. */
534
- declare function CommandSeparator({
535
- ref,
536
- ...props
537
- }: CommandSeparatorProps): ReactNode;
464
+ export declare function CommandSeparator({ ref, ...props }: CommandSeparatorProps): ReactNode;
538
465
  //#endregion
539
466
  //#region src/react/shortcut.d.ts
540
467
  interface CommandShortcutProps extends ComponentPropsWithRef<"kbd"> {
@@ -542,12 +469,7 @@ interface CommandShortcutProps extends ComponentPropsWithRef<"kbd"> {
542
469
  readonly shortcut?: string;
543
470
  }
544
471
  /** Keyboard shortcut display with platform-aware formatting (e.g., Cmd vs Ctrl). */
545
- declare function CommandShortcut({
546
- ref,
547
- shortcut,
548
- children,
549
- ...props
550
- }: CommandShortcutProps): ReactNode;
472
+ export declare function CommandShortcut({ ref, shortcut, children, ...props }: CommandShortcutProps): ReactNode;
551
473
  //#endregion
552
474
  //#region src/react/command.d.ts
553
475
  interface CommandRootProps extends CommandMachineOptions {
@@ -556,14 +478,9 @@ interface CommandRootProps extends CommandMachineOptions {
556
478
  readonly label?: string;
557
479
  }
558
480
  /** Root compound component that provides the command state machine context to all children. */
559
- declare function CommandRoot({
560
- children,
561
- className,
562
- label,
563
- ...machineOptions
564
- }: CommandRootProps): ReactNode;
481
+ declare function CommandRoot({ children, className, label, ...machineOptions }: CommandRootProps): ReactNode;
565
482
  /** Compound component namespace */
566
- declare const Command: typeof CommandRoot & {
483
+ export declare const Command: typeof CommandRoot & {
567
484
  readonly Input: typeof CommandInput;
568
485
  readonly List: typeof CommandList;
569
486
  readonly Item: typeof CommandItem;
@@ -623,8 +540,8 @@ interface CommandStateContextValue {
623
540
  /** Map of visible item IDs to their translateY pixel offsets. null = not virtualizing. */
624
541
  readonly virtualPositionMap: ReadonlyMap<ItemId, number> | null;
625
542
  }
626
- declare const CommandStableContext: Context<CommandStableContextValue | null>;
627
- declare const CommandStateContext: Context<CommandStateContextValue | null>;
543
+ export declare const CommandStableContext: Context<CommandStableContextValue | null>;
544
+ export declare const CommandStateContext: Context<CommandStateContextValue | null>;
628
545
  interface CommandGroupContextValue {
629
546
  readonly groupId: string;
630
547
  readonly headingId: string;
@@ -640,7 +557,7 @@ interface CommandErrorBoundaryState {
640
557
  readonly error: Error | null;
641
558
  }
642
559
  /** Error boundary for graceful failure recovery in command subtrees. */
643
- declare class CommandErrorBoundary extends Component<CommandErrorBoundaryProps, CommandErrorBoundaryState> {
560
+ export declare class CommandErrorBoundary extends Component<CommandErrorBoundaryProps, CommandErrorBoundaryState> {
644
561
  override state: CommandErrorBoundaryState;
645
562
  static getDerivedStateFromError(error: Error): CommandErrorBoundaryState;
646
563
  override componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
@@ -658,32 +575,32 @@ interface UseCommandReturn {
658
575
  readonly id: CommandRootId;
659
576
  }
660
577
  /** Core hook that binds a CommandMachine to React via useSyncExternalStore, useTransition, and useOptimistic. */
661
- declare function useCommand(machine: CommandMachine): UseCommandReturn;
578
+ export declare function useCommand(machine: CommandMachine): UseCommandReturn;
662
579
  //#endregion
663
580
  //#region src/react/hooks/use-command-state.d.ts
664
581
  /** Get the full command state with proper subscription */
665
- declare function useCommandState(): CommandState;
582
+ export declare function useCommandState(): CommandState;
666
583
  /** Get a selected slice of command state — only re-renders when selected value changes */
667
- declare function useCommandState<T>(selector: (state: CommandState) => T): T;
584
+ export declare function useCommandState<T>(selector: (state: CommandState) => T): T;
668
585
  //#endregion
669
586
  //#region src/react/hooks/use-devtools.d.ts
670
587
  /**
671
- * Exposes command palette internals to browser devtools.
672
- * Only active in development — completely tree-shaken in production builds.
673
- *
674
- * @example
675
- * ```tsx
676
- * function MyPalette() {
677
- * useCommandDevtools('main');
678
- * return <Command>...</Command>;
679
- * }
680
- * ```
681
- */
682
- declare function useCommandDevtools(label?: string): void;
588
+ * Exposes command palette internals to browser devtools.
589
+ * Only active in development — completely tree-shaken in production builds.
590
+ *
591
+ * @example
592
+ * ```tsx
593
+ * function MyPalette() {
594
+ * useCommandDevtools('main');
595
+ * return <Command>...</Command>;
596
+ * }
597
+ * ```
598
+ */
599
+ export declare function useCommandDevtools(label?: string): void;
683
600
  //#endregion
684
601
  //#region src/react/hooks/use-keyboard.d.ts
685
602
  /** Create a keydown handler for command palette keyboard navigation */
686
- declare function createKeydownHandler(machine: CommandMachine, getState: () => CommandState): (event: KeyboardEvent) => void;
603
+ export declare function createKeydownHandler(machine: CommandMachine, getState: () => CommandState): (event: KeyboardEvent) => void;
687
604
  //#endregion
688
605
  //#region src/react/hooks/use-register.d.ts
689
606
  /** Options for item registration */
@@ -697,14 +614,14 @@ interface RegisterItemOptions {
697
614
  readonly forceId?: string;
698
615
  }
699
616
  /** Register a command item with the machine — auto-deregisters on unmount */
700
- declare function useRegisterItem(value: string, options?: RegisterItemOptions): ItemId;
617
+ export declare function useRegisterItem(value: string, options?: RegisterItemOptions): ItemId;
701
618
  /** Options for group registration */
702
619
  interface RegisterGroupOptions {
703
620
  readonly priority?: number;
704
621
  readonly forceId?: string;
705
622
  }
706
623
  /** Register a command group with the machine — auto-deregisters on unmount */
707
- declare function useRegisterGroup(heading?: string, options?: RegisterGroupOptions): GroupId;
624
+ export declare function useRegisterGroup(heading?: string, options?: RegisterGroupOptions): GroupId;
708
625
  //#endregion
709
626
  //#region src/react/hooks/use-virtualizer.d.ts
710
627
  interface VirtualizerOptions {
@@ -727,6 +644,6 @@ interface VirtualizerReturn {
727
644
  readonly measureElement: (element: HTMLElement | null) => void;
728
645
  }
729
646
  /** Lightweight virtualizer for large item lists using ResizeObserver and scroll tracking. */
730
- declare function useVirtualizer(options: VirtualizerOptions): VirtualizerReturn;
647
+ export declare function useVirtualizer(options: VirtualizerOptions): VirtualizerReturn;
731
648
  //#endregion
732
- export { type ActivityMode, Command, CommandActivity, type CommandActivityProps, CommandAsyncItems, type CommandAsyncItemsProps, CommandBadge, type CommandBadgeProps, type CommandContextValue, CommandDialog, type CommandDialogProps, CommandEmpty, type CommandEmptyProps, CommandErrorBoundary, type CommandErrorBoundaryProps, CommandGroup, type CommandGroupContextValue, type CommandGroupProps, CommandHighlight, type CommandHighlightProps, CommandInput, type CommandInputProps, CommandItem, type CommandItemProps, CommandList, type CommandListProps, CommandLoading, type CommandLoadingProps, CommandPage, type CommandPageId, type CommandPageProps, type CommandRootId, type CommandRootProps, CommandSeparator, type CommandSeparatorProps, CommandShortcut, type CommandShortcutProps, CommandStableContext, type CommandStableContextValue, CommandStateContext, type CommandStateContextValue, type RegisterGroupOptions, type RegisterItemOptions, type UseCommandReturn, type VirtualItem, type VirtualizerOptions, type VirtualizerReturn, createKeydownHandler, useCommand, useCommandDevtools, useCommandState, useRegisterGroup, useRegisterItem, useVirtualizer };
649
+ export type { ActivityMode, CommandActivityProps, CommandAsyncItemsProps, CommandBadgeProps, CommandContextValue, CommandDialogProps, CommandEmptyProps, CommandErrorBoundaryProps, CommandGroupContextValue, CommandGroupProps, CommandHighlightProps, CommandInputProps, CommandItemProps, CommandListProps, CommandLoadingProps, CommandPageId, CommandPageProps, CommandRootId, CommandRootProps, CommandSeparatorProps, CommandShortcutProps, CommandStableContextValue, CommandStateContextValue, RegisterGroupOptions, RegisterItemOptions, UseCommandReturn, VirtualItem, VirtualizerOptions, VirtualizerReturn };
@@ -98,82 +98,6 @@ function ensureWellFormed(str) {
98
98
  return str.replace(LONE_SURROGATE_RE, REPLACEMENT_CHAR);
99
99
  }
100
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
101
  //#region src/core/types.ts
178
102
  /** Create a branded {@link ItemId} from a plain string. Ensures well-formed Unicode. */
179
103
  function itemId(id) {
@@ -371,6 +295,80 @@ function detectConflicts(shortcuts) {
371
295
  return new Map(grouped.entries().filter(([, group]) => group.length > 1));
372
296
  }
373
297
  //#endregion
298
+ //#region src/core/keyboard/parser.ts
299
+ const isMac = typeof navigator !== "undefined" && (navigator.userAgentData?.platform === "macOS" || /Mac|iPod|iPhone|iPad/.test(navigator.platform));
300
+ /** Modifier aliases — cross-platform Mod resolution */
301
+ const MODIFIER_MAP = {
302
+ mod: isMac ? "meta" : "ctrl",
303
+ meta: "meta",
304
+ cmd: "meta",
305
+ command: "meta",
306
+ ctrl: "ctrl",
307
+ control: "ctrl",
308
+ shift: "shift",
309
+ alt: "alt",
310
+ option: "alt",
311
+ opt: "alt"
312
+ };
313
+ /**
314
+ * Parse a shortcut string like "Mod+Shift+K" into a structured ParsedShortcut.
315
+ * Ensures valid Unicode input via ensureWellFormed helper.
316
+ */
317
+ function parseShortcut(shortcut) {
318
+ const safeShortcut = ensureWellFormed(shortcut);
319
+ const parts = safeShortcut.split("+").map((p) => p.trim().toLowerCase());
320
+ let meta = false;
321
+ let ctrl = false;
322
+ let shift = false;
323
+ let alt = false;
324
+ let key = "";
325
+ for (const part of parts) {
326
+ const modifier = MODIFIER_MAP[part];
327
+ if (modifier) switch (modifier) {
328
+ case "meta":
329
+ meta = true;
330
+ break;
331
+ case "ctrl":
332
+ ctrl = true;
333
+ break;
334
+ case "shift":
335
+ shift = true;
336
+ break;
337
+ case "alt": alt = true;
338
+ }
339
+ else key = part;
340
+ }
341
+ const modifiers = [];
342
+ if (meta) modifiers.push("meta");
343
+ if (ctrl) modifiers.push("ctrl");
344
+ if (shift) modifiers.push("shift");
345
+ if (alt) modifiers.push("alt");
346
+ modifiers.push(key);
347
+ return {
348
+ key,
349
+ meta,
350
+ ctrl,
351
+ shift,
352
+ alt,
353
+ raw: safeShortcut,
354
+ normalized: modifiers.join("+")
355
+ };
356
+ }
357
+ /**
358
+ * Formats a ParsedShortcut for display using platform-appropriate symbols.
359
+ * On macOS: renders glyphs (⌘, ⇧, ⌥, ⌃). On other platforms: text labels joined by "+".
360
+ */
361
+ function formatShortcut(parsed) {
362
+ const parts = [];
363
+ if (parsed.meta) parts.push(isMac ? "⌘" : "Ctrl");
364
+ if (parsed.ctrl && !(!isMac && parsed.meta)) parts.push(isMac ? "⌃" : "Ctrl");
365
+ if (parsed.shift) parts.push(isMac ? "⇧" : "Shift");
366
+ if (parsed.alt) parts.push(isMac ? "⌥" : "Alt");
367
+ const displayKey = parsed.key.length === 1 ? parsed.key.toUpperCase() : parsed.key.charAt(0).toUpperCase() + parsed.key.slice(1);
368
+ parts.push(displayKey);
369
+ return isMac ? parts.join("") : parts.join("+");
370
+ }
371
+ //#endregion
374
372
  //#region src/core/keyboard/index.ts
375
373
  /**
376
374
  * Manages keyboard shortcut bindings with global keydown listening.
@@ -1059,9 +1057,10 @@ function createCommandMachine(options = {}) {
1059
1057
  const loop = options.loop ?? true;
1060
1058
  const currentIdx = activeId ? filteredIdIndex.get(activeId) ?? -1 : -1;
1061
1059
  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;
1060
+ if (direction === "next") {
1061
+ if (currentIdx === -1 || currentIdx >= filteredIds.length - 1) newIdx = loop ? 0 : filteredIds.length - 1;
1062
+ else newIdx = currentIdx + 1;
1063
+ } else if (currentIdx <= 0) newIdx = loop ? filteredIds.length - 1 : 0;
1065
1064
  else newIdx = currentIdx - 1;
1066
1065
  const newActiveId = filteredIds[newIdx] ?? null;
1067
1066
  if (newActiveId !== activeId) {
@@ -1177,7 +1176,6 @@ function createCommandMachine(options = {}) {
1177
1176
  case "UNREGISTER_GROUP":
1178
1177
  registry.unregisterGroup(event.id);
1179
1178
  refilter(state.search);
1180
- break;
1181
1179
  }
1182
1180
  }
1183
1181
  return {
@@ -1294,7 +1292,6 @@ function createKeydownHandler(machine, getState) {
1294
1292
  case "Escape":
1295
1293
  event.preventDefault();
1296
1294
  machine.send({ type: "CLOSE" });
1297
- break;
1298
1295
  }
1299
1296
  };
1300
1297
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modern-cmdk",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
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.6.7",
66
+ "@types/jscodeshift": "17.3.0"
67
67
  },
68
68
  "keywords": [
69
69
  "command-palette",