@studiolxd/brand 46.0.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 (60) hide show
  1. package/CHANGELOG.md +134 -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 +29 -1
  13. package/dist/_types/messages/index.d.ts +1 -1
  14. package/dist/_types/molecules/Breadcrumb/Breadcrumb.d.ts +10 -2
  15. package/dist/_types/molecules/Menu/Menu.d.ts +8 -1
  16. package/dist/_types/molecules/Modal/Modal.d.ts +8 -6
  17. package/dist/_types/molecules/OrgSwitcher/OrgSwitcher.d.ts +15 -1
  18. package/dist/_types/molecules/PrevNextNav/PrevNextNav.d.ts +17 -2
  19. package/dist/_types/molecules/Sheet/Sheet.d.ts +8 -7
  20. package/dist/_types/molecules/SidebarNav/SidebarNav.d.ts +18 -3
  21. package/dist/_types/molecules/SiteNav/SiteNav.d.ts +9 -0
  22. package/dist/_types/molecules/TableOfContents/TableOfContents.d.ts +11 -2
  23. package/dist/_types/molecules/UserMenu/UserMenu.d.ts +16 -1
  24. package/dist/_types/sections/AppHeader/AppHeader.d.ts +8 -2
  25. package/dist/_types/sections/AppRoot/AppRoot.d.ts +12 -1
  26. package/dist/_types/sections/AppShell/AppShell.d.ts +14 -1
  27. package/dist/_types/sections/Sidebar/Sidebar.d.ts +27 -3
  28. package/dist/_types/sections/SiteHeader/SiteHeader.d.ts +22 -3
  29. package/dist/_types/sections/SiteShell/SiteShell.d.ts +11 -5
  30. package/dist/_types/templates/OnboardingShell/OnboardingShell.d.ts +19 -2
  31. package/dist/_types/templates/PublicPageShell/PublicPageShell.d.ts +42 -6
  32. package/dist/app-header.js +1 -1
  33. package/dist/app-launcher.js +62 -58
  34. package/dist/app-root.js +10 -8
  35. package/dist/app-shell.js +51 -50
  36. package/dist/async-multi-select.js +65 -64
  37. package/dist/async-select.js +49 -48
  38. package/dist/breadcrumb.js +24 -21
  39. package/dist/input-phone.js +38 -37
  40. package/dist/menu-button.js +16 -14
  41. package/dist/menu.js +44 -40
  42. package/dist/modal.js +32 -31
  43. package/dist/multi-select.js +106 -105
  44. package/dist/onboarding-shell.js +36 -35
  45. package/dist/org-switcher.js +64 -59
  46. package/dist/popover.js +27 -22
  47. package/dist/prev-next-nav.js +38 -36
  48. package/dist/public-page-shell.js +24 -20
  49. package/dist/select.js +70 -69
  50. package/dist/sheet.js +30 -29
  51. package/dist/sidebar-nav.js +91 -90
  52. package/dist/sidebar.js +72 -71
  53. package/dist/site-header.js +44 -43
  54. package/dist/site-nav.js +27 -25
  55. package/dist/site-shell.js +23 -15
  56. package/dist/table-of-contents.js +30 -27
  57. package/dist/toaster.js +57 -53
  58. package/dist/tooltip.js +45 -41
  59. package/dist/user-menu.js +58 -52
  60. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,140 @@ 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
+
10
144
  ## [46.0.0] — 2026-09-15
11
145
 
12
146
  > **Major.** Séptima familia al proveedor de textos: los envoltorios de diálogo. `Consent`,
@@ -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;
@@ -31,6 +31,20 @@ import type { AppLauncherMessages } from '../molecules/AppLauncher/AppLauncher';
31
31
  import type { FloatingDockMessages } from '../sections/FloatingDock/FloatingDock';
32
32
  import type { NotificationButtonMessages } from '../molecules/NotificationButton/NotificationButton';
33
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';
34
48
  /**
35
49
  * El contrato de textos de la librería: un espacio por componente, y dentro
36
50
  * de cada espacio **todas las claves obligatorias**.
@@ -86,5 +100,19 @@ export interface BrandMessages {
86
100
  floatingDock: FloatingDockMessages;
87
101
  notificationButton: NotificationButtonMessages;
88
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;
89
117
  }
90
- 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, };
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, ConsentMessages, CommandPaletteMessages, AppLauncherMessages, FloatingDockMessages, NotificationButtonMessages, NotificationPanelMessages, } 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';
@@ -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;
@@ -29,6 +29,13 @@ export interface MenuProps {
29
29
  maxWidth?: string;
30
30
  /** Talla de los ítems, la del disparador (32/40/48): el panel desplegado casa con el control plegado, como en el Select. */
31
31
  size?: 'sm' | 'md' | 'lg';
