@studiolxd/brand 49.23.1 → 49.24.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,32 @@ 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.24.0] — 2026-10-04
11
+
12
+ > **Minor.** Disparador propio y ancla sin disparador en `ColorPicker`, a petición de creator (la barra
13
+ > de texto enriquecido y la celda de una tabla). Sin tocar nada, todo sigue igual.
14
+
15
+ ### `ColorPicker`: `trigger` y `anchor`
16
+
17
+ - **`trigger`**: un elemento propio como disparador en lugar de la muestra —un `Toggle` con glifo y
18
+ `ColorSwatch size="sm"`, un `Button`—, con el patrón del `trigger` de `Popover`/`Menu` y las props
19
+ por `render` (`useRender`, como `Button`). Recibe `id`, `aria-haspopup="dialog"`, `aria-expanded`,
20
+ `aria-controls`, `aria-label`/`aria-labelledby`, `aria-invalid`, `disabled` y la descripción con el
21
+ valor (`colorPicker.value`/`empty`); lo que el elemento ya traiga gana, salvo la descripción, que se
22
+ suma, y `disabled`. El `ref` del selector se suma al suyo. El foco vuelve a él al cerrar. No lee
23
+ `colorPicker.trigger`: se nombra por sí mismo o por `aria-label`/la etiqueta.
24
+ - **`anchor`**: coloca el panel contra otro elemento (la prop `anchor` de `Popover`). Sin `trigger`
25
+ no se pinta ninguna muestra: el panel se abre con `open` controlado, y al cerrarse el foco vuelve a
26
+ donde estaba antes de abrir.
27
+ - `ColorPickerField` reenvía las dos; con `trigger`, la etiqueta sigue nombrando el elemento.
28
+ - Stories «Con disparador propio» y «Anclado sin disparador», y sus `Test — …`.
29
+
30
+ ### `Popover`: `anchor`, y `trigger` opcional
31
+
32
+ - **`anchor`** (tipo `PopoverAnchor`): la prop `anchor` del Positioner de Base UI, tal cual.
33
+ - **`trigger` pasa a opcional**: sin él no se pinta disparador y el panel se abre con `open` contra
34
+ `anchor`.
35
+
10
36
  ## [49.23.1] — 2026-10-04
11
37
 
12
38
  > **Patch.** `appHeader` pasa a ser **opcional** en `BrandMessages`. En 49.23.0 entró obligatorio y un
@@ -7,61 +7,62 @@ import { Popover as i } from "../popover.js";
7
7
  import { Slider as a } from "../slider.js";
8
8
  import { t as o } from "./css-properties.js";
9
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";
10
+ import { cloneElement as c, forwardRef as l, useCallback as u, useId as d, useRef as f, useState as p } from "react";
11
+ import { jsx as m, jsxs as h } from "react/jsx-runtime";
12
+ import { useRender as g } from "@base-ui/react/use-render";
13
+ import { useDirection as _ } from "@base-ui/react/direction-provider";
13
14
  //#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({
