@enigmax/primitives 0.18.0 → 0.19.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.
@@ -29,6 +29,38 @@ function substringMatcher(query, items, keys) {
29
29
  }
30
30
  return results.sort((left, right) => left.score - right.score);
31
31
  }
32
+ function subsequenceMatcher(keys = []) {
33
+ return (query, items) => {
34
+ const needle = fold(query);
35
+ const results = [];
36
+ for (const item of items) {
37
+ const fields = keys.length ? keys : [""];
38
+ let best = null;
39
+ for (const key of fields) {
40
+ const haystack = fold(key ? readPath(item, key) : String(item));
41
+ const score = subsequenceScore(needle, haystack);
42
+ if (score < 0) continue;
43
+ const ranked = -score;
44
+ if (!best || ranked < best.score) best = { item, score: ranked, key: key || void 0 };
45
+ }
46
+ if (best) results.push(best);
47
+ }
48
+ return results.sort((left, right) => left.score - right.score);
49
+ };
50
+ }
51
+ function subsequenceScore(query, text) {
52
+ if (!query) return 0;
53
+ let from = 0, score = 0, run = 0;
54
+ for (let i = 0; i < query.length; i++) {
55
+ const at = text.indexOf(query[i], from);
56
+ if (at === -1) return -1;
57
+ run = i > 0 && at === from ? run + 1 : 0;
58
+ const wordStart = at === 0 || /[^a-z0-9]/.test(text[at - 1]);
59
+ score += 10 + run * 6 + (wordStart ? 8 : 0) - Math.min(at - from, 6);
60
+ from = at + 1;
61
+ }
62
+ return score;
63
+ }
32
64
  function createSearch(options = {}) {
33
65
  let opts = { ...options };
34
66
  let items = opts.items ?? [];
@@ -121,6 +153,7 @@ function createSearch(options = {}) {
121
153
  input.addEventListener("input", onInput);
122
154
  input.addEventListener("keydown", onKeyDown);
123
155
  input.dataset.enigmaSearch = "";
156
+ if (input.value) this.searchNow(input.value);
124
157
  return () => {
125
158
  input.removeEventListener("input", onInput);
126
159
  input.removeEventListener("keydown", onKeyDown);
@@ -142,4 +175,4 @@ function createSearch(options = {}) {
142
175
  };
143
176
  }
144
177
 
145
- export { createSearch };
178
+ export { createSearch, subsequenceMatcher };
@@ -0,0 +1,99 @@
1
+ // src/core/palette.ts
2
+ function recentKey(entry) {
3
+ return `${entry.scope ?? ""}\0${entry.href ?? ""}\0${entry.href ? "" : entry.term.trim().toLowerCase()}`;
4
+ }
5
+ function createRecentStore(options = {}) {
6
+ const { key = "enigma:palette:recent", limit = 8, storage = "local" } = options;
7
+ function backing() {
8
+ if (typeof window === "undefined") return null;
9
+ try {
10
+ return storage === "session" ? window.sessionStorage : window.localStorage;
11
+ } catch {
12
+ return null;
13
+ }
14
+ }
15
+ function read() {
16
+ const store = backing();
17
+ if (!store) return [];
18
+ try {
19
+ const raw = store.getItem(key);
20
+ if (!raw) return [];
21
+ const parsed = JSON.parse(raw);
22
+ if (!Array.isArray(parsed)) return [];
23
+ return parsed.filter((entry) => Boolean(entry) && typeof entry.term === "string").sort((a, b) => b.at - a.at).slice(0, limit);
24
+ } catch {
25
+ return [];
26
+ }
27
+ }
28
+ function write(entries) {
29
+ const store = backing();
30
+ const kept = entries.slice(0, limit);
31
+ try {
32
+ store?.setItem(key, JSON.stringify(kept));
33
+ } catch {
34
+ }
35
+ return kept;
36
+ }
37
+ return {
38
+ list: read,
39
+ remember(entry) {
40
+ const next = { ...entry, at: entry.at ?? Date.now() };
41
+ if (!next.term.trim() && !next.href) return read();
42
+ const id = recentKey(next);
43
+ return write([next, ...read().filter((existing) => recentKey(existing) !== id)]);
44
+ },
45
+ forget(entry) {
46
+ const id = recentKey(entry);
47
+ return write(read().filter((existing) => recentKey(existing) !== id));
48
+ },
49
+ clear() {
50
+ const store = backing();
51
+ try {
52
+ store?.removeItem(key);
53
+ } catch {
54
+ }
55
+ }
56
+ };
57
+ }
58
+ function groupRows(rows, labelOf) {
59
+ const groups = [];
60
+ const index = /* @__PURE__ */ new Map();
61
+ rows.forEach((row, position) => {
62
+ const label = labelOf(row);
63
+ let group = index.get(label);
64
+ if (!group) {
65
+ group = { label, rows: [] };
66
+ index.set(label, group);
67
+ groups.push(group);
68
+ }
69
+ group.rows.push({ row, position });
70
+ });
71
+ return groups;
72
+ }
73
+ function moveActive(current, length, key, page = 5) {
74
+ if (length <= 0) return 0;
75
+ switch (key) {
76
+ case "ArrowDown":
77
+ return (current + 1) % length;
78
+ case "ArrowUp":
79
+ return (current - 1 + length) % length;
80
+ case "Home":
81
+ return 0;
82
+ case "End":
83
+ return length - 1;
84
+ case "PageDown":
85
+ return Math.min(length - 1, current + page);
86
+ case "PageUp":
87
+ return Math.max(0, current - page);
88
+ }
89
+ }
90
+ function shortcutLabel(key = "K") {
91
+ const mac = typeof navigator !== "undefined" && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent || "");
92
+ return `${mac ? "\u2318" : "Ctrl"} ${key.toUpperCase()}`;
93
+ }
94
+ function isPaletteShortcut(event, key = "k") {
95
+ if (event.key.toLowerCase() !== key.toLowerCase()) return false;
96
+ return event.metaKey || event.ctrlKey;
97
+ }
98
+
99
+ export { createRecentStore, groupRows, isPaletteShortcut, moveActive, recentKey, shortcutLabel };
@@ -1,4 +1,5 @@
1
- import { createSearch } from './chunk-UZFEEFMF.js';
1
+ import { createRecentStore, shortcutLabel, moveActive, groupRows, isPaletteShortcut } from './chunk-DTWZDONY.js';
2
+ import { subsequenceMatcher, createSearch } from './chunk-D5A2ZMAG.js';
2
3
  import { Slot } from './chunk-HS3X3XCW.js';
3
4
  import { createPortal } from 'react-dom';
4
5
  import { createContext, useContext, useState, useRef, useId, useMemo, useCallback, useEffect } from 'react';
@@ -10,104 +11,6 @@ function usePaletteContext(part) {
10
11
  if (!value) throw new Error(`<${part}> must be rendered inside <SearchPalette.Root>.`);
11
12
  return value;
12
13
  }
13
-
14
- // src/core/palette.ts
15
- function recentKey(entry) {
16
- return `${entry.scope ?? ""}\0${entry.href ?? ""}\0${entry.href ? "" : entry.term.trim().toLowerCase()}`;
17
- }
18
- function createRecentStore(options = {}) {
19
- const { key = "enigma:palette:recent", limit = 8, storage = "local" } = options;
20
- function backing() {
21
- if (typeof window === "undefined") return null;
22
- try {
23
- return storage === "session" ? window.sessionStorage : window.localStorage;
24
- } catch {
25
- return null;
26
- }
27
- }
28
- function read() {
29
- const store = backing();
30
- if (!store) return [];
31
- try {
32
- const raw = store.getItem(key);
33
- if (!raw) return [];
34
- const parsed = JSON.parse(raw);
35
- if (!Array.isArray(parsed)) return [];
36
- return parsed.filter((entry) => Boolean(entry) && typeof entry.term === "string").sort((a, b) => b.at - a.at).slice(0, limit);
37
- } catch {
38
- return [];
39
- }
40
- }
41
- function write(entries) {
42
- const store = backing();
43
- const kept = entries.slice(0, limit);
44
- try {
45
- store?.setItem(key, JSON.stringify(kept));
46
- } catch {
47
- }
48
- return kept;
49
- }
50
- return {
51
- list: read,
52
- remember(entry) {
53
- const next = { ...entry, at: entry.at ?? Date.now() };
54
- if (!next.term.trim() && !next.href) return read();
55
- const id = recentKey(next);
56
- return write([next, ...read().filter((existing) => recentKey(existing) !== id)]);
57
- },
58
- forget(entry) {
59
- const id = recentKey(entry);
60
- return write(read().filter((existing) => recentKey(existing) !== id));
61
- },
62
- clear() {
63
- const store = backing();
64
- try {
65
- store?.removeItem(key);
66
- } catch {
67
- }
68
- }
69
- };
70
- }
71
- function groupRows(rows, labelOf) {
72
- const groups = [];
73
- const index = /* @__PURE__ */ new Map();
74
- rows.forEach((row, position) => {
75
- const label = labelOf(row);
76
- let group = index.get(label);
77
- if (!group) {
78
- group = { label, rows: [] };
79
- index.set(label, group);
80
- groups.push(group);
81
- }
82
- group.rows.push({ row, position });
83
- });
84
- return groups;
85
- }
86
- function moveActive(current, length, key, page = 5) {
87
- if (length <= 0) return 0;
88
- switch (key) {
89
- case "ArrowDown":
90
- return (current + 1) % length;
91
- case "ArrowUp":
92
- return (current - 1 + length) % length;
93
- case "Home":
94
- return 0;
95
- case "End":
96
- return length - 1;
97
- case "PageDown":
98
- return Math.min(length - 1, current + page);
99
- case "PageUp":
100
- return Math.max(0, current - page);
101
- }
102
- }
103
- function shortcutLabel(key = "K") {
104
- const mac = typeof navigator !== "undefined" && /mac|iphone|ipad|ipod/i.test(navigator.platform || navigator.userAgent || "");
105
- return `${mac ? "\u2318" : "Ctrl"} ${key.toUpperCase()}`;
106
- }
107
- function isPaletteShortcut(event, key = "k") {
108
- if (event.key.toLowerCase() !== key.toLowerCase()) return false;
109
- return event.metaKey || event.ctrlKey;
110
- }
111
14
  var RECENTS_SHOWN = 5;
112
15
  function firstString(item) {
113
16
  if (typeof item === "string") return item;
@@ -162,12 +65,16 @@ function PaletteRoot({
162
65
  if (!controlled) setOwnOpen(next);
163
66
  onOpenChange?.(next);
164
67
  }, [controlled, onOpenChange]);
68
+ const ranking = useMemo(
69
+ () => matcher ?? (fuse ? void 0 : subsequenceMatcher(keys ?? [])),
70
+ [matcher, fuse, keys]
71
+ );
165
72
  const engine = useMemo(() => createSearch({
166
73
  items,
167
74
  keys,
168
75
  fuse,
169
76
  fuseOptions,
170
- matcher,
77
+ matcher: ranking,
171
78
  debounce: delay,
172
79
  limit,
173
80
  onResults: (next) => {
@@ -183,8 +90,8 @@ function PaletteRoot({
183
90
  engine.setItems(items ?? []);
184
91
  }, [engine, items]);
185
92
  useEffect(() => {
186
- engine.update({ keys, fuse, fuseOptions, matcher, debounce: delay, limit });
187
- }, [engine, keys, fuse, fuseOptions, matcher, delay, limit]);
93
+ engine.update({ keys, fuse, fuseOptions, matcher: ranking, debounce: delay, limit });
94
+ }, [engine, keys, fuse, fuseOptions, ranking, delay, limit]);
188
95
  useEffect(() => {
189
96
  if (!open) return;
190
97
  setRemembered(recents ? store.list() : []);
@@ -319,11 +226,22 @@ function PaletteTrigger({ asChild = false, children, onClick, ...props }) {
319
226
  }
320
227
  );
321
228
  }
322
- function PaletteContent({ title = "Search", portal = true, overlayProps, children, ...props }) {
229
+ function PaletteContent({ title = "Search", portal = true, overlayProps, closeDuration = 160, children, ...props }) {
323
230
  const palette = usePaletteContext("SearchPalette.Content");
324
231
  const panelRef = useRef(null);
325
232
  const [mounted, setMounted] = useState(false);
233
+ const [present, setPresent] = useState(palette.open);
326
234
  useEffect(() => setMounted(true), []);
235
+ useEffect(() => {
236
+ if (palette.open) {
237
+ setPresent(true);
238
+ return;
239
+ }
240
+ if (!present) return;
241
+ const reduced = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
242
+ const timer = setTimeout(() => setPresent(false), reduced ? 0 : closeDuration);
243
+ return () => clearTimeout(timer);
244
+ }, [palette.open, present, closeDuration]);
327
245
  useEffect(() => {
328
246
  if (!palette.open || typeof document === "undefined") return;
329
247
  const previous = document.activeElement;
@@ -362,13 +280,14 @@ function PaletteContent({ title = "Search", portal = true, overlayProps, childre
362
280
  (palette.triggerRef.current ?? previous)?.focus?.();
363
281
  };
364
282
  }, [palette.open, palette.setOpen, palette.triggerRef]);
365
- if (!palette.open) return null;
366
- const panel = /* @__PURE__ */ jsxs("div", { "data-enigma-palette-portal": "", children: [
283
+ if (!present) return null;
284
+ const panel = /* @__PURE__ */ jsxs("div", { "data-enigma-palette-portal": "", "data-state": palette.open ? "open" : "closed", children: [
367
285
  overlayProps !== null && /* @__PURE__ */ jsx(
368
286
  "div",
369
287
  {
370
288
  ...overlayProps,
371
289
  "data-enigma-palette-overlay": "",
290
+ "data-state": palette.open ? "open" : "closed",
372
291
  onClick: (event) => {
373
292
  overlayProps?.onClick?.(event);
374
293
  if (!event.defaultPrevented) palette.setOpen(false);
@@ -384,6 +303,7 @@ function PaletteContent({ title = "Search", portal = true, overlayProps, childre
384
303
  "aria-modal": "true",
385
304
  "aria-labelledby": palette.ids.title,
386
305
  "data-enigma-palette-content": "",
306
+ "data-state": palette.open ? "open" : "closed",
387
307
  children: [
388
308
  /* @__PURE__ */ jsx("h2", { id: palette.ids.title, "data-enigma-palette-title": "", children: title }),
389
309
  children
@@ -539,4 +459,4 @@ SearchPalette.List = PaletteList;
539
459
  SearchPalette.Item = PaletteItem;
540
460
  SearchPalette.Footer = PaletteFooter;
541
461
 
542
- export { PaletteContent, PaletteField, PaletteFooter, PaletteItem, PaletteList, PaletteRoot, PaletteTrigger, SearchPalette, createRecentStore, groupRows, isPaletteShortcut, moveActive, recentKey, shortcutLabel, usePaletteContext };
462
+ export { PaletteContent, PaletteField, PaletteFooter, PaletteItem, PaletteList, PaletteRoot, PaletteTrigger, SearchPalette, usePaletteContext };
@@ -1,4 +1,4 @@
1
- import { createSearch } from './chunk-UZFEEFMF.js';
1
+ import { createSearch } from './chunk-D5A2ZMAG.js';
2
2
  import { useRef, useState, useMemo, useEffect } from 'react';
3
3
 
4
4
  function useSearch(options = {}) {
@@ -25,7 +25,7 @@ function writeValue(input, next) {
25
25
  input.dispatchEvent(new Event("input", { bubbles: true }));
26
26
  }
27
27
  var PasswordExtras = lazy(() => import('./password-3DRQYAYQ.js').then((module) => ({ default: module.PasswordExtras })));
28
- var SearchExtras = lazy(() => import('./search-P4OHCRXD.js').then((module) => ({ default: module.SearchExtras })));
28
+ var SearchExtras = lazy(() => import('./search-UQEXAPQB.js').then((module) => ({ default: module.SearchExtras })));
29
29
  var Input = forwardRef(function Input2(props, forwardedRef) {
30
30
  const {
31
31
  reveal,
@@ -1,5 +1,5 @@
1
1
  import { ReactNode, ComponentPropsWithoutRef } from 'react';
2
- import { c as SearchOptions, F as FuseConstructor, b as SearchMatch } from './search-CsO3L1Lw.js';
2
+ import { c as SearchOptions, F as FuseConstructor, b as SearchMatch } from './search-DXxY8SEH.js';
3
3
  import { G as GeneratePasswordOptions, E as EstimateOptions, b as PasswordStrengthReport } from './password-C8lG4Zm9.js';
4
4
 
5
5
  /**
package/dist/index.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  export { M as MarqueeHover, a as MarqueeInstance, b as MarqueeOptions, c as createMarquee } from './marquee-CJ3Uwy3E.js';
2
2
  export { I as InputAction, a as InputActionState, b as InputIcon, c as InputInstance, d as InputOptions, e as createInput } from './input-BwXjFenq.js';
3
- export { F as FuseConstructor, a as FuseLike, S as SearchInstance, b as SearchMatch, c as SearchOptions, d as createSearch } from './search-CsO3L1Lw.js';
3
+ export { F as FuseConstructor, a as FuseLike, S as SearchInstance, b as SearchMatch, c as SearchOptions, d as createSearch, s as subsequenceMatcher } from './search-DXxY8SEH.js';
4
4
  export { B as ButtonCooldown, a as ButtonElement, b as ButtonInstance, c as ButtonOptions, d as ButtonState, e as createButton } from './button-CaXaqG_K.js';
5
5
  export { E as EstimateOptions, G as GeneratePasswordOptions, P as PasswordAlphabet, a as PasswordScore, b as PasswordStrengthReport, e as estimatePasswordStrength, g as generatePassword } from './password-C8lG4Zm9.js';
6
6
  export { N as Notification, a as NotificationAction, b as NotificationInput, c as NotificationTone, d as Notifications, e as NotificationsOptions, P as PromiseMessages, f as createNotifications } from './notifications-BpVV6sel.js';
7
7
  export { N as NetworkMonitor, a as NetworkState, S as SERVER_NETWORK_STATE, c as createNetworkMonitor } from './network-D2LsBG_k.js';
8
8
  export { R as RelativeTimeFormat, a as RelativeTimeOptions, b as RelativeTimePrecision, c as RelativeTimeStyle, d as RelativeTimeTense, e as RelativeTimeView, f as ensureZone, n as normalizeDate, p as parseDuration, r as relativeTimeAttributes, g as relativeTimeView } from './relative-time-YpRTG7YH.js';
9
9
  export { F as FLAG_CDN, a as FLAG_RATIO, b as FlagConfig, c as FlagFormat, d as FlagOptions, e as FlagShape, f as FlagSource, g as FlagView, h as configureFlags, i as flagAttributes, j as flagConfig, k as flagName, l as flagSrc, m as flagView, n as normalizeFlagCode, r as resetFlagConfig } from './flags-BBJc9unY.js';
10
+ export { P as PaletteKey, a as PositionedRow, R as RecentEntry, b as RecentStore, c as RecentStoreOptions, d as RowGroup, e as createRecentStore, g as groupRows, i as isPaletteShortcut, m as moveActive, r as recentKey, s as shortcutLabel } from './palette-D7iuQh_T.js';
10
11
 
11
12
  /**
12
13
  * The icon shapes both renderers draw.
package/dist/index.js CHANGED
@@ -6,5 +6,6 @@ export { SERVER_NETWORK_STATE, createNetworkMonitor } from './chunk-2QFTRNAZ.js'
6
6
  export { createNotifications } from './chunk-SNYUBXWQ.js';
7
7
  export { ensureZone, normalizeDate, parseDuration, relativeTimeAttributes, relativeTimeView } from './chunk-IXVMRVD4.js';
8
8
  export { INPUT_ICON_PATHS, iconMarkup } from './chunk-F25CGNQC.js';
9
- export { createSearch } from './chunk-UZFEEFMF.js';
9
+ export { createRecentStore, groupRows, isPaletteShortcut, moveActive, recentKey, shortcutLabel } from './chunk-DTWZDONY.js';
10
+ export { createSearch, subsequenceMatcher } from './chunk-D5A2ZMAG.js';
10
11
  export { createButton } from './chunk-MMQPZGSU.js';
@@ -5,9 +5,9 @@ export { M as MarqueeHover, a as MarqueeInstance, b as MarqueeOptions } from '..
5
5
  export { PasswordStrength, PasswordStrengthProps, UseButtonResult, UseInputResult, getLinkComponent, setLinkComponent, useButton, useInput } from '../react/index.js';
6
6
  export { UseSearchResult, useSearch } from '../react/search.js';
7
7
  export { I as InputAction, b as InputIcon, d as InputOptions } from '../input-BwXjFenq.js';
8
- export { F as FuseConstructor, b as SearchMatch, c as SearchOptions } from '../search-CsO3L1Lw.js';
8
+ export { F as FuseConstructor, a as FuseLike, S as SearchInstance, b as SearchMatch, c as SearchOptions } from '../search-DXxY8SEH.js';
9
9
  export { c as ButtonOptions, d as ButtonState } from '../button-CaXaqG_K.js';
10
- export { B as BreachChecker, a as BreachState, b as BreachStatus, F as FieldAction, I as Input, c as InputBaseProps, d as InputProps, e as InputType, P as PasswordOnlyProps, g as PlainOnlyProps, S as SearchOnlyProps } from '../index-DNXPtY9X.js';
10
+ export { B as BreachChecker, a as BreachState, b as BreachStatus, F as FieldAction, I as Input, c as InputBaseProps, d as InputProps, e as InputType, P as PasswordOnlyProps, g as PlainOnlyProps, S as SearchOnlyProps } from '../index-dTdAbOWl.js';
11
11
  export { Slot, SlotProps, mergeSlotProps } from '../react/slot.js';
12
12
  export { E as EstimateOptions, G as GeneratePasswordOptions, a as PasswordScore, b as PasswordStrengthReport, e as estimatePasswordStrength, g as generatePassword } from '../password-C8lG4Zm9.js';
13
13
  export { UseNotificationsResult, createNotificationQueue, defaultQueue, useNotifications } from '../react/notifications.js';
@@ -15,11 +15,12 @@ export { ToastControls, ToastPosition, Toaster, ToasterProps } from '../react/to
15
15
  export { useNetworkState } from '../react/network.js';
16
16
  export { a as NetworkState } from '../network-D2LsBG_k.js';
17
17
  export { RelativeTime, RelativeTimeProps } from '../react/relative-time.js';
18
+ export { R as RelativeTimeFormat, a as RelativeTimeOptions, b as RelativeTimePrecision, c as RelativeTimeStyle, d as RelativeTimeTense } from '../relative-time-YpRTG7YH.js';
19
+ export { N as Notification, a as NotificationAction, b as NotificationInput, c as NotificationTone, e as NotificationsOptions } from '../notifications-BpVV6sel.js';
18
20
  export { Flag, FlagProps } from '../react/flag.js';
19
21
  export { c as FlagFormat, d as FlagOptions, e as FlagShape, f as FlagSource, h as configureFlags, i as flagAttributes, k as flagName, l as flagSrc, m as flagView, n as normalizeFlagCode } from '../flags-BBJc9unY.js';
20
- export { P as PaletteContent, a as PaletteContextValue, b as PaletteField, c as PaletteFooter, d as PaletteItem, e as PaletteList, f as PaletteListProps, g as PaletteRoot, h as PaletteRootProps, i as PaletteRow, j as PaletteSection, k as PaletteTrigger, R as RecentEntry, l as RecentStore, S as SearchPalette, m as SearchPaletteProps, n as createRecentStore, o as groupRows, p as isPaletteShortcut, q as moveActive, r as recentKey, s as shortcutLabel, u as usePaletteContext } from '../index-D-ARvWpQ.js';
21
- import '../notifications-BpVV6sel.js';
22
- import '../relative-time-YpRTG7YH.js';
22
+ export { PaletteContent, PaletteContextValue, PaletteField, PaletteFooter, PaletteItem, PaletteList, PaletteListProps, PaletteRoot, PaletteRootProps, PaletteRow, PaletteSection, PaletteTrigger, SearchPalette, SearchPaletteProps, usePaletteContext } from '../react/palette.js';
23
+ export { R as RecentEntry, b as RecentStore, e as createRecentStore, g as groupRows, i as isPaletteShortcut, m as moveActive, r as recentKey, s as shortcutLabel } from '../palette-D7iuQh_T.js';
23
24
 
24
25
  /**
25
26
  * The Next.js entry. Same components, wired to `next/link`.
@@ -4,7 +4,7 @@ export { PasswordStrength } from '../chunk-XQHCZAPJ.js';
4
4
  export { Flag } from '../chunk-XNNQRA35.js';
5
5
  export { Toaster } from '../chunk-ZCUFYBPB.js';
6
6
  export { useMarquee } from '../chunk-ZWR2EXHQ.js';
7
- export { useSearch } from '../chunk-WSB655JB.js';
7
+ export { useSearch } from '../chunk-QQFNAKMY.js';
8
8
  export { useNetworkState } from '../chunk-S653GLSF.js';
9
9
  export { createNotificationQueue, defaultQueue, useNotifications } from '../chunk-QYMUIW5I.js';
10
10
  export { RelativeTime } from '../chunk-OCMI7R6H.js';
@@ -15,10 +15,11 @@ import '../chunk-UOSSNUSC.js';
15
15
  import '../chunk-2QFTRNAZ.js';
16
16
  import '../chunk-SNYUBXWQ.js';
17
17
  import '../chunk-IXVMRVD4.js';
18
- export { Input } from '../chunk-IIT6U7LM.js';
18
+ export { Input } from '../chunk-R4ZAEE7V.js';
19
19
  import '../chunk-F25CGNQC.js';
20
- export { PaletteContent, PaletteField, PaletteFooter, PaletteItem, PaletteList, PaletteRoot, PaletteTrigger, SearchPalette, createRecentStore, groupRows, isPaletteShortcut, moveActive, recentKey, shortcutLabel, usePaletteContext } from '../chunk-LKA2UG4P.js';
21
- import '../chunk-UZFEEFMF.js';
20
+ export { PaletteContent, PaletteField, PaletteFooter, PaletteItem, PaletteList, PaletteRoot, PaletteTrigger, SearchPalette, usePaletteContext } from '../chunk-FWVWX67R.js';
21
+ export { createRecentStore, groupRows, isPaletteShortcut, moveActive, recentKey, shortcutLabel } from '../chunk-DTWZDONY.js';
22
+ import '../chunk-D5A2ZMAG.js';
22
23
  import { Button } from '../chunk-6BGBYUSZ.js';
23
24
  export { getLinkComponent, setLinkComponent, useButton } from '../chunk-6BGBYUSZ.js';
24
25
  import '../chunk-MMQPZGSU.js';
@@ -0,0 +1,86 @@
1
+ /**
2
+ * The parts of a command palette that are not rendering: what was searched before, how a
3
+ * flat list becomes groups, and where the highlight goes when a key is pressed.
4
+ *
5
+ * Pure functions and one storage wrapper, so all three are testable without a browser and
6
+ * reusable by a renderer that is not React. The palette's React parts are a thin layer over
7
+ * this file.
8
+ */
9
+ interface RecentEntry {
10
+ /** What was typed. The palette puts it back in the field when the row is chosen. */
11
+ term: string;
12
+ /** A result that was opened, rather than a query that was run. */
13
+ label?: string;
14
+ /** Where that result was. */
15
+ href?: string;
16
+ /** Which scope it was searched in, when the palette has scopes. */
17
+ scope?: string | null;
18
+ /** Epoch ms. Used only for ordering. */
19
+ at: number;
20
+ }
21
+ interface RecentStoreOptions {
22
+ /** Storage key. One per palette, so two palettes on a site do not share a history. */
23
+ key?: string;
24
+ /** How many entries to keep. */
25
+ limit?: number;
26
+ /** `local` outlives the tab, `session` does not. Default local. */
27
+ storage?: "local" | "session";
28
+ }
29
+ interface RecentStore {
30
+ list(): RecentEntry[];
31
+ remember(entry: Omit<RecentEntry, "at"> & {
32
+ at?: number;
33
+ }): RecentEntry[];
34
+ forget(entry: RecentEntry): RecentEntry[];
35
+ clear(): void;
36
+ }
37
+ /** Two entries are the same memory when they point at the same thing in the same scope. */
38
+ declare function recentKey(entry: Pick<RecentEntry, "term" | "href" | "scope">): string;
39
+ /**
40
+ * What was searched before, in this browser.
41
+ *
42
+ * Every read and write is guarded: storage throws in a private window, when the quota is
43
+ * full, and whenever a page is opened from a file URL - and a palette that cannot remember
44
+ * is still a working palette, so none of that is allowed to reach the renderer. Reads also
45
+ * survive a corrupted value, because the key is shared with whatever else the site stores.
46
+ */
47
+ declare function createRecentStore(options?: RecentStoreOptions): RecentStore;
48
+ /** A row after grouping: its own index in the FLAT list is what the keyboard moves through. */
49
+ interface PositionedRow<Row> {
50
+ row: Row;
51
+ position: number;
52
+ }
53
+ interface RowGroup<Row> {
54
+ label: string;
55
+ rows: PositionedRow<Row>[];
56
+ }
57
+ /**
58
+ * Group a flat list while keeping every row's flat position.
59
+ *
60
+ * The flat position is the whole point: the highlight moves through ONE sequence, so a
61
+ * group boundary is invisible to the arrow keys - and a renderer that grouped rows into
62
+ * separate arrays would have to reconstruct that sequence, which is where an off-by-one
63
+ * makes Enter open the row above the highlighted one. Groups keep first-seen order.
64
+ */
65
+ declare function groupRows<Row>(rows: Row[], labelOf: (row: Row) => string): RowGroup<Row>[];
66
+ /** Keys the list responds to. Anything else belongs to the field. */
67
+ type PaletteKey = "ArrowDown" | "ArrowUp" | "Home" | "End" | "PageDown" | "PageUp";
68
+ /**
69
+ * Where the highlight lands.
70
+ *
71
+ * It WRAPS, because a palette is a short list and the row after the last one is the first:
72
+ * clamping instead leaves the arrow key doing nothing at the end, which reads as the panel
73
+ * having frozen. An empty list stays at 0 rather than going negative.
74
+ */
75
+ declare function moveActive(current: number, length: number, key: PaletteKey, page?: number): number;
76
+ /**
77
+ * The shortcut label for this platform: `Cmd K` on a Mac, `Ctrl K` everywhere else.
78
+ *
79
+ * Read from the platform rather than hardcoded, because the wrong modifier in the trigger
80
+ * is a hint that actively misleads - and it is the first thing anyone tries.
81
+ */
82
+ declare function shortcutLabel(key?: string): string;
83
+ /** Whether an event is the palette's open shortcut. Meta on a Mac, Control elsewhere. */
84
+ declare function isPaletteShortcut(event: KeyboardEvent, key?: string): boolean;
85
+
86
+ export { type PaletteKey as P, type RecentEntry as R, type PositionedRow as a, type RecentStore as b, type RecentStoreOptions as c, type RowGroup as d, createRecentStore as e, groupRows as g, isPaletteShortcut as i, moveActive as m, recentKey as r, shortcutLabel as s };
@@ -4,11 +4,11 @@ import { d as InputOptions } from '../input-BwXjFenq.js';
4
4
  export { I as InputAction, b as InputIcon } from '../input-BwXjFenq.js';
5
5
  import { RefObject, ElementType, ComponentPropsWithoutRef, ReactNode } from 'react';
6
6
  export { UseSearchResult, useSearch } from './search.js';
7
- export { F as FuseConstructor, b as SearchMatch, c as SearchOptions } from '../search-CsO3L1Lw.js';
7
+ export { F as FuseConstructor, a as FuseLike, S as SearchInstance, b as SearchMatch, c as SearchOptions } from '../search-DXxY8SEH.js';
8
8
  import { d as ButtonState, c as ButtonOptions } from '../button-CaXaqG_K.js';
9
9
  export { Button, ButtonProps } from './button.js';
10
- import { f as PasswordStrengthClassNames } from '../index-DNXPtY9X.js';
11
- export { B as BreachChecker, a as BreachState, b as BreachStatus, F as FieldAction, I as Input, c as InputBaseProps, d as InputProps, e as InputType, P as PasswordOnlyProps, g as PlainOnlyProps, S as SearchOnlyProps } from '../index-DNXPtY9X.js';
10
+ import { f as PasswordStrengthClassNames } from '../index-dTdAbOWl.js';
11
+ export { B as BreachChecker, a as BreachState, b as BreachStatus, F as FieldAction, I as Input, c as InputBaseProps, d as InputProps, e as InputType, P as PasswordOnlyProps, g as PlainOnlyProps, S as SearchOnlyProps } from '../index-dTdAbOWl.js';
12
12
  import { b as PasswordStrengthReport } from '../password-C8lG4Zm9.js';
13
13
  export { E as EstimateOptions, G as GeneratePasswordOptions, a as PasswordScore, e as estimatePasswordStrength, g as generatePassword } from '../password-C8lG4Zm9.js';
14
14
  export { Slot, SlotProps, mergeSlotProps } from './slot.js';
@@ -17,11 +17,12 @@ export { ToastControls, ToastPosition, Toaster, ToasterProps } from './toast.js'
17
17
  export { useNetworkState } from './network.js';
18
18
  export { a as NetworkState } from '../network-D2LsBG_k.js';
19
19
  export { RelativeTime, RelativeTimeProps } from './relative-time.js';
20
+ export { R as RelativeTimeFormat, a as RelativeTimeOptions, b as RelativeTimePrecision, c as RelativeTimeStyle, d as RelativeTimeTense } from '../relative-time-YpRTG7YH.js';
21
+ export { N as Notification, a as NotificationAction, b as NotificationInput, c as NotificationTone, e as NotificationsOptions } from '../notifications-BpVV6sel.js';
20
22
  export { Flag, FlagProps } from './flag.js';
21
23
  export { c as FlagFormat, d as FlagOptions, e as FlagShape, f as FlagSource, h as configureFlags, i as flagAttributes, k as flagName, l as flagSrc, m as flagView, n as normalizeFlagCode } from '../flags-BBJc9unY.js';
22
- export { P as PaletteContent, a as PaletteContextValue, b as PaletteField, c as PaletteFooter, d as PaletteItem, e as PaletteList, f as PaletteListProps, g as PaletteRoot, h as PaletteRootProps, i as PaletteRow, j as PaletteSection, k as PaletteTrigger, R as RecentEntry, l as RecentStore, S as SearchPalette, m as SearchPaletteProps, n as createRecentStore, o as groupRows, p as isPaletteShortcut, q as moveActive, r as recentKey, s as shortcutLabel, u as usePaletteContext } from '../index-D-ARvWpQ.js';
23
- import '../notifications-BpVV6sel.js';
24
- import '../relative-time-YpRTG7YH.js';
24
+ export { PaletteContent, PaletteContextValue, PaletteField, PaletteFooter, PaletteItem, PaletteList, PaletteListProps, PaletteRoot, PaletteRootProps, PaletteRow, PaletteSection, PaletteTrigger, SearchPalette, SearchPaletteProps, usePaletteContext } from './palette.js';
25
+ export { R as RecentEntry, b as RecentStore, e as createRecentStore, g as groupRows, i as isPaletteShortcut, m as moveActive, r as recentKey, s as shortcutLabel } from '../palette-D7iuQh_T.js';
25
26
 
26
27
  interface UseInputResult {
27
28
  /** Attach to the `<input>`. */
@@ -4,7 +4,7 @@ export { PasswordStrength } from '../chunk-XQHCZAPJ.js';
4
4
  export { Flag } from '../chunk-XNNQRA35.js';
5
5
  export { Toaster } from '../chunk-ZCUFYBPB.js';
6
6
  export { useMarquee } from '../chunk-ZWR2EXHQ.js';
7
- export { useSearch } from '../chunk-WSB655JB.js';
7
+ export { useSearch } from '../chunk-QQFNAKMY.js';
8
8
  export { useNetworkState } from '../chunk-S653GLSF.js';
9
9
  export { createNotificationQueue, defaultQueue, useNotifications } from '../chunk-QYMUIW5I.js';
10
10
  export { RelativeTime } from '../chunk-OCMI7R6H.js';
@@ -15,10 +15,11 @@ import '../chunk-UOSSNUSC.js';
15
15
  import '../chunk-2QFTRNAZ.js';
16
16
  import '../chunk-SNYUBXWQ.js';
17
17
  import '../chunk-IXVMRVD4.js';
18
- export { Input } from '../chunk-IIT6U7LM.js';
18
+ export { Input } from '../chunk-R4ZAEE7V.js';
19
19
  import '../chunk-F25CGNQC.js';
20
- export { PaletteContent, PaletteField, PaletteFooter, PaletteItem, PaletteList, PaletteRoot, PaletteTrigger, SearchPalette, createRecentStore, groupRows, isPaletteShortcut, moveActive, recentKey, shortcutLabel, usePaletteContext } from '../chunk-LKA2UG4P.js';
21
- import '../chunk-UZFEEFMF.js';
20
+ export { PaletteContent, PaletteField, PaletteFooter, PaletteItem, PaletteList, PaletteRoot, PaletteTrigger, SearchPalette, usePaletteContext } from '../chunk-FWVWX67R.js';
21
+ export { createRecentStore, groupRows, isPaletteShortcut, moveActive, recentKey, shortcutLabel } from '../chunk-DTWZDONY.js';
22
+ import '../chunk-D5A2ZMAG.js';
22
23
  export { Button, getLinkComponent, setLinkComponent, useButton } from '../chunk-6BGBYUSZ.js';
23
24
  import '../chunk-MMQPZGSU.js';
24
25
  export { Slot, mergeSlotProps } from '../chunk-HS3X3XCW.js';
@@ -1,4 +1,4 @@
1
- export { B as BreachChecker, a as BreachState, b as BreachStatus, F as FieldAction, I as Input, c as InputBaseProps, d as InputProps, e as InputType, P as PasswordOnlyProps, g as PlainOnlyProps, S as SearchOnlyProps } from '../index-DNXPtY9X.js';
1
+ export { B as BreachChecker, a as BreachState, b as BreachStatus, F as FieldAction, I as Input, c as InputBaseProps, d as InputProps, e as InputType, P as PasswordOnlyProps, g as PlainOnlyProps, S as SearchOnlyProps } from '../index-dTdAbOWl.js';
2
2
  import 'react';
3
- import '../search-CsO3L1Lw.js';
3
+ import '../search-DXxY8SEH.js';
4
4
  import '../password-C8lG4Zm9.js';
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- export { Input } from '../chunk-IIT6U7LM.js';
2
+ export { Input } from '../chunk-R4ZAEE7V.js';
3
3
  import '../chunk-F25CGNQC.js';