32
+ /**
33
+ * Nodo DOM donde montar el portal. Por defecto, el nodo de la superficie que
34
+ * llegue por contexto —`SiteShell` publica el suyo, para que la capa herede
35
+ * la talla de la superficie pública— y, si no hay ninguna, `document.body`.
36
+ * Pásalo solo para llevar la capa a otro sitio: gana siempre.
37
+ */
38
+ container?: HTMLElement | null;
32
39
  className?: string;
33
40
  }
34
41
  /**
@@ -36,4 +43,4 @@ export interface MenuProps {
36
43
  * (tokens `menu.*`) de todos los menús; `ContextMenu`, `UserMenu`,
37
44
  * `OrgSwitcher` o `DropdownField` son este menú con un disparador concreto.
38
45
  */
39
- export declare function Menu({ trigger, items, value, onValueChange, renderLink, open, defaultOpen, onOpenChange, openOnHover, hoverDelay, side, align, sideOffset, minWidth, maxWidth, size, className, }: MenuProps): import("react/jsx-runtime").JSX.Element;
46
+ export declare function Menu({ trigger, items, value, onValueChange, renderLink, open, defaultOpen, onOpenChange, openOnHover, hoverDelay, side, align, sideOffset, minWidth, maxWidth, size, container, className, }: MenuProps): import("react/jsx-runtime").JSX.Element;
@@ -33,12 +33,14 @@ export interface ModalProps extends Omit<React.ComponentPropsWithoutRef<'div'>,
33
33
  */
34
34
  fallbackTitle?: string;
35
35
  /**
36
- * Nodo DOM donde montar el portal del modal (reenviado a Base UI
37
- * `Portal.container`). Por defecto se monta en `document.body`, que
38
- * hereda el tema activado a nivel raíz (`html.dark`/`[data-theme="dark"]`)
39
- * sin configuración adicional. Solo hace falta pasarlo cuando el Modal
40
- * vive dentro de un `.surface-dark` **anidado** (no en la raíz), ya que
41
- * ese contexto no llega a `document.body` por la cascada.
36
+ * Nodo DOM donde montar el portal del modal (reenviado a Base UI `Portal.container`).
37
+ * Por defecto, el nodo de la superficie que llegue por contexto:
38
+ * `SiteShell` publica el suyo, de modo que la capa hereda la talla de la
39
+ * superficie pública en vez de abrirse a la de aplicación. Si no hay
40
+ * superficie, `document.body` — que ya hereda el tema activado en la raíz
41
+ * (`html.dark`/`[data-theme="dark"]`) sin configuración adicional. Pásalo
42
+ * solo para llevar la capa a otro sitio: un `.surface-dark` **anidado**, el
43
+ * cajón de un shell propio. Gana siempre.
42
44
  */
43
45
  container?: React.ComponentPropsWithoutRef<typeof Dialog.Portal>['container'];
