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.
- package/README.md +9 -5
- package/dist/codemod/cli.d.mts +1 -1
- package/dist/codemod/cli.mjs +14677 -61044
- package/dist/codemod/transforms/data-attrs.d.mts +4 -8
- package/dist/codemod/transforms/data-attrs.mjs +1 -2
- package/dist/codemod/transforms/forward-ref.d.mts +4 -8
- package/dist/codemod/transforms/forward-ref.mjs +1 -2
- package/dist/codemod/transforms/import-rewrite.d.mts +4 -8
- package/dist/codemod/transforms/import-rewrite.mjs +1 -2
- package/dist/codemod/transforms/should-filter.d.mts +3 -7
- package/dist/codemod/transforms/should-filter.mjs +1 -2
- package/dist/core/index.d.mts +149 -181
- package/dist/core/index.mjs +42 -47
- package/dist/react/index.d.mts +78 -217
- package/dist/react/index.mjs +141 -166
- package/package.json +8 -8
package/dist/core/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/core/utils/string-wellformed.ts
|
|
2
2
|
/**
|
|
3
3
|
* Regex matching lone surrogates (unpaired high or low surrogates).
|
|
4
4
|
* A lone high surrogate (U+D800–U+DBFF) not followed by a low surrogate,
|
|
@@ -15,8 +15,7 @@ const REPLACEMENT_CHAR = "�";
|
|
|
15
15
|
function ensureWellFormed(str) {
|
|
16
16
|
return str.replace(LONE_SURROGATE_RE, REPLACEMENT_CHAR);
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
//#region src/core/frecency/idb-storage.ts
|
|
18
|
+
// src/core/frecency/idb-storage.ts
|
|
20
19
|
/** Serialize a FrecencyRecord to a JSON-safe format */
|
|
21
20
|
function serializeRecord(record) {
|
|
22
21
|
return {
|
|
@@ -119,8 +118,7 @@ var IdbFrecencyStorage = class {
|
|
|
119
118
|
this.#disposed = true;
|
|
120
119
|
}
|
|
121
120
|
};
|
|
122
|
-
|
|
123
|
-
//#region src/core/types.ts
|
|
121
|
+
// src/core/types.ts
|
|
124
122
|
/** Create a branded {@link ItemId} from a plain string. Ensures well-formed Unicode. */
|
|
125
123
|
function itemId(id) {
|
|
126
124
|
return ensureWellFormed(id);
|
|
@@ -158,8 +156,7 @@ function createInitialState(options) {
|
|
|
158
156
|
lastUpdated: Date.now()
|
|
159
157
|
};
|
|
160
158
|
}
|
|
161
|
-
|
|
162
|
-
//#region src/core/frecency/memory-storage.ts
|
|
159
|
+
// src/core/frecency/memory-storage.ts
|
|
163
160
|
/**
|
|
164
161
|
* In-memory implementation of FrecencyStorage using a Map.
|
|
165
162
|
* Data does not persist across page reloads. Suitable for ephemeral
|
|
@@ -181,8 +178,7 @@ var MemoryFrecencyStorage = class {
|
|
|
181
178
|
this.#store.clear();
|
|
182
179
|
}
|
|
183
180
|
};
|
|
184
|
-
|
|
185
|
-
//#region src/core/frecency/index.ts
|
|
181
|
+
// src/core/frecency/index.ts
|
|
186
182
|
/** Shared empty bonus map — avoids allocation when no frecency records exist */
|
|
187
183
|
const EMPTY_BONUS_MAP = /* @__PURE__ */ new Map();
|
|
188
184
|
/** Pre-computed bucket boundaries in hours — avoids Duration.total() per call */
|
|
@@ -284,8 +280,7 @@ var FrecencyEngine = class {
|
|
|
284
280
|
this.#storage[Symbol.dispose]();
|
|
285
281
|
}
|
|
286
282
|
};
|
|
287
|
-
|
|
288
|
-
//#region src/core/utils/group-by.ts
|
|
283
|
+
// src/core/utils/group-by.ts
|
|
289
284
|
/**
|
|
290
285
|
* Groups items from an iterable into a Map keyed by the result of `keyFn`.
|
|
291
286
|
* Cross-browser replacement for `Map.groupBy()`.
|
|
@@ -300,8 +295,7 @@ function mapGroupBy(items, keyFn) {
|
|
|
300
295
|
}
|
|
301
296
|
return map;
|
|
302
297
|
}
|
|
303
|
-
|
|
304
|
-
//#region src/core/keyboard/matcher.ts
|
|
298
|
+
// src/core/keyboard/matcher.ts
|
|
305
299
|
/**
|
|
306
300
|
* Tests whether a KeyboardEvent exactly matches a ParsedShortcut,
|
|
307
301
|
* comparing all four modifier keys (meta, ctrl, shift, alt) and the primary key.
|
|
@@ -326,8 +320,7 @@ function detectConflicts(shortcuts) {
|
|
|
326
320
|
const grouped = mapGroupBy(shortcuts, (s) => s.normalized);
|
|
327
321
|
return new Map(grouped.entries().filter(([, group]) => group.length > 1));
|
|
328
322
|
}
|
|
329
|
-
|
|
330
|
-
//#region src/core/keyboard/parser.ts
|
|
323
|
+
// src/core/keyboard/parser.ts
|
|
331
324
|
const isMac = typeof navigator !== "undefined" && (navigator.userAgentData?.platform === "macOS" || /Mac|iPod|iPhone|iPad/.test(navigator.platform));
|
|
332
325
|
/** Modifier aliases — cross-platform Mod resolution */
|
|
333
326
|
const MODIFIER_MAP = {
|
|
@@ -366,9 +359,7 @@ function parseShortcut(shortcut) {
|
|
|
366
359
|
case "shift":
|
|
367
360
|
shift = true;
|
|
368
361
|
break;
|
|
369
|
-
case "alt":
|
|
370
|
-
alt = true;
|
|
371
|
-
break;
|
|
362
|
+
case "alt": alt = true;
|
|
372
363
|
}
|
|
373
364
|
else key = part;
|
|
374
365
|
}
|
|
@@ -402,8 +393,7 @@ function formatShortcut(parsed) {
|
|
|
402
393
|
parts.push(displayKey);
|
|
403
394
|
return isMac ? parts.join("") : parts.join("+");
|
|
404
395
|
}
|
|
405
|
-
|
|
406
|
-
//#region src/core/keyboard/index.ts
|
|
396
|
+
// src/core/keyboard/index.ts
|
|
407
397
|
/**
|
|
408
398
|
* Manages keyboard shortcut bindings with global keydown listening.
|
|
409
399
|
* Supports `using` for automatic cleanup of both individual bindings and the
|
|
@@ -474,8 +464,7 @@ var KeyboardShortcutRegistry = class {
|
|
|
474
464
|
this.#bindings.clear();
|
|
475
465
|
}
|
|
476
466
|
};
|
|
477
|
-
|
|
478
|
-
//#region src/core/utils/set-ops.ts
|
|
467
|
+
// src/core/utils/set-ops.ts
|
|
479
468
|
/** Returns a new Set containing elements present in both `a` and `b`. */
|
|
480
469
|
function setIntersection(a, b) {
|
|
481
470
|
const result = /* @__PURE__ */ new Set();
|
|
@@ -518,8 +507,7 @@ function setSymmetricDifference(a, b) {
|
|
|
518
507
|
else result.add(item);
|
|
519
508
|
return result;
|
|
520
509
|
}
|
|
521
|
-
|
|
522
|
-
//#region src/core/registry.ts
|
|
510
|
+
// src/core/registry.ts
|
|
523
511
|
/**
|
|
524
512
|
* Manages registration and lookup of command items and groups.
|
|
525
513
|
* Uses set operation helpers (union/intersection/difference) for efficient ID operations.
|
|
@@ -680,8 +668,23 @@ var CommandRegistry = class {
|
|
|
680
668
|
this.clear();
|
|
681
669
|
}
|
|
682
670
|
};
|
|
683
|
-
|
|
684
|
-
|
|
671
|
+
// src/core/utils/env.ts
|
|
672
|
+
/**
|
|
673
|
+
* `true` unless `process.env.NODE_ENV` is `'production'`.
|
|
674
|
+
*
|
|
675
|
+
* Consumer bundlers (Vite, webpack, Next, esbuild) replace `process.env.NODE_ENV` statically,
|
|
676
|
+
* so the dev-only branches guarded by this flag fold away in production builds. A browser
|
|
677
|
+
* running the unbundled module throws a ReferenceError on the bare `process` reference;
|
|
678
|
+
* the catch turns that into the production value (`false`), so dev-only code stays off.
|
|
679
|
+
*/
|
|
680
|
+
const isDev = (() => {
|
|
681
|
+
try {
|
|
682
|
+
return process.env.NODE_ENV !== "production";
|
|
683
|
+
} catch {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
})();
|
|
687
|
+
// src/core/search/default-scorer.ts
|
|
685
688
|
function isWordSeparator(code) {
|
|
686
689
|
return code === 32 || code === 9 || code === 45 || code === 95 || code === 46 || code === 47 || code === 92;
|
|
687
690
|
}
|
|
@@ -843,11 +846,9 @@ function scoreFuzzy(query, qLen, lowerTarget, tLen) {
|
|
|
843
846
|
matches
|
|
844
847
|
};
|
|
845
848
|
}
|
|
846
|
-
|
|
847
|
-
//#region src/core/search/index.ts
|
|
848
|
-
const __DEV__ = globalThis.process ? globalThis.process.env.NODE_ENV !== "production" : false;
|
|
849
|
+
// src/core/search/index.ts
|
|
849
850
|
let leakRegistry;
|
|
850
|
-
if (
|
|
851
|
+
if (isDev && typeof window !== "undefined") leakRegistry = new FinalizationRegistry((label) => {
|
|
851
852
|
console.warn(`[modern-cmdk] ${label} was garbage collected without being disposed. Use \`using\` or call [Symbol.dispose]() to prevent leaks.`);
|
|
852
853
|
});
|
|
853
854
|
/**
|
|
@@ -863,7 +864,7 @@ function createSearchEngine(options) {
|
|
|
863
864
|
let previousQuery = "";
|
|
864
865
|
let previousResults = /* @__PURE__ */ new Set();
|
|
865
866
|
const sentinel = {};
|
|
866
|
-
if (
|
|
867
|
+
if (leakRegistry) leakRegistry.register(sentinel, "SearchEngine", sentinel);
|
|
867
868
|
return {
|
|
868
869
|
index(items) {
|
|
869
870
|
for (const item of items) indexedEntries.set(item.id, {
|
|
@@ -913,12 +914,11 @@ function createSearchEngine(options) {
|
|
|
913
914
|
[Symbol.dispose]() {
|
|
914
915
|
indexedEntries.clear();
|
|
915
916
|
previousResults.clear();
|
|
916
|
-
if (
|
|
917
|
+
if (leakRegistry) leakRegistry.unregister(sentinel);
|
|
917
918
|
}
|
|
918
919
|
};
|
|
919
920
|
}
|
|
920
|
-
|
|
921
|
-
//#region src/core/utils/event-emitter.ts
|
|
921
|
+
// src/core/utils/event-emitter.ts
|
|
922
922
|
/**
|
|
923
923
|
* Type-safe event emitter with strong references and Disposable subscriptions.
|
|
924
924
|
* Returns Disposable from `on()` for automatic unsubscription via `using`.
|
|
@@ -961,8 +961,7 @@ var TypedEmitter = class {
|
|
|
961
961
|
this.#listeners.clear();
|
|
962
962
|
}
|
|
963
963
|
};
|
|
964
|
-
|
|
965
|
-
//#region src/core/utils/scheduler.ts
|
|
964
|
+
// src/core/utils/scheduler.ts
|
|
966
965
|
/** Whether we're in a browser environment with rAF available */
|
|
967
966
|
const hasRAF = typeof requestAnimationFrame === "function";
|
|
968
967
|
/** Feature detection for cutting-edge scheduling APIs */
|
|
@@ -1023,8 +1022,7 @@ function createScheduler() {
|
|
|
1023
1022
|
}
|
|
1024
1023
|
};
|
|
1025
1024
|
}
|
|
1026
|
-
|
|
1027
|
-
//#region src/core/machine.ts
|
|
1025
|
+
// src/core/machine.ts
|
|
1028
1026
|
/**
|
|
1029
1027
|
* Creates a headless command palette state machine with search, frecency,
|
|
1030
1028
|
* and keyboard shortcut support. Implements Disposable for `using` cleanup.
|
|
@@ -1131,9 +1129,10 @@ function createCommandMachine(options = {}) {
|
|
|
1131
1129
|
const loop = options.loop ?? true;
|
|
1132
1130
|
const currentIdx = activeId ? filteredIdIndex.get(activeId) ?? -1 : -1;
|
|
1133
1131
|
let newIdx;
|
|
1134
|
-
if (direction === "next")
|
|
1135
|
-
|
|
1136
|
-
|
|
1132
|
+
if (direction === "next") {
|
|
1133
|
+
if (currentIdx === -1 || currentIdx >= filteredIds.length - 1) newIdx = loop ? 0 : filteredIds.length - 1;
|
|
1134
|
+
else newIdx = currentIdx + 1;
|
|
1135
|
+
} else if (currentIdx <= 0) newIdx = loop ? filteredIds.length - 1 : 0;
|
|
1137
1136
|
else newIdx = currentIdx - 1;
|
|
1138
1137
|
const newActiveId = filteredIds[newIdx] ?? null;
|
|
1139
1138
|
if (newActiveId !== activeId) {
|
|
@@ -1249,7 +1248,6 @@ function createCommandMachine(options = {}) {
|
|
|
1249
1248
|
case "UNREGISTER_GROUP":
|
|
1250
1249
|
registry.unregisterGroup(event.id);
|
|
1251
1250
|
refilter(state.search);
|
|
1252
|
-
break;
|
|
1253
1251
|
}
|
|
1254
1252
|
}
|
|
1255
1253
|
return {
|
|
@@ -1290,8 +1288,7 @@ function createCommandMachine(options = {}) {
|
|
|
1290
1288
|
}
|
|
1291
1289
|
};
|
|
1292
1290
|
}
|
|
1293
|
-
|
|
1294
|
-
//#region src/core/search/fuzzy-scorer.ts
|
|
1291
|
+
// src/core/search/fuzzy-scorer.ts
|
|
1295
1292
|
/**
|
|
1296
1293
|
* Async-safe fuzzy scorer — wraps scoring in Promise for error resilience.
|
|
1297
1294
|
* Falls back gracefully on error via synchronous-throw capture.
|
|
@@ -1311,8 +1308,7 @@ function batchScoreItems(query, items) {
|
|
|
1311
1308
|
resolve(items.values().map((item) => scoreItem(query, item)).filter((r) => r != null).toArray().toSorted((a, b) => b.score - a.score));
|
|
1312
1309
|
});
|
|
1313
1310
|
}
|
|
1314
|
-
|
|
1315
|
-
//#region src/core/telemetry.ts
|
|
1311
|
+
// src/core/telemetry.ts
|
|
1316
1312
|
/**
|
|
1317
1313
|
* Creates a telemetry middleware that measures command palette interactions.
|
|
1318
1314
|
* Uses Date.now() for millisecond-precision timestamps
|
|
@@ -1349,5 +1345,4 @@ function createTelemetryMiddleware(hooks) {
|
|
|
1349
1345
|
}
|
|
1350
1346
|
};
|
|
1351
1347
|
}
|
|
1352
|
-
//#endregion
|
|
1353
1348
|
export { CommandRegistry, DEFAULT_FRECENCY_DECAY, DEFAULT_MACHINE_OPTIONS, FrecencyEngine, IdbFrecencyStorage, KeyboardShortcutRegistry, MemoryFrecencyStorage, TypedEmitter, batchScoreItems, computeFrecencyBonus, createCommandMachine, createInitialState, createScheduler, createSearchEngine, createTelemetryMiddleware, detectConflicts, findMatchingShortcut, formatShortcut, groupId, itemId, matchesShortcut, parseShortcut, scoreItem, scoreItemAsync };
|