@studiolxd/brand 38.14.0 → 38.16.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,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
+ ## [38.16.0] — 2026-09-15
11
+
12
+ > **Minor.** La barra de filtros deja de reorganizarse mientras escribes,
13
+ > `Alert` gana ranura de acciones y el pie de un diálogo se coloca por el ancho
14
+ > del diálogo, no por el de la ventana.
15
+
16
+ **`FilterBar` — una sola rejilla para los filtros y sus acciones.** Eran dos
17
+ cajas hermanas: la rejilla `auto-fit` de filtros y, aparte, un bloque de
18
+ acciones `flex: none` anclado al extremo con `margin-inline-start: auto`. De
19
+ ahí salían los dos defectos que se veían a diario. El botón de «Limpiar
20
+ filtros» solo se pinta cuando ya hay algo que limpiar —o sea, **mientras se
21
+ escribe**— y, al aparecer, le restaba a la rejilla su ancho más el hueco: si
22
+ ese recorte cruzaba un múltiplo del mínimo de columna, la rejilla perdía una
23
+ columna de golpe y un filtro se caía a la línea siguiente. Medido a 1024px con
24
+ cuatro filtros: sin el botón, una fila de cuatro columnas; con él, dos filas y
25
+ 733px de hueco. A 768px con tres filtros, lo mismo: de tres columnas a dos, con
26
+ 467px de hueco.
27
+
28
+ Ahora el botón es **una celda más de la misma rejilla**, la siguiente al último
29
+ filtro, alineada con los controles. Y la rejilla es `auto-fill` en vez de
30
+ `auto-fit`: las pistas las decide el ancho disponible y **solo** el ancho
31
+ disponible, así que ni el número de columnas ni el ancho de los campos cambian
32
+ porque el botón aparezca o desaparezca — medido a 1536, 1280, 1024, 900, 768,
33
+ 640 y 390px, con dos, tres y cuatro filtros. La contrapartida —con dos filtros
34
+ en una pantalla ancha sobra sitio a la derecha— es la buena: un filtro mide lo
35
+ que mide una celda del sistema (192px, `field-row.cell-md`), no media pantalla.
36
+ `.filter-bar__filters` pasa a `display: contents`: el envoltorio conserva su
37
+ clase pero deja de ser una caja.
38
+
39
+ **`Alert` gana ranura de acciones** (`actions`, o `<Alert.Actions>` para el
40
+ modo composición), con la misma norma y el mismo nombre de clase que sus
41
+ hermanos `Banner` y `ConsentBanner`: por debajo de `md` apila y cada botón
42
+ ocupa la línea. Hasta ahora, quien necesitaba un botón en un aviso lo metía
43
+ dentro de la descripción y en móvil se quedaba a medio ancho. La ranura vive
44
+ **dentro** de `.alert__content`, que es quien declara la superficie interior
45
+ del relleno: un botón fuera de ella leería con la página en vez de con el
46
+ aviso. Tokens nuevos: `alert.actions-gap` y
47
+ `alert.actions-margin-block-start`.
48
+
49
+ **El pie de un diálogo se coloca por el ancho del diálogo** (`@container`, con
50
+ umbral `sm`), no por el de la ventana. `Sheet` ya usaba la pieza compartida
51
+ `.dialog-footer` y apilaba en móvil; el fallo estaba en escritorio, donde un
52
+ cajón lateral mide lo mismo que en un teléfono —320px, 256 de hueco útil— y el
53
+ pie seguía siendo una fila: dos botones con su etiqueta no cabían. Ahora
54
+ `.sheet` y `.modal__content` se declaran contenedor de consulta, y el umbral es
55
+ el que hace falta para una fila de dos botones, no el ancho de una pantalla. El
56
+ cajón apila siempre; el diálogo centrado (560px, 494 de hueco) conserva su fila
57
+ donde la tenía. Es el caso que Fundamentos › Puntos de ruptura ya señalaba como
58
+ propio de `@container`.
59
+
60
+ Nueve historias de contrato nuevas o actualizadas, en el viewport que le toca a
61
+ cada una.
62
+
63
+ ## [38.15.0] — 2026-09-15
64
+
65
+ > **Minor.** El cajón de conversaciones del chat, en móvil: ocupa el ancho y su
66
+ > botón no cambia de forma al abrirse. `Sheet` gana `hideClose`.
67
+
68
+ El cajón medía 320px de 390 porque heredaba el ancho lateral del `Sheet`.
69
+ Mientras está abierto, la lista de conversaciones ES la pantalla: ahora mide lo
70
+ que el armazón. Sin media query, porque el cajón solo se monta por debajo de
71
+ `lg`.
72
+
73
+ Y al abrirse aparecía el aspa del `Sheet` encima del disparador, así que el
74
+ glifo cambiaba de «barra lateral» a «cerrar» según el estado. `Sheet` acepta
75
+ `hideClose` —por defecto no cambia para nadie— y el armazón pinta dentro del
76
+ cajón el MISMO botón que lo abrió, en el mismo sitio: pliega y despliega sin
77
+ cambiar de dibujo. Dos controles de cierre con formas distintas en la misma
78
+ pantalla son dos maneras de decir lo mismo.
79
+
10
80
  ## [38.14.0] — 2026-09-15
