@particle-academy/react-fancy 5.41.1 → 5.42.1

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/button.cjs +3 -3
  3. package/dist/button.js +1 -1
  4. package/dist/{chunk-H6WSJL2X.js → chunk-D354R6T6.js} +62 -14
  5. package/dist/chunk-D354R6T6.js.map +1 -0
  6. package/dist/{chunk-FQLL2JI7.js → chunk-G4WYCWIQ.js} +3 -3
  7. package/dist/{chunk-FQLL2JI7.js.map → chunk-G4WYCWIQ.js.map} +1 -1
  8. package/dist/{chunk-RMJGF7MN.cjs → chunk-ICQJ6475.cjs} +7 -6
  9. package/dist/chunk-ICQJ6475.cjs.map +1 -0
  10. package/dist/{chunk-46IPQEUP.js → chunk-JJRD3WX3.js} +7 -6
  11. package/dist/chunk-JJRD3WX3.js.map +1 -0
  12. package/dist/{chunk-DCDW3LW6.js → chunk-JVGJHIIQ.js} +3 -3
  13. package/dist/{chunk-DCDW3LW6.js.map → chunk-JVGJHIIQ.js.map} +1 -1
  14. package/dist/{chunk-IWQ3ZFLZ.cjs → chunk-K4NHVCY6.cjs} +15 -15
  15. package/dist/{chunk-IWQ3ZFLZ.cjs.map → chunk-K4NHVCY6.cjs.map} +1 -1
  16. package/dist/{chunk-MTUH2X3W.cjs → chunk-MQ4ULIOU.cjs} +4 -4
  17. package/dist/{chunk-MTUH2X3W.cjs.map → chunk-MQ4ULIOU.cjs.map} +1 -1
  18. package/dist/{chunk-5Q7EQQTT.cjs → chunk-MRARASNZ.cjs} +4 -4
  19. package/dist/{chunk-5Q7EQQTT.cjs.map → chunk-MRARASNZ.cjs.map} +1 -1
  20. package/dist/{chunk-2OMB3OOR.js → chunk-P7WMYJ5I.js} +3 -3
  21. package/dist/{chunk-2OMB3OOR.js.map → chunk-P7WMYJ5I.js.map} +1 -1
  22. package/dist/{chunk-YLPVTEUH.js → chunk-SF5OAVGD.js} +3 -3
  23. package/dist/{chunk-YLPVTEUH.js.map → chunk-SF5OAVGD.js.map} +1 -1
  24. package/dist/{chunk-FJ2GMQLC.cjs → chunk-UUBHUSUP.cjs} +6 -6
  25. package/dist/{chunk-FJ2GMQLC.cjs.map → chunk-UUBHUSUP.cjs.map} +1 -1
  26. package/dist/{chunk-35TZQIIN.cjs → chunk-W7IP6RT3.cjs} +61 -13
  27. package/dist/chunk-W7IP6RT3.cjs.map +1 -0
  28. package/dist/command.cjs +3 -3
  29. package/dist/command.d.cts +2 -0
  30. package/dist/command.d.ts +2 -0
  31. package/dist/command.js +1 -1
  32. package/dist/index.cjs +28 -28
  33. package/dist/index.js +6 -6
  34. package/dist/json-editor.cjs +13 -13
  35. package/dist/json-editor.js +2 -2
  36. package/dist/magic-wand.cjs +3 -3
  37. package/dist/magic-wand.js +2 -2
  38. package/dist/prompt-input.cjs +3 -3
  39. package/dist/prompt-input.js +2 -2
  40. package/dist/reason-tag.cjs +3 -3
  41. package/dist/reason-tag.js +2 -2
  42. package/package.json +1 -1
  43. package/dist/chunk-35TZQIIN.cjs.map +0 -1
  44. package/dist/chunk-46IPQEUP.js.map +0 -1
  45. package/dist/chunk-H6WSJL2X.js.map +0 -1
  46. package/dist/chunk-RMJGF7MN.cjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -11,6 +11,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [5.42.1] - 2026-10-17
