@studiolxd/brand 45.1.0 → 47.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 (71) hide show
  1. package/CHANGELOG.md +168 -0
  2. package/dist/_shared/portal-container.js +9 -0
  3. package/dist/_types/atoms/AsyncMultiSelect/AsyncMultiSelect.d.ts +8 -7
  4. package/dist/_types/atoms/AsyncSelect/AsyncSelect.d.ts +8 -6
  5. package/dist/_types/atoms/InputPhone/InputPhone.d.ts +8 -5
  6. package/dist/_types/atoms/MenuButton/MenuButton.d.ts +22 -2
  7. package/dist/_types/atoms/MultiSelect/MultiSelect.d.ts +8 -6
  8. package/dist/_types/atoms/Popover/Popover.d.ts +8 -1
  9. package/dist/_types/atoms/Select/Select.d.ts +8 -7
  10. package/dist/_types/atoms/Tooltip/Tooltip.d.ts +7 -0
  11. package/dist/_types/constants/portal-container.d.ts +42 -0
  12. package/dist/_types/messages/BrandMessages.d.ts +41 -1
  13. package/dist/_types/messages/index.d.ts +1 -1
  14. package/dist/_types/molecules/AppLauncher/AppLauncher.d.ts +43 -8
  15. package/dist/_types/molecules/Breadcrumb/Breadcrumb.d.ts +10 -2
  16. package/dist/_types/molecules/CommandPalette/CommandPalette.d.ts +43 -8
  17. package/dist/_types/molecules/Consent/Consent.d.ts +93 -20
  18. package/dist/_types/molecules/Menu/Menu.d.ts +8 -1
  19. package/dist/_types/molecules/Modal/Modal.d.ts +8 -6
  20. package/dist/_types/molecules/NotificationButton/NotificationButton.d.ts +17 -4
  21. package/dist/_types/molecules/NotificationPanel/NotificationPanel.d.ts +54 -8
  22. package/dist/_types/molecules/OrgSwitcher/OrgSwitcher.d.ts +15 -1
  23. package/dist/_types/molecules/PrevNextNav/PrevNextNav.d.ts +17 -2
  24. package/dist/_types/molecules/Sheet/Sheet.d.ts +8 -7
  25. package/dist/_types/molecules/SidebarNav/SidebarNav.d.ts +18 -3
  26. package/dist/_types/molecules/SiteNav/SiteNav.d.ts +9 -0
  27. package/dist/_types/molecules/TableOfContents/TableOfContents.d.ts +11 -2
  28. package/dist/_types/molecules/UserMenu/UserMenu.d.ts +16 -1
  29. package/dist/_types/sections/AppHeader/AppHeader.d.ts +8 -2
  30. package/dist/_types/sections/AppRoot/AppRoot.d.ts +12 -1
  31. package/dist/_types/sections/AppShell/AppShell.d.ts +14 -1
  32. package/dist/_types/sections/FloatingDock/FloatingDock.d.ts +33 -3
  33. package/dist/_types/sections/Sidebar/Sidebar.d.ts +27 -3
  34. package/dist/_types/sections/SiteHeader/SiteHeader.d.ts +22 -3
  35. package/dist/_types/sections/SiteShell/SiteShell.d.ts +11 -5
  36. package/dist/_types/templates/OnboardingShell/OnboardingShell.d.ts +19 -2
  37. package/dist/_types/templates/PublicPageShell/PublicPageShell.d.ts +42 -6
  38. package/dist/app-header.js +1 -1
  39. package/dist/app-launcher.js +73 -63
  40. package/dist/app-root.js +10 -8
  41. package/dist/app-shell.js +51 -50
  42. package/dist/async-multi-select.js +65 -64
  43. package/dist/async-select.js +49 -48
  44. package/dist/breadcrumb.js +24 -21
  45. package/dist/command-palette.js +38 -36
  46. package/dist/consent.js +75 -73
  47. package/dist/floating-dock.js +42 -41
  48. package/dist/input-phone.js +38 -37
  49. package/dist/menu-button.js +16 -14
  50. package/dist/menu.js +44 -40
  51. package/dist/modal.js +32 -31
  52. package/dist/multi-select.js +106 -105
  53. package/dist/notification-button.js +18 -17
  54. package/dist/notification-panel.js +81 -80
  55. package/dist/onboarding-shell.js +36 -35
  56. package/dist/org-switcher.js +64 -59
  57. package/dist/popover.js +27 -22
  58. package/dist/prev-next-nav.js +38 -36
  59. package/dist/public-page-shell.js +24 -20
  60. package/dist/select.js +70 -69
  61. package/dist/sheet.js +30 -29
  62. package/dist/sidebar-nav.js +91 -90
  63. package/dist/sidebar.js +72 -71
  64. package/dist/site-header.js +44 -43
  65. package/dist/site-nav.js +27 -25
  66. package/dist/site-shell.js +23 -15
  67. package/dist/table-of-contents.js +30 -27
  68. package/dist/toaster.js +57 -53
  69. package/dist/tooltip.js +45 -41
  70. package/dist/user-menu.js +58 -52
  71. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,174 @@ 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
