@studiolxd/brand 44.1.0 → 45.1.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 (37) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/dist/_shared/tokens.js +9 -0
  3. package/dist/_types/messages/BrandMessages.d.ts +13 -1
  4. package/dist/_types/messages/index.d.ts +1 -1
  5. package/dist/_types/molecules/Alert/Alert.d.ts +13 -2
  6. package/dist/_types/molecules/AvatarUpload/AvatarUpload.d.ts +3 -3
  7. package/dist/_types/molecules/Banner/Banner.d.ts +12 -2
  8. package/dist/_types/molecules/ConfirmDialog/ConfirmDialog.d.ts +36 -9
  9. package/dist/_types/molecules/Consent/Consent.d.ts +7 -1
  10. package/dist/_types/molecules/ImageCropDialog/ImageCropDialog.d.ts +3 -3
  11. package/dist/_types/molecules/Modal/Modal.d.ts +21 -4
  12. package/dist/_types/molecules/Sheet/Sheet.d.ts +15 -0
  13. package/dist/_types/molecules/Toast/Toaster.d.ts +18 -4
  14. package/dist/alert.js +50 -49
  15. package/dist/banner.js +24 -23
  16. package/dist/brand.css +137 -6
  17. package/dist/confirm-dialog.js +56 -55
  18. package/dist/consent.js +3 -3
  19. package/dist/modal.js +32 -31
  20. package/dist/multi-select.css +1 -1
  21. package/dist/multi-select.js +1 -2
  22. package/dist/select.css +1 -1
  23. package/dist/select.js +1 -2
  24. package/dist/sheet.js +31 -29
  25. package/dist/toaster.js +44 -43
  26. package/dist/tokens.css +137 -6
  27. package/package.json +1 -1
  28. package/src/tokens/components/control.css +4 -1
  29. package/src/tokens/components/multi-select.css +3 -0
  30. package/src/tokens/components/select.css +3 -0
  31. package/src/tokens/molecules/filter-bar.css +2 -2
  32. package/src/tokens/scss/components/_control.scss +4 -1
  33. package/src/tokens/scss/components/_multi-select.scss +3 -0
  34. package/src/tokens/scss/components/_select.scss +3 -0
  35. package/src/tokens/scss/molecules/_filter-bar.scss +2 -2
  36. package/src/tokens/surface-public.css +124 -2
  37. package/src/tokens/tokens.json +9 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,85 @@ 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