15
+ var v = 1, y = 10, b = (e) => Math.min(100, Math.max(0, e)), x = l(function({ hueColor: e, saturation: t, brightness: n, onChange: r, onCommit: i, label: a, roleDescription: s, valueText: c, disabled: l = !1 }, d) {
16
+ let p = _() === "rtl", h = f(null), g = f(null), x = f({
16
17
  s: 0,
17
18
  v: 0
18
19
  }), S = o({
19
- "--color-picker-area-x": `${m ? 100 - t : t}%`,
20
+ "--color-picker-area-x": `${p ? 100 - t : t}%`,
20
21
  "--color-picker-area-y": `${100 - n}%`,
21
22
  "--color-picker-area-hue": e
22
- }), C = l((e) => {
23
- y.current = e, S(e);
23
+ }), C = u((e) => {
24
+ h.current = e, S(e);
24
25
  }, [S]), w = (e) => {
25
26
  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
27
  return {
27
- s: v((m ? 1 - n : n) * 100),
28
- v: v((1 - r) * 100)
28
+ s: b((p ? 1 - n : n) * 100),
29
+ v: b((1 - r) * 100)
29
30
  };
30
31
  }, T = () => {
31
- ((typeof f == "function" ? null : f?.current) ?? y.current?.querySelector("[role=\"slider\"]"))?.focus({ preventScroll: !0 });
32
+ ((typeof d == "function" ? null : d?.current) ?? h.current?.querySelector("[role=\"slider\"]"))?.focus({ preventScroll: !0 });
32
33
  }, E = (e) => {
33
- if (u || e.button !== 0) return;
34
+ if (l || e.button !== 0) return;
34
35
  e.preventDefault();
35
36
  try {
36
37
  e.currentTarget.setPointerCapture?.(e.pointerId);
37
38
  } catch {}
38
- b.current = e.pointerId, T();
39
+ g.current = e.pointerId, T();
39
40
  let t = w(e);
40
41
  x.current = t, r(t);
41
42
  }, D = (e) => {
42
- if (b.current !== e.pointerId) return;
43
+ if (g.current !== e.pointerId) return;
43
44
  let t = w(e);
44
45
  x.current = t, r(t);
45
46
  }, O = (e) => {
46
- if (b.current === e.pointerId) {
47
- b.current = null;
47
+ if (g.current === e.pointerId) {
48
+ g.current = null;
48
49
  try {
49
50
  e.currentTarget.releasePointerCapture?.(e.pointerId);
50
51
  } catch {}
51
52
  i(x.current);
52
53
  }
53
54
  }, k = (e) => {
54
- if (u) return;
55
- let a = e.shiftKey ? _ : g, { s: o, v: s } = {
55
+ if (l) return;
56
+ let a = e.shiftKey ? y : v, { s: o, v: s } = {
56
57
  s: t,
57
58
  v: n
58
59
  };
59
60
  switch (e.key) {
60
61
  case "ArrowRight":
61
- o += m ? -a : a;
62
+ o += p ? -a : a;
62
63
  break;
63
64
  case "ArrowLeft":
64
- o += m ? a : -a;
65
+ o += p ? a : -a;
65
66
  break;
66
67
  case "ArrowUp":
67
68
  s += a;
@@ -70,10 +71,10 @@ var g = 1, _ = 10, v = (e) => Math.min(100, Math.max(0, e)), y = c(function({ hu
70
71
  s -= a;
71
72
  break;
72
73
  case "PageUp":
73
- e.shiftKey ? o += _ : s += _;
74
+ e.shiftKey ? o += y : s += y;
74
75
  break;
75
76
  case "PageDown":
76
- e.shiftKey ? o -= _ : s -= _;
77
+ e.shiftKey ? o -= y : s -= y;
77
78
  break;
78
79
  case "Home":
79
80
  e.ctrlKey || e.metaKey ? s = 0 : o = 0;
@@ -85,37 +86,37 @@ var g = 1, _ = 10, v = (e) => Math.min(100, Math.max(0, e)), y = c(function({ hu
85
86
  }
86
87
  e.preventDefault();
87
88
  let c = {
88
- s: v(o),
89
- v: v(s)
89
+ s: b(o),
90
+ v: b(s)
90
91
  };
91
92
  r(c), i(c);
92
93
  };
93
- return /* @__PURE__ */ p("div", {
94
+ return /* @__PURE__ */ m("div", {
94
95
  ref: C,
95
96
  className: "color-picker__area",
96
- "data-direction": m ? "rtl" : "ltr",
97
- "data-disabled": u ? "" : void 0,
97
+ "data-direction": p ? "rtl" : "ltr",
98
+ "data-disabled": l ? "" : void 0,
98
99
  onPointerDown: E,
99
100
  onPointerMove: D,
100
101
  onPointerUp: O,
101
102
  onPointerCancel: O,
102
- children: /* @__PURE__ */ p("div", {
103
- ref: f,
103
+ children: /* @__PURE__ */ m("div", {
104
+ ref: d,
104
105
  className: "color-picker__area-thumb",
105
106
  role: "slider",
106
- tabIndex: u ? -1 : 0,
107
+ tabIndex: l ? -1 : 0,
107
108
  "aria-label": a,
108
109
  "aria-roledescription": s,
109
110
  "aria-valuemin": 0,
110
111
  "aria-valuemax": 100,
111
112
  "aria-valuenow": Math.round(t),
112
113
  "aria-valuetext": c,
113
- "aria-disabled": u || void 0,
114
+ "aria-disabled": l || void 0,
114
115
  onKeyDown: k
115
116
  })
116
117
  });
117
- }), b = (e, t, n) => Math.min(n, Math.max(t, e));
118
- function x(e) {
118
+ }), S = (e, t, n) => Math.min(n, Math.max(t, e));
119
+ function C(e) {
119
120
  let t = e.trim().replace(/^#/, "");
120
121
  if (!/^[0-9a-f]+$/i.test(t)) return null;
121
122
  let n;
@@ -130,12 +131,12 @@ function x(e) {
130
131
  a: n.length === 8 ? r(3) / 255 : 1
131
132
  };
132
133
  }
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;
134
+ var w = (e) => S(Math.round(e), 0, 255).toString(16).padStart(2, "0");
135
+ function T({ r: e, g: t, b: n, a: r }, i) {
136
+ let a = `#${w(e)}${w(t)}${w(n)}`;
137
+ return i ? `${a}${w(S(r, 0, 1) * 255)}` : a;
137
138
  }
138
- function w({ r: e, g: t, b: n, a: r }) {
139
+ function E({ r: e, g: t, b: n, a: r }) {
139
140
  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
141
  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
142
  h: l,
@@ -144,8 +145,8 @@ function w({ r: e, g: t, b: n, a: r }) {
144
145
  a: r
145
146
  };
146
147
  }
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;
148
+ function D({ h: e, s: t, v: n, a: r }) {
149
+ let i = (e % 360 + 360) % 360, a = S(t, 0, 100) / 100, o = S(n, 0, 100) / 100, s = o * a, c = s * (1 - Math.abs(i / 60 % 2 - 1)), l = o - s, u;
149
150
  return u = i < 60 ? [
150
151
  s,
151
152
  c,
@@ -174,21 +175,21 @@ function T({ h: e, s: t, v: n, a: r }) {
174
175
  r: (u[0] + l) * 255,
175
176
  g: (u[1] + l) * 255,
176
177
  b: (u[2] + l) * 255,
177
- a: b(r, 0, 1)
178
+ a: S(r, 0, 1)
178
179
  };
179
180
  }
180
- function E(e) {
181
- let t = x(e);
182
- return t ? w(t) : null;
181
+ function O(e) {
182
+ let t = C(e);
183
+ return t ? E(t) : null;
183
184
  }
184
- function D(e, t) {
185
- return C(T(e), t);
185
+ function k(e, t) {
186
+ return T(D(e), t);
186
187
  }
187
- function O(e, t) {
188
- let n = x(e);
189
- return n ? C(n, t) : null;
188
+ function A(e, t) {
189
+ let n = C(e);
190
+ return n ? T(n, t) : null;
190
191
  }
191
- function k() {
192
+ function ee() {
192
193
  return [
193
194
  0,
194
195
  60,
@@ -197,7 +198,7 @@ function k() {
197
198
  240,
198
199
  300,
199
200
  360
200
- ].map((e) => D({
201
+ ].map((e) => k({
201
202
  h: e,
202
203
  s: 100,
203
204
  v: 100,
@@ -206,205 +207,228 @@ function k() {
206
207
  }
207
208
  //#endregion
208
209
  //#region src/stories/molecules/ColorPicker/ColorPicker.tsx
209
- var A = {
210
+ var j = {
210
211
  h: 0,
211
212
  s: 0,
212
213
  v: 0,
213
214
  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,
215
+ }, te = l(function({ value: l, defaultValue: v = null, onValueChange: y, onValueCommitted: b, alpha: S = !1, presets: C, clearable: w = !1, onClear: T, open: E, defaultOpen: D = !1, onOpenChange: te, size: M = "md", disabled: N = !1, error: P = !1, locale: ne = "es-ES", id: re, name: F, "aria-label": I, "aria-labelledby": L, "aria-describedby": ie, dialogLabel: ae, clearLabel: oe, trigger: R, anchor: z, className: se }, B) {
216
+ let V = e("colorPicker"), H = _() === "rtl", [ce, U] = p(D), W = E ?? ce, G = l !== void 0, [le, ue] = p(v), K = G ? l : le, q = K ? A(K, S) : null, [J, de] = p(() => q && O(q) || j), [fe, pe] = p(q);
217
+ q !== fe && (pe(q), q && k(J, S) !== q && de(O(q) ?? j));
218
+ let me = k(J, S), he = k({
219
+ ...J,
219
220
  a: 1
220
- }, !1), Y = l((e, t) => {
221
- let n = b ? e : {
221
+ }, !1), Y = u((e, t) => {
222
+ let n = S ? e : {
222
223
  ...e,
223
224
  a: 1
224
225
  };
225
- q(n);
226
- let r = D(n, b);
227
- H || U(r), _?.(r), t && v?.(r);
226
+ de(n);
227
+ let r = k(n, S);
228
+ G || ue(r), y?.(r), t && b?.(r);
228
229
  }, [
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;
230
+ S,
231
+ G,
232
+ y,
233
+ b
234
+ ]), [X, Z] = p(null), [ge, _e] = p(W);
235
+ W !== ge && (_e(W), W || Z(null));
236
+ let ve = (e, t) => {
237
+ let n = A(e, S), r = n ? O(n) : null;
237
238
  return r ? (Y(r, t), !0) : !1;
238
- }, me = (e) => {
239
+ }, ye = (e) => {
239
240
  let t = e.target.value;
240
241
  Z(t);
241
242
  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,
243
+ (n === 6 || S && n === 8) && ve(t, !0);
244
+ }, be = () => {
245
+ X !== null && ve(X, !0), Z(null);
246
+ }, xe = () => {
247
+ G || ue(null), T?.(), E === void 0 && U(!1);
248
+ }, Se = (e, t) => {
249
+ e && N || (E === void 0 && U(e), te?.(e, t));
250
+ }, Ce = f(null), Q = d(), we = o({
251
+ "--color-picker-hue-gradient": `linear-gradient(to ${H ? "left" : "right"}, ${ee().join(", ")})`,
252
+ "--color-picker-alpha-gradient": `linear-gradient(to ${H ? "left" : "right"}, transparent, ${he})`
253
+ }), Te = (e) => Y({
254
+ ...J,
254
255
  s: e.s,
255
256
  v: e.v
256
- }, !1), xe = (e) => Y({
257
- ...K,
257
+ }, !1), Ee = (e) => Y({
258
+ ...J,
258
259
  s: e.s,
259
260
  v: e.v
260
- }, !0), Se = (x ?? []).map((e) => ({
261
+ }, !0), De = (C ?? []).map((e) => ({
261
262
  ...e,
262
- hex: O(e.color, b)
263
- })).filter((e) => e.hex !== null), Ce = [
263
+ hex: A(e.color, S)
264
+ })).filter((e) => e.hex !== null), Oe = [
264
265
  "color-picker",
265
266
  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,
267
+ P ? "color-picker--error" : "",
268
+ se ?? ""
269
+ ].filter(Boolean).join(" "), ke = [Q, ie].filter(Boolean).join(" "), Ae = /* @__PURE__ */ h("button", {
270
+ ref: B,
271
+ id: re,
271
272
  type: "button",
272
273
  className: "color-picker__trigger",
273
- disabled: ee,
274
- "aria-label": I ?? (L ? void 0 : R("trigger")),
274
+ disabled: N,
275
+ "aria-label": I ?? (L ? void 0 : V("trigger")),
275
276
  "aria-labelledby": I ? void 0 : L,
276
- "aria-describedby": we,
277
+ "aria-describedby": ke,
277
278
  "aria-haspopup": "dialog",
278
- "aria-expanded": V,
279
- "aria-invalid": N || void 0,
280
- children: [/* @__PURE__ */ p(s, {
281
- color: W,
279
+ "aria-expanded": W,
280
+ "aria-invalid": P || void 0,
281
+ children: [/* @__PURE__ */ m(s, {
282
+ color: K,
282
283
  className: "color-picker__swatch"
283
- }), /* @__PURE__ */ p(t, {
284
- id: ve,
285
- children: W ? R("value")(G ?? W) : R("empty")
284
+ }), /* @__PURE__ */ m(t, {
285
+ id: Q,
286
+ children: K ? V("value")(q ?? K) : V("empty")
286
287
  })]
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
- ]
288
+ }), je = R?.props ?? {}, Me = g({
289
+ render: R && c(R, {
290
+ disabled: N || je.disabled || void 0,
291
+ "aria-describedby": [ke, je["aria-describedby"]].filter(Boolean).join(" ")
292
+ }),
293
+ ref: B,
294
+ enabled: R !== void 0,
295
+ props: {
296
+ id: re,
297
+ "aria-label": I,
298
+ "aria-labelledby": I ? void 0 : L,
299
+ "aria-haspopup": "dialog",
300
+ "aria-expanded": W,
301
+ "aria-invalid": P || void 0
302
+ }
303
+ }), $;
304
+ return Me ? $ = Me : z === void 0 && ($ = Ae), /* @__PURE__ */ h("div", {
305
+ className: Oe,
306
+ children: [
307
+ F && /* @__PURE__ */ m("input", {
308
+ type: "hidden",
309
+ name: F,
310
+ value: q ?? ""
311
+ }),
312
+ R && /* @__PURE__ */ m(t, {
313
+ id: Q,
314
+ children: K ? V("value")(q ?? K) : V("empty")
315
+ }),
316
+ /* @__PURE__ */ m(i, {
317
+ trigger: $,
318
+ anchor: z,
319
+ label: V("dialog", ae),
320
+ open: W,
321
+ onOpenChange: Se,
322
+ side: "bottom",
323
+ align: "start",
324
+ initialFocus: Ce,
325
+ className: "color-picker__popover",
326
+ children: /* @__PURE__ */ h("div", {
327
+ ref: we,
328
+ className: "color-picker__panel",
329
+ children: [
330
+ /* @__PURE__ */ m(x, {
331
+ ref: Ce,
332
+ hueColor: k({
333
+ h: J.h,
334
+ s: 100,
335
+ v: 100,
336
+ a: 1
337
+ }, !1),
338
+ saturation: J.s,
339
+ brightness: J.v,
340
+ onChange: Te,
341
+ onCommit: Ee,
342
+ label: V("area"),
343
+ roleDescription: V("areaDescription"),
344
+ valueText: V("areaValue")(Math.round(J.s), Math.round(J.v))
345
+ }),
346
+ /* @__PURE__ */ m(a, {
347
+ className: "color-picker__channel color-picker__channel--hue",
348
+ label: V("hue"),
349
+ min: 0,
350
+ max: 360,
351
+ step: 1,
352
+ value: Math.round(J.h),
353
+ format: {
354
+ style: "unit",
355
+ unit: "degree"
356
+ },
357
+ locale: ne,
358
+ onValueChange: (e) => Y({
359
+ ...J,
360
+ h: e
361
+ }, !1),
362
+ onValueCommitted: (e) => Y({
363
+ ...J,
364
+ h: e
365
+ }, !0)
366
+ }),
367
+ S && /* @__PURE__ */ m(a, {
368
+ className: "color-picker__channel color-picker__channel--alpha",
369
+ label: V("alpha"),
370
+ min: 0,
371
+ max: 100,
372
+ step: 1,
373
+ value: Math.round(J.a * 100),
374
+ format: {
375
+ style: "unit",
376
+ unit: "percent"
377
+ },
378
+ locale: ne,
379
+ onValueChange: (e) => Y({
380
+ ...J,
381
+ a: e / 100
382
+ }, !1),
383
+ onValueCommitted: (e) => Y({
384
+ ...J,
385
+ a: e / 100
386
+ }, !0)
387
+ }),
388
+ /* @__PURE__ */ m(r, {
389
+ className: "color-picker__hex",
390
+ type: "text",
391
+ size: M,
392
+ "aria-label": V("hex"),
393
+ autoComplete: "off",
394
+ spellCheck: !1,
395
+ maxLength: S ? 9 : 7,
396
+ value: X ?? me,
397
+ onChange: ye,
398
+ onBlur: be,
399
+ onKeyDown: (e) => {
400
+ e.key === "Enter" && (e.preventDefault(), be());
401
+ }
402
+ }),
403
+ De.length > 0 && /* @__PURE__ */ m("div", {
404
+ className: "color-picker__presets",
405
+ role: "group",
406
+ "aria-label": V("presets"),
407
+ children: De.map((e) => /* @__PURE__ */ m("button", {
408
+ type: "button",
409
+ className: "color-picker__preset",
410
+ title: e.title,
411
+ "aria-label": e.title,
412
+ "aria-pressed": e.hex === me,
413
+ onClick: () => Y(O(e.hex) ?? j, !0),
414
+ children: /* @__PURE__ */ m(s, {
415
+ color: e.hex,
416
+ className: "color-picker__preset-swatch"
417
+ })
418
+ }, `${e.hex}-${e.title}`))
419
+ }),
420
+ w && /* @__PURE__ */ m(n, {
421
+ variant: "ghost",
422
+ size: "sm",
423
+ className: "color-picker__clear",
424
+ onClick: xe,
425
+ children: V("clear", oe)
426
+ })
427
+ ]
428
+ })
405
429
  })
406
- })]
430
+ ]
407
431
  });
408
432
  });
409
433
  //#endregion
410
- export { j as t };
434
+ export { te as t };
@@ -8,9 +8,25 @@ import './Popover.css';
8
8
  * forma a mano.
9
9
  */
10
10
  export type PopoverChangeDetails = Parameters<NonNullable<React.ComponentProps<typeof BasePopover.Root>['onOpenChange']>>[1];
11
+ /**
12
+ * Elemento contra el que se coloca el panel cuando no es el disparador. Es la
13
+ * prop `anchor` del Positioner de Base UI, tal cual: un elemento, un `ref`, un
14
+ * elemento virtual o una función que lo devuelva.
15
+ */
16
+ export type PopoverAnchor = React.ComponentProps<typeof BasePopover.Positioner>['anchor'];
11
17
  export interface PopoverProps {
12
- /** Elemento que abre el panel. Recibe las props del disparador vía `render`. */
13
- trigger: ReactNode;
18
+ /**
19
+ * Elemento que abre el panel. Recibe las props del disparador vía `render`.
20
+ * Sin él no se pinta disparador: el panel se abre con `open` y se coloca
21
+ * contra `anchor`.
22
+ */
23
+ trigger?: ReactNode;
24
+ /**
25
+ * Coloca el panel contra otro elemento que no es el disparador —o, sin
26
+ * disparador, contra el único que hay—. Por defecto, el disparador. Sin
27
+ * disparador, al cerrarse el foco vuelve a donde estaba antes de abrir.
28
+ */
29
+ anchor?: PopoverAnchor;
14
30
  /** Contenido del panel. */
15
31
  children: ReactNode;
16
32
  /**
@@ -74,4 +90,4 @@ export interface PopoverProps {
74
90
  * mantener el panel abierto cuando el clic cae en algo que el motor no
75
91
  * reconoce como suyo.
76
92
  */
77
- export declare function Popover({ trigger, children, label, open, defaultOpen, onOpenChange, onPointerDownOutside, onFocusOutside, onEscapeKeyDown, side, align, sideOffset, initialFocus, container, className, }: PopoverProps): import("react/jsx-runtime").JSX.Element;
93
+ export declare function Popover({ trigger, anchor, children, label, open, defaultOpen, onOpenChange, onPointerDownOutside, onFocusOutside, onEscapeKeyDown, side, align, sideOffset, initialFocus, container, className, }: PopoverProps): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,5 @@
1
- import type { PopoverChangeDetails } from '../../atoms/Popover/Popover';
1
+ import type { ReactElement } from 'react';
2
+ import type { PopoverAnchor, PopoverChangeDetails } from '../../atoms/Popover/Popover';
2
3
  import './ColorPicker.css';
3
4
  /**
4
5
  * El cromo del selector de color. Ninguno trae el castellano puesto: salen
@@ -115,6 +116,24 @@ export interface ColorPickerProps {
115
116
  dialogLabel?: string;
116
117
  /** Texto de «Quitar color». **Sin default**: sin él, `colorPicker.clear`. */
117
118
  clearLabel?: string;
119
+ /**
120
+ * Disparador propio en lugar de la muestra: un `Toggle` con icono, un
121
+ * `Button`… Como el `trigger` de `Popover`, recibe las props del disparador
122
+ * por `render`, así que tiene que reenviarlas (y el `ref`) a su elemento.
123
+ * El selector le añade `id`, `disabled`, `aria-haspopup`, `aria-expanded`,
124
+ * `aria-invalid`, `aria-label` / `aria-labelledby` y la descripción con el
125
+ * valor actual; lo que el elemento ya traiga gana, salvo la descripción, que
126
+ * se suma, y `disabled`, que basta con que lo diga uno. Lo que pinte dentro
127
+ * (y su `pressed`, si es un `Toggle`) lo decide quien lo usa.
128
+ */
129
+ trigger?: ReactElement<Record<string, unknown>>;
130
+ /**
131
+ * Coloca el panel contra un elemento que no es el disparador —la celda de una
132
+ * tabla— (la prop `anchor` de `Popover`). Sin `trigger`, no se pinta ningún
133
+ * disparador: el panel se abre solo con `open`, y al cerrarse el foco vuelve
134
+ * a donde estaba antes de abrir.
135
+ */
136
+ anchor?: PopoverAnchor;
118
137
  /** Se añade DESPUÉS de las clases propias. */
119
138
  className?: string;
120
139
  }
@@ -125,6 +144,6 @@ export interface ColorPickerProps {
125
144
  *
126
145
  * Todo es Base UI salvo el área 2D: el `Popover` (foco, portal, cierre), las
127
146
  * bandas (`Slider`) y el campo (`Input`) son los de brand. El `ref` va al
128
- * disparador.
147
+ * disparador, sea la muestra o el `trigger` propio.
129
148
  */
130
149
  export declare const ColorPicker: import("react").ForwardRefExoticComponent<ColorPickerProps & import("react").RefAttributes<HTMLButtonElement>>;
package/dist/popover.js CHANGED
@@ -12,26 +12,27 @@ function a() {
12
12
  let e = document.documentElement;
13
13
  return i(getComputedStyle(e).getPropertyValue("--popover-offset").trim());
14
14
  }
15
- function o({ trigger: i, children: o, label: s, open: c, defaultOpen: l, onOpenChange: u, onPointerDownOutside: d, onFocusOutside: f, onEscapeKeyDown: p, side: m = "bottom", align: h = "start", sideOffset: g, initialFocus: _, container: v, className: y }) {
16
- let b = e(v);
15
+ function o({ trigger: i, anchor: o, children: s, label: c, open: l, defaultOpen: u, onOpenChange: d, onPointerDownOutside: f, onFocusOutside: p, onEscapeKeyDown: m, side: h = "bottom", align: g = "start", sideOffset: _, initialFocus: v, container: y, className: b }) {
16
+ let x = e(y);
17
17
  return /* @__PURE__ */ n(r.Root, {
18
- open: c,
19
- defaultOpen: l,
18
+ open: l,
19
+ defaultOpen: u,
20
20
  onOpenChange: (e, t) => {
21
- e || (t.reason === "outside-press" ? d?.(t) : t.reason === "focus-out" ? f?.(t) : t.reason === "escape-key" && p?.(t)), u?.(e, t);
21
+ e || (t.reason === "outside-press" ? f?.(t) : t.reason === "focus-out" ? p?.(t) : t.reason === "escape-key" && m?.(t)), d?.(e, t);
22
22
  },
23
- children: [/* @__PURE__ */ t(r.Trigger, { render: i }), /* @__PURE__ */ t(r.Portal, {
24
- container: b,
23
+ children: [i !== void 0 && /* @__PURE__ */ t(r.Trigger, { render: i }), /* @__PURE__ */ t(r.Portal, {
24
+ container: x,
25
25
  children: /* @__PURE__ */ t(r.Positioner, {
26
26
  className: "popover__positioner",
27
- side: m,
28
- align: h,
29
- sideOffset: g ?? a,
27
+ anchor: o,
28
+ side: h,
29
+ align: g,
30
+ sideOffset: _ ?? a,
30
31
  children: /* @__PURE__ */ t(r.Popup, {
31
- "aria-label": s,
32
- initialFocus: _,
33
- className: ["popover", y].filter(Boolean).join(" "),
34
- children: o
32
+ "aria-label": c,
33
+ initialFocus: v,
34
+ className: ["popover", b].filter(Boolean).join(" "),
35
+ children: s
35
36
  })
36
37
  })
37
38
  })]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studiolxd/brand",
3
- "version": "49.23.1",
3
+ "version": "49.24.0",
4
4
  "description": "El sistema de diseño de Studio LXD: componentes React, tokens y documentación de la suite SLXD.",
5
5
  "repository": {
6
6
  "type": "git",