+ ## [47.0.0] — 2026-09-15
11
+
12
+ > **Major.** Octava familia al proveedor de textos: el cromo de aplicación y la navegación.
13
+ > Catorce espacios nuevos, y con ellos la familia donde más claves ya existían en el
14
+ > catálogo de la suite. Además, los portales dejan de abrirse en la talla equivocada dentro
15
+ > de una página pública, y el `main` de `PublicPageShell` se puede pedir a sangre.
16
+
17
+ ### La navegación lee del proveedor
18
+
19
+ Catorce espacios nuevos en `BrandMessages`: `menuButton`, `appRoot`, `appShell`, `sidebar`,
20
+ `sidebarNav`, `siteNav`, `siteHeader`, `userMenu`, `orgSwitcher`, `breadcrumb`,
21
+ `tableOfContents`, `prevNextNav`, `publicPageShell` y `onboardingShell`. Mismo orden —**prop
22
+ → proveedor → error**— y cada texto se lee **donde se pinta**: una barra fuera de un
23
+ `AppShell` no tiene asa y no exige sus dos textos, una navegación sin entradas vacías no
24
+ exige su marca, un menú de cuenta sin contador no exige el plural, un paso sin acciones no
25
+ exige el nombre de su pie.
26
+
27
+ La frontera se decide por el valor. **Cromo**: el nombre de una región de navegación
28
+ («Principal», «En esta página», «Migas de pan»), el salto al contenido, qué hace el
29
+ logotipo, la dirección de un par anterior/siguiente. **Contenido**: los ítems de un menú,
30
+ los nombres de las organizaciones, el nombre de la persona, los títulos de destino del
31
+ `PrevNextNav`, el rótulo visible de un índice. `PrevNextNav` es el caso que mejor lo
32
+ enseña: «Anterior» y «Siguiente» son catálogo, pero un par que navega semanas quiere decir
33
+ «Semana anterior» y para eso siguen estando las props, que ganan.
34
+
35
+ ### Tres piezas entran al alcance por arrastre
36
+
37
+ `MenuButton` es donde vivía el castellano que reenviaban las dos cabeceras: migrarlo deja
38
+ `AppHeader.menuLabel` y `SiteHeader.menuLabel` como **reenvíos puros**, una sola clave en
39
+ vez de tres. `AppRoot` tiene la misma frase de salto que `AppShell` y se habría quedado
40
+ cableada. Y `PublicPageShell` tenía que migrar para que `OnboardingShell.preferencesLabel`
41
+ pudiera ser reenvío puro: es la misma banda y la misma clave.
42
+
43
+ `Switcher` estaba en la lista y **no entra**: no emite ningún texto propio. Lo nombra la
44
+ etiqueta de su campo.
45
+
46
+ ### Breaking — `MenuButton` abierto dice «cerrar»
47
+
48
+ El nombre accesible pasa a seguir al estado: cerrado lee `menuButton.open`, abierto lee
49
+ `menuButton.close`. Antes, con el menú abierto el botón seguía llamándose igual salvo que
50
+ el consumidor pasara `closeLabel` a mano, así que la cara de cerrar casi nunca se pintaba.
51
+ Ahora que el catálogo trae las dos, el nombre ya no se queda a medias. **Un test que
52
+ consulte el botón por su nombre con la barra abierta deja de encontrarlo**: es el punto
53
+ donde esto rompe en silencio.
54
+
55
+ `UserMenu` tenía un texto que ni siquiera era prop —el contador de notificaciones llevaba
56
+ `${count} notificaciones sin leer` escrito en el JSX—. Ahora es `userMenu.unread`, una
57
+ función, y `notifications.unreadCount` de la suite ya la satisface con su plural.
58
+
59
+ ### Los portales heredan la superficie
60
+
61
+ La v45.1.0 puso los controles en talla `lg` dentro de `.site-shell` por herencia CSS, y
62
+ dejó apuntado lo que no cubría: la lista de un `Select` y el calendario de un `DatePicker`
63
+ los monta un portal en `document.body`, que no es descendiente del bloque. El campo se
64
+ pintaba a 48px/20 y su lista se abría a 40px/16. El tema oscuro no tenía este problema
65
+ porque se activa en `<html>` y cascadea a todo el documento; la superficie de lectura se
66
+ activa a media altura del árbol.
67
+
68
+ `SiteShell` publica ahora su nodo raíz por `PortalContainerContext`, y todo componente con
69
+ portal lo toma como destino cuando no recibe `container`. La resolución es **prop →
70
+ contexto → `document.body`**, y la prop gana siempre. No hay nada que pasar en cada uso: el
71
+ árbol de React sabe dónde está el shell aunque el árbol del DOM no lo sepa. El nodo viaja
72
+ en **estado y no en una ref**, porque el destino tiene que existir en el render en el que
73
+ el portal se monta — el mismo patrón que `ChatShell` ya usaba para el `container` de su
74
+ cajón. `SiteShell` pasa a ser componente cliente.
75
+
76
+ Lo consumen por defecto `Select`, `MultiSelect`, `AsyncSelect`, `AsyncMultiSelect`,
77
+ `InputPhone`, `Modal`, `Sheet`, `AppLauncher`, `OrgSwitcher`, `UserMenu` y `Toaster`.
78
+ `Popover`, `Tooltip` y `Menu` **estrenan prop `container`** —son los primitivos
79
+ componibles, y sin ella no había escotilla—, y con ellos heredan sin tocar nada
80
+ `DatePicker`, `DateTimeField`, `TimeSelect`, `TimeField`, `ContextMenu`, `DropdownField`,
81
+ `NotificationButton`, `ConfirmDialog`, `ImageCropDialog`, `AvatarUpload`, `CommandPalette`
82
+ y `Consent`. `FloatingDock` queda intacto: monta su panel dentro de su propia ancla a
83
+ propósito y no pasa por el contexto.
84
+
85
+ **`AppShell` no provee el contexto, y es deliberado.** La superficie de aplicación es la
86
+ del `:root`, así que `document.body` ya resuelve los mismos valores; meter los portales
87
+ dentro de `.app-shell` —que es `overflow: clip` y de altura fija— solo añadiría riesgo de
88
+ recorte sin arreglar nada. El día que la superficie de aplicación cambie de talla, el
89
+ arreglo es montar ahí el mismo proveedor: una línea.
90
+
91
+ Los campos `*Field` siguen **sin** reenviar `container`, y también a propósito: obligar a
92
+ cada app a pasar un nodo en cada uso era el problema, no la solución. La escotilla vive en
93
+ el primitivo.
94
+
95
+ ### El `main` de `PublicPageShell` se puede pedir a sangre
96
+
97
+ `PublicPageShell` montaba su `main` como `Container as="main" space="xl"` fijo. Es lo que
98
+ quiere una página corriente, pero no una **portada**: la que abre con un `Hero` de lado a
99
+ lado no cabía en el molde y tenía que montarse a mano con `SiteShell` + `Container`, que es
100
+ justo lo que el molde único existe para evitar.
101
+
102
+ El `main` lleva ahora los mismos tres mandos que un `Container` —`mainWidth`, `mainSpace` y
103
+ `mainFlush`—, con el prefijo de la ranura porque el marco tiene cuatro y un `width` pelado
104
+ no diría cuál gobierna. **Los defaults son los de hoy** (`'xl'`, `'xl'`, `false`): quien no
105
+ los toque se pinta exactamente igual, así que esta parte no es breaking. Una portada pide
106
+ `mainWidth="full" mainSpace="none" mainFlush` y apila secciones, poniendo su propio
107
+ `Container` a lo que quiera columna.
108
+
109
+ El `main` sigue siendo el `main`, con su `id` y su `tabIndex`, así que el enlace de salto al
110
+ contenido llega igual a una portada abierta a sangre.
111
+
112
+ ### Para quien actualice
113
+
114
+ El catálogo del `BrandMessagesProvider` tiene que crecer con los catorce espacios, o la
115
+ primera pantalla con un `Breadcrumb`, un `AppRoot` o un `MenuButton` **lanza en render**.
116
+ Estas son las claves que hay que aportar:
117
+
118
+ | Espacio | Claves | Qué es |
119
+ | --- | --- | --- |
120
+ | `menuButton` | `open`, `close` | qué hace el botón de menú, en sus dos caras |
121
+ | `appRoot` | `skipToContent` | el salto al contenido del documento |
122
+ | `appShell` | `skipToContent` | el salto al contenido de la aplicación |
123
+ | `sidebar` | `label`, `resizer`, `resizerValue(width)` | la región, el asa y su ancho hablado |
124
+ | `sidebarNav` | `label`, `empty` | la región y la marca de una entrada sin contenido |
125
+ | `siteNav` | `label` | la región del índice del sitio |
126
+ | `siteHeader` | `logo` | qué hace el logotipo — **lleva la marca dentro** |
127
+ | `userMenu` | `trigger(name)`, `unread(count)` | el botón de cuenta y su contador |
128
+ | `orgSwitcher` | `trigger(name)` | el botón del conmutador de organización |
129
+ | `breadcrumb` | `label` | la región del rastro |
130
+ | `tableOfContents` | `label` | la región del índice de la página |
131
+ | `prevNextNav` | `previous`, `next` | la dirección, no el destino |
132
+ | `publicPageShell` | `preferences` | la banda de idioma y tema |
133
+ | `onboardingShell` | `actions` | el grupo de acciones del pie del alta |
134
+
135
+ Cuatro de ellas interpolan un dato (`sidebar.resizerValue`, `userMenu.trigger`,
136
+ `userMenu.unread`, `orgSwitcher.trigger`), así que son funciones. `siteHeader.logo` la
137
+ escribe cada producto con su propia marca: el default retirado decía «Studio LXD — ir al
138
+ inicio».
139
+
140
+ A cambio, dejan de hacer falta para traducir `AppHeader.menuLabel` y `menuCloseLabel`,
141
+ `SiteHeader.menuLabel` y `menuCloseLabel`, y `OnboardingShell.preferencesLabel`: son
142
+ reenvíos puros y siguen existiendo solo como anulación puntual.
143
+
144
+ ## [46.0.0] — 2026-09-15
145
+
146
+ > **Major.** Séptima familia al proveedor de textos: los envoltorios de diálogo. `Consent`,
147
+ > `CommandPalette`, `AppLauncher`, `FloatingDock`, `NotificationButton` y
148
+ > `NotificationPanel` dejan de traer castellano puesto.
149
+
150
+ ### Los envoltorios leen del proveedor
151
+
152
+ Seis espacios nuevos en `BrandMessages`: `consent`, `commandPalette`, `appLauncher`,
153
+ `floatingDock`, `notificationButton` y `notificationPanel`. Mismo orden —**prop →
154
+ proveedor → error**—. `CommandPalette` y `AppLauncher` relajan su API de paso: los textos
155
+ que antes eran props obligatorias en cada uso ahora son opcionales, porque los pone el
156
+ catálogo.
157
+
158
+ ### Lo que se queda como prop, por valor y no por nombre
159
+
160
+ `ConsentBanner.description` y `policyLabel` son **obligatorias y sin default**, como el
161
+ `confirmLabel` de un diálogo: el texto legal depende de la jurisdicción y de lo que cada
162
+ producto guarde. El tipo exige `policyLabel` en cuanto hay `policyHref` —o el enlace no
163
+ está, o está entero—, así que una política sin nombre no compila.
164
+
165
+ `AppLauncherLabels.trigger` no va al catálogo por una razón distinta: su **presencia**
166
+ decide la cara del disparador (solo icono, o icono con rótulo), y un texto de catálogo está
167
+ siempre presente. Meterlo ahí obligaría a todos los lanzadores de la suite a llevar rótulo.
168
+
169
+ ### `FloatingDock` tiene su propio aspa, y por qué no pasa por `Modal`
170
+
171
+ Se miró antes de decidirlo, y la razón es real: es un diálogo **no modal** —sin velo, con
172
+ la página viva detrás—, no atrapa el foco, su portal monta dentro del propio ancla para
173
+ heredar la superficie por cascada, y va anclado a una esquina con el aspa fuera de la
174
+ cabecera. El `Modal` del sistema es lo contrario en las cuatro cosas. Hacerlo pasar por él
175
+ no era quitar una clave: era cambiar el componente. Queda escrito en el componente y en su
176
+ documentación para que no se vuelva a abrir.
177
+
10
178
  ## [45.1.0] — 2026-09-15