+ ## [45.1.0] — 2026-09-15
11
+
12
+ > **Minor.** La superficie pública pone los controles en talla lg, igual que hace con el
13
+ > texto.
14
+
15
+ ### `.site-shell` parte de lg también en los controles
16
+
17
+ El bloque subía el cuerpo a 20px y dejaba los campos en la talla de aplicación: en una
18
+ página pública el texto era grande y los buscadores, filtros y botones de al lado no. Misma
19
+ omisión que tenía el término de la ficha hasta la v39.0.0, y misma respuesta: en el bloque,
20
+ no en cada app.
21
+
22
+ No se enumeran controles a mano. Cada control ya declara su talla lg en tokens hermanos
23
+ (`input.lg-height` junto a `input.height`), de donde bebe su modificador `--lg`; ahora
24
+ `.site-shell` apunta cada token de partida a su hermano `lg-*`, y lo que hereda de un
25
+ control sube con él. Un control nuevo entra solo por tener sus tokens `lg-*`. La familia
26
+ base (`control.*`) estrena su par lg, y el motor de tokens arrastra ahora una referencia
27
+ metida dentro de una fórmula —sin eso el renglón reservado para el rótulo de la barra de
28
+ filtros se quedaba corto y descolocaba el interruptor—.
29
+
30
+ **El botón entra**: 40→48px y 16→20px, porque un botón md junto a un campo de 48 se lee
31
+ como un control de otra talla justo donde más se juntan. **El chevron del `Select`** era lo
32
+ único de la caja que no subía —su tamaño salía de una prop de React y no de un token— y
33
+ ahora es token (16→24px).
34
+
35
+ Medido en Chromium: dentro del shell, campo, selector, selector múltiple, campo de fecha y
36
+ botón a 48px/20px, exactamente lg; fuera, 40px/16px. El interruptor, su campo y el botón de
37
+ acciones de la barra siguen con el centro en el mismo píxel.
38
+
39
+ **Dos matices, documentados.** `size="sm"` sigue mandando dentro del shell; lo que ya no
40
+ se distingue de lg es un `size="md"` escrito a mano. Y **lo que sale por un portal** —la
41
+ lista de un `Select`, el calendario de un `DatePicker`— monta en `document.body` y no
42
+ hereda la superficie: el disparador va a 48/20 y su lista se queda en la talla de
43
+ aplicación. Es el mismo caso que `Modal` y `Sheet` documentan, y la misma respuesta
44
+ (`container`), pero los campos `*Field` no lo exponen todavía.
45
+
46
+ ## [45.0.0] — 2026-09-15
47
+
48
+ > **Major.** Sexta familia al proveedor de textos: diálogos y superficies. `Modal`, `Sheet`,
49
+ > `ConfirmDialog`, `Alert`, `Banner` y `Toaster` dejan de traer castellano puesto — y el
50
+ > botón de confirmar de un diálogo pasa a exigir su texto.
51
+
52
+ ### Los diálogos leen del proveedor
53
+
54
+ Seis espacios nuevos en `BrandMessages`: `modal` (close, fallbackTitle), `sheet` (close),
55
+ `confirmDialog` (cancel, pending), `alert` (close), `banner` (dismiss) y `toaster`
56
+ (container, close). Mismo orden —**prop → proveedor → error**— y cada texto se lee **donde
57
+ se pinta**: el título de respaldo solo sin `title`, el aspa del aviso solo si es
58
+ descartable, el «Confirmando…» solo mientras la promesa corre. La mayoría de los usos no
59
+ exige ninguna clave nueva.
60
+
61
+ Con ello se cierran los dos reenvíos que la v44 dejó apuntados (`ImageCropDialog.closeLabel`
62
+ y `AvatarUpload.cropCloseLabel` llegan ya a un `Modal` que lee del proveedor), y
63
+ `Consent.closeLabel` pierde su default por lo mismo: tapaba el del `Modal`.
64
+
65
+ ### Breaking — `ConfirmDialog.confirmLabel` es obligatorio
66
+
67
+ Pasa a **obligatorio y sin default**, y **no entra en el catálogo** aunque `common.confirm`
68
+ exista. El botón de confirmar es el único punto del diálogo donde se toma la decisión, y
69
+ por eso es el único donde el texto tiene que nombrar la consecuencia —«Borrar la
70
+ organización», «Revocar la clave»—. Un default lo haría decir «Confirmar» en todas partes
71
+ sin que nada fallara, que es justo el rótulo que la documentación del componente lleva
72
+ pidiendo que no se use; y siendo opcional, nadie llegaría a escribir el bueno: el default
73
+ es lo que quita la presión de pensarlo. Mismo trato que el de `ImageCropDialog`.
74
+
75
+ `pendingLabel`, en cambio, sí es cromo aunque se pinte sobre el mismo botón: se lee
76
+ **mientras ya se ejecuta**, sobre un control deshabilitado. Nadie decide nada leyéndolo.
77
+
78
+ ### Lo que se queda como prop
79
+
80
+ `title`, `description`, los pies, el texto de cada aviso, `secondaryActionLabel`, y los
81
+ `confirmPhraseLabel` / `confirmPhraseMismatch` de la v39, que siguen obligatorios.
82
+
83
+ ### Para quien actualice
84
+
85
+ El `<Toaster />` tiene que quedar **dentro** del `BrandMessagesProvider`: montado como
86
+ hermano suyo revienta en el primer render. Y cada `ConfirmDialog` sin `confirmLabel` deja de
87
+ compilar — los que hoy caían en «Confirmar» son exactamente los que estaban mal.
88
+
10
89
  ## [44.1.0] — 2026-09-15
11
90
 
12
91
  > **Minor.** Las estrellas ganadas de `StarRating` se rellenan en accent-2 sobre superficie
