@studiolxd/brand 41.0.0 → 42.0.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 (44) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/dist/_shared/tokens.js +3 -0
  3. package/dist/_types/atoms/AsyncMultiSelect/AsyncMultiSelect.d.ts +28 -5
  4. package/dist/_types/atoms/AsyncSelect/AsyncSelect.d.ts +26 -6
  5. package/dist/_types/atoms/Button/Button.d.ts +17 -4
  6. package/dist/_types/atoms/InputPhone/InputPhone.d.ts +15 -4
  7. package/dist/_types/atoms/MultiSelect/MultiSelect.d.ts +20 -1
  8. package/dist/_types/atoms/NumberInput/NumberInput.d.ts +14 -4
  9. package/dist/_types/atoms/OtpInput/OtpInput.d.ts +15 -4
  10. package/dist/_types/atoms/Select/Select.d.ts +18 -1
  11. package/dist/_types/messages/BrandMessages.d.ts +25 -1
  12. package/dist/_types/messages/index.d.ts +1 -1
  13. package/dist/_types/molecules/Card/Card.d.ts +13 -4
  14. package/dist/_types/molecules/DocsSearch/DocsSearch.d.ts +31 -12
  15. package/dist/_types/molecules/FilterBar/FilterBar.d.ts +10 -1
  16. package/dist/_types/molecules/InputField/InputField.d.ts +16 -2
  17. package/dist/_types/molecules/MultiSelectField/MultiSelectField.d.ts +9 -1
  18. package/dist/_types/molecules/PasswordField/PasswordField.d.ts +22 -2
  19. package/dist/_types/molecules/SearchForm/SearchForm.d.ts +18 -6
  20. package/dist/_types/molecules/SelectField/SelectField.d.ts +5 -0
  21. package/dist/_types/organisms/AnnotationThread/AnnotationThread.d.ts +10 -1
  22. package/dist/annotation-thread.css +1 -1
  23. package/dist/async-multi-select.js +50 -49
  24. package/dist/async-select.js +89 -88
  25. package/dist/brand.css +4 -1
  26. package/dist/card.css +1 -1
  27. package/dist/docs-search.js +38 -37
  28. package/dist/filter-bar.css +1 -1
  29. package/dist/filter-bar.js +19 -17
  30. package/dist/input-field.js +66 -65
  31. package/dist/input-phone.js +39 -38
  32. package/dist/multi-select.js +109 -108
  33. package/dist/number-input.js +61 -60
  34. package/dist/otp-input.js +86 -85
  35. package/dist/password-field.js +46 -45
  36. package/dist/search-form.js +35 -34
  37. package/dist/select.js +75 -71
  38. package/dist/tokens.css +4 -1
  39. package/package.json +1 -1
  40. package/src/tokens/molecules/annotation-thread.css +1 -0
  41. package/src/tokens/molecules/filter-bar.css +2 -0
  42. package/src/tokens/scss/molecules/_annotation-thread.scss +1 -0
  43. package/src/tokens/scss/molecules/_filter-bar.scss +2 -0
  44. package/src/tokens/tokens.json +3 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,125 @@ 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