11
179
 
12
180
  > **Minor.** La superficie pública pone los controles en talla lg, igual que hace con el
@@ -0,0 +1,9 @@
1
+ import { createContext as e, useContext as t } from "react";
2
+ //#region src/stories/constants/portal-container.ts
3
+ var n = e(null);
4
+ function r(e) {
5
+ let r = t(n);
6
+ return e === void 0 ? r ?? void 0 : e;
7
+ }
8
+ //#endregion
9
+ export { r as n, n as t };
@@ -89,13 +89,14 @@ export interface AsyncMultiSelectProps {
89
89
  */
90
90
  loadingLabel?: string;
91
91
  /**
92
- * Nodo DOM donde montar el portal del dropdown (reenviado a Base UI
93
- * `Portal.container`). Por defecto se monta en `document.body`, que
94
- * hereda el tema activado a nivel raíz (`html.dark`/`[data-theme="dark"]`)
95
- * sin configuración adicional. Solo hace falta pasarlo cuando el
96
- * AsyncMultiSelect vive dentro de un `.surface-dark` **anidado** (no en
97
- * la raíz), ya que ese contexto no llega a `document.body` por la
98
- * cascada.
92
+ * Nodo DOM donde montar el portal del dropdown (reenviado a Base UI `Portal.container`).
93
+ * Por defecto, el nodo de la superficie que llegue por contexto:
94
+ * `SiteShell` publica el suyo, de modo que la capa hereda la talla de la
95
+ * superficie pública en vez de abrirse a la de aplicación. Si no hay
96
+ * superficie, `document.body` — que ya hereda el tema activado en la raíz
97
+ * (`html.dark`/`[data-theme="dark"]`) sin configuración adicional. Pásalo
98
+ * solo para llevar la capa a otro sitio: un `.surface-dark` **anidado**, el
99
+ * cajón de un shell propio. Gana siempre.
99
100
  */
100
101
  container?: React.ComponentPropsWithoutRef<typeof BasePopover.Portal>['container'];
101
102
  }
