modern-cmdk 1.4.0 → 1.6.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/README.md +54 -34
- package/THIRD-PARTY-NOTICES.md +303 -0
- package/dist/codemod/bin.mjs +14 -0
- package/dist/codemod/chunk-jscodeshift.mjs +36210 -0
- package/dist/codemod/chunk-print-options.mjs +43 -0
- package/dist/codemod/chunk-worker.mjs +485 -0
- package/dist/codemod/cli.mjs +297 -43660
- package/dist/codemod/transforms/data-attrs.mjs +583 -39
- package/dist/codemod/transforms/forward-ref.mjs +197 -32
- package/dist/codemod/transforms/import-rewrite.mjs +389 -30
- package/dist/codemod/transforms/should-filter.mjs +199 -10
- package/dist/codemod/worker.mjs +1 -0
- package/dist/core/index.d.mts +122 -35
- package/dist/core/index.mjs +466 -292
- package/dist/react/dialog.mjs +0 -1
- package/dist/react/index.d.mts +25 -4
- package/dist/react/index.mjs +58 -25
- package/dist/react/styles.css +33 -31
- package/package.json +5 -7
package/dist/react/dialog.mjs
CHANGED
package/dist/react/index.d.mts
CHANGED
|
@@ -17,14 +17,19 @@ interface CommandActivityProps {
|
|
|
17
17
|
*/
|
|
18
18
|
export declare function CommandActivity({ mode, children }: CommandActivityProps): ReactNode;
|
|
19
19
|
interface CommandAsyncItemsProps {
|
|
20
|
-
/** Promise that resolves to items */
|
|
20
|
+
/** Promise that resolves to items; keep it stable across renders (state, a ref, or `useMemo`) or the boundary re-suspends on every render */
|
|
21
21
|
readonly items: Promise<readonly CommandItem$1[]>;
|
|
22
22
|
/** Fallback content while loading */
|
|
23
23
|
readonly fallback?: ReactNode;
|
|
24
24
|
/** Render function for resolved items */
|
|
25
25
|
readonly children: (items: readonly CommandItem$1[]) => ReactNode;
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Suspense-based async item loader that resolves a promise of items using React 19 `use()`.
|
|
29
|
+
*
|
|
30
|
+
* The `items` promise must be kept stable across renders (held in state, a ref, or `useMemo`):
|
|
31
|
+
* a new promise on every render, such as `items={fetchItems()}`, suspends again on every render.
|
|
32
|
+
*/
|
|
28
33
|
export declare function CommandAsyncItems({ items, fallback, children }: CommandAsyncItemsProps): ReactNode;
|
|
29
34
|
interface CommandBadgeProps extends ComponentPropsWithRef<"span"> {}
|
|
30
35
|
/** Inline badge for categorization or status indicators on command items. */
|
|
@@ -35,7 +40,10 @@ export declare function CommandEmpty({ ref, children, ...props }: CommandEmptyPr
|
|
|
35
40
|
interface CommandGroupProps extends ComponentPropsWithRef<"div"> {
|
|
36
41
|
/** Heading text displayed above the group */
|
|
37
42
|
readonly heading?: string;
|
|
38
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Orders the keys of `CommandState.groupedIds` (lower first). React renders the groups in the JSX order
|
|
45
|
+
* of the group elements, not by this number.
|
|
46
|
+
*/
|
|
39
47
|
readonly priority?: number;
|
|
40
48
|
/** Force a specific ID */
|
|
41
49
|
readonly forceId?: string;
|
|
@@ -60,6 +68,7 @@ export declare function CommandInput({ ref, placeholder, onValueChange, ...props
|
|
|
60
68
|
interface CommandItemProps extends Omit<ComponentPropsWithRef<"div">, "onSelect" | "value"> {
|
|
61
69
|
readonly value: string;
|
|
62
70
|
readonly keywords?: readonly string[];
|
|
71
|
+
/** Called when the item is selected by click, Enter or shortcut (no argument in 1.x; the value arrives in 2.0) */
|
|
63
72
|
readonly onSelect?: () => void;
|
|
64
73
|
readonly disabled?: boolean;
|
|
65
74
|
readonly shortcut?: string;
|
|
@@ -181,7 +190,16 @@ interface CommandGroupContextValue {
|
|
|
181
190
|
}
|
|
182
191
|
interface CommandErrorBoundaryProps {
|
|
183
192
|
readonly children: ReactNode;
|
|
184
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Rendered in place of the children after an error. A function receives the error and a `reset`
|
|
195
|
+
* callback that clears it, so the children render again (a retry button, for example).
|
|
196
|
+
*/
|
|
197
|
+
readonly fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode);
|
|
198
|
+
/**
|
|
199
|
+
* While the boundary shows its fallback, a change in these values (compared entry by entry with
|
|
200
|
+
* `Object.is`; a different length counts as a change) clears the error and renders the children again.
|
|
201
|
+
*/
|
|
202
|
+
readonly resetKeys?: readonly unknown[];
|
|
185
203
|
readonly onError?: (error: Error, errorInfo: ErrorInfo) => void;
|
|
186
204
|
}
|
|
187
205
|
interface CommandErrorBoundaryState {
|
|
@@ -192,6 +210,9 @@ export declare class CommandErrorBoundary extends Component<CommandErrorBoundary
|
|
|
192
210
|
override state: CommandErrorBoundaryState;
|
|
193
211
|
static getDerivedStateFromError(error: Error): CommandErrorBoundaryState;
|
|
194
212
|
override componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
|
|
213
|
+
override componentDidUpdate(prevProps: CommandErrorBoundaryProps, prevState: CommandErrorBoundaryState): void;
|
|
214
|
+
/** Clears the captured error so the children render again. */
|
|
215
|
+
reset: () => void;
|
|
195
216
|
override render(): ReactNode;
|
|
196
217
|
}
|
|
197
218
|
interface UseCommandReturn {
|
package/dist/react/index.mjs
CHANGED
|
@@ -33,14 +33,42 @@ function AsyncItemsInner({ items: itemsPromise, children }) {
|
|
|
33
33
|
}, [stable.machine, items]);
|
|
34
34
|
return /* @__PURE__ */ jsx(Fragment, { children: children(items) });
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Rendered next to the Suspense fallback: while it is mounted its source counts as pending,
|
|
38
|
+
* so `state.loading` (Command.Loading, the list's aria-busy) follows the suspended promise.
|
|
39
|
+
* The fallback unmounts when the items resolve, reject into an error boundary, or this
|
|
40
|
+
* AsyncItems unmounts, and the cleanup then clears the source.
|
|
41
|
+
*/
|
|
42
|
+
function PendingSignal() {
|
|
43
|
+
const stable = useStableContext("Command.AsyncItems");
|
|
44
|
+
const source = useId();
|
|
45
|
+
useLayoutEffect(() => {
|
|
46
|
+
stable.machine.send({
|
|
47
|
+
type: "LOADING",
|
|
48
|
+
source,
|
|
49
|
+
pending: true
|
|
50
|
+
});
|
|
51
|
+
return () => {
|
|
52
|
+
stable.machine.send({
|
|
53
|
+
type: "LOADING",
|
|
54
|
+
source,
|
|
55
|
+
pending: false
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
}, [stable.machine, source]);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Suspense-based async item loader that resolves a promise of items using React 19 `use()`.
|
|
63
|
+
*
|
|
64
|
+
* The `items` promise must be kept stable across renders (held in state, a ref, or `useMemo`):
|
|
65
|
+
* a new promise on every render, such as `items={fetchItems()}`, suspends again on every render.
|
|
66
|
+
*/
|
|
37
67
|
function CommandAsyncItems({ items, fallback, children }) {
|
|
38
|
-
const stableRef = useRef(items);
|
|
39
|
-
if (stableRef.current !== items) stableRef.current = items;
|
|
40
68
|
return /* @__PURE__ */ jsx(Suspense, {
|
|
41
|
-
fallback,
|
|
69
|
+
fallback: /* @__PURE__ */ jsxs(Fragment, { children: [fallback, /* @__PURE__ */ jsx(PendingSignal, {})] }),
|
|
42
70
|
children: /* @__PURE__ */ jsx(AsyncItemsInner, {
|
|
43
|
-
items
|
|
71
|
+
items,
|
|
44
72
|
children
|
|
45
73
|
})
|
|
46
74
|
});
|
|
@@ -83,6 +111,14 @@ function useRegisterItem(value, options) {
|
|
|
83
111
|
const dataRef = useRef(options?.data);
|
|
84
112
|
dataRef.current = options?.data;
|
|
85
113
|
const keywordsDep = options?.keywords?.join("\0");
|
|
114
|
+
const registeredRef = useRef(false);
|
|
115
|
+
useLayoutEffect(() => () => {
|
|
116
|
+
registeredRef.current = false;
|
|
117
|
+
stable.machine.send({
|
|
118
|
+
type: "UNREGISTER_ITEM",
|
|
119
|
+
id
|
|
120
|
+
});
|
|
121
|
+
}, [stable.machine, id]);
|
|
86
122
|
useLayoutEffect(() => {
|
|
87
123
|
const item = {
|
|
88
124
|
id,
|
|
@@ -95,15 +131,10 @@ function useRegisterItem(value, options) {
|
|
|
95
131
|
data: dataRef.current
|
|
96
132
|
};
|
|
97
133
|
stable.machine.send({
|
|
98
|
-
type: "REGISTER_ITEM",
|
|
134
|
+
type: registeredRef.current ? "UPDATE_ITEM" : "REGISTER_ITEM",
|
|
99
135
|
item
|
|
100
136
|
});
|
|
101
|
-
|
|
102
|
-
stable.machine.send({
|
|
103
|
-
type: "UNREGISTER_ITEM",
|
|
104
|
-
id
|
|
105
|
-
});
|
|
106
|
-
};
|
|
137
|
+
registeredRef.current = true;
|
|
107
138
|
}, [
|
|
108
139
|
stable.machine,
|
|
109
140
|
id,
|
|
@@ -150,13 +181,14 @@ const HIDDEN_STYLE = { display: "none" };
|
|
|
150
181
|
/** Visual grouping container with an optional heading that hides when no items match. */
|
|
151
182
|
function CommandGroup({ ref, children, heading, priority, forceId, ...props }) {
|
|
152
183
|
const stateCtx = useStateContext("Command.Group");
|
|
184
|
+
const stable = useStableContext("Command.Group");
|
|
153
185
|
const headingId = useId();
|
|
154
186
|
const groupId = useRegisterGroup(heading, {
|
|
155
187
|
...priority !== void 0 && { priority },
|
|
156
188
|
...forceId !== void 0 && { forceId }
|
|
157
189
|
});
|
|
158
|
-
const
|
|
159
|
-
const hasVisibleItems =
|
|
190
|
+
const registry = stable.machine.getRegistry();
|
|
191
|
+
const hasVisibleItems = stateCtx.state.groupedIds.get(groupId)?.some((id) => registry.getItem(id)?.groupId === groupId) ?? false;
|
|
160
192
|
const groupContext = useMemo(() => ({
|
|
161
193
|
groupId,
|
|
162
194
|
headingId
|
|
@@ -678,10 +710,20 @@ var CommandErrorBoundary = class extends Component {
|
|
|
678
710
|
componentDidCatch(error, errorInfo) {
|
|
679
711
|
this.props.onError?.(error, errorInfo);
|
|
680
712
|
}
|
|
713
|
+
componentDidUpdate(prevProps, prevState) {
|
|
714
|
+
if (this.state.error === null || prevState.error === null) return;
|
|
715
|
+
const prev = prevProps.resetKeys;
|
|
716
|
+
const next = this.props.resetKeys;
|
|
717
|
+
if (prev !== next && (prev?.length !== next?.length || next?.some((key, index) => !Object.is(key, prev?.[index])))) this.reset();
|
|
718
|
+
}
|
|
719
|
+
/** Clears the captured error so the children render again. */
|
|
720
|
+
reset = () => {
|
|
721
|
+
this.setState(INITIAL_STATE);
|
|
722
|
+
};
|
|
681
723
|
render() {
|
|
682
724
|
if (this.state.error) {
|
|
683
725
|
const { fallback } = this.props;
|
|
684
|
-
if (typeof fallback === "function") return fallback(this.state.error);
|
|
726
|
+
if (typeof fallback === "function") return fallback(this.state.error, this.reset);
|
|
685
727
|
if (fallback) return fallback;
|
|
686
728
|
return null;
|
|
687
729
|
}
|
|
@@ -696,15 +738,7 @@ function useCommandState(selector) {
|
|
|
696
738
|
const getSnapshot = useCallback(() => selectorRef.current ? selectorRef.current(stable.machine.getState()) : stable.machine.getState(), [stable.machine]);
|
|
697
739
|
return useSyncExternalStore(stable.machine.subscribe, getSnapshot, getSnapshot);
|
|
698
740
|
}
|
|
699
|
-
// src/
|
|
700
|
-
/**
|
|
701
|
-
* `true` unless `process.env.NODE_ENV` is `'production'`.
|
|
702
|
-
*
|
|
703
|
-
* Consumer bundlers (Vite, webpack, Next, esbuild) replace `process.env.NODE_ENV` statically,
|
|
704
|
-
* so the dev-only branches guarded by this flag fold away in production builds. A browser
|
|
705
|
-
* running the unbundled module throws a ReferenceError on the bare `process` reference;
|
|
706
|
-
* the catch turns that into the production value (`false`), so dev-only code stays off.
|
|
707
|
-
*/
|
|
741
|
+
// src/react/hooks/use-devtools.ts
|
|
708
742
|
const isDev = (() => {
|
|
709
743
|
try {
|
|
710
744
|
return process.env.NODE_ENV !== "production";
|
|
@@ -712,7 +746,6 @@ const isDev = (() => {
|
|
|
712
746
|
return false;
|
|
713
747
|
}
|
|
714
748
|
})();
|
|
715
|
-
// src/react/hooks/use-devtools.ts
|
|
716
749
|
/** Branded key for the global devtools instance map */
|
|
717
750
|
const DEVTOOLS_KEY = "__CRIMSON_COMMAND_DEVTOOLS__";
|
|
718
751
|
/**
|
package/dist/react/styles.css
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
/* modern-cmdk/react — tokens, item and list transitions; the dialog and overlay transitions are declared but inert until DT-19 */
|
|
2
|
-
/*
|
|
3
|
-
/* Spring easing via linear() approximation — perceptually smooth */
|
|
4
|
-
/* Scroll-driven animations via animation-timeline: scroll() */
|
|
5
|
-
/* WCAG 2.1 AA: forced-colors, prefers-contrast, prefers-reduced-motion */
|
|
6
|
-
/* CSS Logical Properties: full RTL/LTR support */
|
|
7
|
-
/* CSS Nesting, @layer cascade control, oklch() color space */
|
|
8
|
-
/* Container queries for responsive item layout */
|
|
2
|
+
/* Also: scroll-driven animations (gated by @supports), WCAG 2.1 AA forced-colors, prefers-contrast and prefers-reduced-motion, logical properties for RTL/LTR, nesting, @layer, oklch(), container queries */
|
|
9
3
|
/* Secondary text (group headings, shortcuts, empty state, placeholder) is coloured with
|
|
10
4
|
--command-muted-color, never faded with opacity: opacity stacks on the consumer's text
|
|
11
5
|
colour and cannot be checked against it. The default is light-dark(), so it follows the
|
|
@@ -191,7 +185,6 @@
|
|
|
191
185
|
[data-command-list] {
|
|
192
186
|
overflow-y: auto;
|
|
193
187
|
overscroll-behavior: contain;
|
|
194
|
-
scroll-timeline: --list-scroll block;
|
|
195
188
|
will-change: height;
|
|
196
189
|
transition: height var(--command-duration-list) var(--command-spring-easing);
|
|
197
190
|
scrollbar-gutter: stable;
|
|
@@ -209,6 +202,7 @@
|
|
|
209
202
|
|
|
210
203
|
[data-command-item] {
|
|
211
204
|
cursor: pointer;
|
|
205
|
+
-webkit-user-select: none;
|
|
212
206
|
user-select: none;
|
|
213
207
|
transition: background-color var(--command-duration-item) linear(0, 0.25, 0.5, 0.75, 1);
|
|
214
208
|
scroll-margin-block: 8px;
|
|
@@ -237,6 +231,7 @@
|
|
|
237
231
|
/* ─── Group ─── */
|
|
238
232
|
|
|
239
233
|
[data-command-group-heading] {
|
|
234
|
+
-webkit-user-select: none;
|
|
240
235
|
user-select: none;
|
|
241
236
|
font-size: 0.75em;
|
|
242
237
|
text-transform: uppercase;
|
|
@@ -340,9 +335,7 @@
|
|
|
340
335
|
overlay var(--command-duration-exit) allow-discrete;
|
|
341
336
|
}
|
|
342
337
|
|
|
343
|
-
/* ─── Dialog Animations ─── */
|
|
344
|
-
/* Dialog transitions: inert until DT-19 */
|
|
345
|
-
/* Spring easing via linear() approximation */
|
|
338
|
+
/* ─── Dialog Animations (inert until DT-19) ─── */
|
|
346
339
|
|
|
347
340
|
[data-command-dialog][data-state="open"] {
|
|
348
341
|
@starting-style {
|
|
@@ -400,24 +393,16 @@
|
|
|
400
393
|
&::before {
|
|
401
394
|
inset-block-start: 0;
|
|
402
395
|
background: linear-gradient(to bottom, currentColor, transparent);
|
|
403
|
-
opacity: 0.08;
|
|
404
|
-
animation: fade-edge-top linear both;
|
|
405
|
-
animation-timeline: --list-scroll;
|
|
406
|
-
animation-range: 0px 24px;
|
|
407
396
|
}
|
|
408
397
|
|
|
409
398
|
/* Bottom fade — visible when not scrolled to bottom */
|
|
410
399
|
&::after {
|
|
411
400
|
inset-block-end: 0;
|
|
412
401
|
background: linear-gradient(to top, currentColor, transparent);
|
|
413
|
-
opacity: 0.08;
|
|
414
|
-
animation: fade-edge-bottom linear both;
|
|
415
|
-
animation-timeline: --list-scroll;
|
|
416
|
-
animation-range: calc(100% - 24px) 100%;
|
|
417
402
|
}
|
|
418
403
|
}
|
|
419
404
|
|
|
420
|
-
@keyframes fade-edge
|
|
405
|
+
@keyframes fade-edge {
|
|
421
406
|
from {
|
|
422
407
|
opacity: 0;
|
|
423
408
|
}
|
|
@@ -426,23 +411,12 @@
|
|
|
426
411
|
}
|
|
427
412
|
}
|
|
428
413
|
|
|
429
|
-
@keyframes fade-edge-bottom {
|
|
430
|
-
from {
|
|
431
|
-
opacity: 0.08;
|
|
432
|
-
}
|
|
433
|
-
to {
|
|
434
|
-
opacity: 0;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
414
|
/* ─── Scroll-Driven Progress Indicator ─── */
|
|
439
415
|
|
|
440
416
|
[data-command-scroll-indicator] {
|
|
441
417
|
block-size: 2px;
|
|
442
418
|
transform-origin: inline-start center;
|
|
443
419
|
scale: 0 1;
|
|
444
|
-
animation: scroll-progress linear both;
|
|
445
|
-
animation-timeline: --list-scroll;
|
|
446
420
|
will-change: scale;
|
|
447
421
|
}
|
|
448
422
|
|
|
@@ -455,6 +429,34 @@
|
|
|
455
429
|
}
|
|
456
430
|
}
|
|
457
431
|
|
|
432
|
+
/* Safari < 26 and Firefox < 159 lack animation-timeline: a time-based run would settle in its end state, so the wiring waits */
|
|
433
|
+
@supports (animation-timeline: scroll()) {
|
|
434
|
+
[data-command-list] {
|
|
435
|
+
scroll-timeline: --list-scroll;
|
|
436
|
+
|
|
437
|
+
&::before {
|
|
438
|
+
animation: fade-edge linear both;
|
|
439
|
+
animation-range: 0px 24px;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
&::after {
|
|
443
|
+
animation: fade-edge linear both reverse;
|
|
444
|
+
animation-range: calc(100% - 24px) 100%;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
&::before,
|
|
448
|
+
&::after {
|
|
449
|
+
opacity: 0.08;
|
|
450
|
+
animation-timeline: --list-scroll;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
[data-command-scroll-indicator] {
|
|
455
|
+
animation: scroll-progress linear both;
|
|
456
|
+
animation-timeline: --list-scroll;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
458
460
|
/* ─── Focus Indicators ─── */
|
|
459
461
|
|
|
460
462
|
[data-command-item]:focus-visible {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modern-cmdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The definitive command palette engine for the modern web",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,11 +30,12 @@
|
|
|
30
30
|
"main": "./dist/core/index.mjs",
|
|
31
31
|
"types": "./dist/core/index.d.mts",
|
|
32
32
|
"bin": {
|
|
33
|
-
"modern-cmdk": "./dist/codemod/
|
|
33
|
+
"modern-cmdk": "./dist/codemod/bin.mjs"
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
36
|
"dist",
|
|
37
|
-
"LICENSE"
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"THIRD-PARTY-NOTICES.md"
|
|
38
39
|
],
|
|
39
40
|
"sideEffects": [
|
|
40
41
|
"./dist/react/styles.css"
|
|
@@ -56,10 +57,7 @@
|
|
|
56
57
|
"idb-keyval": "6.3.0"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
59
|
-
"
|
|
60
|
-
"jscodeshift": "17.4.0",
|
|
61
|
-
"radix-ui": "1.8.2-rc.1791984254107",
|
|
62
|
-
"@types/jscodeshift": "17.3.0"
|
|
60
|
+
"radix-ui": "1.8.2-rc.1791984254107"
|
|
63
61
|
},
|
|
64
62
|
"keywords": [
|
|
65
63
|
"command-palette",
|