+ ## [42.0.0] — 2026-09-15
11
+
12
+ > **Major.** Tercera familia al proveedor de textos: los átomos y moléculas de formulario
13
+ > dejan de traer castellano puesto. Y la barra de filtros apila de verdad por debajo del
14
+ > punto de ruptura, no solo cuando la aritmética de la rejilla lo permitía.
15
+
16
+ ### Los formularios leen del proveedor
17
+
18
+ Doce componentes, doce espacios nuevos en `BrandMessages`: `inputField`, `passwordField`,
19
+ `select`, `multiSelect`, `numberInput`, `otpInput`, `inputPhone`, `asyncSelect`,
20
+ `asyncMultiSelect`, `searchForm`, `docsSearch` y `filterBar`. Los `*Field` que los envuelven
21
+ son reenvío puro y no tienen espacio propio: pasan la prop al átomo, y el átomo lee del
22
+ catálogo. Mismo orden que en las dos olas anteriores —**prop → proveedor → error**— y
23
+ mismo carácter: incompatible **en tiempo de compilación**, que es lo que se busca.
24
+
25
+ Esta familia iba ahora, y no más tarde, por un reenvío: `DataTable` pasaba
26
+ `searchClearLabel` a un `InputField` que seguía con su «Borrar» cableado, así que las
27
+ tablas no quedaban limpias del todo en una aplicación francesa hasta que cayera el átomo.
28
+ Ese reenvío está cerrado. Y de paso se ha visto lo que tapaba: `removeLabel`,
29
+ `decrementLabel`, `incrementLabel`, `digitLabel`, `countryLabel` y `loadingLabel` **no se
30
+ pasaban en ningún sitio de la suite** — esos controles salían en castellano dentro de las
31
+ aplicaciones en francés, alemán, neerlandés y portugués, y nadie lo había parcheado porque
32
+ nadie lo veía. Con el proveedor se corrigen sin tocar un solo punto de uso.
33
+
34
+ ### Lo que se queda como prop, y las dudosas
35
+
36
+ `label`, `helperText`, `errorMessage` y el `placeholder` que dice algo del campo son
37
+ **contenido de ese campo** y siguen siendo props; ninguno traía castellano que retirar. Las
38
+ que hubo que decidir mirando **el valor y no el nombre**: `Select.placeholder`
39
+ («Seleccionar…») es cromo, y la prop gana cuando el marcador dice algo del campo;
40
+ `SearchForm.label` («Buscar») es cromo, porque el buscador de sitio se llama igual en toda
41
+ la suite; `AsyncSelect.emptyMessage` («Sin resultados») es cromo, con la prop intacta para
42
+ un vacío propio. `DocsSearch.clearLabel` no tiene clave: el aspa es la del `InputField` de
43
+ debajo, y darle clave obligaría a traducir «Borrar» dos veces y a que coincidieran.
44
+ `InputPhone.internationalLabel` conserva su «🌐»: un glifo no se traduce.
45
+
46
+ El sistema **no tiene marca de obligatorio ni de «opcional»** — ni `Label` ni ningún
47
+ `*Field` la emiten. No había nada que migrar ahí; si algún día se quiere, es una pieza
48
+ nueva.
49
+
50
+ ### `FilterBar`: una columna por debajo de `md`, de verdad
51
+
52
+ Su documentación prometía una columna por debajo del punto de ruptura y sus acciones sí
53
+ conmutaban ahí, pero los filtros se dejaban a la aritmética de la rejilla
54
+ (`minmax(min(192px, 100%), 1fr)`), que solo apila por fuerza por debajo de unos 400px.
55
+ Medido en Chromium: a 320 y 390px, una columna; **a 430, 600, 700 y 760px, dos o tres
56
+ columnas y un selector a media línea**. Es justo lo que se veía en un teléfono apaisado.
57
+ Ahora la base es `1fr` y la rejilla `auto-fill` vive dentro del `@media (min-width: 768px)`
58
+ que ya existía.
59
+
60
+ El test que debía haberlo cogido medía la caja equivocada: comprobaba que la **celda**
61
+ llenaba la línea —y lo hacía siempre—, no el **control** de dentro, que era lo que se
62
+ quedaba corto, y solo en una franja que ningún preset de ventana de Storybook toca. El test
63
+ nuevo mide el control y mide a 600px.
64
+
65
+ `FilterBar` pasa a ser componente cliente: leer del contexto lo exige.
66
+
67
+ ### Un solo fixture inglés para las historias
68
+
69
+ Las historias «Textos desde el proveedor (otro idioma)» de esta ola y de las dos anteriores
70
+ importan un único `.storybook/brandMessagesFixtureEn.ts`, hermano del castellano, en vez de
71
+ repetir el literal en cada una. El test que vigila que ningún fixture se publica ahora
72
+ enumera lo que hay en `.storybook/`, así que el de la próxima ola queda cubierto por
73
+ existir.
74
+
75
+ ## [41.1.0] — 2026-09-15
76
+
77
+ > **Minor.** El interruptor de la barra de filtros se centra con el campo que tiene al
78
+ > lado, el pie de una tarjeta cumple la norma de las acciones por sí solo, y `block` queda
79
+ > escrito como lo que es: la excepción.
80
+
81
+ ### `FilterBar`: un control sin rótulo, a la altura del que sí lo lleva
82
+
83
+ Un interruptor no lleva rótulo encima y un campo sí, así que en la rejilla el interruptor
84
+ se pegaba arriba, a la altura de los **rótulos** en vez de a la de los **campos**. Ahora la
85
+ barra le reserva a esa celda el renglón del rótulo —medido por token, no a ojo— y, en el
86
+ espacio que queda, abre una caja de **la altura de un campo** y centra el control dentro.
87
+
88
+ Medido en Chromium: los centros de la caja del campo, del interruptor y del botón de las
89
+ acciones caen en el mismo píxel. La referencia es la **talla estándar del campo**, no el
90
+ alto real del renglón, y eso es lo que permite tener las dos cosas a la vez: un control que
91
+ crece hacia abajo —un selector múltiple con fichas— sigue creciendo sin mover a nadie, y
92
+ los rótulos siguen todos en su línea. Donde ningún filtro lleva rótulo no se reserva nada,
93
+ y apilado, por debajo del punto de ruptura, tampoco.
94
+
95
+ ### `CardFooter` cumple la norma solo
96
+
97
+ Era la única ranura de acciones del sistema que no lo hacía: siempre una fila, con la
98
+ columna a pedir a mano — la prop de escape que la norma vino a quitar, mudada del botón al
99
+ contenedor. Ahora, por debajo de `md`, sus acciones ocupan la línea como en las otras once
100
+ ranuras.
101
+
102
+ `direction="column"` **se queda**, y con un significado más limpio: ya no es «acuérdate de
103
+ apilar en móvil», sino «apila **siempre**, también donde hay sitio» — el pie con una línea
104
+ de texto sobre el botón, o la tarjeta que se sabe estrecha en escritorio.
105
+
106
+ **Por qué por ventana y no por contenedor**, que es el hallazgo que merece quedar escrito:
107
+ se intentó como el pie de un diálogo y se midió antes de darlo por bueno. Declarar la
108
+ tarjeta como contenedor (`container-type: inline-size`) le quita el ancho que saca de su
109
+ contenido: dos tarjetas dentro de un `Inline` pasan de medir lo que mide su texto a 34px,
110
+ solo su propio aire. **Una tarjeta no puede ser contenedor** porque se usa de las dos
111
+ maneras —unas veces la estira su hueco, otras la mide su contenido—; un diálogo sí, porque
112
+ su ancho siempre viene de fuera. Queda en `Foundations › Puntos de ruptura` como el primer
113
+ límite documentado de la técnica.
114
+
115
+ ### `Button.block`, escrito al derecho
116
+
117
+ Su documentación decía que era «lo que quiere un botón suelto dentro de una página», que es
118
+ justo la invitación a usarlo en vez de buscar la ranura. Ahora dice lo contrario, y la
119
+ norma tiene su mitad negativa escrita:
120
+
121
+ > Todo botón vive en una ranura de acciones. Si no hay ranura que le encaje, eso es un
122
+ > hueco del sistema que se reporta — no un `block` que se añade.
123
+
124
+ Con la lista de las ranuras que dan la línea entera y de las que no la dan a propósito
125
+ —las que viven dentro de una fila, donde estirar rompería la fila que les da sentido—.
126
+ `AnnotationThread` sale de la lista de dudosos: vive en un panel estrecho también en
127
+ escritorio, así que sus acciones ocupan la línea **siempre**, sin punto de ruptura.
128
+
10
129
  ## [41.0.0] — 2026-09-15