@@ -78,12 +78,14 @@ export interface AsyncSelectProps {
78
78
  */
79
79
  clearLabel?: string;
80
80
  /**
81
- * Nodo DOM donde montar el portal del dropdown (reenviado a Base UI
82
- * `Portal.container`). Por defecto se monta en `document.body`, que
83
- * hereda el tema activado a nivel raíz (`html.dark`/`[data-theme="dark"]`)
84
- * sin configuración adicional. Solo hace falta pasarlo cuando el
85
- * AsyncSelect vive dentro de un `.surface-dark` **anidado** (no en la
86
- * raíz), ya que ese contexto no llega a `document.body` por la cascada.
81
+ * Nodo DOM donde montar el portal del dropdown (reenviado a Base UI `Portal.container`).
82
+ * Por defecto, el nodo de la superficie que llegue por contexto:
83
+ * `SiteShell` publica el suyo, de modo que la capa hereda la talla de la
84
+ * superficie pública en vez de abrirse a la de aplicación. Si no hay
85
+ * superficie, `document.body` — que ya hereda el tema activado en la raíz
86
+ * (`html.dark`/`[data-theme="dark"]`) sin configuración adicional. Pásalo
87
+ * solo para llevar la capa a otro sitio: un `.surface-dark` **anidado**, el
88
+ * cajón de un shell propio. Gana siempre.
87
89
  */
88
90
  container?: React.ComponentPropsWithoutRef<typeof BasePopover.Portal>['container'];
89
91
  }
