@studiolxd/brand 49.20.0 → 49.22.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/dist/_shared/colorpicker.js +410 -0
  3. package/dist/_shared/tokens.js +62 -0
  4. package/dist/_types/atoms/ColorSwatch/ColorSwatch.d.ts +35 -0
  5. package/dist/_types/messages/BrandMessages.d.ts +3 -1
  6. package/dist/_types/messages/index.d.ts +1 -1
  7. package/dist/_types/molecules/ColorPicker/ColorArea.d.ts +51 -0
  8. package/dist/_types/molecules/ColorPicker/ColorPicker.d.ts +130 -0
  9. package/dist/_types/molecules/ColorPicker/colorModel.d.ts +54 -0
  10. package/dist/_types/molecules/ColorPickerField/ColorPickerField.d.ts +26 -0
  11. package/dist/brand.css +137 -1
  12. package/dist/color-picker-field.css +1 -0
  13. package/dist/color-picker-field.js +46 -0
  14. package/dist/color-picker.js +3 -0
  15. package/dist/color-swatch.css +1 -0
  16. package/dist/color-swatch.js +29 -0
  17. package/dist/colorpicker.css +1 -0
  18. package/dist/tokens.css +146 -1
  19. package/package.json +16 -1
  20. package/src/tokens/components/color-swatch.css +22 -0
  21. package/src/tokens/components/color-swatch.ts +7 -0
  22. package/src/tokens/index.css +3 -0
  23. package/src/tokens/molecules/color-picker-field.css +19 -0
  24. package/src/tokens/molecules/color-picker-field.ts +4 -0
  25. package/src/tokens/molecules/color-picker.css +63 -0
  26. package/src/tokens/molecules/color-picker.ts +8 -0
  27. package/src/tokens/scss/_index.legacy.scss +3 -0
  28. package/src/tokens/scss/_index.scss +3 -0
  29. package/src/tokens/scss/components/_color-swatch.scss +12 -0
  30. package/src/tokens/scss/molecules/_color-picker-field.scss +9 -0
  31. package/src/tokens/scss/molecules/_color-picker.scss +50 -0
  32. package/src/tokens/surface-dark-derived.css +8 -0
  33. package/src/tokens/surface-invert.css +14 -0
  34. package/src/tokens/surface-light.css +14 -0
  35. package/src/tokens/surface-public.css +2 -0
  36. package/src/tokens/tokens.json +62 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,76 @@ 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.22.0] — 2026-10-04