11
130
 
12
131
  > **Major.** Segunda familia al proveedor de textos: `Table` y `DataTable` pierden sus
@@ -2539,6 +2539,8 @@ var e = {
2539
2539
  "--filter-bar-row-gap": "0.75rem",
2540
2540
  "--filter-bar-column-min-inline-size": "12rem",
2541
2541
  "--filter-bar-actions-gap": "0.75rem",
2542
+ "--filter-bar-label-offset": "calc(0.875rem * 1.5 + 0.5rem)",
2543
+ "--filter-bar-control-block-size": "2.5rem",
2542
2544
  "--form-field-gap": "0.25rem",
2543
2545
  "--image-crop-dialog-gap": "1rem",
2544
2546
  "--image-crop-dialog-area-max-height": "60vh",
@@ -3093,6 +3095,7 @@ var e = {
3093
3095
  "--annotation-thread-item-gap": "0.5rem",
3094
3096
  "--annotation-thread-items-gap": "1rem",
3095
3097
  "--annotation-thread-header-gap": "0.5rem",
3098
+ "--annotation-thread-actions-gap": "0.75rem",
3096
3099
  "--annotation-thread-author-font-family": "\"Google Sans Flex\", system-ui, sans-serif",
3097
3100
  "--annotation-thread-author-font-size": "0.875rem",
3098
3101
  "--annotation-thread-author-font-weight": "500",
@@ -4,6 +4,21 @@ export interface AsyncMultiSelectOption {
4
4
  value: string;
5
5
  label: string;
6
6
  }
7
+ /**
8
+ * Los textos que el control emite por su cuenta. Todos son cromo: dicen lo
9
+ * mismo en toda la suite y no hablan de lo que se busca. Lo que sí es de esta
10
+ * pantalla —las opciones que devuelve `onSearch`— no pasa por aquí.
11
+ */
12
+ export interface AsyncMultiSelectMessages {
13
+ /** Pista dentro del campo de búsqueda. */
14
+ placeholder: string;
15
+ /** Aviso cuando la búsqueda no devuelve opciones. */
16
+ empty: string;
17
+ /** Nombre accesible del spinner mientras se busca. */
18
+ loading: string;
19
+ /** Nombre accesible del aspa de cada ficha, con la etiqueta de su opción. */
20
+ remove: (label: string) => string;
21
+ }
7
22
  export interface AsyncMultiSelectProps {
8
23
  onSearch: (query: string) => Promise<AsyncMultiSelectOption[]>;
9
24
  value?: string[];
@@ -21,6 +36,10 @@ export interface AsyncMultiSelectProps {
21
36
  * componente las recuerda—, solo para los valores de `defaultValue`.
22
37
  */
23
38
  selectedOptions?: AsyncMultiSelectOption[];
39
+ /**
40
+ * Pista dentro del campo de búsqueda. **Sin default**: sale de la clave
41
+ * `placeholder` del espacio de este control.
42
+ */
24
43
  placeholder?: string;
25
44
  disabled?: boolean;
26
45
  readOnly?: boolean;
@@ -53,16 +72,20 @@ export interface AsyncMultiSelectProps {
53
72
  */
54
73
  'aria-label'?: string;
55
74
  'aria-describedby'?: string;
56
- /** aria-label del botón que quita un valor. Default: `Quitar ${etiqueta}` (castellano). */
75
+ /**
76
+ * aria-label del botón que quita un valor. **Sin default**: sale de
77
+ * `asyncMultiSelect.remove`.
78
+ */
57
79
  removeLabel?: (label: string) => string;
58
80
  /**
59
- * Texto mostrado cuando la búsqueda no devuelve opciones. Default: "Sin resultados"
60
- * (castellano). Es texto **visible**: una app multiidioma debe pasarlo traducido.
81
+ * Texto mostrado cuando la búsqueda no devuelve opciones. **Sin default**:
82
+ * sale de la clave `empty` del espacio de este control en el
83
+ * `BrandMessagesProvider`.
61
84
  */
62
85
  emptyMessage?: string;
63
86
  /**
64
- * Etiqueta accesible del spinner mientras se busca. Default: "Buscando…" (castellano).
65
- * Una app multiidioma debe pasarla traducida.
87
+ * Etiqueta accesible del spinner mientras se busca. **Sin default**: sale de
88
+ * la clave `loading` del espacio de este control.
66
89
  */
67
90
  loadingLabel?: string;
68
91
  /**
@@ -4,12 +4,31 @@ export interface AsyncSelectOption {
4
4
  value: string;
5
5
  label: string;
6
6
  }
7
+ /**
8
+ * Los textos que el control emite por su cuenta. Todos son cromo: dicen lo
9
+ * mismo en toda la suite y no hablan de lo que se busca. Lo que sí es de esta
10
+ * pantalla —las opciones que devuelve `onSearch`— no pasa por aquí.
11
+ */
12
+ export interface AsyncSelectMessages {
13
+ /** Pista dentro del campo de búsqueda. */
14
+ placeholder: string;
15
+ /** Aviso cuando la búsqueda no devuelve opciones. */
16
+ empty: string;
17
+ /** Nombre accesible del spinner mientras se busca. */
18
+ loading: string;
19
+ /** Nombre accesible del botón que vacía la selección. */
20
+ clear: string;
21
+ }
7
22
  export interface AsyncSelectProps {
8
23
  onSearch: (query: string) => Promise<AsyncSelectOption[]>;
9
24
  value?: string | null;
10
25
  onValueChange?: (value: string | null, option: AsyncSelectOption | null) => void;
11
26
  /** Label of the currently selected option — required when `value` is set so the component can display it */
12
27
  selectedOption?: AsyncSelectOption | null;
28
+ /**
29
+ * Pista dentro del campo de búsqueda. **Sin default**: sale de la clave
30
+ * `placeholder` del espacio de este control.
31
+ */
13
32
  placeholder?: string;
14
33
  disabled?: boolean;
15
34
  readOnly?: boolean;
@@ -43,18 +62,19 @@ export interface AsyncSelectProps {
43
62
  'aria-label'?: string;
44
63
  'aria-describedby'?: string;
45
64
  /**
46
- * Texto mostrado cuando la búsqueda no devuelve opciones. Default: "Sin resultados"
47
- * (castellano). Es texto **visible**: una app multiidioma debe pasarlo traducido.
65
+ * Texto mostrado cuando la búsqueda no devuelve opciones. **Sin default**:
66
+ * sale de la clave `empty` del espacio de este control en el
67
+ * `BrandMessagesProvider`.
48
68
  */
49
69
  emptyMessage?: string;
50
70
  /**
51
- * Etiqueta accesible del spinner mientras se busca. Default: "Buscando…" (castellano).
52
- * Una app multiidioma debe pasarla traducida.
71
+ * Etiqueta accesible del spinner mientras se busca. **Sin default**: sale de
72
+ * la clave `loading` del espacio de este control.
53
73
  */
54
74
  loadingLabel?: string;
55
75
  /**
56
- * aria-label del botón de limpiar selección. Default: "Limpiar selección" (castellano).
57
- * Una app multiidioma debe pasarla traducida.
76
+ * aria-label del botón de limpiar selección. **Sin default**: sale de
77
+ * `asyncSelect.clear`.
58
78
  */
59
79
  clearLabel?: string;
60
80
  /**
@@ -28,10 +28,23 @@ export interface ButtonBaseProps extends Omit<React.ComponentPropsWithoutRef<'bu
28
28
  /** Size of the button */
29
29
  size?: 'sm' | 'md' | 'lg';
30
30
  /**
31
- * Estira el botón hasta el ancho de su contenedor. `'mobile'` lo hace solo
32
- * por debajo de `md`: es lo que quiere un botón suelto dentro de una página
33
- * —una acción que en escritorio se lee bien con su ancho natural y en una
34
- * pantalla estrecha queda mejor ocupando la línea entera.
31
+ * Estira el botón hasta el ancho de su contenedor (`'mobile'`, solo por
32
+ * debajo de `md`). **Es la excepción marcada, no el camino normal.**
33
+ *
34
+ * Todo botón vive en una **ranura de acciones**: el pie de un `Form` o de un
35
+ * diálogo, las `actions` de un `Alert`, de una `FilterBar`, de un `Hero`, de
36
+ * un `PageIntro`… Y el ancho lo decide la ranura, no el botón: la norma del
37
+ * sistema (Fundamentos › **Puntos de ruptura**) hace que en móvil las
38
+ * acciones tomen la línea entera desde el CSS del contenedor, sin prop que
39
+ * acordarse de pasar. Dentro de una ranura del sistema `block` no hace falta,
40
+ * y pasarlo es pelearse con ella.
41
+ *
42
+ * **Si no hay ranura que le encaje, eso es un hueco del sistema y se
43
+ * reporta** — no un `block` que se añade.
44
+ *
45
+ * Queda, entonces, para el botón que de verdad NO está en una ranura de
46
+ * acciones: la llamada a la acción dentro de un texto, o la fila que un
47
+ * producto monta a mano mientras el sistema no tiene su ranura.
35
48
  */
36
49
  block?: boolean | 'mobile';
37
50
  /**
@@ -1,6 +1,15 @@
1
1
  import { Select as BaseSelect } from '@base-ui/react/select';
2
2
  import type { Country } from 'react-phone-number-input';
3
3
  import './InputPhone.css';
4
+ /**
5
+ * El único texto que el campo emite por su cuenta: el nombre accesible del
6
+ * selector de país. Los **nombres de los países** no están aquí: los resuelve
7
+ * `Intl` desde el `locale`, como los meses y las fechas.
8
+ */
9
+ export interface InputPhoneMessages {
10
+ /** Nombre accesible del selector de prefijo/país. */
11
+ country: string;
12
+ }
4
13
  export interface InputPhoneProps {
5
14
  value?: string;
6
15
  defaultCountry?: Country;
@@ -24,14 +33,16 @@ export interface InputPhoneProps {
24
33
  onBlur?: React.FocusEventHandler<HTMLInputElement>;
25
34
  onFocus?: React.FocusEventHandler<HTMLInputElement>;
26
35
  /**
27
- * aria-label del selector de país. Default: "País" (castellano).
28
- * Una app multiidioma debe pasarla traducida.
36
+ * aria-label del selector de país. **Sin default**: sale de
37
+ * `inputPhone.country` del `BrandMessagesProvider`.
29
38
  */
30
39
  countryLabel?: string;
31
40
  /**
32
41
  * Lo que enseña el selector cuando no hay país elegido (número en formato
33
- * internacional). Default: "🌐". Es contenido visible: una app que no quiera
34
- * el emoji pasa aquí su propio texto o glifo.
42
+ * internacional). Default: "🌐". **No pasa por el catálogo de textos a
43
+ * propósito**: un glifo no se traduce, dice lo mismo en los seis idiomas y
44
+ * meterlo en el catálogo obligaría a repetirlo seis veces. Una app que no
45
+ * quiera el emoji pasa aquí su propio texto o glifo.
35
46
  */
36
47
  internationalLabel?: string;
37
48
  /**
@@ -1,5 +1,17 @@
1
1
  import { Popover as BasePopover } from '@base-ui/react/popover';
2
2
  import './MultiSelect.css';
3
+ /**
4
+ * Los dos textos que el control emite por su cuenta: el marcador de sitio sin
5
+ * nada elegido y el nombre del aspa de cada ficha. Los dos son cromo — dicen
6
+ * lo mismo en toda la suite, y el segundo solo interpola la etiqueta de la
7
+ * opción, que es un dato.
8
+ */
9
+ export interface MultiSelectMessages {
10
+ /** Marcador de sitio de la caja sin valores elegidos. */
11
+ placeholder: string;
12
+ /** Nombre accesible del aspa de una ficha, con la etiqueta de su opción. */
13
+ remove: (label: string) => string;
14
+ }
3
15
  export interface MultiSelectOption {
4
16
  value: string;
5
17
  label: string;
@@ -9,6 +21,10 @@ export interface MultiSelectProps {
9
21
  options: MultiSelectOption[];
10
22
  value?: string[];
11
23
  defaultValue?: string[];
24
+ /**
25
+ * Marcador de sitio sin valores elegidos. **Sin default**: sale de
26
+ * `multiSelect.placeholder` del `BrandMessagesProvider`.
27
+ */
12
28
  placeholder?: string;
13
29
  disabled?: boolean;
14
30
  readOnly?: boolean;
@@ -32,7 +48,10 @@ export interface MultiSelectProps {
32
48
  'aria-labelledby'?: string;
33
49
  /** Ids de ayuda/error que describen el control (lo pone el campo). */
34
50
  'aria-describedby'?: string;
35
- /** aria-label del botón que quita un valor. Default: `Quitar ${etiqueta}` (castellano). */
51
+ /**
52
+ * aria-label del botón que quita un valor. **Sin default**: sale de
53
+ * `multiSelect.remove` del `BrandMessagesProvider`.
54
+ */
36
55
  removeLabel?: (label: string) => string;
37
56
  /**
38
57
  * Nodo DOM donde montar el portal del dropdown (reenviado a Base UI
@@ -1,5 +1,15 @@
1
1
  import { type ComponentPropsWithoutRef } from 'react';
2
2
  import './NumberInput.css';
3
+ /**
4
+ * Los dos textos que el control emite por su cuenta: los nombres accesibles de
5
+ * sus dos botones. Cromo puro — no dicen nada de qué se cuenta.
6
+ */
7
+ export interface NumberInputMessages {
8
+ /** Nombre accesible del botón que resta un paso. */
9
+ decrement: string;
10
+ /** Nombre accesible del botón que suma un paso. */
11
+ increment: string;
12
+ }
3
13
  export interface NumberInputProps extends Omit<ComponentPropsWithoutRef<'input'>, 'size' | 'type' | 'value' | 'defaultValue' | 'onChange'> {
4
14
  value?: number;
5
15
  defaultValue?: number;
@@ -20,13 +30,13 @@ export interface NumberInputProps extends Omit<ComponentPropsWithoutRef<'input'>
20
30
  /** Se añade DESPUÉS de las clases propias del componente (el consumidor añade, no sustituye). */
21
31
  className?: string;
22
32
  /**
23
- * aria-label del botón de decremento. Default: "Decrementar" (castellano).
24
- * Una app multiidioma debe pasarla traducida.
33
+ * aria-label del botón de decremento. **Sin default**: sale de
34
+ * `numberInput.decrement` del `BrandMessagesProvider`.
25
35
  */
26
36
  decrementLabel?: string;
27
37
  /**
28
- * aria-label del botón de incremento. Default: "Incrementar" (castellano).
29
- * Una app multiidioma debe pasarla traducida.
38
+ * aria-label del botón de incremento. **Sin default**: sale de
39
+ * `numberInput.increment` del `BrandMessagesProvider`.
30
40
  */
31
41
  incrementLabel?: string;
32
42
  onChange?: (value: number) => void;
@@ -1,4 +1,15 @@
1
1
  import './OtpInput.css';
2
+ /**
3
+ * Los textos que el control emite por su cuenta: el nombre del grupo cuando va
4
+ * suelto y el de cada celda. Cromo — el segundo solo interpola la posición de
5
+ * la celda, que es una cifra.
6
+ */
7
+ export interface OtpInputMessages {
8
+ /** Nombre accesible del grupo de celdas cuando el control va suelto. */
9
+ group: string;
10
+ /** Nombre accesible de una celda, con su posición y el total. */
11
+ digit: (index: number, length: number) => string;
12
+ }
2
13
  export interface OtpInputProps {
3
14
  /** Número de celdas a renderizar. Requerido. */
4
15
  length: number;
@@ -22,8 +33,8 @@ export interface OtpInputProps {
22
33
  'aria-labelledby'?: string;
23
34
  /**
24
35
  * Nombre accesible del grupo cuando no se pasa `aria-label` ni
25
- * `aria-labelledby` — el caso del control suelto. Default: "Código de
26
- * verificación" (castellano). Una app multiidioma debe pasarla traducida.
36
+ * `aria-labelledby` — el caso del control suelto. **Sin default**: sale de
37
+ * `otpInput.group` del `BrandMessagesProvider`.
27
38
  */
28
39
  groupLabel?: string;
29
40
  id?: string;
@@ -39,8 +50,8 @@ export interface OtpInputProps {
39
50
  /** Se añade DESPUÉS de las clases propias del componente. */
40
51
  className?: string;
41
52
  /**
42
- * Etiqueta accesible de cada celda. Default: `Dígito N de M` (castellano).
43
- * Una app multiidioma debe pasarla traducida.
53
+ * Etiqueta accesible de cada celda. **Sin default**: sale de
54
+ * `otpInput.digit` del `BrandMessagesProvider`.
44
55
  */
45
56
  digitLabel?: (index: number, length: number) => string;
46
57
  }
@@ -2,6 +2,18 @@ import type { ReactNode } from 'react';
2
2
  import { Select as BaseSelect } from '@base-ui/react/select';
3
3
  import type { SeparatorProps as BaseSeparatorProps } from '@base-ui/react/separator';
4
4
  import './Select.css';
5
+ /**
6
+ * El único texto que el desplegable emite por su cuenta: el marcador de sitio
7
+ * genérico del disparador, el que dice «aquí no has elegido nada todavía».
8
+ *
9
+ * Es cromo, no contenido: cuando el marcador dice algo de ESTE campo («Elige
10
+ * un país») lo escribe quien monta el campo y viaja por la prop `placeholder`,
11
+ * que sigue ganando. Las **opciones** tampoco están aquí: son datos.
12
+ */
13
+ export interface SelectMessages {
14
+ /** Marcador de sitio del disparador sin valor elegido. */
15
+ placeholder: string;
16
+ }
5
17
  export interface SelectOption {
6
18
  value: string;
7
19
  label: string;
@@ -34,7 +46,12 @@ export interface SelectProps {
34
46
  options: SelectOptionOrGroup[];
35
47
  value?: string;
36
48
  defaultValue?: string;
37
- /** Placeholder del trigger. Default: "Seleccionar…" (en la API compuesta lo pone cada consumidor vía `Select.Value`). */
49
+ /**
50
+ * Placeholder del trigger. **Sin default**: sale de `select.placeholder` del
51
+ * `BrandMessagesProvider`, y esta prop es la anulación puntual cuando el
52
+ * marcador dice algo de este campo concreto. En la API compuesta lo pone cada
53
+ * consumidor vía `Select.Value`.
54
+ */
38
55
  placeholder?: string;
39
56
  disabled?: boolean;
40
57
  readOnly?: boolean;
@@ -1,6 +1,18 @@
1
1
  import type { PaginationMessages } from '../molecules/Pagination/Pagination';
2
2
  import type { TableMessages } from '../molecules/Table/Table';
3
3
  import type { DataTableMessages } from '../organisms/DataTable/DataTable';
4
+ import type { InputFieldMessages } from '../molecules/InputField/InputField';
5
+ import type { PasswordFieldMessages } from '../molecules/PasswordField/PasswordField';
6
+ import type { SelectMessages } from '../atoms/Select/Select';
7
+ import type { MultiSelectMessages } from '../atoms/MultiSelect/MultiSelect';
8
+ import type { NumberInputMessages } from '../atoms/NumberInput/NumberInput';
9
+ import type { OtpInputMessages } from '../atoms/OtpInput/OtpInput';
10
+ import type { InputPhoneMessages } from '../atoms/InputPhone/InputPhone';
11
+ import type { AsyncSelectMessages } from '../atoms/AsyncSelect/AsyncSelect';
12
+ import type { AsyncMultiSelectMessages } from '../atoms/AsyncMultiSelect/AsyncMultiSelect';
13
+ import type { DocsSearchMessages } from '../molecules/DocsSearch/DocsSearch';
14
+ import type { SearchFormMessages } from '../molecules/SearchForm/SearchForm';
15
+ import type { FilterBarMessages } from '../molecules/FilterBar/FilterBar';
4
16
  /**
5
17
  * El contrato de textos de la librería: un espacio por componente, y dentro
6
18
  * de cada espacio **todas las claves obligatorias**.
@@ -26,5 +38,17 @@ export interface BrandMessages {
26
38
  pagination: PaginationMessages;
27
39
  table: TableMessages;
28
40
  dataTable: DataTableMessages;
41
+ inputField: InputFieldMessages;
42
+ passwordField: PasswordFieldMessages;
43
+ select: SelectMessages;
44
+ multiSelect: MultiSelectMessages;
45
+ numberInput: NumberInputMessages;
46
+ otpInput: OtpInputMessages;
47
+ inputPhone: InputPhoneMessages;
48
+ asyncSelect: AsyncSelectMessages;
49
+ asyncMultiSelect: AsyncMultiSelectMessages;
50
+ docsSearch: DocsSearchMessages;
51
+ searchForm: SearchFormMessages;
52
+ filterBar: FilterBarMessages;
29
53
  }
30
- export type { PaginationMessages, TableMessages, DataTableMessages };
54
+ export type { PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, };
@@ -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, } from './BrandMessages';
5
+ export type { BrandMessages, PaginationMessages, TableMessages, DataTableMessages, InputFieldMessages, PasswordFieldMessages, SelectMessages, MultiSelectMessages, NumberInputMessages, OtpInputMessages, InputPhoneMessages, AsyncSelectMessages, AsyncMultiSelectMessages, DocsSearchMessages, SearchFormMessages, FilterBarMessages, } from './BrandMessages';
@@ -142,11 +142,20 @@ export declare const CardAction: import("react").ForwardRefExoticComponent<Omit<
142
142
  export declare const CardContent: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
143
143
  export interface CardFooterProps extends CardPartProps {
144
144
  /**
145
- * `row` (por defecto): las acciones en fila. `column`: apiladas y a todo
146
- * el ancho — para un pie con una línea de texto sobre el botón (una nota
147
- * de prueba, una condición) que debe quedar pegada a él.
145
+ * `row` (por defecto): las acciones en fila **en escritorio**; por debajo de
146
+ * `md` apilan y ocupan la línea entera solas, que es la norma del sistema
147
+ * (Fundamentos › Puntos de ruptura) — no hay que pedirlo.
148
+ *
149
+ * `column`: apiladas y a todo el ancho **siempre, también donde hay sitio**.
150
+ * Es la excepción declarada, para un pie con una línea de texto sobre el
151
+ * botón (una nota de prueba, una condición) que debe quedar pegada a él, y
152
+ * para una tarjeta que se sabe estrecha en escritorio —una rejilla de tres
153
+ * columnas—, porque el pie mide su hueco y no la ventana.
148
154
  */
149
155
  direction?: 'row' | 'column';
150
156
  }
151
- /** Pie de la tarjeta: sus acciones, en fila o apiladas. */
157
+ /**
158
+ * Pie de la tarjeta: sus acciones. En móvil apila y da la línea entera a cada
159
+ * una; en escritorio, fila —salvo `direction="column"`—.
160
+ */
152
161
  export declare const CardFooter: import("react").ForwardRefExoticComponent<CardFooterProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -17,6 +17,27 @@ export type DocsSearchRenderLinkProps = React.AnchorHTMLAttributes<HTMLAnchorEle
17
17
  href: string;
18
18
  className: string;
19
19
  };
20
+ /**
21
+ * Los textos que el buscador emite por su cuenta. Los seis son cromo: en toda
22
+ * la suite el buscador de la documentación se llama igual y avisa igual. Los
23
+ * **resultados** no están aquí — son datos que llegan por `results`.
24
+ *
25
+ * El nombre del aspa tampoco: el aspa es la del `InputField` que hay debajo y
26
+ * sale de `inputField.clear`. Es la misma palabra y el mismo botón; darle una
27
+ * clave propia solo obligaría a traducir «Borrar» dos veces.
28
+ */
29
+ export interface DocsSearchMessages {
30
+ /** Etiqueta del campo, que nombra también el punto de referencia. */
31
+ label: string;
32
+ /** Pista dentro del campo. */
33
+ placeholder: string;
34
+ /** Nombre accesible de la lista de resultados. */
35
+ results: string;
36
+ /** Aviso cuando la búsqueda no encuentra nada. */
37
+ empty: string;
38
+ /** Aviso mientras se busca. */
39
+ loading: string;
40
+ }
20
41
  export interface DocsSearchProps {
21
42
  /** `id` del campo. Ata la etiqueta con el campo y el campo con la lista. */
22
43
  id?: string;
@@ -29,15 +50,14 @@ export interface DocsSearchProps {
29
50
  /** Hay una búsqueda en curso: el aviso de estado lo dice. */
30
51
  loading?: boolean;
31
52
  /**
32
- * Etiqueta del campo. Default castellano.
33
- * @default 'Buscar en la documentación'
53
+ * Etiqueta del campo. **Sin default**: sale de `docsSearch.label` del
54
+ * `BrandMessagesProvider`.
34
55
  */
35
56
  label?: string;
36
57
  /** Oculta la etiqueta a la vista; el lector de pantalla la sigue leyendo. */
37
58
  labelHidden?: boolean;
38
59
  /**
39
- * Pista dentro del campo. Default castellano.
40
- * @default 'Buscar…'
60
+ * Pista dentro del campo. **Sin default**: sale de `docsSearch.placeholder`.
41
61
  */
42
62
  placeholder?: string;
43
63
  /**
@@ -47,23 +67,22 @@ export interface DocsSearchProps {
47
67
  */
48
68
  clearable?: boolean;
49
69
  /**
50
- * Nombre accesible del botón de borrado. Default castellano.
51
- * @default 'Borrar'
70
+ * Nombre accesible del botón de borrado. Reenvío puro al `InputField`: sin
71
+ * él, el texto sale de `inputField.clear` del `BrandMessagesProvider`.
52
72
  */
53
73
  clearLabel?: string;
54
74
  /**
55
- * Nombre accesible de la lista de resultados. Default castellano.
56
- * @default 'Resultados'
75
+ * Nombre accesible de la lista de resultados. **Sin default**: sale de
76
+ * `docsSearch.results`.
57
77
  */
58
78
  resultsLabel?: string;
59
79
  /**
60
- * Aviso cuando la búsqueda no encuentra nada. Default castellano.
61
- * @default 'Sin resultados.'
80
+ * Aviso cuando la búsqueda no encuentra nada. **Sin default**: sale de
81
+ * `docsSearch.empty`.
62
82
  */
63
83
  emptyLabel?: string;
64
84
  /**
65
- * Aviso mientras se busca. Default castellano.
66
- * @default 'Buscando…'
85
+ * Aviso mientras se busca. **Sin default**: sale de `docsSearch.loading`.
67
86
  */
68
87
  loadingLabel?: string;
69
88
  /** Talla del campo. */
@@ -1,5 +1,14 @@
1
1
  import { type ComponentPropsWithoutRef, type ReactNode } from 'react';
2
2
  import './FilterBar.css';
3
+ /**
4
+ * El único texto que la barra emite por su cuenta: su nombre accesible como
5
+ * punto de referencia de búsqueda. Los rótulos de los filtros no están aquí —
6
+ * los escribe cada campo, y dicen qué filtran.
7
+ */
8
+ export interface FilterBarMessages {
9
+ /** Nombre accesible del punto de referencia `search` que es la barra. */
10
+ label: string;
11
+ }
3
12
  export interface FilterBarProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
4
13
  /**
5
14
  * El buscador: el campo de búsqueda del sistema —un `InputField kind="search"`,
@@ -22,7 +31,7 @@ export interface FilterBarProps extends Omit<ComponentPropsWithoutRef<'div'>, 'c
22
31
  actions?: ReactNode;
23
32
  /**
24
33
  * Nombre accesible del punto de referencia `search` que es la barra.
25
- * Default: «Filtros» (castellano). Una app multiidioma debe pasarlo traducido.
34
+ * **Sin default**: sale de `filterBar.label` del `BrandMessagesProvider`.
26
35
  */
27
36
  ariaLabel?: string;
28
37
  /** Se añade DESPUÉS de las clases propias. */