@@ -47,11 +47,14 @@ export interface InputPhoneProps {
47
47
  internationalLabel?: string;
48
48
  /**
49
49
  * Nodo DOM donde montar el portal del dropdown de país (reenviado a
50
- * `Select.Portal` de Base UI). Por defecto se monta en `document.body`, que
51
- * hereda el tema activado a nivel raíz (`html.dark`/`[data-theme="dark"]`)
52
- * sin configuración adicional. Solo hace falta pasarlo cuando el
53
- * InputPhone vive dentro de un `.surface-dark` **anidado** (no en la
54
- * raíz), ya que ese contexto no llega a `document.body` por la cascada.
50
+ * `Select.Portal` de Base UI).
51
+ * Por defecto, el nodo de la superficie que llegue por contexto:
52
+ * `SiteShell` publica el suyo, de modo que la capa hereda la talla de la
53
+ * superficie pública en vez de abrirse a la de aplicación. Si no hay
54
+ * superficie, `document.body` — que ya hereda el tema activado en la raíz
55
+ * (`html.dark`/`[data-theme="dark"]`) sin configuración adicional. Pásalo
56
+ * solo para llevar la capa a otro sitio: un `.surface-dark` **anidado**, el
57
+ * cajón de un shell propio. Gana siempre.
55
58
  */
56
59
  container?: React.ComponentPropsWithoutRef<typeof BaseSelect.Portal>['container'];
57
60
  }
@@ -1,11 +1,31 @@
1
1
  import { type ComponentPropsWithoutRef } from 'react';
2
2
  import './MenuButton.css';