44
46
  /**
@@ -6,8 +6,22 @@ export interface OrgOption {
6
6
  name: string;
7
7
  logoUrl?: string;
8
8
  }
9
+ /**
10
+ * El único texto que el conmutador dice por su cuenta, y es **cromo**: cómo se
11
+ * nombra su botón. Interpola la organización activa, así que es una función.
12
+ * Los nombres de las organizaciones son **contenido** y vienen en
13
+ * `organizations`.
14
+ */
15
+ export interface OrgSwitcherMessages {
16
+ /** Nombre accesible del botón, a partir del nombre de la organización. */
17
+ trigger: (name: string) => string;
18
+ }
9
19
  export interface OrgSwitcherProps {
10
- /** Nombre accesible del botón. Por defecto, «Organización: ‹nombre›». */
20
+ /**
21
+ * Nombre accesible del botón. **Sin default**: sin él, sale de
22
+ * `orgSwitcher.trigger` del `BrandMessagesProvider`, que recibe el nombre de
23
+ * la organización activa.
24
+ */
11
25
  label?: string;
12
26
  /** Ocupa todo el ancho disponible (en la Sidebar). Por defecto mide lo que su contenido. */
13
27
  block?: boolean;
@@ -16,10 +16,14 @@ export interface PrevNextNavProps {
16
16
  /**
17
17
  * Rótulo del control anterior. Sin `prevTitle` es el `aria-label` del
18
18
  * chevron; con `prevTitle` es el rótulo **visible** que lo encabeza.
19
- * Default: "Anterior"
19
+ * **Sin default**: sin él, sale de `prevNextNav.previous` del
20
+ * `BrandMessagesProvider`.
20
21
  */
21
22
  prevLabel?: string;
22
- /** Rótulo del control siguiente. Mismo contrato que `prevLabel`. Default: "Siguiente" */
23
+ /**
24
+ * Rótulo del control siguiente. Mismo contrato que `prevLabel`. **Sin
25
+ * default**: sale de `prevNextNav.next`.
26
+ */
23
27
  nextLabel?: string;
24
28
  /**
25
29
  * Título visible del destino anterior (el de la página, el capítulo…). Con
@@ -47,4 +51,15 @@ export interface PrevNextNavProps {
47
51
  /** Variante de densidad. Default: "md" */
48
52
  size?: 'sm' | 'md';
49
53
  }
54
+ /**
55
+ * Los dos textos del par, y los dos son **cromo**: «anterior» y «siguiente»
56
+ * dicen la dirección, no el destino. El destino —`prevTitle`, `nextTitle`, el
57
+ * rótulo del medio— es **contenido** y lo escribe la página.
58
+ */
59
+ export interface PrevNextNavMessages {
60
+ /** Rótulo del control anterior. */
61
+ previous: string;
62
+ /** Rótulo del control siguiente. */
63
+ next: string;
64
+ }
50
65
  export declare function PrevNextNav({ prevHref, nextHref, prevOnClick, nextOnClick, prevLabel, nextLabel, prevTitle, nextTitle, label, labelId, linkComponent, size, }: PrevNextNavProps): import("react/jsx-runtime").JSX.Element;
@@ -39,13 +39,14 @@ export interface SheetProps extends Omit<React.ComponentPropsWithoutRef<'div'>,
39
39
  /** Elemento que abre el panel. Sin él, la apertura la controla el consumidor. */
40
40
  trigger?: ReactNode;
41
41
  /**
42
- * Nodo DOM donde montar el portal del panel (reenviado a Base UI
43
- * `Portal.container`). Por defecto se monta en `document.body`, que
44
- * hereda el tema activado a nivel raíz (`html.dark`/`[data-theme="dark"]`)
45
- * sin configuración adicional. Solo hace falta pasarlo cuando el Sheet
46
- * vive dentro de una superficie **anidada** (un `.surface-dark` que no está
47
- * en la raíz, o dentro de `SiteShell`/`.site-shell`), ya que ese contexto
48
- * no llega a `document.body` por la cascada.
42
+ * Nodo DOM donde montar el portal del panel (reenviado a Base UI `Portal.container`).
43
+ * Por defecto, el nodo de la superficie que llegue por contexto:
44
+ * `SiteShell` publica el suyo, de modo que la capa hereda la talla de la
45
+ * superficie pública en vez de abrirse a la de aplicación. Si no hay
46
+ * superficie, `document.body` — que ya hereda el tema activado en la raíz
47
+ * (`html.dark`/`[data-theme="dark"]`) sin configuración adicional. Pásalo
48
+ * solo para llevar la capa a otro sitio: un `.surface-dark` **anidado**, el
49
+ * cajón de un shell propio. Gana siempre.
49
50
  */
50
51
  container?: React.ComponentPropsWithoutRef<typeof Dialog.Portal>['container'];
51
52
  /**
@@ -41,11 +41,14 @@ export type SidebarNavRenderLinkProps = React.AnchorHTMLAttributes<HTMLAnchorEle
41
41
  'aria-current'?: 'page';
42
42
  };
43
43
  export interface SidebarNavProps {
44
- /** Nombre accesible del `nav`. */
44
+ /**
45
+ * Nombre accesible del `nav`. **Sin default**: sin él, sale de
46
+ * `sidebarNav.label` del `BrandMessagesProvider`.
47
+ */
45
48
  label?: string;
46
49
  /**
47
- * Marca de las entradas vacías (`empty`). Por defecto, en castellano:
48
- * «sin docs».
50
+ * Marca de las entradas vacías (`empty`). **Sin default**: sale de
51
+ * `sidebarNav.empty`. Solo se lee cuando hay alguna entrada vacía.
49
52
  */
50
53
  emptyLabel?: string;
51
54
  /** Solo iconos: los enlaces con tooltip, los grupos como menú. Sin él, lo decide la `Sidebar` (rail). */
@@ -56,4 +59,16 @@ export interface SidebarNavProps {
56
59
  onValueChange?: (value: string[]) => void;
57
60
  renderLink?: (props: SidebarNavRenderLinkProps) => ReactNode;
58
61
  }
62
+ /**
63
+ * Los dos textos de la navegación, los dos **cromo**: el nombre de la región
64
+ * («Principal», el mismo en toda la suite) y la marca que se pone a una entrada
65
+ * sin contenido. Los rótulos de las entradas son **contenido** y siguen
66
+ * viniendo en `entries`.
67
+ */
68
+ export interface SidebarNavMessages {
69
+ /** Nombre accesible del `nav`. */
70
+ label: string;
71
+ /** Marca de las entradas sin contenido. */
72
+ empty: string;
73
+ }
59
74
  export declare function SidebarNav({ label, emptyLabel, rail, entries, defaultValue, value, onValueChange, renderLink, }: SidebarNavProps): import("react/jsx-runtime").JSX.Element;