@@ -684,6 +684,9 @@ var e = {
684
684
  "--control-focus-ring-inset-offset": "1px",
685
685
  "--control-padding-inline": "1rem",
686
686
  "--control-padding-block": "1rem",
687
+ "--control-lg-height": "3rem",
688
+ "--control-lg-font-size": "1.25rem",
689
+ "--control-lg-padding-inline": "1.5rem",
687
690
  "--copyable-value-gap": "0.75rem",
688
691
  "--description-list-border-width": "1px",
689
692
  "--description-list-border-style": "solid",
@@ -1202,6 +1205,9 @@ var e = {
1202
1205
  "--multi-select-item-selected-font-weight": "700",
1203
1206
  "--multi-select-icon-transition-easing": "ease",
1204
1207
  "--multi-select-selection-gap": "0.25rem",
1208
+ "--multi-select-icon-size": "16px",
1209
+ "--multi-select-sm-icon-size": "8px",
1210
+ "--multi-select-lg-icon-size": "24px",
1205
1211
  "--multi-select-sm-font-size": "0.875rem",
1206
1212
  "--multi-select-sm-padding-inline": "0.5rem",
1207
1213
  "--multi-select-sm-item-padding-block": "0.25rem",
@@ -1475,6 +1481,9 @@ var e = {
1475
1481
  "--select-item-selected-font-weight": "500",
1476
1482
  "--select-item-highlighted-bg": "#111e30",
1477
1483
  "--select-item-highlighted-color": "#ffffff",
1484
+ "--select-icon-size": "16px",
1485
+ "--select-sm-icon-size": "8px",
1486
+ "--select-lg-icon-size": "24px",
1478
1487
  "--select-sm-font-size": "0.875rem",
1479
1488
  "--select-sm-padding-inline": "0.5rem",
1480
1489
  "--select-sm-item-padding-block": "0.25rem",
@@ -19,6 +19,12 @@ import type { TimeSelectMessages } from '../atoms/TimeSelect/TimeSelect';
19
19
  import type { FileUploadMessages } from '../atoms/FileUpload/FileUpload';
20
20
  import type { ImageCropDialogMessages } from '../molecules/ImageCropDialog/ImageCropDialog';
21
21
  import type { AvatarUploadMessages } from '../molecules/AvatarUpload/AvatarUpload';
22
+ import type { ModalMessages } from '../molecules/Modal/Modal';
23
+ import type { SheetMessages } from '../molecules/Sheet/Sheet';
24
+ import type { ConfirmDialogMessages } from '../molecules/ConfirmDialog/ConfirmDialog';
25
+ import type { AlertMessages } from '../molecules/Alert/Alert';
26
+ import type { BannerMessages } from '../molecules/Banner/Banner';
27
+ import type { ToasterMessages } from '../molecules/Toast/Toaster';
22
28
  /**
23
29
  * El contrato de textos de la librería: un espacio por componente, y dentro
24
30
  * de cada espacio **todas las claves obligatorias**.
@@ -62,5 +68,11 @@ export interface BrandMessages {
62
68
  fileUpload: FileUploadMessages;
63
69
  imageCropDialog: ImageCropDialogMessages;
64
70
  avatarUpload: AvatarUploadMessages;
71
+ modal: ModalMessages;
72
+ sheet: SheetMessages;
73
+ confirmDialog: ConfirmDialogMessages;
74
+ alert: AlertMessages;
75
+ banner: BannerMessages;
76
+ toaster: ToasterMessages;
65
77
  }
66
- export type { PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, FileUploadMessages, ImageCropDialogMessages, AvatarUploadMessages, };
78
+ export type { PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, FileUploadMessages, ImageCropDialogMessages, AvatarUploadMessages, ModalMessages, SheetMessages, ConfirmDialogMessages, AlertMessages, BannerMessages, ToasterMessages, };
@@ -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, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, FileUploadMessages, ImageCropDialogMessages, AvatarUploadMessages, } from './BrandMessages';
5
+ export type { BrandMessages, PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, CalendarMessages, DatePickerMessages, TimeSelectMessages, FileUploadMessages, ImageCropDialogMessages, AvatarUploadMessages, ModalMessages, SheetMessages, ConfirmDialogMessages, AlertMessages, BannerMessages, ToasterMessages, } from './BrandMessages';
@@ -1,4 +1,14 @@
1
1
  import './Alert.css';
2
+ /**
3
+ * El cromo del aviso. Solo hay uno: el aspa que lo descarta, que dice lo
4
+ * mismo en todos los avisos del sistema. El `title`, la `description` y lo
5
+ * que digan las acciones son contenido —el aviso habla de lo que ha pasado en
6
+ * ESA pantalla— y siguen llegando por props.
7
+ */
8
+ export interface AlertMessages {
9
+ /** Nombre accesible del aspa que descarta el aviso. */
10
+ close: string;
11
+ }
2
12
  export type AlertVariant = 'default' | 'success' | 'error' | 'warning';
3
13
  export interface AlertProps extends React.ComponentPropsWithoutRef<'div'> {
4
14
  variant?: AlertVariant;
@@ -24,8 +34,9 @@ export interface AlertProps extends React.ComponentPropsWithoutRef<'div'> {
24
34
  */
25
35
  finalFocus?: React.RefObject<HTMLElement | null>;
26
36
  /**
27
- * Etiqueta accesible del botón de cierre. Default: «Cerrar» (castellano).
28
- * Una app multiidioma debe pasarla traducida.
37
+ * Nombre accesible del botón de cierre. **Sin default**: sin él, sale de
38
+ * `alert.close` del `BrandMessagesProvider`. Solo se lee cuando el aspa se
39
+ * pinta: un aviso sin `dismissible` no lo exige.
29
40
  */
30
41
  closeLabel?: string;
31
42
  }
@@ -187,9 +187,9 @@ export interface AvatarUploadProps {
187
187
  */
188
188
  cropConfirmLabel?: ReactNode;
189
189
  /**
190
- * Etiqueta del aspa de cerrar. Se reenvía **tal cual** al `ImageCropDialog`
191
- * y de ahí al `Modal`, que todavía no lee del proveedor: mientras no se
192
- * migre, sin esta prop el aspa dice lo que diga `Modal`.
190
+ * Nombre accesible del aspa de cerrar. **Reenvío puro** al
191
+ * `ImageCropDialog` y de ahí al `Modal`: sin esta prop, el aspa lee
192
+ * `modal.close` del `BrandMessagesProvider`.
193
193
  */
194
194
  cropCloseLabel?: string;
195
195
  /**
@@ -1,4 +1,13 @@
1
1
  import './Banner.css';
2
+ /**
3
+ * El cromo de la barra. Solo hay uno: el aspa. Lo que la barra DICE
4
+ * (`children`) y lo que ofrezcan sus acciones son contenido —«estás viendo la
5
+ * aplicación como alguien», «dejar de suplantar»— y los pone la aplicación.
6
+ */
7
+ export interface BannerMessages {
8
+ /** Nombre accesible del aspa que descarta la barra. */
9
+ dismiss: string;
10
+ }
2
11
  export type BannerVariant = 'info' | 'warning';
3
12
  export interface BannerProps extends React.ComponentPropsWithoutRef<'div'> {
4
13
  /** Intención de la barra. Default `'info'` (relleno prusia); `'warning'` es el relleno de aviso. */
@@ -14,8 +23,9 @@ export interface BannerProps extends React.ComponentPropsWithoutRef<'div'> {
14
23
  */
15
24
  onDismiss?: () => void;
16
25
  /**
17
- * Nombre accesible del aspa. Default: «Descartar aviso» (castellano). Una app
18
- * multiidioma debe pasarlo traducido.
26
+ * Nombre accesible del aspa. **Sin default**: sin él, sale de
27
+ * `banner.dismiss` del `BrandMessagesProvider`. Solo se lee cuando el aspa
28
+ * se pinta, o sea cuando hay `onDismiss`.
19
29
  */
20
30
  dismissLabel?: string;
21
31
  }
@@ -1,6 +1,30 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import { type ModalProps } from '../Modal/Modal';
3
3
  import './ConfirmDialog.css';
4
+ /**
5
+ * El cromo de la confirmación, y **solo el cromo**. Aquí la línea entre
6
+ * cromo y contenido cae en medio del pie, así que conviene decirla entera:
7
+ *
8
+ * - **`cancel` es cromo.** La salida segura no cambia de una pantalla a otra:
9
+ * se sale de todas igual, y «Cancelar» describe lo único que hace el botón
10
+ * —no seguir—. No nombra ninguna consecuencia porque no la tiene.
11
+ * - **`pending` es cromo.** Es un estado, no una decisión: se pinta sobre el
12
+ * botón ya deshabilitado, mientras la acción corre. Nadie elige nada
13
+ * leyéndolo, así que no tiene que nombrar el verbo de la acción.
14
+ * - **`confirmLabel` NO está aquí y es una prop obligatoria.** Es la única
15
+ * parte del diálogo donde se toma la decisión, y por eso tiene que nombrar
16
+ * lo que va a pasar: «Eliminar la organización», «Revocar la clave»,
17
+ * «Expulsar del equipo». Un default de catálogo lo haría decir «Confirmar»
18
+ * en todas partes sin que nada fallara, que es exactamente el rótulo que el
19
+ * sistema no quiere — y, siendo opcional, nadie llegaría a escribir el
20
+ * bueno. Obligatoria, como el `confirmLabel` del `ImageCropDialog`.
21
+ */
22
+ export interface ConfirmDialogMessages {
23
+ /** Rótulo del botón que cancela. */
24
+ cancel: string;
25
+ /** Rótulo del botón de confirmar mientras la acción está en curso. */
26
+ pending: string;
27
+ }
4
28
  export interface ConfirmDialogBaseProps {
5
29
  open: boolean;
6
30
  /** Título del diálogo: la pregunta, no «Confirmar». */
@@ -43,23 +67,26 @@ export interface ConfirmDialogBaseProps {
43
67
  */
44
68
  destructive?: boolean;
45
69
  /**
46
- * Rótulo del botón que confirma. Default castellano.
47
- * @default 'Confirmar'
70
+ * Rótulo del botón que confirma. **Obligatorio y sin default**: es donde se
71
+ * toma la decisión, así que tiene que nombrar lo que va a pasar («Eliminar
72
+ * la organización»), y eso lo sabe la pantalla, no el diálogo. No sale del
73
+ * catálogo a propósito — ver `ConfirmDialogMessages`.
48
74
  */
49
- confirmLabel?: string;
75
+ confirmLabel: string;
50
76
  /**
51
- * Rótulo del botón que cancela. Default castellano.
52
- * @default 'Cancelar'
77
+ * Rótulo del botón que cancela. **Sin default**: sin él, sale de
78
+ * `confirmDialog.cancel` del `BrandMessagesProvider`.
53
79
  */
54
80
  cancelLabel?: string;
55
81
  /**
56
- * Rótulo del botón de confirmar mientras la acción está en curso. Default castellano.
57
- * @default 'Confirmando…'
82
+ * Rótulo del botón de confirmar mientras la acción está en curso. **Sin
83
+ * default**: sin él, sale de `confirmDialog.pending`. Solo se lee mientras
84
+ * la acción corre.
58
85
  */
59
86
  pendingLabel?: string;
60
87
  /**
61
- * Etiqueta del aspa de cierre. Default castellano.
62
- * @default 'Cerrar'
88
+ * Nombre accesible del aspa de cierre. **Reenvío puro al `Modal`**: sin él,
89
+ * el aspa lee `modal.close` del proveedor, como cualquier otro diálogo.
63
90
  */
64
91
  closeLabel?: string;
65
92
  /** Nodo donde montar el portal, como en `Modal`. */
@@ -93,7 +93,13 @@ export interface ConsentPreferencesProps {
93
93
  side?: 'top' | 'right' | 'bottom' | 'left';
94
94
  /** Título del panel. Default castellano: `'Preferencias de cookies'`. */
95
95
  title?: ReactNode;
96
- /** Etiqueta del botón de cerrar. Default castellano: `'Cerrar'`. */
96
+ /**
97
+ * Nombre accesible del botón de cerrar. **Reenvío puro** al `Modal` o al
98
+ * `Sheet` sobre el que se abre el panel: sin él, el aspa lee `modal.close`
99
+ * o `sheet.close` del `BrandMessagesProvider`. El resto de los textos de
100
+ * `Consent` sigue con su default castellano — este componente todavía no
101
+ * está migrado al proveedor.
102
+ */
97
103
  closeLabel?: string;
98
104
  /** Marca de una categoría necesaria. Default castellano: `'Siempre activa'`. */
99
105
  alwaysOnLabel?: string;
@@ -36,9 +36,9 @@ export interface ImageCropDialogProps {
36
36
  cancelLabel: ReactNode;
37
37
  confirmLabel: ReactNode;
38
38
  /**
39
- * Etiqueta del botón de cierre del diálogo. Se reenvía **tal cual** al
40
- * `Modal`, que todavía no lee del proveedor: mientras no se migre, sin esta
41
- * prop el aspa sigue diciendo lo que diga `Modal`.
39
+ * Nombre accesible del botón de cierre del diálogo. **Reenvío puro** al
40
+ * `Modal`: sin esta prop, el aspa lee `modal.close` del
41
+ * `BrandMessagesProvider`, como la de cualquier otro diálogo del sistema.
42
42
  */
43
43
  closeLabel?: string;
44
44
  /**
@@ -1,18 +1,35 @@
1
1
  import { Dialog } from '@base-ui/react/dialog';
2
2
  import './Modal.css';
3
+ /**
4
+ * El cromo del diálogo, y solo el cromo: las dos cosas que el `Modal` dice por
5
+ * su cuenta, sin que se las pase nadie.
6
+ *
7
+ * Aquí no hay nada que decidir por pantalla. El aspa cierra el diálogo —este y
8
+ * todos—, y el nombre de respaldo es lo que se anuncia cuando el diálogo no
9
+ * trae título: ninguno de los dos cambia de una pantalla a otra, así que los
10
+ * dos son catálogo. El `title`, la `description` y lo que digan los botones del
11
+ * pie son contenido y siguen viniendo de quien abre el diálogo.
12
+ */
13
+ export interface ModalMessages {
14
+ /** Nombre accesible del aspa que cierra el diálogo. */
15
+ close: string;
16
+ /** Nombre accesible del diálogo cuando no hay `title`. */
17
+ fallbackTitle: string;
18
+ }
3
19
  export interface ModalProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'title' | 'className'> {
4
20
  open: boolean;
5
21
  onClose: () => void;
6
22
  title?: string;
7
23
  children: React.ReactNode;
8
24
  /**
9
- * Nombre accesible del aspa de cierre. Default: «Cerrar» (castellano).
10
- * Una app multiidioma debe pasarlo traducido.
25
+ * Nombre accesible del aspa de cierre. **Sin default**: sin él, sale de
26
+ * `modal.close` del `BrandMessagesProvider`.
11
27
  */
12
28
  closeLabel?: string;
13
29
  /**
14
- * Nombre accesible del diálogo cuando no hay `title`. Default: «Diálogo»
15
- * (castellano). Una app multiidioma debe pasarlo traducido.
30
+ * Nombre accesible del diálogo cuando no hay `title`. **Sin default**: sin
31
+ * él, sale de `modal.fallbackTitle` del `BrandMessagesProvider`. Solo se
32
+ * lee cuando de verdad no hay título: un diálogo con `title` no lo exige.
16
33
  */
17
34
  fallbackTitle?: string;
18
35
  /**
@@ -1,6 +1,16 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import { Dialog } from '@base-ui/react/dialog';
3
3
  import './Sheet.css';
4
+ /**
5
+ * El cromo del panel. Solo hay uno: el aspa cierra el cajón, aquí y en
6
+ * cualquier otro, así que es catálogo. El `title` y la `description` son
7
+ * contenido y los sigue pasando quien abre el panel — este componente los
8
+ * exige como props, y el título además es obligatorio.
9
+ */
10
+ export interface SheetMessages {
11
+ /** Nombre accesible del aspa que cierra el panel. */
12
+ close: string;
13
+ }
4
14
  export interface SheetProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'title'> {
5
15
  open: boolean;
6
16
  onOpenChange: (open: boolean) => void;
@@ -14,6 +24,11 @@ export interface SheetProps extends Omit<React.ComponentPropsWithoutRef<'div'>,
14
24
  /** Fila de acciones al pie del panel. */
15
25
  footer?: ReactNode;
16
26
  children: ReactNode;
27
+ /**
28
+ * Nombre accesible del aspa de cierre. **Sin default**: sin él, sale de
29
+ * `sheet.close` del `BrandMessagesProvider`. Solo se lee cuando el aspa se
30
+ * pinta: un panel con `hideClose` no lo exige.
31
+ */
17
32
  closeLabel?: string;
18
33
  /**
19
34
  * Oculta el aspa de la esquina. Para un cajón cuyo propio disparador queda
@@ -1,17 +1,31 @@
1
1
  import { type ToastIntent } from './toast';
2
2
  import './Toast.css';
3
+ /**
4
+ * El cromo de la cola de avisos. Los dos textos son del punto de montaje, no
5
+ * de ningún aviso concreto: el rótulo de la región donde aterrizan y el aspa
6
+ * que los cierra. Lo que DICE cada aviso —su título, su descripción, el
7
+ * rótulo de su acción— lo pasa quien llama a `toast(...)`, y ya no tiene
8
+ * default castellano.
9
+ */
10
+ export interface ToasterMessages {
11
+ /** Nombre accesible de la región donde se apilan los avisos. */
12
+ container: string;
13
+ /** Nombre accesible del aspa que cierra un aviso. */
14
+ close: string;
15
+ }
3
16
  export type ToastPosition = 'bottom-right' | 'bottom-left' | 'bottom-center' | 'top-right' | 'top-left' | 'top-center';
4
17
  export interface ToasterProps {
5
18
  /** Esquina de la ventana donde se monta la pila. Default: `bottom-right`. */
6
19
  position?: ToastPosition;
7
20
  /**
8
- * Nombre accesible de la región de notificaciones. Default: «Notificaciones»
9
- * (castellano). Una app multiidioma debe pasarlo traducido.
21
+ * Nombre accesible de la región de notificaciones. **Sin default**: sin él,
22
+ * sale de `toaster.container` del `BrandMessagesProvider`.
10
23
  */
11
24
  containerAriaLabel?: string;
12
25
  /**
13
- * Etiqueta accesible del aspa de cierre. Default: «Cerrar» (castellano).
14
- * Una app multiidioma debe pasarla traducida.
26
+ * Nombre accesible del aspa de cierre. **Sin default**: sin él, sale de
27
+ * `toaster.close` del `BrandMessagesProvider`. Solo se lee cuando el aspa se
28
+ * pinta: un `Toaster` con `closeButton={false}` no lo exige.
15
29
  */
16
30
  closeLabel?: string;
17
31
  /** Muestra el aspa de cierre en cada aviso. Default: `true`. */
package/dist/alert.js CHANGED
@@ -1,48 +1,49 @@
1
1
  'use client';
2
2
  import './alert.css';
3
- import { CloseButton as e } from "./close-button.js";
4
- import { forwardRef as t, useState as n } from "react";
5
- import { jsx as r, jsxs as i } from "react/jsx-runtime";
3
+ import { n as e } from "./_shared/brandmessagescontext.js";
4
+ import { CloseButton as t } from "./close-button.js";
5
+ import { forwardRef as n, useState as r } from "react";
6
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
7
  //#region src/stories/molecules/Alert/Alert.tsx
7
- var a = {
8
+ var o = {
8
9
  default: "status",
9
10
  success: "status",
10
11
  error: "alert",
11
12
  warning: "alert"
12
- }, o = t(function({ className: e, children: t, ...n }, i) {
13
- return /* @__PURE__ */ r("p", {
14
- ref: i,
13
+ }, s = n(function({ className: e, children: t, ...n }, r) {
14
+ return /* @__PURE__ */ i("p", {
15
+ ref: r,
15
16
  className: ["alert__title", e ?? ""].filter(Boolean).join(" "),
16
17
  ...n,
17
18
  children: t
18
19
  });
19
- }), s = t(function({ className: e, children: t, ...n }, i) {
20
- return /* @__PURE__ */ r("div", {
21
- ref: i,
20
+ }), c = n(function({ className: e, children: t, ...n }, r) {
21
+ return /* @__PURE__ */ i("div", {
22
+ ref: r,
22
23
  className: ["alert__description", e ?? ""].filter(Boolean).join(" "),
23
24
  ...n,
24
25
  children: t
25
26
  });
26
- }), c = t(function({ className: e, children: t, ...n }, i) {
27
- return /* @__PURE__ */ r("div", {
28
- ref: i,
27
+ }), l = n(function({ className: e, children: t, ...n }, r) {
28
+ return /* @__PURE__ */ i("div", {
29
+ ref: r,
29
30
  className: ["alert__actions", e ?? ""].filter(Boolean).join(" "),
30
31
  ...n,
31
32
  children: t
32
33
  });
33
- }), l = t(function({ variant: t = "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] = n(!1);
35
- if (v) return null;
36
- let b = [
34
+ }), u = n(function({ variant: n = "default", title: s, description: c, actions: l, dismissible: u = !1, onDismiss: d, finalFocus: f, closeLabel: p, className: m, children: h, role: g, ..._ }, v) {
35
+ let y = e("alert"), [b, x] = r(!1);
36
+ if (b) return null;
37
+ let S = [
37
38
  "alert",
38
- t === "default" ? "" : `alert--${t}`,
39
- t === "success" || t === "error" ? "surface-dark" : "",
40
- l ? "alert--dismissible" : "",
41
- p ?? ""
42
- ].filter(Boolean).join(" "), x = t === "default" ? " surface-invert" : "";
43
- function S() {
39
+ n === "default" ? "" : `alert--${n}`,
40
+ n === "success" || n === "error" ? "surface-dark" : "",
41
+ u ? "alert--dismissible" : "",
42
+ m ?? ""
43
+ ].filter(Boolean).join(" "), C = n === "default" ? " surface-invert" : "";
44
+ function w() {
44
45
  if (typeof document > "u") return;
45
- let e = d?.current;
46
+ let e = f?.current;
46
47
  if (e) {
47
48
  e.focus();
48
49
  return;
@@ -50,41 +51,41 @@ var a = {
50
51
  let t = document.body, n = t.hasAttribute("tabindex");
51
52
  n || t.setAttribute("tabindex", "-1"), t.focus(), n || t.removeAttribute("tabindex");
52
53
  }
53
- function C() {
54
- S(), u ? u() : y(!0);
54
+ function T() {
55
+ w(), d ? d() : x(!0);
55
56
  }
56
- return /* @__PURE__ */ i("div", {
57
- ref: _,
58
- role: h ?? a[t],
59
- className: b,
60
- ...g,
61
- children: [/* @__PURE__ */ i("div", {
62
- className: `alert__content${x}`,
57
+ return /* @__PURE__ */ a("div", {
58
+ ref: v,
59
+ role: g ?? o[n],
60
+ className: S,
61
+ ..._,
62
+ children: [/* @__PURE__ */ a("div", {
63
+ className: `alert__content${C}`,
63
64
  children: [
64
- o && /* @__PURE__ */ r("p", {
65
+ s && /* @__PURE__ */ i("p", {
65
66
  className: "alert__title",
66
- children: o
67
+ children: s
67
68
  }),
68
- s && /* @__PURE__ */ r("div", {
69
+ c && /* @__PURE__ */ i("div", {
69
70
  className: "alert__description",
70
- children: s
71
+ children: c
71
72
  }),
72
- m,
73
- c && /* @__PURE__ */ r("div", {
73
+ h,
74
+ l && /* @__PURE__ */ i("div", {
74
75
  className: "alert__actions",
75
- children: c
76
+ children: l
76
77
  })
77
78
  ]
78
- }), l && /* @__PURE__ */ r(e, {
79
- className: `alert__close${x}`,
80
- label: f,
81
- onClick: C
79
+ }), u && /* @__PURE__ */ i(t, {
80
+ className: `alert__close${C}`,
81
+ label: y("close", p),
82
+ onClick: T
82
83
  })]
83
84
  });
84
- }), u = Object.assign(l, {
85
- Title: o,
86
- Description: s,
87
- Actions: c
85
+ }), d = Object.assign(u, {
86
+ Title: s,
87
+ Description: c,
88
+ Actions: l
88
89
  });
89
90
  //#endregion
90
- export { u as Alert, c as AlertActions, s as AlertDescription, o as AlertTitle };
91
+ export { d as Alert, l as AlertActions, c as AlertDescription, s as AlertTitle };
package/dist/banner.js CHANGED
@@ -1,39 +1,40 @@
1
1
  'use client';
2
2
  import './banner.css';
3
- import { CloseButton as e } from "./close-button.js";
4
- import { forwardRef as t } from "react";
5
- import { jsx as n, jsxs as r } from "react/jsx-runtime";
3
+ import { n as e } from "./_shared/brandmessagescontext.js";
4
+ import { CloseButton as t } from "./close-button.js";
5
+ import { forwardRef as n } from "react";
6
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
6
7
  //#region src/stories/molecules/Banner/Banner.tsx
7
- var i = t(function({ variant: t = "info", children: i, actions: a, onDismiss: o, dismissLabel: s = "Descartar aviso", className: c, role: l, "aria-live": u, ...d }, f) {
8
- let p = [
8
+ var a = n(function({ variant: n = "info", children: a, actions: o, onDismiss: s, dismissLabel: c, className: l, role: u, "aria-live": d, ...f }, p) {
9
+ let m = e("banner"), h = [
9
10
  "banner",
10
- `banner--${t}`,
11
- t === "info" ? "surface-dark" : "",
12
- o ? "banner--dismissible" : "",
13
- c ?? ""
11
+ `banner--${n}`,
12
+ n === "info" ? "surface-dark" : "",
13
+ s ? "banner--dismissible" : "",
14
+ l ?? ""
14
15
  ].filter(Boolean).join(" ");
15
- return /* @__PURE__ */ r("div", {
16
- ref: f,
17
- role: l ?? "status",
18
- "aria-live": u ?? "polite",
19
- className: p,
20
- ...d,
16
+ return /* @__PURE__ */ i("div", {
17
+ ref: p,
18
+ role: u ?? "status",
19
+ "aria-live": d ?? "polite",
20
+ className: h,
21
+ ...f,
21
22
  children: [
22
- /* @__PURE__ */ n("div", {
23
+ /* @__PURE__ */ r("div", {
23
24
  className: "banner__content",
24
- children: i
25
+ children: a
25
26
  }),
26
- a && /* @__PURE__ */ n("div", {
27
+ o && /* @__PURE__ */ r("div", {
27
28
  className: "banner__actions",
28
- children: a
29
+ children: o
29
30
  }),
30
- o && /* @__PURE__ */ n(e, {
31
+ s && /* @__PURE__ */ r(t, {
31
32
  className: "banner__close",
32
- label: s,
33
- onClick: o
33
+ label: m("dismiss", c),
34
+ onClick: s
34
35
  })
35
36
  ]
36
37
  });
37
38
  });
38
39
  //#endregion
39
- export { i as Banner };
40
+ export { a as Banner };