3
+ /**
4
+ * Los dos textos del botón de menú, y los dos son **cromo**: no dicen de qué
5
+ * menú son, dicen qué hace el botón. Son los mismos en la cabecera de la
6
+ * aplicación y en la del sitio, así que van al catálogo una sola vez y las dos
7
+ * cabeceras los reenvían sin repetir la clave.
8
+ */
9
+ export interface MenuButtonMessages {
10
+ /** Nombre accesible del botón con el menú cerrado. */
11
+ open: string;
12
+ /** Nombre accesible del botón con el menú abierto. */
13
+ close: string;
14
+ }
3
15
  export interface MenuButtonProps extends Omit<ComponentPropsWithoutRef<'button'>, 'children'> {
4
16
  /** Estado del menú que gobierna. Abierto, el glifo `menu` se convierte en `close`. */
5
17
  isOpen?: boolean;
6
- /** Texto accesible. Dice qué abre, no qué forma tiene. */
18
+ /**
19
+ * Texto accesible con el menú cerrado. Dice qué abre, no qué forma tiene.
20
+ * **Sin default**: sin él, sale de `menuButton.open` del
21
+ * `BrandMessagesProvider`.
22
+ */
7
23
  label?: string;
8
- /** Texto accesible cuando el menú está abierto («Cerrar menú»). Sin él, se usa `label` con `aria-expanded`. */
24
+ /**
25
+ * Texto accesible con el menú abierto. **Sin default**: sin él, sale de
26
+ * `menuButton.close` del `BrandMessagesProvider`. Solo se lee cuando el menú
27
+ * está abierto: un botón que nunca se abre no exige esa clave.
28
+ */
9
29
  closeLabel?: string;
10
30
  /** Talla del botón: un cuadrado de 32, 40 o 48px. En `lg` el glifo mide 48px. */
11
31
  size?: 'sm' | 'md' | 'lg';
@@ -54,12 +54,14 @@ export interface MultiSelectProps {
54
54
  */
55
55
  removeLabel?: (label: string) => string;
56
56
  /**
57
- * Nodo DOM donde montar el portal del dropdown (reenviado a Base UI
58
- * `Portal.container`). Por defecto se monta en `document.body`, que
59
- * hereda el tema activado a nivel raíz (`html.dark`/`[data-theme="dark"]`)
60
- * sin configuración adicional. Solo hace falta pasarlo cuando el
61
- * MultiSelect vive dentro de un `.surface-dark` **anidado** (no en la
62
- * raíz), ya que ese contexto no llega a `document.body` por la cascada.
57
+ * Nodo DOM donde montar el portal del dropdown (reenviado a Base UI `Portal.container`).
58
+ * Por defecto, el nodo de la superficie que llegue por contexto:
59
+ * `SiteShell` publica el suyo, de modo que la capa hereda la talla de la
60
+ * superficie pública en vez de abrirse a la de aplicación. Si no hay
61
+ * superficie, `document.body` — que ya hereda el tema activado en la raíz
62
+ * (`html.dark`/`[data-theme="dark"]`) sin configuración adicional. Pásalo
63
+ * solo para llevar la capa a otro sitio: un `.surface-dark` **anidado**, el
64
+ * cajón de un shell propio. Gana siempre.
63
65
  */
64
66
  container?: React.ComponentPropsWithoutRef<typeof BasePopover.Portal>['container'];
65
67
  }
@@ -54,6 +54,13 @@ export interface PopoverProps {
54
54
  * un `ref`, o una función que lo devuelva. Es la prop de Base UI, tal cual.
55
55
  */
56
56
  initialFocus?: React.ComponentProps<typeof BasePopover.Popup>['initialFocus'];
57
+ /**
58
+ * Nodo DOM donde montar el portal. Por defecto, el nodo de la superficie que
59
+ * llegue por contexto —`SiteShell` publica el suyo, para que la capa herede
60
+ * la talla de la superficie pública— y, si no hay ninguna, `document.body`.
61
+ * Pásalo solo para llevar la capa a otro sitio: gana siempre.
62
+ */
63
+ container?: HTMLElement | null;
57
64
  /** Clase adicional para el panel. */
58
65
  className?: string;
59
66
  }
@@ -67,4 +74,4 @@ export interface PopoverProps {
67
74
  * mantener el panel abierto cuando el clic cae en algo que el motor no
68
75
  * reconoce como suyo.
69
76
  */
70
- export declare function Popover({ trigger, children, label, open, defaultOpen, onOpenChange, onPointerDownOutside, onFocusOutside, onEscapeKeyDown, side, align, sideOffset, initialFocus, className, }: PopoverProps): import("react/jsx-runtime").JSX.Element;
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;
@@ -70,13 +70,14 @@ export interface SelectProps {
70
70
  /** Estado de error accesible (lo pone el campo). */
71
71
  'aria-invalid'?: boolean;
72
72
  /**
73
- * Nodo DOM donde montar el portal del dropdown (reenviado a `Select.Portal`
74
- * de Base UI). Por defecto el portal se monta en `document.body`, que hereda
75
- * el tema activado a nivel raíz (`html.dark`/`[data-theme="dark"]`) sin
76
- * configuración adicional. Solo hace falta pasar `container` cuando el Select
77
- * vive dentro de un `.surface-dark` **anidado** (no en la raíz): ese contexto
78
- * no llega a `document.body` por la cascada, así que hay que montar el portal
79
- * dentro del propio contenedor con la clase.
73
+ * Nodo DOM donde montar el portal del dropdown (reenviado a `Select.Portal` de Base UI).
74
+ * Por defecto, el nodo de la superficie que llegue por contexto:
75
+ * `SiteShell` publica el suyo, de modo que la capa hereda la talla de la
76
+ * superficie pública en vez de abrirse a la de aplicación. Si no hay
77
+ * superficie, `document.body` — que ya hereda el tema activado en la raíz
78
+ * (`html.dark`/`[data-theme="dark"]`) sin configuración adicional. Pásalo
79
+ * solo para llevar la capa a otro sitio: un `.surface-dark` **anidado**, el
80
+ * cajón de un shell propio. Gana siempre.
80
81
  */
81
82
  container?: SelectPortalContainer;
82
83
  }
@@ -41,6 +41,13 @@ export interface TooltipProps extends Omit<React.HTMLAttributes<HTMLElement>, 'c
41
41
  * @default true
42
42
  */
43
43
  describe?: boolean;
44
+ /**
45
+ * Nodo DOM donde montar el portal. Por defecto, el nodo de la superficie que
46
+ * llegue por contexto —`SiteShell` publica el suyo, para que la capa herede
47
+ * la talla de la superficie pública— y, si no hay ninguna, `document.body`.
48
+ * Pásalo solo para llevar la capa a otro sitio: gana siempre.
49
+ */
50
+ container?: HTMLElement | null;
44
51
  /** Clase adicional para el **bocadillo** (no para el disparador). */
45
52
  className?: string;
46
53
  }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * El nodo donde montan su portal los componentes que abren una capa flotante
3
+ * —la lista de un `Select`, el calendario de un `DatePicker`, el panel de un
4
+ * `Popover`, el velo de un `Modal`— cuando no se les pasa `container`.
5
+ *
6
+ * **Por qué hace falta.** Un portal monta en `document.body`, que no es
7
+ * descendiente de `.site-shell`. El tema oscuro sobrevive a eso porque se
8
+ * activa en `<html>` y cascadea a todo el documento; la **superficie de
9
+ * lectura** no: `.site-shell` remapea los tokens de texto y pone los controles
10
+ * en talla `lg` (v45.1.0) desde una clase que está a media altura del árbol.
11
+ * Resultado antes de esto: el campo se pintaba a 48px/20 y su lista se abría a
12
+ * 40px/16, fuera del shell.
13
+ *
14
+ * **Cómo se arregla.** `SiteShell` publica su nodo raíz por este contexto y
15
+ * todo componente con portal lo toma como destino por defecto. No hay nada que
16
+ * pasar en cada uso: el árbol de React ya sabe dónde está el shell aunque el
17
+ * árbol del DOM no lo sepa. El valor se guarda en **estado**, no en una ref —
18
+ * el destino tiene que existir en el render en el que el portal se monta, y
19
+ * una ref no provoca repintado al rellenarse. Es el patrón que `ChatShell` ya
20
+ * usaba para el `container` de su cajón.
21
+ *
22
+ * La prop `container` sigue existiendo y **gana siempre**: es la salida para
23
+ * quien quiera otro destino (el ancla de `FloatingDock`, un `.surface-dark`
24
+ * anidado).
25
+ *
26
+ * `AppShell` **no** lo provee, y es deliberado: la superficie de aplicación es
27
+ * la del `:root`, así que `document.body` ya resuelve los mismos valores y
28
+ * meter los portales dentro de `.app-shell` —que es `overflow: clip` y de
29
+ * altura fija— solo añadiría riesgo de recorte sin arreglar nada. El día que
30
+ * la superficie de aplicación cambie de talla, el arreglo es una línea: montar
31
+ * este mismo proveedor en `AppShell`.
32
+ */
33
+ export declare const PortalContainerContext: import("react").Context<HTMLElement | null>;
34
+ /**
35
+ * Resuelve el destino del portal: la prop si el consumidor la pasa, y si no,
36
+ * el nodo de la superficie que venga por contexto.
37
+ *
38
+ * Se llama **siempre**, con o sin prop —es un hook—, y devuelve `undefined`
39
+ * cuando no hay ni una cosa ni la otra, que es lo que Base UI entiende por
40
+ * «monta en `document.body`».
41
+ */
42
+ export declare function usePortalContainer<T>(container: T): T | HTMLElement | undefined;
@@ -25,6 +25,26 @@ import type { ConfirmDialogMessages } from '../molecules/ConfirmDialog/ConfirmDi
25
25
  import type { AlertMessages } from '../molecules/Alert/Alert';
26
26
  import type { BannerMessages } from '../molecules/Banner/Banner';
27
27
  import type { ToasterMessages } from '../molecules/Toast/Toaster';
28
+ import type { ConsentMessages } from '../molecules/Consent/Consent';
29
+ import type { CommandPaletteMessages } from '../molecules/CommandPalette/CommandPalette';
30
+ import type { AppLauncherMessages } from '../molecules/AppLauncher/AppLauncher';
31
+ import type { FloatingDockMessages } from '../sections/FloatingDock/FloatingDock';
32
+ import type { NotificationButtonMessages } from '../molecules/NotificationButton/NotificationButton';
33
+ import type { NotificationPanelMessages } from '../molecules/NotificationPanel/NotificationPanel';
34
+ import type { MenuButtonMessages } from '../atoms/MenuButton/MenuButton';
35
+ import type { AppRootMessages } from '../sections/AppRoot/AppRoot';
36
+ import type { AppShellMessages } from '../sections/AppShell/AppShell';
37
+ import type { SidebarMessages } from '../sections/Sidebar/Sidebar';
38
+ import type { SidebarNavMessages } from '../molecules/SidebarNav/SidebarNav';
39
+ import type { SiteNavMessages } from '../molecules/SiteNav/SiteNav';
40
+ import type { SiteHeaderMessages } from '../sections/SiteHeader/SiteHeader';
41
+ import type { UserMenuMessages } from '../molecules/UserMenu/UserMenu';
42
+ import type { OrgSwitcherMessages } from '../molecules/OrgSwitcher/OrgSwitcher';
43
+ import type { BreadcrumbMessages } from '../molecules/Breadcrumb/Breadcrumb';
44
+ import type { TableOfContentsMessages } from '../molecules/TableOfContents/TableOfContents';
45
+ import type { PrevNextNavMessages } from '../molecules/PrevNextNav/PrevNextNav';
46
+ import type { PublicPageShellMessages } from '../templates/PublicPageShell/PublicPageShell';
47
+ import type { OnboardingShellMessages } from '../templates/OnboardingShell/OnboardingShell';
28
48
  /**
29
49
  * El contrato de textos de la librería: un espacio por componente, y dentro
30
50
  * de cada espacio **todas las claves obligatorias**.
@@ -74,5 +94,25 @@ export interface BrandMessages {
74
94
  alert: AlertMessages;
75
95
  banner: BannerMessages;
76
96
  toaster: ToasterMessages;
97
+ consent: ConsentMessages;
98
+ commandPalette: CommandPaletteMessages;
99
+ appLauncher: AppLauncherMessages;
100
+ floatingDock: FloatingDockMessages;
101
+ notificationButton: NotificationButtonMessages;
102
+ notificationPanel: NotificationPanelMessages;
103
+ menuButton: MenuButtonMessages;
104
+ appRoot: AppRootMessages;
105
+ appShell: AppShellMessages;
106
+ sidebar: SidebarMessages;
107
+ sidebarNav: SidebarNavMessages;
108
+ siteNav: SiteNavMessages;
109
+ siteHeader: SiteHeaderMessages;
110
+ userMenu: UserMenuMessages;
111
+ orgSwitcher: OrgSwitcherMessages;
112
+ breadcrumb: BreadcrumbMessages;
113
+ tableOfContents: TableOfContentsMessages;
114
+ prevNextNav: PrevNextNavMessages;
115
+ publicPageShell: PublicPageShellMessages;
116
+ onboardingShell: OnboardingShellMessages;
77
117
  }
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, };
118
+ 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, ConsentMessages, CommandPaletteMessages, AppLauncherMessages, FloatingDockMessages, NotificationButtonMessages, NotificationPanelMessages, MenuButtonMessages, AppRootMessages, AppShellMessages, SidebarMessages, SidebarNavMessages, SiteNavMessages, SiteHeaderMessages, UserMenuMessages, OrgSwitcherMessages, BreadcrumbMessages, TableOfContentsMessages, PrevNextNavMessages, PublicPageShellMessages, OnboardingShellMessages, };
@@ -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, ModalMessages, SheetMessages, ConfirmDialogMessages, AlertMessages, BannerMessages, ToasterMessages, } 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, ConsentMessages, CommandPaletteMessages, AppLauncherMessages, FloatingDockMessages, NotificationButtonMessages, NotificationPanelMessages, MenuButtonMessages, AppRootMessages, AppShellMessages, SidebarMessages, SidebarNavMessages, SiteNavMessages, SiteHeaderMessages, UserMenuMessages, OrgSwitcherMessages, BreadcrumbMessages, TableOfContentsMessages, PrevNextNavMessages, PublicPageShellMessages, OnboardingShellMessages, } from './BrandMessages';
@@ -1,4 +1,24 @@
1
1
  import './AppLauncher.css';
2
+ /**
3
+ * El cromo del lanzador, y **solo el cromo**: el nombre accesible del
4
+ * disparador, el título del diálogo y la marca de app nueva. Las tres valen
5
+ * igual en todas las apps de la suite —el lanzador es el mismo mueble en
6
+ * todas— y ninguna nombra una aplicación concreta: eso viaja en `apps`.
7
+ *
8
+ * **`trigger` no está aquí** y sigue siendo prop. No es un texto de más: su
9
+ * presencia decide la cara del disparador —solo icono, o icono con rótulo—, y
10
+ * un texto de catálogo está siempre presente, así que ponerlo aquí obligaría a
11
+ * todos los lanzadores de la suite a llevar rótulo. Es una decisión de
12
+ * maqueta que se toma en el sitio donde se monta.
13
+ */
14
+ export interface AppLauncherMessages {
15
+ /** Nombre accesible del disparador cuando es solo icono («Abrir launcher de apps»). */
16
+ open: string;
17
+ /** Texto del distintivo de app nueva. */
18
+ new: string;
19
+ /** Título del diálogo con `presentation="modal"`. */
20
+ title: string;
21
+ }
2
22
  export interface LauncherApp {
3
23
  id: string;
4
24
  name: string;
@@ -6,10 +26,18 @@ export interface LauncherApp {
6
26
  isNew?: boolean;
7
27
  }
8
28
  export interface AppLauncherLabels {
9
- /** Texto accesible del trigger («Abrir launcher de apps»). Solo se usa como `aria-label` cuando no hay `trigger`: con texto visible, el nombre accesible es ese texto. */
10
- open: string;
11
- /** Texto del badge de app nueva. */
12
- new: string;
29
+ /**
30
+ * Texto accesible del trigger («Abrir launcher de apps»). Solo se usa como
31
+ * `aria-label` cuando no hay `trigger`: con texto visible, el nombre
32
+ * accesible es ese texto. **Sin default**: sin él, sale de
33
+ * `appLauncher.open` del `BrandMessagesProvider`.
34
+ */
35
+ open?: string;
36
+ /**
37
+ * Texto del badge de app nueva. **Sin default**: sin él, sale de
38
+ * `appLauncher.new` del proveedor.
39
+ */
40
+ new?: string;
13
41
  /**
14
42
  * Texto visible del disparador (p. ej. «Aplicaciones»), a la derecha del
15
43
  * icono de rejilla. Sin él, el disparador se queda como hoy: solo icono,
@@ -17,14 +45,21 @@ export interface AppLauncherLabels {
17
45
  */
18
46
  trigger?: string;
19
47
  /**
20
- * Título del diálogo cuando `presentation="modal"`. Default: «Aplicaciones»
21
- * (castellano). Sin uso en `presentation="popover"`, que no lleva título.
48
+ * Título del diálogo cuando `presentation="modal"`. **Sin default**: sin él,
49
+ * sale de `appLauncher.title` del proveedor. Sin uso en
50
+ * `presentation="popover"`, que no lleva título.
22
51
  */
23
52
  title?: string;
24
53
  }
25
54
  export interface AppLauncherProps {
26
55
  apps: LauncherApp[];
27
- labels: AppLauncherLabels;
56
+ /**
57
+ * Anulaciones puntuales de los textos del lanzador. **Ya no es
58
+ * obligatoria**: sin ella, el cromo sale del espacio `appLauncher` del
59
+ * `BrandMessagesProvider`. Sigue haciendo falta para `trigger`, que no es
60
+ * catálogo.
61
+ */
62
+ labels?: AppLauncherLabels;
28
63
  /** Id de la app actual — se marca en la rejilla. */
29
64
  currentAppId?: string;
30
65
  open?: boolean;
@@ -39,4 +74,4 @@ export interface AppLauncherProps {
39
74
  */
40
75
  presentation?: 'modal' | 'popover';
41
76
  }
42
- export declare function AppLauncher({ presentation, ...rest }: AppLauncherProps): import("react/jsx-runtime").JSX.Element;
77
+ export declare function AppLauncher({ presentation, labels, ...rest }: AppLauncherProps): import("react/jsx-runtime").JSX.Element;
@@ -14,10 +14,18 @@ export interface BreadcrumbProps {
14
14
  renderLink?: (props: BreadcrumbRenderLinkProps) => ReactNode;
15
15
  separator?: ReactNode;
16
16
  /**
17
- * `aria-label` del `<nav>`. Default: «Migas de pan» (castellano).
18
- * Una app multiidioma debe pasarlo traducido.
17
+ * `aria-label` del `<nav>`. **Sin default**: sin él, sale de
18
+ * `breadcrumb.label` del `BrandMessagesProvider`.
19
19
  */
20
20
  ariaLabel?: string;
21
21
  className?: string;
22
22
  }
23
+ /**
24
+ * El único texto que las migas dicen por su cuenta, y es **cromo**: el nombre de
25
+ * la región. Los rótulos del rastro son **contenido** y vienen en `items`.
26
+ */
27
+ export interface BreadcrumbMessages {
28
+ /** Nombre accesible del `nav`. */
29
+ label: string;
30
+ }
23
31
  export declare function Breadcrumb({ items, renderLink, separator, ariaLabel, className, }: BreadcrumbProps): import("react/jsx-runtime").JSX.Element;