11
+
12
+ > **Minor.** Muestra y selector de color: `ColorSwatch`, `ColorPicker` y `ColorPickerField`, sin
13
+ > dependencias nuevas (Base UI y un área 2D propia). Espacio nuevo `colorPicker` en `BrandMessages`.
14
+
15
+ ### Muestra y selector de color
16
+
17
+ Creator pintaba unas 17 muestras a mano y cuatro selectores con `react-color`, fuera del sistema.
18
+ Ahora tiene sus piezas:
19
+
20
+ - **`ColorSwatch`** (átomo, `@studiolxd/brand/color-swatch`): enseña un color CSS cualquiera que viene
21
+ de un documento, sobre un damero que solo asoma donde el color es transparente. Tallas `sm`/`md`/`lg`
22
+ (16/24/48), `label` → `role="img"`; sin él, decorativa. **Sin `style`**: el color va en el `fill`
23
+ de un SVG (atributo de presentación), así que llega en el HTML del servidor y la CSP no lo descarta.
24
+ - **`ColorPicker`** (molécula, `@studiolxd/brand/color-picker`): la muestra como disparador, a la
25
+ talla de los campos, que abre un `Popover` con el área de saturación y brillo, la banda de tono, la
26
+ de opacidad (`alpha`), el campo hex, los predefinidos (`presets`, con `title`) y «Quitar color»
27
+ (`clearable` + `onClear`). Emite siempre hex en minúsculas, `#rrggbb` o `#rrggbbaa`;
28
+ `onValueChange` en cada paso y `onValueCommitted` al terminar el gesto.
29
+ - **Apertura controlada**: `open`, `defaultOpen` y `onOpenChange(open, details)`, con la forma del
30
+ `Popover`, en `ColorPicker` y `ColorPickerField`. Por defecto elegir no cierra el panel; quien
31
+ quiera cerrarlo al elegir —la celda de una tabla— lo hace en `onValueCommitted`.
32
+ - **`ColorPickerField`** (molécula, `@studiolxd/brand/color-picker-field`): el selector con etiqueta,
33
+ ayuda y error, como `DatePickerField`.
34
+
35
+ Todo es Base UI —el `Popover`, el `Slider` para las bandas, el `Input` para el hex— salvo el **área 2D**,
36
+ que Base UI no tiene: un único `role="slider"` con `aria-roledescription` y `aria-valuetext`
37
+ (saturación y brillo), con teclado en los dos ejes, puntero con captura, RTL por el
38
+ `DirectionProvider` de Base UI y la posición escrita por el CSSOM (`useCssProperties`). La conversión
39
+ hex ↔ HSV son funciones puras propias, con sus pruebas. Sin versión nativa: ninguna app nativa la
40
+ ha pedido.
41
+
42
+ ### Tokens
43
+
44
+ Tres conjuntos nuevos: `tokens/component/color-swatch.json`, `tokens/molecule/color-picker.json` y
45
+ `color-picker-field.json`, con sus pares `surface-dark-*` por la regla de derivación. **Ningún color
46
+ nuevo**: el damero es `color.white` + `color.grey-light`, los degradados del área son `color.white` y
47
+ `color.black` (el modelo HSV) y el degradado de tono sale del propio modelo, no de una lista de hex.
48
+
49
+ ### Internacionalización
50
+
51
+ Un espacio nuevo en `BrandMessages`: **`colorPicker`** (`trigger`, `value(hex)`, `empty`, `dialog`,
52
+ `area`, `areaDescription`, `areaValue(saturación, brillo)`, `hue`, `alpha`, `hex`, `presets`,
53
+ `clear`). **Una aplicación que no lo rellene no compila**, que es el contrato de siempre. La tabla de
54
+ Foundations › Internacionalización queda actualizada.
55
+
56
+ ## [49.21.0] — 2026-10-04
57
+
58
+ > **Minor, solo nativo.** `Banner`, `Menu`/`ContextMenu`, `Tabs`, `DatePickerField` y `PageIntro` en SwiftUI (iOS y
59
+ > macOS) y Compose, con la misma API que React. El paquete de npm no cambia.
60
+
61
+ ### Brand nativo R6 — las piezas que la primera app tuvo que hacer por su cuenta
62
+
63
+ Cinco componentes de React que Homenize reescribió a mano, ahora en SwiftUI (iOS 17 y macOS 14) y Compose, con
64
+ ficha de paridad, pruebas, capturas claro/oscuro y parejas con Storybook. No cambia React ni la versión.
65
+
66
+ - **`Banner`** → `BrandBanner` (`info`/`warning`/`error`, ranura `actions`, aspa con `onDismiss`, apila por debajo de 480).
67
+ Sustituye al `OfflineBanner` de Homenize (iOS y Android).
68
+ - **`Menu` y `ContextMenu`** → `BrandMenu`, `BrandContextMenu`, `BrandMenuItem` (`button`, `separator`, `label`, `radio`).
69
+ iOS/macOS: el `Menu` del sistema por dentro con el disparador de brand; Android: `Popup` propio con los tokens `menu.*`.
70
+ Sustituyen a los `DropdownMenu` de Material y los `Menu { … }` de Homenize.
71
+ - **`Tabs`** → `BrandTabs` + `BrandTab` (`underline`/`pill`, horizontal/vertical): solo la barra; el contenido lo pinta la app.
72
+ Sustituye al `PrimaryTabRow` de Homenize.
73
+ - **`DatePickerField`** → `BrandDatePickerField`: campo de brand con el selector del sistema (`DatePicker` gráfico en
74
+ popover u hoja; `DatePickerDialog` en Android). Fechas de calendario sin hora (`Date` normalizada / `LocalDate`).
75
+ - **`PageIntro`** → `BrandPageIntro` (eyebrow, título, entradilla, acciones). No sustituye al `ScreenHeader` de Homenize,
76
+ que es la barra de navegación de la app y sigue siendo la del sistema.
77
+ - Tokens de componente nativos nuevos: `banner`, `tabs`, `page-intro`, `date-picker`, `date-picker-field`.
78
+ - Compose: `BrandCloseButton` admite tinta propia (interno) y `pair-comparison.sh` de Android recorta bien los lienzos más altos que anchos.
79
+
10
80
  ## [49.20.0] — 2026-10-04
11
81
 
12
82
  > **Minor.** `Autocomplete` y `AutocompleteField` (sugerencias con texto libre), tachado en `Text`, y `NumberInput`
