@studiolxd/brand 49.1.0 → 49.2.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/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,33 @@ El paquete sigue [semver](https://semver.org/lang/es/): **patch** para bug fixes
|
|
|
7
7
|
regeneración de `dist`, **minor** para componentes/props/variantes/tokens nuevos, **major**
|
|
8
8
|
para breaking changes.
|
|
9
9
|
|
|
10
|
+
## [49.2.0] — 2026-09-16
|
|
11
|
+
|
|
12
|
+
> **Minor.** `CommandPalette` deja de ser dueña exclusiva de su consulta: `onQueryChange`
|
|
13
|
+
> avisa de cada cambio del texto del buscador (y de `""` al cerrarse) y `filter`
|
|
14
|
+
> (`'internal'` | `'none'`, global o por grupo con `CommandPaletteGroup.filter`) permite
|
|
15
|
+
> apagar el filtrado interno para un grupo que ya llega filtrado desde fuera.
|
|
16
|
+
|
|
17
|
+
### El porqué
|
|
18
|
+
|
|
19
|
+
Un consumidor que busca en servidor (el `PublicCommandMenu` de la suite, resultados de una
|
|
20
|
+
API con *debounce*) no tenía forma de leer lo que el usuario tecleaba salvo envolviendo la
|
|
21
|
+
paleta en un contenedor con `onInput` y leyendo el valor por el árbol — una lectura por la
|
|
22
|
+
puerta de atrás. Ese mismo consumidor, además, tenía que meter la consulta en `keywords` de
|
|
23
|
+
cada resultado para que el filtrado interno no se los comiera, aunque los resultados ya
|
|
24
|
+
llegaran filtrados.
|
|
25
|
+
|
|
26
|
+
### El arreglo
|
|
27
|
+
|
|
28
|
+
`onQueryChange?: (query: string) => void` se llama con el texto tal cual lo escribe quien
|
|
29
|
+
usa la paleta, y con `""` cuando la paleta se cierra, para que el consumidor no arrastre una
|
|
30
|
+
consulta vieja a la siguiente apertura. `query?: string` permite además controlarla desde
|
|
31
|
+
fuera. `filter?: 'internal' | 'none'` (por defecto `'internal'`, sin cambio de
|
|
32
|
+
comportamiento) apaga el filtrado por `label`/`keywords` cuando vale `'none'`; se puede fijar
|
|
33
|
+
también por grupo (`CommandPaletteGroup.filter`) para mezclar, en una misma paleta, un grupo
|
|
34
|
+
con filtrado interno y otro que ya llega filtrado de fuera. Story «Búsqueda en servidor» y
|
|
35
|
+
MDX § «Buscar fuera de la paleta».
|
|
36
|
+
|
|
10
37
|
## [49.1.0] — 2026-09-16
|
|
11
38
|
|
|
12
39
|
> **Minor.** Regla visual nueva, sin cambios de API: **un enlace dentro de un `Alert` o de un
|
|
@@ -37,6 +37,13 @@ export interface CommandPaletteGroup {
|
|
|
37
37
|
id: string;
|
|
38
38
|
heading: string;
|
|
39
39
|
items: CommandPaletteItem[];
|
|
40
|
+
/**
|
|
41
|
+
* Filtrado de este grupo. Anula al `filter` global de la paleta:
|
|
42
|
+
* - `'internal'` (por defecto, el del global): filtra por `label`/`keywords` como siempre.
|
|
43
|
+
* - `'none'`: el grupo enseña sus ítems tal cual, sin comparar con la consulta —
|
|
44
|
+
* para un grupo que ya llega filtrado desde fuera (búsqueda en servidor).
|
|
45
|
+
*/
|
|
46
|
+
filter?: 'internal' | 'none';
|
|
40
47
|
}
|
|
41
48
|
export interface CommandPaletteProps {
|
|
42
49
|
open: boolean;
|
|
@@ -81,6 +88,27 @@ export interface CommandPaletteProps {
|
|
|
81
88
|
* Por defecto, el del entorno.
|
|
82
89
|
*/
|
|
83
90
|
locale?: Intl.LocalesArgument;
|
|
91
|
+
/**
|
|
92
|
+
* Filtrado global de la paleta:
|
|
93
|
+
* - `'internal'` (por defecto): filtra los ítems por `label`/`keywords` contra la consulta.
|
|
94
|
+
* - `'none'`: la paleta no filtra nada — enseña los ítems de `groups` tal cual se los
|
|
95
|
+
* pasan. Es lo que necesita una búsqueda en servidor (con `onQueryChange` y su propio
|
|
96
|
+
* debounce), que ya trae los resultados filtrados.
|
|
97
|
+
*
|
|
98
|
+
* Un grupo concreto puede anular este valor con `CommandPaletteGroup.filter`.
|
|
99
|
+
*/
|
|
100
|
+
filter?: 'internal' | 'none';
|
|
101
|
+
/**
|
|
102
|
+
* Consulta del buscador, para controlarla desde fuera (p. ej. resetearla al elegir un
|
|
103
|
+
* filtro externo). Sin ella, la paleta lleva su propio estado interno.
|
|
104
|
+
*/
|
|
105
|
+
query?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Se llama con cada cambio del texto del buscador (ya recortado por el filtrado interno
|
|
108
|
+
* cuando lo hay) y con `""` al cerrarse la paleta. Es la vía de lectura de la consulta
|
|
109
|
+
* para quien necesite buscar en servidor sin envolver la paleta ni leer el DOM.
|
|
110
|
+
*/
|
|
111
|
+
onQueryChange?: (query: string) => void;
|
|
84
112
|
className?: string;
|
|
85
113
|
}
|
|
86
114
|
/**
|
|
@@ -92,4 +120,4 @@ export interface CommandPaletteProps {
|
|
|
92
120
|
* de Base UI en modo `inline` — sin popup propio, porque la superficie ya la
|
|
93
121
|
* pone el `Modal`, que también se queda con Escape y el foco atrapado.
|
|
94
122
|
*/
|
|
95
|
-
export declare function CommandPalette({ open, onOpenChange, groups, title, placeholder, emptyLabel, listLabel, closeLabel, shortcut, locale, className, }: CommandPaletteProps): import("react/jsx-runtime").JSX.Element;
|
|
123
|
+
export declare function CommandPalette({ open, onOpenChange, groups, title, placeholder, emptyLabel, listLabel, closeLabel, shortcut, locale, filter: filterMode, query, onQueryChange, className, }: CommandPaletteProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/command-palette.js
CHANGED
|
@@ -2,63 +2,71 @@
|
|
|
2
2
|
import './command-palette.css';
|
|
3
3
|
import { n as e } from "./_shared/brandmessagescontext.js";
|
|
4
4
|
import { Modal as t } from "./modal.js";
|
|
5
|
-
import { useCallback as n, useEffect as r } from "react";
|
|
6
|
-
import { jsx as
|
|
7
|
-
import { Autocomplete as
|
|
5
|
+
import { useCallback as n, useEffect as r, useRef as i } from "react";
|
|
6
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
7
|
+
import { Autocomplete as s } from "@base-ui/react/autocomplete";
|
|
8
8
|
//#region src/stories/molecules/CommandPalette/CommandPalette.tsx
|
|
9
|
-
function
|
|
10
|
-
let
|
|
9
|
+
function c({ open: c, onOpenChange: l, groups: u, title: d, placeholder: f, emptyLabel: p, listLabel: m, closeLabel: h, shortcut: g = "k", locale: _, filter: v = "internal", query: y, onQueryChange: b, className: x }) {
|
|
10
|
+
let S = e("commandPalette"), C = i(c);
|
|
11
11
|
r(() => {
|
|
12
|
-
|
|
12
|
+
C.current && !c && b?.(""), C.current = c;
|
|
13
|
+
}, [c, b]), r(() => {
|
|
14
|
+
if (g === !1) return;
|
|
13
15
|
let e = (e) => {
|
|
14
|
-
typeof e.key == "string" && e.key.toLowerCase() ===
|
|
16
|
+
typeof e.key == "string" && e.key.toLowerCase() === g && (e.metaKey || e.ctrlKey) && (e.preventDefault(), l(!c));
|
|
15
17
|
};
|
|
16
18
|
return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
|
|
17
19
|
}, [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
g,
|
|
21
|
+
c,
|
|
22
|
+
l
|
|
21
23
|
]);
|
|
22
|
-
let
|
|
24
|
+
let w = s.useFilter({
|
|
23
25
|
sensitivity: "base",
|
|
24
|
-
locale:
|
|
25
|
-
}),
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
locale: _
|
|
27
|
+
}), T = n((e, t) => (u.find((t) => t.items.includes(e))?.filter ?? v) === "none" ? !0 : w.contains(e.label, t) || (e.keywords ?? []).some((e) => w.contains(e, t)), [
|
|
28
|
+
w,
|
|
29
|
+
u,
|
|
30
|
+
v
|
|
31
|
+
]);
|
|
32
|
+
return /* @__PURE__ */ a(t, {
|
|
33
|
+
open: c,
|
|
34
|
+
onClose: () => l(!1),
|
|
35
|
+
title: S("title", d),
|
|
36
|
+
...h ? { closeLabel: h } : {},
|
|
37
|
+
children: /* @__PURE__ */ a(s.Root, {
|
|
32
38
|
inline: !0,
|
|
33
39
|
open: !0,
|
|
34
|
-
items:
|
|
35
|
-
filter:
|
|
40
|
+
items: u,
|
|
41
|
+
filter: T,
|
|
36
42
|
autoHighlight: "always",
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
...y === void 0 ? {} : { value: y },
|
|
44
|
+
onValueChange: (e) => b?.(e),
|
|
45
|
+
children: /* @__PURE__ */ o("div", {
|
|
46
|
+
className: ["command-palette", x].filter(Boolean).join(" "),
|
|
39
47
|
children: [
|
|
40
|
-
/* @__PURE__ */
|
|
48
|
+
/* @__PURE__ */ a(s.Input, {
|
|
41
49
|
className: "command-palette__input",
|
|
42
|
-
placeholder:
|
|
50
|
+
placeholder: S("placeholder", f),
|
|
43
51
|
autoFocus: !0
|
|
44
52
|
}),
|
|
45
|
-
/* @__PURE__ */
|
|
53
|
+
/* @__PURE__ */ a(s.List, {
|
|
46
54
|
className: "command-palette__list",
|
|
47
|
-
"aria-label":
|
|
48
|
-
children: (e) => /* @__PURE__ */
|
|
55
|
+
"aria-label": S("list", m),
|
|
56
|
+
children: (e) => /* @__PURE__ */ o(s.Group, {
|
|
49
57
|
items: e.items,
|
|
50
58
|
className: "command-palette__group",
|
|
51
|
-
children: [/* @__PURE__ */
|
|
59
|
+
children: [/* @__PURE__ */ a(s.GroupLabel, {
|
|
52
60
|
className: "command-palette__heading",
|
|
53
61
|
children: e.heading
|
|
54
|
-
}), /* @__PURE__ */
|
|
62
|
+
}), /* @__PURE__ */ a(s.Collection, { children: (e) => /* @__PURE__ */ o(s.Item, {
|
|
55
63
|
value: e,
|
|
56
64
|
disabled: e.disabled,
|
|
57
65
|
className: "command-palette__item",
|
|
58
66
|
onClick: () => {
|
|
59
|
-
|
|
67
|
+
l(!1), e.onSelect();
|
|
60
68
|
},
|
|
61
|
-
children: [e.icon && /* @__PURE__ */
|
|
69
|
+
children: [e.icon && /* @__PURE__ */ a("span", {
|
|
62
70
|
className: "command-palette__item-icon",
|
|
63
71
|
"aria-hidden": "true",
|
|
64
72
|
children: e.icon
|
|
@@ -66,9 +74,9 @@ function s({ open: s, onOpenChange: c, groups: l, title: u, placeholder: d, empt
|
|
|
66
74
|
}, e.id) })]
|
|
67
75
|
}, e.id)
|
|
68
76
|
}),
|
|
69
|
-
/* @__PURE__ */
|
|
77
|
+
/* @__PURE__ */ a(s.Empty, {
|
|
70
78
|
className: "command-palette__empty",
|
|
71
|
-
children:
|
|
79
|
+
children: S("empty", p)
|
|
72
80
|
})
|
|
73
81
|
]
|
|
74
82
|
})
|
|
@@ -76,4 +84,4 @@ function s({ open: s, onOpenChange: c, groups: l, title: u, placeholder: d, empt
|
|
|
76
84
|
});
|
|
77
85
|
}
|
|
78
86
|
//#endregion
|
|
79
|
-
export {
|
|
87
|
+
export { c as CommandPalette };
|