@cosxai/ui 0.18.2 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosxai/ui",
3
- "version": "0.18.2",
3
+ "version": "0.19.0",
4
4
  "description": "COSX design system — React 19 component primitives shared across product-meta and other consumers",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -21,11 +21,19 @@ export interface CommandPaletteProps {
21
21
  // here come last in registration order.
22
22
  groupOrder?: string[];
23
23
  placeholder?: string;
24
+ // Fires whenever the query changes — on every keystroke and on the
25
+ // reset-to-empty when the palette opens. Lets a consumer drive an
26
+ // ASYNC command source (debounce → fetch → register the results as
27
+ // items via useCommandSource) that the built-in client-side filter
28
+ // can't provide on its own. Optional + backward compatible: omit it
29
+ // and the palette behaves exactly as before (static items only).
30
+ onQueryChange?: ((query: string) => void) | undefined;
24
31
  }
25
32
 
26
33
  export function CommandPalette({
27
34
  groupOrder = [],
28
35
  placeholder = "Type a command or search…",
36
+ onQueryChange,
29
37
  }: CommandPaletteProps) {
30
38
  const ctx = useContext(CommandContext);
31
39
  if (!ctx) throw new Error("<CommandPalette> must be inside <CommandProvider>");
@@ -34,12 +42,21 @@ export function CommandPalette({
34
42
  const [selectedIdx, setSelectedIdx] = useState(0);
35
43
  const inputRef = useRef<HTMLInputElement>(null);
36
44
  const listRef = useRef<HTMLDivElement>(null);
45
+ // Latest onQueryChange held in a ref so the open-reset effect can
46
+ // notify it WITHOUT taking it as a dep — an inline callback changes
47
+ // identity every render, which would otherwise re-run the effect and
48
+ // clear the query on every keystroke.
49
+ const onQueryChangeRef = useRef(onQueryChange);
50
+ onQueryChangeRef.current = onQueryChange;
37
51
 
38
52
  // Reset query + focus on every open.
39
53
  useEffect(() => {
40
54
  if (open) {
41
55
  setQ("");
42
56
  setSelectedIdx(0);
57
+ // Tell the consumer the query cleared, so an async source drops
58
+ // its stale results when the palette reopens.
59
+ onQueryChangeRef.current?.("");
43
60
  // RAF so the modal element exists before focus.
44
61
  requestAnimationFrame(() => inputRef.current?.focus());
45
62
  }
@@ -164,6 +181,7 @@ export function CommandPalette({
164
181
  onChange={(e) => {
165
182
  setQ(e.target.value);
166
183
  setSelectedIdx(0);
184
+ onQueryChange?.(e.target.value);
167
185
  }}
168
186
  placeholder={placeholder}
169
187
  style={{