11
81
 
12
82
  > **Minor.** En móvil, las acciones ocupan la línea porque lo decide el sitio
@@ -141,6 +141,8 @@ var e = {
141
141
  "--alert-border-width": "1px",
142
142
  "--alert-gap": "0.75rem",
143
143
  "--alert-content-gap": "0.5rem",
144
+ "--alert-actions-gap": "0.75rem",
145
+ "--alert-actions-margin-block-start": "0.75rem",
144
146
  "--alert-bg": "#111e30",
145
147
  "--alert-border-color": "#ffffff",
146
148
  "--alert-title-font-size": "1rem",
@@ -5,6 +5,13 @@ export interface AlertProps extends React.ComponentPropsWithoutRef<'div'> {
5
5
  /** Título del alert. **Opcional**: en modo composición usa `children` (p. ej. `<Alert.Title>`). */
6
6
  title?: string;
7
7
  description?: React.ReactNode;
8
+ /**
9
+ * Ranura de acciones del aviso —normalmente un `Button` del sistema—, al pie
10
+ * del cuerpo. Los botones van **aquí y no dentro de la descripción**: la
11
+ * ranura es la que aplica la norma del sistema (por debajo de `md` apilan y
12
+ * cada uno ocupa la línea), y dentro del texto se quedan a medio ancho.
13
+ */
14
+ actions?: React.ReactNode;
8
15
  dismissible?: boolean;
9
16
  onDismiss?: () => void;
10
17
  /**
@@ -24,10 +31,16 @@ export interface AlertProps extends React.ComponentPropsWithoutRef<'div'> {
24
31
  }
25
32
  export type AlertTitleProps = React.ComponentPropsWithoutRef<'p'>;
26
33
  export type AlertDescriptionProps = React.ComponentPropsWithoutRef<'div'>;
34
+ export type AlertActionsProps = React.ComponentPropsWithoutRef<'div'>;
27
35
  /** Subparte de composición: título del alert. */
28
36
  export declare const AlertTitle: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
29
37
  /** Subparte de composición: descripción del alert. */
30
38
  export declare const AlertDescription: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
39
+ /**
40
+ * Subparte de composición: las acciones del alert. Equivale a la prop
41
+ * `actions` y es la pieza para el modo composición.
42
+ */
43
+ export declare const AlertActions: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
31
44
  /**
32
45
  * Namespace de composición. Las subpartes también están disponibles como **named
33
46
  * exports** (`AlertTitle`, `AlertDescription`): en **Server Components (RSC)** usa los
@@ -36,4 +49,5 @@ export declare const AlertDescription: import("react").ForwardRefExoticComponent
36
49
  export declare const Alert: import("react").ForwardRefExoticComponent<AlertProps & import("react").RefAttributes<HTMLDivElement>> & {
37
50
  Title: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
38
51
  Description: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
52
+ Actions: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
39
53
  };
@@ -15,6 +15,12 @@ export interface SheetProps extends Omit<React.ComponentPropsWithoutRef<'div'>,
15
15
  footer?: ReactNode;
16
16
  children: ReactNode;
17
17
  closeLabel?: string;
18
+ /**
19
+ * Oculta el aspa de la esquina. Para un cajón cuyo propio disparador queda
20
+ * a la vista y ya sirve para cerrarlo: dos controles de cierre en la misma
21
+ * pantalla, con glifos distintos, son dos formas de decir lo mismo.
22
+ */
23
+ hideClose?: boolean;
18
24
  /** Elemento que abre el panel. Sin él, la apertura la controla el consumidor. */
19
25
  trigger?: ReactNode;
20
26
  /**
@@ -53,4 +59,4 @@ export declare function SheetFooter({ className, ...props }: React.HTMLAttribute
53
59
  * handlers son lo que permite montar la barrera de eventos cuando el panel se
54
60
  * abre desde dentro de una tarjeta clicable, sin `div`s de producto alrededor.
55
61
  */
56
- export declare function Sheet({ open, onOpenChange, side, title, titleHidden, description, footer, children, closeLabel, trigger, container, onAnimationEndCapture, className, ...rest }: SheetProps): import("react/jsx-runtime").JSX.Element;
62
+ export declare function Sheet({ open, onOpenChange, side, title, titleHidden, description, footer, children, closeLabel, hideClose, trigger, container, onAnimationEndCapture, className, ...rest }: SheetProps): import("react/jsx-runtime").JSX.Element;
package/dist/alert.css CHANGED
@@ -1 +1 @@
1
- :root{--alert-padding-block:var(--spacing-4);--alert-padding-inline:var(--spacing-5);--alert-gap:var(--spacing-3);--alert-content-gap:var(--spacing-2);--alert-title-line-height:var(--line-height-snug);--alert-close-size:var(--size-component-sm);--alert-close-inset:var(--spacing-2);--alert-border-radius:var(--border-radius-default);--alert-border-width:var(--border-width-default);--alert-bg:var(--color-primary);--alert-border-color:var(--color-text-on-dark);--alert-title-font-size:var(--text-font-size);--alert-title-font-weight:var(--font-weight-emphasis);--alert-title-color:var(--color-text-on-dark);--alert-description-font-size:var(--text-font-size);--alert-description-line-height:var(--text-line-height);--alert-description-color:var(--color-text-on-dark);--alert-success-bg:var(--color-success-fill);--alert-success-border-color:var(--color-success-fill);--alert-success-title-color:var(--color-success-fill-text);--alert-success-description-color:var(--color-success-fill-text);--alert-error-bg:var(--color-error-fill);--alert-error-border-color:var(--color-error-fill);--alert-error-title-color:var(--color-error-fill-text);--alert-error-description-color:var(--color-error-fill-text);--alert-warning-bg:var(--color-warning-fill);--alert-warning-border-color:var(--color-warning-fill);--alert-warning-title-color:var(--color-warning-fill-text);--alert-warning-description-color:var(--color-warning-fill-text);--alert-warning-close-color:var(--color-warning-fill-text)}.surface-dark,.surface-invert,[data-theme=dark],html.dark{--alert-bg:var(--color-text-on-dark);--alert-border-color:var(--color-text-on-dark);--alert-title-color:var(--color-primary);--alert-description-color:var(--color-primary)}.alert{background-color:var(--alert-bg);border:var(--alert-border-width) solid var(--alert-border-color);border-radius:var(--alert-border-radius);padding-block:var(--alert-padding-block);padding-inline:var(--alert-padding-inline);align-items:flex-start;gap:var(--alert-gap);box-sizing:border-box;--alert-title-ink:var(--alert-title-color);--alert-description-ink:var(--alert-description-color);display:flex;position:relative}.alert.alert--dismissible{padding-inline-end:calc(var(--alert-close-inset) * 2 + var(--alert-close-size))}.alert__content{flex:1;min-width:0}.alert__title{font-size:var(--alert-title-font-size);font-weight:var(--alert-title-font-weight);color:var(--alert-title-ink);line-height:var(--alert-title-line-height);margin:0}.alert__description{font-size:var(--alert-description-font-size);color:var(--alert-description-ink);line-height:var(--alert-description-line-height);margin:0;align-items:start;gap:var(--alert-content-gap);flex-direction:column;margin-block-start:var(--alert-content-gap);display:flex}.alert .alert__close{--close-button-size:var(--alert-close-size);position:absolute;inset-block-start:var(--alert-close-inset);inset-inline-end:var(--alert-close-inset)}.alert.alert--success{--alert-bg:var(--alert-success-bg);--alert-border-color:var(--alert-success-border-color);--alert-title-color:var(--alert-success-title-color);--alert-description-color:var(--alert-success-description-color)}.alert.alert--error{--alert-bg:var(--alert-error-bg);--alert-border-color:var(--alert-error-border-color);--alert-title-color:var(--alert-error-title-color);--alert-description-color:var(--alert-error-description-color)}.alert.alert--warning{--alert-bg:var(--alert-warning-bg);--alert-border-color:var(--alert-warning-border-color);--alert-title-color:var(--alert-warning-title-color);--alert-description-color:var(--alert-warning-description-color);--close-button-color:var(--alert-warning-close-color);--close-button-focus-ring-color:var(--alert-warning-close-color)}
1
+ :root{--alert-padding-block:var(--spacing-4);--alert-padding-inline:var(--spacing-5);--alert-gap:var(--spacing-3);--alert-content-gap:var(--spacing-2);--alert-actions-margin-block-start:var(--spacing-3);--alert-title-line-height:var(--line-height-snug);--alert-close-size:var(--size-component-sm);--alert-close-inset:var(--spacing-2);--alert-border-radius:var(--border-radius-default);--alert-border-width:var(--border-width-default);--alert-actions-gap:var(--form-actions-gap);--alert-bg:var(--color-primary);--alert-border-color:var(--color-text-on-dark);--alert-title-font-size:var(--text-font-size);--alert-title-font-weight:var(--font-weight-emphasis);--alert-title-color:var(--color-text-on-dark);--alert-description-font-size:var(--text-font-size);--alert-description-line-height:var(--text-line-height);--alert-description-color:var(--color-text-on-dark);--alert-success-bg:var(--color-success-fill);--alert-success-border-color:var(--color-success-fill);--alert-success-title-color:var(--color-success-fill-text);--alert-success-description-color:var(--color-success-fill-text);--alert-error-bg:var(--color-error-fill);--alert-error-border-color:var(--color-error-fill);--alert-error-title-color:var(--color-error-fill-text);--alert-error-description-color:var(--color-error-fill-text);--alert-warning-bg:var(--color-warning-fill);--alert-warning-border-color:var(--color-warning-fill);--alert-warning-title-color:var(--color-warning-fill-text);--alert-warning-description-color:var(--color-warning-fill-text);--alert-warning-close-color:var(--color-warning-fill-text)}.surface-dark,.surface-invert,[data-theme=dark],html.dark{--alert-bg:var(--color-text-on-dark);--alert-border-color:var(--color-text-on-dark);--alert-title-color:var(--color-primary);--alert-description-color:var(--color-primary)}.alert{background-color:var(--alert-bg);border:var(--alert-border-width) solid var(--alert-border-color);border-radius:var(--alert-border-radius);padding-block:var(--alert-padding-block);padding-inline:var(--alert-padding-inline);align-items:flex-start;gap:var(--alert-gap);box-sizing:border-box;--alert-title-ink:var(--alert-title-color);--alert-description-ink:var(--alert-description-color);display:flex;position:relative}.alert.alert--dismissible{padding-inline-end:calc(var(--alert-close-inset) * 2 + var(--alert-close-size))}.alert__content{flex:1;min-width:0}.alert__title{font-size:var(--alert-title-font-size);font-weight:var(--alert-title-font-weight);color:var(--alert-title-ink);line-height:var(--alert-title-line-height);margin:0}.alert__description{font-size:var(--alert-description-font-size);color:var(--alert-description-ink);line-height:var(--alert-description-line-height);margin:0;align-items:start;gap:var(--alert-content-gap);flex-direction:column;margin-block-start:var(--alert-content-gap);display:flex}.alert__actions{align-items:stretch;gap:var(--alert-actions-gap);flex-direction:column;margin-block-start:var(--alert-actions-margin-block-start);display:flex}.alert__actions>*{inline-size:100%}@media (width>=768px){.alert__actions{flex-flow:wrap;align-items:center}.alert__actions>*{inline-size:auto}}.alert .alert__close{--close-button-size:var(--alert-close-size);position:absolute;inset-block-start:var(--alert-close-inset);inset-inline-end:var(--alert-close-inset)}.alert.alert--success{--alert-bg:var(--alert-success-bg);--alert-border-color:var(--alert-success-border-color);--alert-title-color:var(--alert-success-title-color);--alert-description-color:var(--alert-success-description-color)}.alert.alert--error{--alert-bg:var(--alert-error-bg);--alert-border-color:var(--alert-error-border-color);--alert-title-color:var(--alert-error-title-color);--alert-description-color:var(--alert-error-description-color)}.alert.alert--warning{--alert-bg:var(--alert-warning-bg);--alert-border-color:var(--alert-warning-border-color);--alert-title-color:var(--alert-warning-title-color);--alert-description-color:var(--alert-warning-description-color);--close-button-color:var(--alert-warning-close-color);--close-button-focus-ring-color:var(--alert-warning-close-color)}
package/dist/alert.js CHANGED
@@ -23,19 +23,26 @@ var a = {
23
23
  ...r,
24
24
  children: n
25
25
  });
26
- }), c = r(function({ variant: r = "default", title: o, description: s, dismissible: c = !1, onDismiss: l, finalFocus: u, closeLabel: d = "Cerrar", className: f, children: p, role: m, ...h }, g) {
27
- let [_, v] = i(!1);
28
- if (_) return null;
29
- let y = [
26
+ }), c = r(function({ className: e, children: n, ...r }, i) {
27
+ return /* @__PURE__ */ t("div", {
28
+ ref: i,
29
+ className: ["alert__actions", e ?? ""].filter(Boolean).join(" "),
30
+ ...r,
31
+ children: n
32
+ });
33
+ }), l = r(function({ variant: r = "default", title: o, description: s, actions: c, dismissible: l = !1, onDismiss: u, finalFocus: d, closeLabel: f = "Cerrar", className: p, children: m, role: h, ...g }, _) {
34
+ let [v, y] = i(!1);
35
+ if (v) return null;
36
+ let b = [
30
37
  "alert",
31
38
  r === "default" ? "" : `alert--${r}`,
32
39
  r === "success" || r === "error" ? "surface-dark" : "",
33
- c ? "alert--dismissible" : "",
34
- f ?? ""
35
- ].filter(Boolean).join(" "), b = r === "default" ? " surface-invert" : "";
36
- function x() {
40
+ l ? "alert--dismissible" : "",
41
+ p ?? ""
42
+ ].filter(Boolean).join(" "), x = r === "default" ? " surface-invert" : "";
43
+ function S() {
37
44
  if (typeof document > "u") return;
38
- let e = u?.current;
45
+ let e = d?.current;
39
46
  if (e) {
40
47
  e.focus();
41
48
  return;
@@ -43,16 +50,16 @@ var a = {
43
50
  let t = document.body, n = t.hasAttribute("tabindex");
44
51
  n || t.setAttribute("tabindex", "-1"), t.focus(), n || t.removeAttribute("tabindex");
45
52
  }
46
- function S() {
47
- x(), l ? l() : v(!0);
53
+ function C() {
54
+ S(), u ? u() : y(!0);
48
55
  }
49
56
  return /* @__PURE__ */ n("div", {
50
- ref: g,
51
- role: m ?? a[r],
52
- className: y,
53
- ...h,
57
+ ref: _,
58
+ role: h ?? a[r],
59
+ className: b,
60
+ ...g,
54
61
  children: [/* @__PURE__ */ n("div", {
55
- className: `alert__content${b}`,
62
+ className: `alert__content${x}`,
56
63
  children: [
57
64
  o && /* @__PURE__ */ t("p", {
58
65
  className: "alert__title",
@@ -62,17 +69,22 @@ var a = {
62
69
  className: "alert__description",
63
70
  children: s
64
71
  }),
65
- p
72
+ m,
73
+ c && /* @__PURE__ */ t("div", {
74
+ className: "alert__actions",
75
+ children: c
76
+ })
66
77
  ]
67
- }), c && /* @__PURE__ */ t(e, {
68
- className: `alert__close${b}`,
69
- label: d,
70
- onClick: S
78
+ }), l && /* @__PURE__ */ t(e, {
79
+ className: `alert__close${x}`,
80
+ label: f,
81
+ onClick: C
71
82
  })]
72
83
  });
73
- }), l = Object.assign(c, {
84
+ }), u = Object.assign(l, {
74
85
  Title: o,
75
- Description: s
86
+ Description: s,
87
+ Actions: c
76
88
  });
77
89
  //#endregion
78
- export { l as Alert, s as AlertDescription, o as AlertTitle };
90
+ export { u as Alert, c as AlertActions, s as AlertDescription, o as AlertTitle };