15
+
16
+ ### Fixed
17
+
18
+ - **A filled `Button`'s icon and badge now take the label's colour** (react-fancy#34,
19
+ from the MOIC estate). They were hard-coded `text-white`, so on
20
+ `color="brand"` with a host's per-mode pair (pale blue `#BFD7EA` with navy
21
+ `#003057` contrast) the label turned navy and the icon stayed WHITE on pale
22
+ blue — nearly invisible. The same bug hit **every host** on `amber`, `yellow`
23
+ and `lime`, whose labels are dark: white icons on yellow. The icon is now
24
+ `text-current` and the badge `bg-current/20 text-current`, following the
25
+ colour's own text class. White-label colours (`blue`, `red`, …) look exactly
26
+ as before.
27
+ - **A `badge` or `avatar` no longer renders twice.** With `badgeTrailing` /
28
+ `avatarTrailing` unset, the check `badgeTrailing ?? trailing` was true in BOTH
29
+ the leading and trailing passes, so every badge appeared before and after the
30
+ label. They now render once, leading unless the `…Trailing` prop says
31
+ otherwise, as the docs and `alertIconTrailing` already had it.
32
+
33
+ ### Added
34
+
35
+ - `data-action-icon` (`leading` / `trailing`) on a Button's icon wrapper, beside
36
+ the existing `data-action-badge` / `data-action-avatar` handles.
37
+
38
+ **What you must DO: nothing.** If you had added a `className` to force a dark
39
+ icon onto a light-filled button, you can remove it; if you had hidden one of
40
+ the two duplicate badges with CSS, remove that too.
41
+
42
+ ## [5.42.0] - 2026-10-17
43
+
44
+ ### Fixed
45
+
46
+ - **Enter in `Command.Input` now picks an item**: the active one, or the first
47
+ visible one when none is active. Before, typing a query and pressing Enter did
48
+ nothing — `Command` handled no Enter, and only a *focused* item took it, as a
49
+ native click. Found by Genie 2's real-window test.
50
+
51
+ ### Changed
52
+
53
+ - **`Command` is a proper combobox: focus stays in the input.** ArrowUp/Down move
54
+ the *active* item (marked `aria-selected="true"` and `data-active`, scrolled into
55
+ view, highlighted) and the input announces it through `aria-activedescendant`;
56
+ the input is `role="combobox"` with `aria-controls` pointing at the list. Typing
57
+ resets the active item, so Enter picks the new first match. Hovering an item
58
+ makes it active.
59
+
60
+ **Visible change:** the arrows used to move keyboard focus onto the item buttons,
61
+ and items were in the Tab order; now focus stays in the input and items are
62
+ `tabIndex={-1}`. **What you must DO: nothing**, unless you styled
63
+ `:focus` on `Command.Item` to show the highlighted row — style `[data-active]`
64
+ (or `aria-selected="true"`) instead.
65
+
14
66
  ## [5.41.1] - 2026-10-17
15
67
 
16
68
  ### Fixed
package/dist/button.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  require('./chunk-M5MUGSON.cjs');
4
- var chunkRMJGF7MN_cjs = require('./chunk-RMJGF7MN.cjs');
4
+ var chunkICQJ6475_cjs = require('./chunk-ICQJ6475.cjs');
5
5
  require('./chunk-BFKCVSNK.cjs');
6
6
  require('./chunk-XCZZVRBY.cjs');
7
7
  require('./chunk-QKFOJKVE.cjs');
@@ -11,11 +11,11 @@ require('./chunk-ZU5Q77OT.cjs');
11
11
 
12
12
  Object.defineProperty(exports, "Action", {
13
13
  enumerable: true,
14
- get: function () { return chunkRMJGF7MN_cjs.Action; }
14
+ get: function () { return chunkICQJ6475_cjs.Action; }
15
15
  });
16
16
  Object.defineProperty(exports, "Button", {
17
17
  enumerable: true,
18
- get: function () { return chunkRMJGF7MN_cjs.Button; }
18
+ get: function () { return chunkICQJ6475_cjs.Button; }
19
19
  });