@@ -0,0 +1,410 @@
1
+ import '../colorpicker.css';
2
+ import { n as e } from "./brandmessagescontext.js";
3
+ import { VisuallyHidden as t } from "../visually-hidden.js";
4
+ import { Button as n } from "../button.js";
5
+ import { Input as r } from "../input.js";
6
+ import { Popover as i } from "../popover.js";
7
+ import { Slider as a } from "../slider.js";
8
+ import { t as o } from "./css-properties.js";
9
+ import { ColorSwatch as s } from "../color-swatch.js";
10
+ import { forwardRef as c, useCallback as l, useId as u, useRef as d, useState as f } from "react";
11
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
12
+ import { useDirection as h } from "@base-ui/react/direction-provider";
13
+ //#region src/stories/molecules/ColorPicker/ColorArea.tsx
14
+ var g = 1, _ = 10, v = (e) => Math.min(100, Math.max(0, e)), y = c(function({ hueColor: e, saturation: t, brightness: n, onChange: r, onCommit: i, label: a, roleDescription: s, valueText: c, disabled: u = !1 }, f) {
15
+ let m = h() === "rtl", y = d(null), b = d(null), x = d({
16
+ s: 0,
17
+ v: 0
18
+ }), S = o({
19
+ "--color-picker-area-x": `${m ? 100 - t : t}%`,
20
+ "--color-picker-area-y": `${100 - n}%`,
21
+ "--color-picker-area-hue": e
22
+ }), C = l((e) => {
23
+ y.current = e, S(e);
24
+ }, [S]), w = (e) => {
25
+ let t = e.currentTarget.getBoundingClientRect(), n = t.width ? (e.clientX - t.left) / t.width : 0, r = t.height ? (e.clientY - t.top) / t.height : 0;
26
+ return {
27
+ s: v((m ? 1 - n : n) * 100),
28
+ v: v((1 - r) * 100)
29
+ };
30
+ }, T = () => {
31
+ ((typeof f == "function" ? null : f?.current) ?? y.current?.querySelector("[role=\"slider\"]"))?.focus({ preventScroll: !0 });
32
+ }, E = (e) => {
33
+ if (u || e.button !== 0) return;
34
+ e.preventDefault();
35
+ try {
36
+ e.currentTarget.setPointerCapture?.(e.pointerId);
37
+ } catch {}
38
+ b.current = e.pointerId, T();
39
+ let t = w(e);
40
+ x.current = t, r(t);
41
+ }, D = (e) => {
42
+ if (b.current !== e.pointerId) return;
43
+ let t = w(e);
44
+ x.current = t, r(t);
45
+ }, O = (e) => {
46
+ if (b.current === e.pointerId) {
47
+ b.current = null;
48
+ try {
49
+ e.currentTarget.releasePointerCapture?.(e.pointerId);
50
+ } catch {}
51
+ i(x.current);
52
+ }
53
+ }, k = (e) => {
54
+ if (u) return;
55
+ let a = e.shiftKey ? _ : g, { s: o, v: s } = {
56
+ s: t,
57
+ v: n
58
+ };
59
+ switch (e.key) {
60
+ case "ArrowRight":
61
+ o += m ? -a : a;
62
+ break;
63
+ case "ArrowLeft":
64
+ o += m ? a : -a;
65
+ break;
66
+ case "ArrowUp":
67
+ s += a;
68
+ break;
69
+ case "ArrowDown":
70
+ s -= a;
71
+ break;
72
+ case "PageUp":
73
+ e.shiftKey ? o += _ : s += _;
74
+ break;
75
+ case "PageDown":
76
+ e.shiftKey ? o -= _ : s -= _;
77
+ break;
78
+ case "Home":
79
+ e.ctrlKey || e.metaKey ? s = 0 : o = 0;
80
+ break;
81
+ case "End":
82
+ e.ctrlKey || e.metaKey ? s = 100 : o = 100;
83
+ break;
84
+ default: return;
85
+ }
86
+ e.preventDefault();
87
+ let c = {
88
+ s: v(o),
89
+ v: v(s)
90
+ };
91
+ r(c), i(c);
92
+ };
93
+ return /* @__PURE__ */ p("div", {
94
+ ref: C,
95
+ className: "color-picker__area",
96
+ "data-direction": m ? "rtl" : "ltr",
97
+ "data-disabled": u ? "" : void 0,
98
+ onPointerDown: E,
99
+ onPointerMove: D,
100
+ onPointerUp: O,
101
+ onPointerCancel: O,
102
+ children: /* @__PURE__ */ p("div", {
103
+ ref: f,
104
+ className: "color-picker__area-thumb",
105
+ role: "slider",
106
+ tabIndex: u ? -1 : 0,
107
+ "aria-label": a,
108
+ "aria-roledescription": s,
109
+ "aria-valuemin": 0,
110
+ "aria-valuemax": 100,
111
+ "aria-valuenow": Math.round(t),
112
+ "aria-valuetext": c,
113
+ "aria-disabled": u || void 0,
114
+ onKeyDown: k
115
+ })
116
+ });
117
+ }), b = (e, t, n) => Math.min(n, Math.max(t, e));
118
+ function x(e) {
119
+ let t = e.trim().replace(/^#/, "");
120
+ if (!/^[0-9a-f]+$/i.test(t)) return null;
121
+ let n;
122
+ if (t.length === 3 || t.length === 4) n = t.split("").map((e) => e + e).join("");
123
+ else if (t.length === 6 || t.length === 8) n = t;
124
+ else return null;
125
+ let r = (e) => parseInt(n.slice(e * 2, e * 2 + 2), 16);
126
+ return {
127
+ r: r(0),
128
+ g: r(1),
129
+ b: r(2),
130
+ a: n.length === 8 ? r(3) / 255 : 1
131
+ };
132
+ }
133
+ var S = (e) => b(Math.round(e), 0, 255).toString(16).padStart(2, "0");
134
+ function C({ r: e, g: t, b: n, a: r }, i) {
135
+ let a = `#${S(e)}${S(t)}${S(n)}`;
136
+ return i ? `${a}${S(b(r, 0, 1) * 255)}` : a;
137
+ }
138
+ function w({ r: e, g: t, b: n, a: r }) {
139
+ let i = e / 255, a = t / 255, o = n / 255, s = Math.max(i, a, o), c = s - Math.min(i, a, o), l = 0;
140
+ return c !== 0 && (l = s === i ? (a - o) / c % 6 : s === a ? (o - i) / c + 2 : (i - a) / c + 4, l *= 60, l < 0 && (l += 360)), {
141
+ h: l,
142
+ s: s === 0 ? 0 : c / s * 100,
143
+ v: s * 100,
144
+ a: r
145
+ };
146
+ }
147
+ function T({ h: e, s: t, v: n, a: r }) {
148
+ let i = (e % 360 + 360) % 360, a = b(t, 0, 100) / 100, o = b(n, 0, 100) / 100, s = o * a, c = s * (1 - Math.abs(i / 60 % 2 - 1)), l = o - s, u;
149
+ return u = i < 60 ? [
150
+ s,
151
+ c,
152
+ 0
153
+ ] : i < 120 ? [
154
+ c,
155
+ s,
156
+ 0
157
+ ] : i < 180 ? [
158
+ 0,
159
+ s,
160
+ c
161
+ ] : i < 240 ? [
162
+ 0,
163
+ c,
164
+ s
165
+ ] : i < 300 ? [
166
+ c,
167
+ 0,
168
+ s
169
+ ] : [
170
+ s,
171
+ 0,
172
+ c
173
+ ], {
174
+ r: (u[0] + l) * 255,
175
+ g: (u[1] + l) * 255,
176
+ b: (u[2] + l) * 255,
177
+ a: b(r, 0, 1)
178
+ };
179
+ }
180
+ function E(e) {
181
+ let t = x(e);
182
+ return t ? w(t) : null;
183
+ }
184
+ function D(e, t) {
185
+ return C(T(e), t);
186
+ }
187
+ function O(e, t) {
188
+ let n = x(e);
189
+ return n ? C(n, t) : null;
190
+ }
191
+ function k() {
192
+ return [
193
+ 0,
194
+ 60,
195
+ 120,
196
+ 180,
197
+ 240,
198
+ 300,
199
+ 360
200
+ ].map((e) => D({
201
+ h: e,
202
+ s: 100,
203
+ v: 100,
204
+ a: 1
205
+ }, !1));
206
+ }
207
+ //#endregion
208
+ //#region src/stories/molecules/ColorPicker/ColorPicker.tsx
209
+ var A = {
210
+ h: 0,
211
+ s: 0,
212
+ v: 0,
213
+ a: 1
214
+ }, j = c(function({ value: c, defaultValue: g = null, onValueChange: _, onValueCommitted: v, alpha: b = !1, presets: x, clearable: S = !1, onClear: C, open: w, defaultOpen: T = !1, onOpenChange: j, size: M = "md", disabled: ee = !1, error: N = !1, locale: P = "es-ES", id: te, name: F, "aria-label": I, "aria-labelledby": L, "aria-describedby": ne, dialogLabel: re, clearLabel: ie, className: ae }, oe) {
215
+ let R = e("colorPicker"), z = h() === "rtl", [se, B] = f(T), V = w ?? se, H = c !== void 0, [ce, U] = f(g), W = H ? c : ce, G = W ? O(W, b) : null, [K, q] = f(() => G && E(G) || A), [le, ue] = f(G);
216
+ G !== le && (ue(G), G && D(K, b) !== G && q(E(G) ?? A));
217
+ let J = D(K, b), de = D({
218
+ ...K,
219
+ a: 1
220
+ }, !1), Y = l((e, t) => {
221
+ let n = b ? e : {
222
+ ...e,
223
+ a: 1
224
+ };
225
+ q(n);
226
+ let r = D(n, b);
227
+ H || U(r), _?.(r), t && v?.(r);
228
+ }, [
229
+ b,
230
+ H,
231
+ _,
232
+ v
233
+ ]), [X, Z] = f(null), [fe, pe] = f(V);
234
+ V !== fe && (pe(V), V || Z(null));
235
+ let Q = (e, t) => {
236
+ let n = O(e, b), r = n ? E(n) : null;
237
+ return r ? (Y(r, t), !0) : !1;
238
+ }, me = (e) => {
239
+ let t = e.target.value;
240
+ Z(t);
241
+ let n = t.trim().replace(/^#/, "").length;
242
+ (n === 6 || b && n === 8) && Q(t, !0);
243
+ }, $ = () => {
244
+ X !== null && Q(X, !0), Z(null);
245
+ }, he = () => {
246
+ H || U(null), C?.(), w === void 0 && B(!1);
247
+ }, ge = (e, t) => {
248
+ e && ee || (w === void 0 && B(e), j?.(e, t));
249
+ }, _e = d(null), ve = u(), ye = o({
250
+ "--color-picker-hue-gradient": `linear-gradient(to ${z ? "left" : "right"}, ${k().join(", ")})`,
251
+ "--color-picker-alpha-gradient": `linear-gradient(to ${z ? "left" : "right"}, transparent, ${de})`
252
+ }), be = (e) => Y({
253
+ ...K,
254
+ s: e.s,
255
+ v: e.v
256
+ }, !1), xe = (e) => Y({
257
+ ...K,
258
+ s: e.s,
259
+ v: e.v
260
+ }, !0), Se = (x ?? []).map((e) => ({
261
+ ...e,
262
+ hex: O(e.color, b)
263
+ })).filter((e) => e.hex !== null), Ce = [
264
+ "color-picker",
265
+ M === "md" ? "" : `color-picker--${M}`,
266
+ N ? "color-picker--error" : "",
267
+ ae ?? ""
268
+ ].filter(Boolean).join(" "), we = [ve, ne].filter(Boolean).join(" "), Te = /* @__PURE__ */ m("button", {
269
+ ref: oe,
270
+ id: te,
271
+ type: "button",
272
+ className: "color-picker__trigger",
273
+ disabled: ee,
274
+ "aria-label": I ?? (L ? void 0 : R("trigger")),
275
+ "aria-labelledby": I ? void 0 : L,
276
+ "aria-describedby": we,
277
+ "aria-haspopup": "dialog",
278
+ "aria-expanded": V,
279
+ "aria-invalid": N || void 0,
280
+ children: [/* @__PURE__ */ p(s, {
281
+ color: W,
282
+ className: "color-picker__swatch"
283
+ }), /* @__PURE__ */ p(t, {
284
+ id: ve,
285
+ children: W ? R("value")(G ?? W) : R("empty")
286
+ })]
287
+ });
288
+ return /* @__PURE__ */ m("div", {
289
+ className: Ce,
290
+ children: [F && /* @__PURE__ */ p("input", {
291
+ type: "hidden",
292
+ name: F,
293
+ value: G ?? ""
294
+ }), /* @__PURE__ */ p(i, {
295
+ trigger: Te,
296
+ label: R("dialog", re),
297
+ open: V,
298
+ onOpenChange: ge,
299
+ side: "bottom",
300
+ align: "start",
301
+ initialFocus: _e,
302
+ className: "color-picker__popover",
303
+ children: /* @__PURE__ */ m("div", {
304
+ ref: ye,
305
+ className: "color-picker__panel",
306
+ children: [
307
+ /* @__PURE__ */ p(y, {
308
+ ref: _e,
309
+ hueColor: D({
310
+ h: K.h,
311
+ s: 100,
312
+ v: 100,
313
+ a: 1
314
+ }, !1),
315
+ saturation: K.s,
316
+ brightness: K.v,
317
+ onChange: be,
318
+ onCommit: xe,
319
+ label: R("area"),
320
+ roleDescription: R("areaDescription"),
321
+ valueText: R("areaValue")(Math.round(K.s), Math.round(K.v))
322
+ }),
323
+ /* @__PURE__ */ p(a, {
324
+ className: "color-picker__channel color-picker__channel--hue",
325
+ label: R("hue"),
326
+ min: 0,
327
+ max: 360,
328
+ step: 1,
329
+ value: Math.round(K.h),
330
+ format: {
331
+ style: "unit",
332
+ unit: "degree"
333
+ },
334
+ locale: P,
335
+ onValueChange: (e) => Y({
336
+ ...K,
337
+ h: e
338
+ }, !1),
339
+ onValueCommitted: (e) => Y({
340
+ ...K,
341
+ h: e
342
+ }, !0)
343
+ }),
344
+ b && /* @__PURE__ */ p(a, {
345
+ className: "color-picker__channel color-picker__channel--alpha",
346
+ label: R("alpha"),
347
+ min: 0,
348
+ max: 100,
349
+ step: 1,
350
+ value: Math.round(K.a * 100),
351
+ format: {
352
+ style: "unit",
353
+ unit: "percent"
354
+ },
355
+ locale: P,
356
+ onValueChange: (e) => Y({
357
+ ...K,
358
+ a: e / 100
359
+ }, !1),
360
+ onValueCommitted: (e) => Y({
361
+ ...K,
362
+ a: e / 100
363
+ }, !0)
364
+ }),
365
+ /* @__PURE__ */ p(r, {
366
+ className: "color-picker__hex",
367
+ type: "text",
368
+ size: M,
369
+ "aria-label": R("hex"),
370
+ autoComplete: "off",
371
+ spellCheck: !1,
372
+ maxLength: b ? 9 : 7,
373
+ value: X ?? J,
374
+ onChange: me,
375
+ onBlur: $,
376
+ onKeyDown: (e) => {
377
+ e.key === "Enter" && (e.preventDefault(), $());
378
+ }
379
+ }),
380
+ Se.length > 0 && /* @__PURE__ */ p("div", {
381
+ className: "color-picker__presets",
382
+ role: "group",
383
+ "aria-label": R("presets"),
384
+ children: Se.map((e) => /* @__PURE__ */ p("button", {
385
+ type: "button",
386
+ className: "color-picker__preset",
387
+ title: e.title,
388
+ "aria-label": e.title,
389
+ "aria-pressed": e.hex === J,
390
+ onClick: () => Y(E(e.hex) ?? A, !0),
391
+ children: /* @__PURE__ */ p(s, {
392
+ color: e.hex,
393
+ className: "color-picker__preset-swatch"
394
+ })
395
+ }, `${e.hex}-${e.title}`))
396
+ }),
397
+ S && /* @__PURE__ */ p(n, {
398
+ variant: "ghost",
399
+ size: "sm",
400
+ className: "color-picker__clear",
401
+ onClick: he,
402
+ children: R("clear", ie)
403
+ })
404
+ ]
405
+ })
406
+ })]
407
+ });
408
+ });
409
+ //#endregion
410
+ export { j as t };
@@ -687,6 +687,15 @@ var e = {
687
687
  "--collapsible-focus-ring-width": "2px",
688
688
  "--collapsible-focus-ring-offset": "1px",
689
689
  "--collapsible-focus-ring-color": "#111e30",
690
+ "--color-swatch-size-sm": "16px",
691
+ "--color-swatch-size-md": "24px",
692
+ "--color-swatch-size-lg": "48px",
693
+ "--color-swatch-border-width": "1px",
694
+ "--color-swatch-border-color": "#d0d0d0",
695
+ "--color-swatch-border-radius": "0px",
696
+ "--color-swatch-checker-color": "#d0d0d0",
697
+ "--color-swatch-checker-bg": "#ffffff",
698
+ "--color-swatch-checker-size": "0.5rem",
690
699
  "--columns-gap-md": "2rem",
691
700
  "--columns-gap-lg": "4rem",
692
701
  "--columns-stack-gap-md": "2rem",
@@ -2429,6 +2438,59 @@ var e = {
2429
2438
  "--clock-widget-elapsed-label-font-size": "0.875rem",
2430
2439
  "--clock-widget-elapsed-label-color": "#4a4a4a",
2431
2440
  "--clock-widget-footer-margin-block-start": "0.5rem",
2441
+ "--color-picker-field-gap": "0.5rem",
2442
+ "--color-picker-field-helper-font-family": "\"Google Sans Flex\", system-ui, sans-serif",
2443
+ "--color-picker-field-helper-font-size": "0.875rem",
2444
+ "--color-picker-field-helper-font-weight": "300",
2445
+ "--color-picker-field-helper-line-height": "1.5",
2446
+ "--color-picker-field-helper-color": "#111e30",
2447
+ "--color-picker-trigger-size": "2.5rem",
2448
+ "--color-picker-trigger-sm-size": "2rem",
2449
+ "--color-picker-trigger-lg-size": "3rem",
2450
+ "--color-picker-trigger-padding": "0.25rem",
2451
+ "--color-picker-trigger-bg": "#ffffff",
2452
+ "--color-picker-trigger-border-width": "1px",
2453
+ "--color-picker-trigger-border-style": "solid",
2454
+ "--color-picker-trigger-border-color": "#111e30",
2455
+ "--color-picker-trigger-border-radius": "0px",
2456
+ "--color-picker-trigger-cursor": "pointer",
2457
+ "--color-picker-trigger-focus-border-color": "#111e30",
2458
+ "--color-picker-trigger-focus-ring-width": "2px",
2459
+ "--color-picker-trigger-focus-ring-inset-offset": "1px",
2460
+ "--color-picker-trigger-focus-ring-color": "#111e30",
2461
+ "--color-picker-trigger-error-border-color": "#b30000",
2462
+ "--color-picker-trigger-error-focus-ring-color": "#b30000",
2463
+ "--color-picker-trigger-disabled-bg": "#f2f2f2",
2464
+ "--color-picker-trigger-disabled-border-color": "#d0d0d0",
2465
+ "--color-picker-trigger-disabled-cursor": "not-allowed",
2466
+ "--color-picker-trigger-disabled-opacity": "0.4",
2467
+ "--color-picker-panel-gap": "0.75rem",
2468
+ "--color-picker-panel-inline-size": "calc(8 * 24px + 7 * 0.5rem)",
2469
+ "--color-picker-area-block-size": "calc(6 * 24px + 5 * 0.5rem)",
2470
+ "--color-picker-area-border-width": "1px",
2471
+ "--color-picker-area-border-color": "#d0d0d0",
2472
+ "--color-picker-area-saturation-start": "#ffffff",
2473
+ "--color-picker-area-brightness-end": "#000000",
2474
+ "--color-picker-area-cursor": "crosshair",
2475
+ "--color-picker-channel-track-size": "0.75rem",
2476
+ "--color-picker-thumb-size": "16px",
2477
+ "--color-picker-thumb-border-width": "2px",
2478
+ "--color-picker-thumb-border-color": "#ffffff",
2479
+ "--color-picker-thumb-outline-width": "1px",
2480
+ "--color-picker-thumb-outline-color": "#111e30",
2481
+ "--color-picker-thumb-border-radius": "0px",
2482
+ "--color-picker-thumb-focus-ring-width": "2px",
2483
+ "--color-picker-thumb-focus-ring-offset": "2px",
2484
+ "--color-picker-thumb-focus-ring-color": "#111e30",
2485
+ "--color-picker-preset-size": "24px",
2486
+ "--color-picker-preset-gap": "0.5rem",
2487
+ "--color-picker-preset-cursor": "pointer",
2488
+ "--color-picker-preset-focus-ring-width": "2px",
2489
+ "--color-picker-preset-focus-ring-offset": "2px",
2490
+ "--color-picker-preset-focus-ring-color": "#111e30",
2491
+ "--color-picker-preset-selected-ring-width": "2px",
2492
+ "--color-picker-preset-selected-ring-offset": "1px",
2493
+ "--color-picker-preset-selected-ring-color": "#111e30",
2432
2494
  "--command-palette-max-height": "min(24rem, 60vh)",
2433
2495
  "--command-palette-input-padding-block": "0.75rem",
2434
2496
  "--command-palette-input-padding-inline": "0.5rem",
@@ -0,0 +1,35 @@
1
+ import './ColorSwatch.css';
2
+ export interface ColorSwatchProps {
3
+ /**
4
+ * El color que se enseña: **cualquier color CSS** (`#111e30`, `#11223380`,
5
+ * `rgb(…)`, `transparent`, un nombre). Viene del documento, así que no se
6
+ * valida: lo que el navegador no entiende se pinta como vacío. Sin color
7
+ * (`null`, `undefined` o cadena vacía) solo asoma el damero.
8
+ */
9
+ color?: string | null;
10
+ /** Talla: `sm` (16px), `md` (24px, por defecto) o `lg` (48px). */
11
+ size?: 'sm' | 'md' | 'lg';
12
+ /**
13
+ * Nombre accesible. Con él la muestra es una imagen con nombre
14
+ * (`role="img"`): «Lavanda», «Color de fondo: #baabff». Sin él es
15
+ * decorativa (`aria-hidden`), que es lo correcto cuando el color ya se dice
16
+ * en el texto de al lado.
17
+ */
18
+ label?: string;
19
+ /** Se añade DESPUÉS de las clases propias. */
20
+ className?: string;
21
+ }
22
+ /**
23
+ * Una muestra de color: enseña un color que viene de un documento —el de un
24
+ * tema, una categoría, una celda—, sin interacción. Para elegirlo,
25
+ * `ColorPicker`.
26
+ *
27
+ * Detrás del color va siempre un damero, que solo se ve cuando el color tiene
28
+ * transparencia: así `transparent` o `#ffffff80` no se confunden con el blanco.
29
+ *
30
+ * **Sin atributo `style`.** El color llega al HTML como atributo de
31
+ * presentación de SVG (`fill`), que la CSP `style-src 'self'` no bloquea y que
32
+ * ya está en el primer render del servidor; el damero sale de la hoja, con
33
+ * tokens.
34
+ */
35
+ export declare function ColorSwatch({ color, size, label, className }: ColorSwatchProps): import("react/jsx-runtime").JSX.Element;
@@ -16,6 +16,7 @@ import type { SiteSearchMessages } from '../organisms/SiteSearch/SiteSearch';
16
16
  import type { FilterBarMessages } from '../molecules/FilterBar/FilterBar';
17
17
  import type { CalendarMessages } from '../molecules/Calendar/Calendar';
18
18
  import type { DatePickerMessages } from '../molecules/DatePicker/DatePicker';
19
+ import type { ColorPickerMessages } from '../molecules/ColorPicker/ColorPicker';
19
20
  import type { TimeSelectMessages } from '../atoms/TimeSelect/TimeSelect';
20
21
  import type { FileUploadMessages } from '../atoms/FileUpload/FileUpload';
21
22
  import type { ImageCropDialogMessages } from '../molecules/ImageCropDialog/ImageCropDialog';
@@ -121,6 +122,7 @@ export interface BrandMessages {
121
122
  filterBar: FilterBarMessages;
122
123
  calendar: CalendarMessages;
123
124
  datePicker: DatePickerMessages;
125
+ colorPicker: ColorPickerMessages;
124
126
  timeSelect: TimeSelectMessages;
125
127
  fileUpload: FileUploadMessages;
126
128
  imageCropDialog: ImageCropDialogMessages;
@@ -187,4 +189,4 @@ export interface BrandMessages {
187
189
  connectorExternalSignIn: ConnectorExternalSignInMessages;
188
190
  connectorRejection: ConnectorRejectionMessages;
189
191
  }
190
- export type { PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, SiteSearchMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, FileUploadMessages, ImageCropDialogMessages, AvatarUploadMessages, ModalMessages, SheetMessages, ConfirmDialogMessages, AlertMessages, BannerMessages, ToasterMessages, ConsentMessages, CommandPaletteMessages, AppLauncherMessages, FloatingDockMessages, NotificationButtonMessages, NotificationPanelMessages, MenuButtonMessages, AppRootMessages, AppShellMessages, SidebarMessages, SidebarNavMessages, SiteNavMessages, SiteHeaderMessages, UserMenuMessages, OrgSwitcherMessages, BreadcrumbMessages, TableOfContentsMessages, PrevNextNavMessages, PublicPageShellMessages, OnboardingShellMessages, CopyMessages, CodeBlockMessages, DotsButtonMessages, ProgressBarMessages, SpinnerMessages, SliderMessages, TreeViewMessages, ClockWidgetMessages, HeatmapMessages, OrgChartMessages, PlanningGridMessages, RecurrenceFieldMessages, TimelineMessages, UptimeBarsMessages, ChartMessages, StepperMessages, CarouselMessages, LanguageSwitcherMessages, ProjectCardMessages, LegalFooterMessages, CalendarRosterMessages, CalendarPlannerMessages, NotificationListMessages, MessageComposerMessages, ConversationListMessages, ConversationThreadMessages, TypingIndicatorMessages, AnnotationThreadMessages, ChatShellMessages, UntrustedTextMessages, ConnectorRequestSummaryMessages, ConnectorConsentMessages, ConnectorSignInMessages, ConnectorExternalSignInMessages, ConnectorRejectionMessages, };
192
+ export type { PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, SiteSearchMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, ColorPickerMessages, TimeSelectMessages, FileUploadMessages, ImageCropDialogMessages, AvatarUploadMessages, ModalMessages, SheetMessages, ConfirmDialogMessages, AlertMessages, BannerMessages, ToasterMessages, ConsentMessages, CommandPaletteMessages, AppLauncherMessages, FloatingDockMessages, NotificationButtonMessages, NotificationPanelMessages, MenuButtonMessages, AppRootMessages, AppShellMessages, SidebarMessages, SidebarNavMessages, SiteNavMessages, SiteHeaderMessages, UserMenuMessages, OrgSwitcherMessages, BreadcrumbMessages, TableOfContentsMessages, PrevNextNavMessages, PublicPageShellMessages, OnboardingShellMessages, CopyMessages, CodeBlockMessages, DotsButtonMessages, ProgressBarMessages, SpinnerMessages, SliderMessages, TreeViewMessages, ClockWidgetMessages, HeatmapMessages, OrgChartMessages, PlanningGridMessages, RecurrenceFieldMessages, TimelineMessages, UptimeBarsMessages, ChartMessages, StepperMessages, CarouselMessages, LanguageSwitcherMessages, ProjectCardMessages, LegalFooterMessages, CalendarRosterMessages, CalendarPlannerMessages, NotificationListMessages, MessageComposerMessages, ConversationListMessages, ConversationThreadMessages, TypingIndicatorMessages, AnnotationThreadMessages, ChatShellMessages, UntrustedTextMessages, ConnectorRequestSummaryMessages, ConnectorConsentMessages, ConnectorSignInMessages, ConnectorExternalSignInMessages, ConnectorRejectionMessages, };
@@ -2,4 +2,4 @@ export { BrandMessagesProvider } from './BrandMessagesProvider';
2
2
  export type { BrandMessagesProviderProps } from './BrandMessagesProvider';
3
3
  export { useBrandMessages } from './BrandMessagesContext';
4
4
  export type { BrandMessagesReader } from './BrandMessagesContext';
5
- export type { BrandMessages, PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, SiteSearchMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, FileUploadMessages, ImageCropDialogMessages, AvatarUploadMessages, ModalMessages, SheetMessages, ConfirmDialogMessages, AlertMessages, BannerMessages, ToasterMessages, ConsentMessages, CommandPaletteMessages, AppLauncherMessages, FloatingDockMessages, NotificationButtonMessages, NotificationPanelMessages, MenuButtonMessages, AppRootMessages, AppShellMessages, SidebarMessages, SidebarNavMessages, SiteNavMessages, SiteHeaderMessages, UserMenuMessages, OrgSwitcherMessages, BreadcrumbMessages, TableOfContentsMessages, PrevNextNavMessages, PublicPageShellMessages, OnboardingShellMessages, CopyMessages, CodeBlockMessages, DotsButtonMessages, ProgressBarMessages, SpinnerMessages, SliderMessages, TreeViewMessages, ClockWidgetMessages, HeatmapMessages, OrgChartMessages, PlanningGridMessages, RecurrenceFieldMessages, TimelineMessages, UptimeBarsMessages, ChartMessages, StepperMessages, CarouselMessages, LanguageSwitcherMessages, ProjectCardMessages, LegalFooterMessages, CalendarRosterMessages, CalendarPlannerMessages, NotificationListMessages, MessageComposerMessages, ConversationListMessages, ConversationThreadMessages, TypingIndicatorMessages, AnnotationThreadMessages, ChatShellMessages, UntrustedTextMessages, ConnectorRequestSummaryMessages, ConnectorConsentMessages, ConnectorSignInMessages, ConnectorExternalSignInMessages, ConnectorRejectionMessages, } from './BrandMessages';
5
+ export type { BrandMessages, PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, SiteSearchMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, ColorPickerMessages, TimeSelectMessages, FileUploadMessages, ImageCropDialogMessages, AvatarUploadMessages, ModalMessages, SheetMessages, ConfirmDialogMessages, AlertMessages, BannerMessages, ToasterMessages, ConsentMessages, CommandPaletteMessages, AppLauncherMessages, FloatingDockMessages, NotificationButtonMessages, NotificationPanelMessages, MenuButtonMessages, AppRootMessages, AppShellMessages, SidebarMessages, SidebarNavMessages, SiteNavMessages, SiteHeaderMessages, UserMenuMessages, OrgSwitcherMessages, BreadcrumbMessages, TableOfContentsMessages, PrevNextNavMessages, PublicPageShellMessages, OnboardingShellMessages, CopyMessages, CodeBlockMessages, DotsButtonMessages, ProgressBarMessages, SpinnerMessages, SliderMessages, TreeViewMessages, ClockWidgetMessages, HeatmapMessages, OrgChartMessages, PlanningGridMessages, RecurrenceFieldMessages, TimelineMessages, UptimeBarsMessages, ChartMessages, StepperMessages, CarouselMessages, LanguageSwitcherMessages, ProjectCardMessages, LegalFooterMessages, CalendarRosterMessages, CalendarPlannerMessages, NotificationListMessages, MessageComposerMessages, ConversationListMessages, ConversationThreadMessages, TypingIndicatorMessages, AnnotationThreadMessages, ChatShellMessages, UntrustedTextMessages, ConnectorRequestSummaryMessages, ConnectorConsentMessages, ConnectorSignInMessages, ConnectorExternalSignInMessages, ConnectorRejectionMessages, } from './BrandMessages';