20
20
  //# sourceMappingURL=button.cjs.map
21
21
  //# sourceMappingURL=button.cjs.map
package/dist/button.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import './chunk-LQ4ICCN2.js';
2
- export { Action, Button } from './chunk-46IPQEUP.js';
2
+ export { Action, Button } from './chunk-JJRD3WX3.js';
3
3
  import './chunk-XJXQG34J.js';
4
4
  import './chunk-45BBNJQD.js';
5
5
  import './chunk-IVRYSSM7.js';
@@ -4,7 +4,7 @@ import { Portal } from './chunk-WHEXTDPV.js';
4
4
  import { useEscapeKey } from './chunk-JXE5XID6.js';
5
5
  import { useControllableState } from './chunk-EDYAXGUM.js';
6
6
  import { cn } from './chunk-MMW2JGKZ.js';
7
- import { createContext, useState, useRef, useCallback, useEffect, useMemo, useContext } from 'react';
7
+ import { createContext, useState, useRef, useId, useCallback, useEffect, useLayoutEffect, useMemo, useContext } from 'react';
8
8
  import { Search } from 'lucide-react';
9
9
  import { jsx, jsxs } from 'react/jsx-runtime';
10
10
 
@@ -22,13 +22,17 @@ function CommandInput({
22
22
  placeholder = "Type a command or search...",
23
23
  className
24
24
  }) {
25
- const { query, setQuery } = useCommand();
25
+ const { query, setQuery, listId } = useCommand();
26
26
  return /* @__PURE__ */ jsxs("div", { "data-react-fancy-command-input": "", className: "flex items-center border-b border-zinc-200 px-4 dark:border-zinc-700", children: [
27
27
  /* @__PURE__ */ jsx(Search, { size: 16, className: "shrink-0 text-zinc-400" }),
28
28
  /* @__PURE__ */ jsx(
29
29
  "input",
30
30
  {
31
31
  type: "text",
32
+ role: "combobox",
33
+ "aria-expanded": "true",
34
+ "aria-controls": listId,
35
+ "aria-autocomplete": "list",
32
36
  value: query,
33
37
  onChange: (e) => setQuery(e.target.value),
34
38
  placeholder,
@@ -43,9 +47,11 @@ function CommandInput({
43
47
  }
44
48
  CommandInput.displayName = "CommandInput";
45
49
  function CommandList({ children, className }) {
50
+ const { listId } = useCommand();
46
51
  return /* @__PURE__ */ jsx(
47
52
  "div",
48
53
  {
54
+ id: listId,
49
55
  "data-react-fancy-command-list": "",
50
56
  role: "listbox",
51
57
  className: cn("max-h-72 overflow-y-auto p-2", className),
@@ -60,7 +66,8 @@ function CommandItem({
60
66
  onSelect,
61
67
  className
62
68
  }) {
63
- const { query, close, shouldFilter } = useCommand();
69
+ const { query, close, shouldFilter, setActiveIndex } = useCommand();
70
+ const id = useId();
64
71
  const text = value ?? (typeof children === "string" ? children : "");
65
72
  if (shouldFilter && query && !text.toLowerCase().includes(query.toLowerCase())) {
66
73
  return null;
@@ -68,12 +75,19 @@ function CommandItem({
68
75
  return /* @__PURE__ */ jsx(
69
76
  "button",
70
77
  {
78
+ id,
71
79
  "data-react-fancy-command-item": "",
72
80
  type: "button",
73
81
  role: "option",
82
+ "aria-selected": false,
83
+ tabIndex: -1,
84
+ onMouseEnter: (e) => {
85
+ const options = e.currentTarget.closest("[data-react-fancy-command]")?.querySelectorAll('[role="option"]');
86
+ if (options) setActiveIndex(Array.from(options).indexOf(e.currentTarget));
87
+ },
74
88
  className: cn(
75
89
  "flex w-full items-center rounded-lg px-3 py-2 text-left text-sm transition-colors",
76
- "text-zinc-700 hover:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800",
90
+ "text-zinc-700 hover:bg-zinc-100 data-[active]:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800 dark:data-[active]:bg-zinc-800",
77
91
  className
78
92
  ),
79
93
  onClick: () => {
@@ -125,6 +139,7 @@ function CommandRoot({
125
139
  const [query, setQuery] = useControllableState(controlledQuery, "", onQueryChange);
126
140
  const [activeIndex, setActiveIndex] = useState(-1);
127
141
  const panelRef = useRef(null);
142
+ const listId = useId();
128
143
  const close = useCallback(() => {
129
144
  onClose();
130
145
  setQuery("");
@@ -150,27 +165,60 @@ function CommandRoot({
150
165
  if (!items?.length) return;
151
166
  if (e.key === "ArrowDown") {
152
167
  e.preventDefault();
153
- const next = activeIndex < items.length - 1 ? activeIndex + 1 : 0;
154
- setActiveIndex(next);
155
- items[next]?.focus();
168
+ setActiveIndex(activeIndex < items.length - 1 ? activeIndex + 1 : 0);
156
169
  } else if (e.key === "ArrowUp") {
157
170
  e.preventDefault();
158
- const prev = activeIndex > 0 ? activeIndex - 1 : items.length - 1;
159
- setActiveIndex(prev);
160
- items[prev]?.focus();
171
+ setActiveIndex(activeIndex > 0 ? activeIndex - 1 : items.length - 1);
172
+ } else if (e.key === "Enter") {
173
+ if (e.target?.getAttribute("role") === "option") return;
174
+ const pick = items[activeIndex] ?? items[0];
175
+ e.preventDefault();
176
+ pick.click();
161
177
  }
162
178
  };
163
179
  document.addEventListener("keydown", handleKeyDown);
164
180
  return () => document.removeEventListener("keydown", handleKeyDown);
165
181
  }, [open, activeIndex]);
182
+ useLayoutEffect(() => {
183
+ const panel = panelRef.current;
184
+ if (!panel) return;
185
+ const items = Array.from(panel.querySelectorAll('[role="option"]'));
186
+ const active = items[activeIndex];
187
+ items.forEach((item) => {
188
+ const on = item === active;
189
+ item.setAttribute("aria-selected", on ? "true" : "false");
190
+ if (on) item.setAttribute("data-active", "");
191
+ else item.removeAttribute("data-active");
192
+ });
193
+ const input = panel.querySelector("[data-react-fancy-command-input] input");
194
+ if (active?.id) input?.setAttribute("aria-activedescendant", active.id);
195
+ else input?.removeAttribute("aria-activedescendant");
196
+ active?.scrollIntoView?.({ block: "nearest" });
197
+ });
198
+ const changeQuery = useCallback(
199
+ (next) => {
200
+ setQuery(next);
201
+ setActiveIndex(-1);
202
+ },
203
+ [setQuery]
204
+ );
166
205
  const { mounted, className: animClass, ref: animRef } = useAnimation({
167
206
  open,
168
207
  enterClass: "fancy-slide-up",
169
208
  exitClass: "fancy-fade-out"
170
209
  });
171
210
  const ctx = useMemo(
172
- () => ({ open, close, query, setQuery, activeIndex, setActiveIndex, shouldFilter }),
173
- [open, close, query, setQuery, activeIndex, shouldFilter]
211
+ () => ({
212
+ open,
213
+ close,
214
+ query,
215
+ setQuery: changeQuery,
216
+ activeIndex,
217
+ setActiveIndex,
218
+ shouldFilter,
219
+ listId
220
+ }),
221
+ [open, close, query, changeQuery, activeIndex, shouldFilter, listId]
174
222
  );
175
223
  if (!mounted) return null;
176
224
  return /* @__PURE__ */ jsx(CommandContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-start justify-center pt-[20vh]", children: [
@@ -209,5 +257,5 @@ var Command = Object.assign(CommandRoot, {
209
257
  });
210
258
 
211
259
  export { Command, useCommand };
212
- //# sourceMappingURL=chunk-H6WSJL2X.js.map
213
- //# sourceMappingURL=chunk-H6WSJL2X.js.map
260
+ //# sourceMappingURL=chunk-D354R6T6.js.map
261
+ //# sourceMappingURL=chunk-D354R6T6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Command/Command.context.ts","../src/components/Command/CommandInput.tsx","../src/components/Command/CommandList.tsx","../src/components/Command/CommandItem.tsx","../src/components/Command/CommandGroup.tsx","../src/components/Command/CommandEmpty.tsx","../src/components/Command/Command.tsx"],"names":["jsx","jsxs","useId"],"mappings":"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","file":"chunk-D354R6T6.js","sourcesContent":["import { createContext, useContext } from \"react\";\nimport type { CommandContextValue } from \"./Command.types\";\n\nexport const CommandContext = createContext<CommandContextValue | null>(null);\n\nexport function useCommand(): CommandContextValue {\n const ctx = useContext(CommandContext);\n if (!ctx) {\n throw new Error(\n \"Command compound components must be used within <Command>\",\n );\n }\n return ctx;\n}\n","import { Search } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useCommand } from \"./Command.context\";\nimport type { CommandInputProps } from \"./Command.types\";\n\nexport function CommandInput({\n placeholder = \"Type a command or search...\",\n className,\n}: CommandInputProps) {\n const { query, setQuery, listId } = useCommand();\n\n return (\n <div data-react-fancy-command-input=\"\" className=\"flex items-center border-b border-zinc-200 px-4 dark:border-zinc-700\">\n <Search size={16} className=\"shrink-0 text-zinc-400\" />\n <input\n type=\"text\"\n // A combobox: focus stays here while the arrows move the active option,\n // which Command announces through aria-activedescendant.\n role=\"combobox\"\n aria-expanded=\"true\"\n aria-controls={listId}\n aria-autocomplete=\"list\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={placeholder}\n className={cn(\n \"flex-1 bg-transparent px-3 py-3 text-sm outline-none placeholder:text-zinc-400\",\n className,\n )}\n autoFocus\n />\n </div>\n );\n}\n\nCommandInput.displayName = \"CommandInput\";\n","import { cn } from \"../../utils/cn\";\nimport { useCommand } from \"./Command.context\";\nimport type { CommandListProps } from \"./Command.types\";\n\nexport function CommandList({ children, className }: CommandListProps) {\n const { listId } = useCommand();\n\n return (\n <div\n id={listId}\n data-react-fancy-command-list=\"\"\n role=\"listbox\"\n className={cn(\"max-h-72 overflow-y-auto p-2\", className)}\n >\n {children}\n </div>\n );\n}\n\nCommandList.displayName = \"CommandList\";\n","import { useId } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { useCommand } from \"./Command.context\";\nimport type { CommandItemProps } from \"./Command.types\";\n\nexport function CommandItem({\n children,\n value,\n onSelect,\n className,\n}: CommandItemProps) {\n const { query, close, shouldFilter, setActiveIndex } = useCommand();\n // Called before the filter's early return, so the hook order never changes.\n const id = useId();\n\n // Filter by query — unless the caller filters for itself (`shouldFilter={false}`).\n const text = value ?? (typeof children === \"string\" ? children : \"\");\n if (shouldFilter && query && !text.toLowerCase().includes(query.toLowerCase())) {\n return null;\n }\n\n return (\n <button\n id={id}\n data-react-fancy-command-item=\"\"\n type=\"button\"\n role=\"option\"\n // Marked active by Command itself (aria-selected + data-active), since an\n // item cannot know its own position among the rendered options.\n aria-selected={false}\n // Keyboard focus stays in the input; the items are reached with the arrows.\n tabIndex={-1}\n onMouseEnter={(e) => {\n const options = e.currentTarget\n .closest(\"[data-react-fancy-command]\")\n ?.querySelectorAll('[role=\"option\"]');\n if (options) setActiveIndex(Array.from(options).indexOf(e.currentTarget));\n }}\n className={cn(\n \"flex w-full items-center rounded-lg px-3 py-2 text-left text-sm transition-colors\",\n \"text-zinc-700 hover:bg-zinc-100 data-[active]:bg-zinc-100 dark:text-zinc-300 dark:hover:bg-zinc-800 dark:data-[active]:bg-zinc-800\",\n className,\n )}\n onClick={() => {\n onSelect?.();\n close();\n }}\n >\n {children}\n </button>\n );\n}\n\nCommandItem.displayName = \"CommandItem\";\n","import { cn } from \"../../utils/cn\";\nimport type { CommandGroupProps } from \"./Command.types\";\n\nexport function CommandGroup({\n children,\n heading,\n className,\n}: CommandGroupProps) {\n return (\n <div data-react-fancy-command-group=\"\" role=\"group\" className={cn(\"py-1\", className)}>\n {heading && (\n <div className=\"px-3 py-1.5 text-xs font-medium text-zinc-400\">\n {heading}\n </div>\n )}\n {children}\n </div>\n );\n}\n\nCommandGroup.displayName = \"CommandGroup\";\n","import { cn } from \"../../utils/cn\";\nimport type { CommandEmptyProps } from \"./Command.types\";\n\nexport function CommandEmpty({\n children = \"No results found.\",\n className,\n}: CommandEmptyProps) {\n return (\n <div\n data-react-fancy-command-empty=\"\"\n className={cn(\n \"py-6 text-center text-sm text-zinc-500 dark:text-zinc-400\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nCommandEmpty.displayName = \"CommandEmpty\";\n","import {\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Portal } from \"../Portal\";\nimport { CommandContext } from \"./Command.context\";\nimport { CommandInput } from \"./CommandInput\";\nimport { CommandList } from \"./CommandList\";\nimport { CommandItem } from \"./CommandItem\";\nimport { CommandGroup } from \"./CommandGroup\";\nimport { CommandEmpty } from \"./CommandEmpty\";\nimport { useFocusTrap } from \"../../hooks/use-focus-trap\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\nimport { useAnimation } from \"../../hooks/use-animation\";\nimport { useControllableState } from \"../../hooks/use-controllable-state\";\nimport type { CommandProps } from \"./Command.types\";\n\nfunction CommandRoot({\n children,\n open,\n onClose,\n className,\n shouldFilter = true,\n query: controlledQuery,\n onQueryChange,\n}: CommandProps) {\n const [query, setQuery] = useControllableState(controlledQuery, \"\", onQueryChange);\n const [activeIndex, setActiveIndex] = useState(-1);\n const panelRef = useRef<HTMLDivElement>(null);\n const listId = useId();\n\n const close = useCallback(() => {\n onClose();\n setQuery(\"\");\n setActiveIndex(-1);\n }, [onClose]);\n\n useEscapeKey(close, open);\n useFocusTrap(panelRef, open);\n\n // Cmd+K global shortcut is handled by the consumer\n useEffect(() => {\n if (open) {\n const original = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = original;\n };\n }\n }, [open]);\n\n /*\n * Keyboard navigation, as a combobox: the arrows move the ACTIVE item while\n * focus stays in the input (announced through aria-activedescendant), and\n * Enter picks the active item — or the first visible one when none is active.\n *\n * Focus used to move onto the items, and Enter was handled nowhere, so typing\n * a query and pressing Enter did nothing: only a focused item took Enter, as a\n * native click. Found by Genie 2's real-window test.\n */\n useEffect(() => {\n if (!open) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const items = panelRef.current?.querySelectorAll<HTMLElement>(\n '[role=\"option\"]',\n );\n if (!items?.length) return;\n\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActiveIndex(activeIndex < items.length - 1 ? activeIndex + 1 : 0);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActiveIndex(activeIndex > 0 ? activeIndex - 1 : items.length - 1);\n } else if (e.key === \"Enter\") {\n // A focused item takes Enter natively, as a click; picking here as well\n // would select it twice.\n if ((e.target as HTMLElement | null)?.getAttribute(\"role\") === \"option\") return;\n const pick = items[activeIndex] ?? items[0];\n e.preventDefault();\n pick.click();\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, activeIndex]);\n\n /*\n * Mark the active item and point the input at it. Done on the DOM after each\n * render because an item cannot know its own index — that is its position\n * among the options currently rendered, which filtering changes.\n */\n useLayoutEffect(() => {\n const panel = panelRef.current;\n if (!panel) return;\n\n const items = Array.from(panel.querySelectorAll<HTMLElement>('[role=\"option\"]'));\n const active = items[activeIndex];\n items.forEach((item) => {\n const on = item === active;\n item.setAttribute(\"aria-selected\", on ? \"true\" : \"false\");\n if (on) item.setAttribute(\"data-active\", \"\");\n else item.removeAttribute(\"data-active\");\n });\n\n const input = panel.querySelector<HTMLInputElement>(\"[data-react-fancy-command-input] input\");\n if (active?.id) input?.setAttribute(\"aria-activedescendant\", active.id);\n else input?.removeAttribute(\"aria-activedescendant\");\n active?.scrollIntoView?.({ block: \"nearest\" });\n });\n\n // A new query is a new list: nothing in it is active yet, so Enter picks the first match.\n const changeQuery = useCallback(\n (next: string) => {\n setQuery(next);\n setActiveIndex(-1);\n },\n [setQuery],\n );\n\n const { mounted, className: animClass, ref: animRef } = useAnimation({\n open,\n enterClass: \"fancy-slide-up\",\n exitClass: \"fancy-fade-out\",\n });\n\n const ctx = useMemo(\n () => ({\n open,\n close,\n query,\n setQuery: changeQuery,\n activeIndex,\n setActiveIndex,\n shouldFilter,\n listId,\n }),\n [open, close, query, changeQuery, activeIndex, shouldFilter, listId],\n );\n\n if (!mounted) return null;\n\n return (\n <CommandContext.Provider value={ctx}>\n <Portal>\n <div className=\"fixed inset-0 z-50 flex items-start justify-center pt-[20vh]\">\n <div\n className=\"absolute inset-0 bg-black/50 backdrop-blur-sm\"\n onClick={close}\n aria-hidden=\"true\"\n />\n <div\n ref={(node) => {\n panelRef.current = node;\n (animRef as React.MutableRefObject<HTMLElement | null>).current =\n node;\n }}\n data-react-fancy-command=\"\"\n className={cn(\n \"relative w-full max-w-lg overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-2xl dark:border-zinc-700 dark:bg-zinc-900\",\n animClass,\n className,\n )}\n >\n {children}\n </div>\n </div>\n </Portal>\n </CommandContext.Provider>\n );\n}\n\nexport const Command = Object.assign(CommandRoot, {\n Input: CommandInput,\n List: CommandList,\n Item: CommandItem,\n Group: CommandGroup,\n Empty: CommandEmpty,\n});\n"]}
@@ -7,7 +7,7 @@ import { DisplayValue } from './chunk-KKWNKBKR.js';
7
7
  import { resolveOption } from './chunk-GFYSELJF.js';
8
8
  import { ColorPicker } from './chunk-F2GAZZVS.js';
9
9
  import { Badge } from './chunk-6FCQD2KQ.js';
10
- import { Button } from './chunk-46IPQEUP.js';
10
+ import { Button } from './chunk-JJRD3WX3.js';
11
11
  import { Callout } from './chunk-ZXZJYVWP.js';
12
12
  import { Text } from './chunk-5RLP77KK.js';
13
13
  import { useInlineEdit } from './chunk-OL53XYHF.js';
@@ -1337,5 +1337,5 @@ function buildItems({
1337
1337
  }
1338
1338
 
1339
1339
  export { JSON_FIELD_TYPES, JsonEditor, applyJsonEdit, describeEdit, findJsonConflicts, getAtPath, inferType, parseKeyMap, parsePath, pathToString, resolveKeyRule, typeMatches };
1340
- //# sourceMappingURL=chunk-FQLL2JI7.js.map
1341
- //# sourceMappingURL=chunk-FQLL2JI7.js.map
1340
+ //# sourceMappingURL=chunk-G4WYCWIQ.js.map
1341
+ //# sourceMappingURL=chunk-G4WYCWIQ.js.map