@studiolxd/brand 49.7.0 → 49.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,82 @@ 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
+ ## [49.8.1] — 2026-09-18
11
+
12
+ > **Patch.** `AppShell` ya no revienta sin `ResizeObserver`.
13
+
14
+ ### El armazón mide la barra de sistema solo si hay `ResizeObserver`
15
+
16
+ Desde 49.8.0, `AppShell` medía la ranura `banner` con `new ResizeObserver(...)` en el
17
+ callback ref de montaje. En Vitest + jsdom sin polyfill (o en cualquier entorno que no lo
18
+ implemente) eso caía con `ReferenceError: ResizeObserver is not defined` — lo sufrió
19
+ `@slxd/app-shell` de la suite, que lo tapó con un polyfill en su propio setup. Un componente
20
+ del sistema tiene que ser inofensivo sin DOM real.
21
+
22
+ `AppShell` guarda ahora la creación del observer tras `typeof ResizeObserver === 'undefined'`:
23
+ sin él, mide una vez con `getBoundingClientRect` y no observa (la barra queda con el
24
+ comportamiento previo, sin reobservar redimensionados). `useIsDesktop` aplica la misma guarda
25
+ sobre `window.matchMedia`, la otra API de navegador que el armazón usa al montar.
26
+
27
+ ## [49.8.0] — 2026-09-18
28
+
29
+ > **Minor.** Lo que cae dentro de un `Banner` lee con la tinta del relleno en todas las
30
+ > variantes, llega `Banner variant="error"`, y `AppShell` gana la ranura `banner` por encima
31
+ > de la cabecera.
32
+
33
+ ### Los botones dentro del aviso ya no salen blancos sobre amarillo
34
+
35
+ `Banner` declaraba superficie solo en `info`: en `warning` fijaba a tinta el aspa y se
36
+ olvidaba de la ranura de acciones, así que sobre página oscura un `Button variant="outline"`
37
+ heredaba la tinta ambiente y salía **blanco sobre amarillo** (1,50:1). `Alert warning` tenía
38
+ el mismo hueco.
39
+
40
+ La respuesta no es un `!important` por componente sino la pieza que faltaba en el sistema de
41
+ superficies: **`.surface-light`**, el contrapunto de `.surface-dark`, para el interior de un
42
+ relleno **claro y universal**. `.surface-invert` no valía —es la cara *contraria* a la
43
+ ambiente, o sea oscura sobre página clara— y `.surface-dark` es justo al revés. La clase no
44
+ está en `DARK_SELECTORS`: sobre página clara no hace nada, porque los tokens ya están en
45
+ claro, y `src/tokens/surface-light.css` —generado por `pnpm build:tokens`, con los mismos
46
+ nombres y valores que `surface-invert.css`— los devuelve a claro cuando cae dentro de una
47
+ superficie oscura.
48
+
49
+ `Banner warning` la abre sobre el contenido, las acciones y el aspa (y copia antes su tinta
50
+ en `--banner-ink`, que es lo que consumen contenido y acciones); `Alert warning` hace lo
51
+ mismo por el camino que ya tenía (`interiorSurface`). Un botón, un enlace o el aspa dentro
52
+ del aviso leen en prusia en las dos superficies **sin que el consumidor configure nada**.
53
+
54
+ ### `Banner variant="error"`
55
+
56
+ `error` es para el estado que hay que ver antes que nada: la suplantación es el caso de
57
+ referencia. Relleno de error del sistema —`error-fill` / `error-fill-text`, los mismos roles
58
+ que `Alert error`, universales en las dos superficies— con el aspa y las acciones en la
59
+ tinta del relleno, que declara la raíz (`.surface-dark`) como en `info`. Tokens
60
+ `banner.error.*` calcados de `banner.warning.*`.
61
+
62
+ Con la variante llega el **rol por variante**, el mismo criterio que en `Alert`: `warning` y
63
+ `error` interrumpen (`role="alert"`, `aria-live="assertive"`) e `info` informa sin
64
+ interrumpir (`role="status"`, `aria-live="polite"`). Las props `role` y `aria-live` siguen
65
+ mandando. Es un cambio de comportamiento en `warning`, que antes anunciaba como `status`.
66
+
67
+ ### `AppShell`: la ranura `banner`, por encima de la cabecera
68
+
69
+ Prop `banner?: ReactNode`, pintada **antes de `header`** dentro de `.app-shell` y a ancho
70
+ completo. Es para el estado de sesión que no se puede perder de vista —la suplantación—: va
71
+ por encima de todo, incluida la cabecera. La maqueta no cambia: el armazón sigue siendo una
72
+ columna de `100dvh`, el cuerpo se queda con lo que sobra (`flex: 1; min-block-size: 0`) y la
73
+ sidebar sigue midiendo el cien por cien del cuerpo. La cabecera es `sticky` contra un
74
+ contenedor que no hace scroll, así que la barra ni la tapa ni queda tapada.
75
+
76
+ En **móvil**, el cajón de la sidebar y su velo arrancaban en
77
+ `calc(var(--app-header-height) + env(safe-area-inset-top))`: con barra tienen que arrancar
78
+ por debajo de cabecera **más** barra. Como el alto de la barra lo decide su contenido —el
79
+ mensaje parte en dos líneas, las acciones apilan— no se puede fijar: el armazón la mide con
80
+ un `ResizeObserver` y publica el alto en `--app-shell-banner-height` por el CSSOM
81
+ (`useCssProperties`, como ya hacía con `--app-shell-sidebar-width`). De ahí sale
82
+ `--app-shell-chrome-block-start`, el offset único que consumen el velo (`AppShell.css`) y el
83
+ cajón (`Sidebar.css`, con fallback para un `Sidebar` fuera de un `AppShell`). Sin ranura
84
+ `banner` el valor es cero y todo queda como estaba.
85
+
10
86
  ## [49.7.0] — 2026-09-18
11
87
 
12
88
  > **Minor.** El legend de `Fieldset` gana aire por debajo, igual que un `Heading` suelto.
@@ -2149,6 +2149,9 @@ var e = {
2149
2149
  "--banner-warning-color": "#111e30",
2150
2150
  "--banner-warning-border-color": "#ffcd00",
2151
2151
  "--banner-warning-close-color": "#111e30",
2152
+ "--banner-error-bg": "#b30000",
2153
+ "--banner-error-color": "#ffffff",
2154
+ "--banner-error-border-color": "#b30000",
2152
2155
  "--calendar-planner-gap": "0.5rem",
2153
2156
  "--calendar-planner-font-family": "\"Google Sans Flex\", system-ui, sans-serif",
2154
2157
  "--calendar-planner-nav-color": "#111e30",
@@ -8,9 +8,13 @@ export interface BannerMessages {
8
8
  /** Nombre accesible del aspa que descarta la barra. */
9
9
  dismiss: string;
10
10
  }
11
- export type BannerVariant = 'info' | 'warning';
11
+ export type BannerVariant = 'info' | 'warning' | 'error';
12
12
  export interface BannerProps extends React.ComponentPropsWithoutRef<'div'> {
13
- /** Intención de la barra. Default `'info'` (relleno prusia); `'warning'` es el relleno de aviso. */
13
+ /**
14
+ * Intención de la barra. Default `'info'` (relleno prusia); `'warning'` es el
15
+ * relleno de aviso y `'error'` el de error, para el estado que hay que ver
16
+ * antes que nada.
17
+ */
14
18
  variant?: BannerVariant;
15
19
  /** El mensaje. Texto corriente: una frase, no un bloque. */
16
20
  children?: React.ReactNode;
@@ -42,8 +46,9 @@ export interface BannerProps extends React.ComponentPropsWithoutRef<'div'> {
42
46
  * No fija su posición: `sticky` lo decide la aplicación con el layout del
43
47
  * sistema. Tampoco se oculta sola — `onDismiss` avisa y la app decide.
44
48
  *
45
- * Anuncia como `role="status"` con `aria-live="polite"`, que es lo que
46
- * corresponde a un aviso que no interrumpe. Ambos se pueden sobrescribir.
49
+ * El rol sale de la variante, como en `Alert`: `error` y `warning` interrumpen
50
+ * (`alert`, live `assertive`) y `info` informa sin interrumpir (`status`, live
51
+ * `polite`). Ambos se pueden sobrescribir.
47
52
  *
48
53
  * Extiende los atributos nativos de `<div>` y reenvía `{...rest}` al raíz.
49
54
  */
@@ -4,6 +4,17 @@ import './AppShell.css';
4
4
  export { useAppShell } from './AppShellContext';
5
5
  export type { AppShellContextValue, SidebarState } from './AppShellContext';
6
6
  export interface AppShellProps {
7
+ /**
8
+ * Ranura para una barra de sistema (`Banner`), **por encima de todo, incluida
9
+ * la cabecera**. Es para el estado de sesión que no se puede perder de vista
10
+ * —la suplantación es el caso de referencia—, no para un aviso de pantalla:
11
+ * eso es un `Alert` dentro del contenido.
12
+ *
13
+ * El armazón la mide (`ResizeObserver`) y publica su alto en
14
+ * `--app-shell-banner-height`, de donde lo toman el cajón de la sidebar y su
15
+ * velo para arrancar por debajo de cabecera **más** barra en móvil.
16
+ */
17
+ banner?: ReactNode;
7
18
  /** La barra superior: un `AppHeader`. Siempre visible. */
8
19
  header: ReactNode;
9
20
  /** La barra lateral: un `Sidebar`. Columna en escritorio, cajón en móvil. */
@@ -40,4 +51,4 @@ export interface AppShellMessages {
40
51
  * modo y su asa) y `SidebarNav` (rail). Persistir el estado es del producto:
41
52
  * `onSidebarChange` / `onSidebarWidthChange` avisan de cada cambio.
42
53
  */
43
- export declare function AppShell({ header, sidebar, children, defaultSidebar, sidebarState, onSidebarChange, defaultSidebarWidth, onSidebarWidthChange, skipLabel, }: AppShellProps): import("react/jsx-runtime").JSX.Element;
54
+ export declare function AppShell({ banner, header, sidebar, children, defaultSidebar, sidebarState, onSidebarChange, defaultSidebarWidth, onSidebarWidthChange, skipLabel, }: AppShellProps): import("react/jsx-runtime").JSX.Element;
package/dist/alert.js CHANGED
@@ -10,40 +10,45 @@ var o = {
10
10
  success: "status",
11
11
  error: "alert",
12
12
  warning: "alert"
13
- }, s = n(function({ className: e, children: t, ...n }, r) {
13
+ }, s = {
14
+ default: " surface-invert",
15
+ warning: " surface-light",
16
+ success: "",
17
+ error: ""
18
+ }, c = n(function({ className: e, children: t, ...n }, r) {
14
19
  return /* @__PURE__ */ i("p", {
15
20
  ref: r,
16
21
  className: ["alert__title", e ?? ""].filter(Boolean).join(" "),
17
22
  ...n,
18
23
  children: t
19
24
  });
20
- }), c = n(function({ className: e, children: t, ...n }, r) {
25
+ }), l = n(function({ className: e, children: t, ...n }, r) {
21
26
  return /* @__PURE__ */ i("div", {
22
27
  ref: r,
23
28
  className: ["alert__description", e ?? ""].filter(Boolean).join(" "),
24
29
  ...n,
25
30
  children: t
26
31
  });
27
- }), l = n(function({ className: e, children: t, ...n }, r) {
32
+ }), u = n(function({ className: e, children: t, ...n }, r) {
28
33
  return /* @__PURE__ */ i("div", {
29
34
  ref: r,
30
35
  className: ["alert__actions", e ?? ""].filter(Boolean).join(" "),
31
36
  ...n,
32
37
  children: t
33
38
  });
34
- }), u = n(function({ variant: n = "default", title: s, description: c, actions: l, dismissible: u = !1, onDismiss: d, finalFocus: f, closeLabel: p, className: m, children: h, role: g, ..._ }, v) {
35
- let y = e("alert"), [b, x] = r(!1);
36
- if (b) return null;
37
- let S = [
39
+ }), d = n(function({ variant: n = "default", title: c, description: l, actions: u, dismissible: d = !1, onDismiss: f, finalFocus: p, closeLabel: m, className: h, children: g, role: _, ...v }, y) {
40
+ let b = e("alert"), [x, S] = r(!1);
41
+ if (x) return null;
42
+ let C = [
38
43
  "alert",
39
44
  n === "default" ? "" : `alert--${n}`,
40
45
  n === "success" || n === "error" ? "surface-dark" : "",
41
- u ? "alert--dismissible" : "",
42
- m ?? ""
43
- ].filter(Boolean).join(" "), C = n === "default" ? " surface-invert" : "";
44
- function w() {
46
+ d ? "alert--dismissible" : "",
47
+ h ?? ""
48
+ ].filter(Boolean).join(" "), w = s[n];
49
+ function T() {
45
50
  if (typeof document > "u") return;
46
- let e = f?.current;
51
+ let e = p?.current;
47
52
  if (e) {
48
53
  e.focus();
49
54
  return;
@@ -51,41 +56,41 @@ var o = {
51
56
  let t = document.body, n = t.hasAttribute("tabindex");
52
57
  n || t.setAttribute("tabindex", "-1"), t.focus(), n || t.removeAttribute("tabindex");
53
58
  }
54
- function T() {
55
- w(), d ? d() : x(!0);
59
+ function E() {
60
+ T(), f ? f() : S(!0);
56
61
  }
57
62
  return /* @__PURE__ */ a("div", {
58
- ref: v,
59
- role: g ?? o[n],
60
- className: S,
61
- ..._,
63
+ ref: y,
64
+ role: _ ?? o[n],
65
+ className: C,
66
+ ...v,
62
67
  children: [/* @__PURE__ */ a("div", {
63
- className: `alert__content${C}`,
68
+ className: `alert__content${w}`,
64
69
  children: [
65
- s && /* @__PURE__ */ i("p", {
70
+ c && /* @__PURE__ */ i("p", {
66
71
  className: "alert__title",
67
- children: s
68
- }),
69
- c && /* @__PURE__ */ i("div", {
70
- className: "alert__description",
71
72
  children: c
72
73
  }),
73
- h,
74
74
  l && /* @__PURE__ */ i("div", {
75
- className: "alert__actions",
75
+ className: "alert__description",
76
76
  children: l
77
+ }),
78
+ g,
79
+ u && /* @__PURE__ */ i("div", {
80
+ className: "alert__actions",
81
+ children: u
77
82
  })
78
83
  ]
79
- }), u && /* @__PURE__ */ i(t, {
80
- className: `alert__close${C}`,
81
- label: y("close", p),
82
- onClick: T
84
+ }), d && /* @__PURE__ */ i(t, {
85
+ className: `alert__close${w}`,
86
+ label: b("close", m),
87
+ onClick: E
83
88
  })]
84
89
  });
85
- }), d = Object.assign(u, {
86
- Title: s,
87
- Description: c,
88
- Actions: l
90
+ }), f = Object.assign(d, {
91
+ Title: c,
92
+ Description: l,
93
+ Actions: u
89
94
  });
90
95
  //#endregion
91
- export { d as Alert, l as AlertActions, c as AlertDescription, s as AlertTitle };
96
+ export { f as Alert, u as AlertActions, l as AlertDescription, c as AlertTitle };
@@ -1 +1 @@
1
- .app-shell{--app-shell-sidebar-width:var(--sidebar-width);flex-direction:column;block-size:100dvh;display:flex;overflow:clip}.app-shell__body{flex:1;min-block-size:0;display:flex;position:relative}.app-shell__content{min-inline-size:0;padding-inline:var(--section-padding-inline);padding-block:var(--section-padding-block-lg);flex:1;padding-block-end:max(var(--section-padding-block-lg), env(safe-area-inset-bottom));padding-inline-end:max(var(--section-padding-inline), env(safe-area-inset-right));overflow:auto}.app-shell__backdrop{inset:0;background-color:var(--sidebar-backdrop-bg);opacity:var(--sidebar-backdrop-opacity);z-index:var(--sidebar-backdrop-z-index);position:fixed;inset-block-start:calc(var(--app-header-height) + env(safe-area-inset-top))}
1
+ .app-shell{--app-shell-sidebar-width:var(--sidebar-width);--app-shell-banner-height:0px;--app-shell-chrome-block-start:calc(var(--app-shell-banner-height) + var(--app-header-height) + env(safe-area-inset-top));flex-direction:column;block-size:100dvh;display:flex;overflow:clip}.app-shell__banner{flex-shrink:0}.app-shell__body{flex:1;min-block-size:0;display:flex;position:relative}.app-shell__content{min-inline-size:0;padding-inline:var(--section-padding-inline);padding-block:var(--section-padding-block-lg);flex:1;padding-block-end:max(var(--section-padding-block-lg), env(safe-area-inset-bottom));padding-inline-end:max(var(--section-padding-inline), env(safe-area-inset-right));overflow:auto}.app-shell__backdrop{inset:0;background-color:var(--sidebar-backdrop-bg);opacity:var(--sidebar-backdrop-opacity);z-index:var(--sidebar-backdrop-z-index);position:fixed;inset-block-start:var(--app-shell-chrome-block-start)}
package/dist/app-shell.js CHANGED
@@ -10,73 +10,93 @@ import { jsx as u, jsxs as d } from "react/jsx-runtime";
10
10
  //#region src/stories/sections/AppShell/AppShell.tsx
11
11
  var f = "(min-width: 1024px)";
12
12
  function p() {
13
- let [e, t] = l(() => typeof window > "u" ? !0 : window.matchMedia(f).matches);
13
+ let [e, t] = l(() => typeof window > "u" || typeof window.matchMedia != "function" ? !0 : window.matchMedia(f).matches);
14
14
  return s(() => {
15
+ if (typeof window.matchMedia != "function") return;
15
16
  let e = window.matchMedia(f), n = () => t(e.matches);
16
17
  return n(), e.addEventListener("change", n), () => e.removeEventListener("change", n);
17
18
  }, []), e;
18
19
  }
19
- function m({ header: i, sidebar: f, children: m, defaultSidebar: h = "open", sidebarState: g, onSidebarChange: _, defaultSidebarWidth: v, onSidebarWidthChange: y, skipLabel: b }) {
20
- let x = e("appShell"), S = p(), [C, w] = l(h), [T, E] = l(!1), [D, O] = l(v), k = S ? g ?? C : T ? "open" : "closed", A = o((e) => {
21
- S ? (w(e), _?.(e)) : E(e === "open");
22
- }, [S, _]), j = o(() => A(k === "open" ? "closed" : "open"), [A, k]), M = o(() => A("closed"), [A]), N = o((e) => {
23
- O(e), y?.(e);
24
- }, [y]);
20
+ function m({ banner: i, header: f, sidebar: m, children: h, defaultSidebar: g = "open", sidebarState: _, onSidebarChange: v, defaultSidebarWidth: y, onSidebarWidthChange: b, skipLabel: x }) {
21
+ let S = e("appShell"), C = p(), [w, T] = l(g), [E, D] = l(!1), [O, k] = l(y), A = C ? _ ?? w : E ? "open" : "closed", j = o((e) => {
22
+ C ? (T(e), v?.(e)) : D(e === "open");
23
+ }, [C, v]), M = o(() => j(A === "open" ? "closed" : "open"), [j, A]), N = o(() => j("closed"), [j]), P = o((e) => {
24
+ k(e), b?.(e);
25
+ }, [b]);
25
26
  s(() => {
26
- if (S || !T) return;
27
+ if (C || !E) return;
27
28
  let e = (e) => {
28
- e.key === "Escape" && E(!1);
29
+ e.key === "Escape" && D(!1);
29
30
  };
30
31
  document.addEventListener("keydown", e);
31
32
  let t = document.body.style.overflow;
32
33
  return document.body.style.overflow = "hidden", () => {
33
34
  document.removeEventListener("keydown", e), document.body.style.overflow = t;
34
35
  };
35
- }, [S, T]);
36
- let P = c(() => ({
37
- sidebar: k,
38
- setSidebar: A,
39
- sidebarWidth: D ?? 0,
40
- setSidebarWidth: N,
41
- toggleSidebar: j,
42
- closeSidebar: M,
43
- isDesktop: S
36
+ }, [C, E]);
37
+ let F = c(() => ({
38
+ sidebar: A,
39
+ setSidebar: j,
40
+ sidebarWidth: O ?? 0,
41
+ setSidebarWidth: P,
42
+ toggleSidebar: M,
43
+ closeSidebar: N,
44
+ isDesktop: C
44
45
  }), [
45
- k,
46
46
  A,
47
- D,
48
- N,
49
47
  j,
48
+ O,
49
+ P,
50
50
  M,
51
- S
52
- ]), F = n({ "--app-shell-sidebar-width": D ? `${D}px` : void 0 }), I = !S && T;
51
+ N,
52
+ C
53
+ ]), [I, L] = l(0), R = o((e) => {
54
+ if (!e) return;
55
+ let t = () => L(e.getBoundingClientRect().height);
56
+ if (t(), typeof ResizeObserver > "u") return;
57
+ let n = new ResizeObserver(t);
58
+ return n.observe(e), () => {
59
+ n.disconnect(), L(0);
60
+ };
61
+ }, []), z = n({
62
+ "--app-shell-sidebar-width": O ? `${O}px` : void 0,
63
+ "--app-shell-banner-height": i ? `${I}px` : void 0
64
+ }), B = !C && E;
53
65
  return /* @__PURE__ */ u(a.Provider, {
54
- value: P,
66
+ value: F,
55
67
  children: /* @__PURE__ */ d(r, { children: [/* @__PURE__ */ u(t, {
56
68
  href: "#main-content",
57
- children: x("skipToContent", b)
69
+ children: S("skipToContent", x)
58
70
  }), /* @__PURE__ */ d("div", {
59
- ref: F,
71
+ ref: z,
60
72
  className: "app-shell",
61
- "data-sidebar": k,
62
- children: [i, /* @__PURE__ */ d("div", {
63
- className: "app-shell__body",
64
- children: [
65
- f,
66
- I && /* @__PURE__ */ u("div", {
67
- className: "app-shell__backdrop",
68
- onClick: M,
69
- "aria-hidden": "true"
70
- }),
71
- /* @__PURE__ */ u("main", {
72
- id: "main-content",
73
- tabIndex: -1,
74
- className: "app-shell__content",
75
- inert: I || void 0,
76
- children: m
77
- })
78
- ]
79
- })]
73
+ "data-sidebar": A,
74
+ children: [
75
+ i && /* @__PURE__ */ u("div", {
76
+ ref: R,
77
+ className: "app-shell__banner",
78
+ children: i
79
+ }),
80
+ f,
81
+ /* @__PURE__ */ d("div", {
82
+ className: "app-shell__body",
83
+ children: [
84
+ m,
85
+ B && /* @__PURE__ */ u("div", {
86
+ className: "app-shell__backdrop",
87
+ onClick: N,
88
+ "aria-hidden": "true"
89
+ }),
90
+ /* @__PURE__ */ u("main", {
91
+ id: "main-content",
92
+ tabIndex: -1,
93
+ className: "app-shell__content",
94
+ inert: B || void 0,
95
+ children: h
96
+ })
97
+ ]
98
+ })
99
+ ]
80
100
  })] })
81
101
  });
82
102
  }
package/dist/banner.css CHANGED
@@ -1 +1 @@
1
- :root{--banner-padding-block:var(--spacing-3);--banner-padding-inline:var(--spacing-5);--banner-gap:var(--spacing-4);--banner-close-size:var(--size-component-sm);--banner-close-inset:var(--spacing-2);--banner-border-width:var(--border-width-default);--banner-font-size:var(--text-font-size);--banner-line-height:var(--text-line-height);--banner-info-bg:var(--color-primary);--banner-info-color:var(--color-text-on-dark);--banner-info-border-color:var(--color-text-on-dark);--banner-warning-bg:var(--color-warning-fill);--banner-warning-border-color:var(--color-warning-fill);--banner-warning-color:var(--color-warning-fill-text);--banner-warning-close-color:var(--color-warning-fill-text)}.banner{box-sizing:border-box;background-color:var(--banner-bg);inline-size:100%;color:var(--banner-color);border-block:var(--banner-border-width) solid var(--banner-border-color);padding-block:var(--banner-padding-block);padding-inline:var(--banner-padding-inline);font-size:var(--banner-font-size);line-height:var(--banner-line-height);align-items:flex-start;gap:var(--banner-gap);border-inline:0;flex-direction:column;display:flex;position:relative}.banner.banner--dismissible{padding-inline-end:calc(var(--banner-close-inset) * 2 + var(--banner-close-size))}.banner__content{min-inline-size:0}.banner__actions{align-self:stretch;align-items:stretch;gap:var(--banner-gap);flex-direction:column;display:flex}.banner__actions>*{inline-size:100%}.banner .banner__close{--close-button-size:var(--banner-close-size);position:absolute;inset-block-start:var(--banner-close-inset);inset-inline-end:var(--banner-close-inset)}@media (width>=768px){.banner{flex-direction:row;align-items:center}.banner__content{flex:1}.banner__actions{flex-flow:wrap;align-self:auto;align-items:center}.banner__actions>*{inline-size:auto}}.banner.banner--info{--banner-bg:var(--banner-info-bg);--banner-color:var(--banner-info-color);--banner-border-color:var(--banner-info-border-color)}.banner.banner--warning{--banner-bg:var(--banner-warning-bg);--banner-color:var(--banner-warning-color);--banner-border-color:var(--banner-warning-border-color);--close-button-color:var(--banner-warning-close-color);--close-button-focus-ring-color:var(--banner-warning-close-color)}
1
+ :root{--banner-padding-block:var(--spacing-3);--banner-padding-inline:var(--spacing-5);--banner-gap:var(--spacing-4);--banner-close-size:var(--size-component-sm);--banner-close-inset:var(--spacing-2);--banner-border-width:var(--border-width-default);--banner-font-size:var(--text-font-size);--banner-line-height:var(--text-line-height);--banner-info-bg:var(--color-primary);--banner-info-color:var(--color-text-on-dark);--banner-info-border-color:var(--color-text-on-dark);--banner-warning-bg:var(--color-warning-fill);--banner-warning-border-color:var(--color-warning-fill);--banner-error-bg:var(--color-error-fill);--banner-error-color:var(--color-error-fill-text);--banner-error-border-color:var(--color-error-fill);--banner-warning-color:var(--color-warning-fill-text);--banner-warning-close-color:var(--color-warning-fill-text)}.banner{box-sizing:border-box;background-color:var(--banner-bg);inline-size:100%;color:var(--banner-color);border-block:var(--banner-border-width) solid var(--banner-border-color);padding-block:var(--banner-padding-block);padding-inline:var(--banner-padding-inline);font-size:var(--banner-font-size);line-height:var(--banner-line-height);--banner-ink:var(--banner-color);align-items:flex-start;gap:var(--banner-gap);border-inline:0;flex-direction:column;display:flex;position:relative}.banner.banner--dismissible{padding-inline-end:calc(var(--banner-close-inset) * 2 + var(--banner-close-size))}.banner__content{min-inline-size:0}.banner .banner__content,.banner .banner__actions{color:var(--banner-ink)}.banner__actions{align-self:stretch;align-items:stretch;gap:var(--banner-gap);flex-direction:column;display:flex}.banner__actions>*{inline-size:100%}.banner .banner__close{--close-button-size:var(--banner-close-size);position:absolute;inset-block-start:var(--banner-close-inset);inset-inline-end:var(--banner-close-inset)}@media (width>=768px){.banner{flex-direction:row;align-items:center}.banner__content{flex:1}.banner__actions{flex-flow:wrap;align-self:auto;align-items:center}.banner__actions>*{inline-size:auto}}.banner.banner--info{--banner-bg:var(--banner-info-bg);--banner-color:var(--banner-info-color);--banner-border-color:var(--banner-info-border-color)}.banner.banner--warning{--banner-bg:var(--banner-warning-bg);--banner-color:var(--banner-warning-color);--banner-border-color:var(--banner-warning-border-color);--close-button-color:var(--banner-warning-close-color);--close-button-focus-ring-color:var(--banner-warning-close-color)}.banner.banner--error{--banner-bg:var(--banner-error-bg);--banner-color:var(--banner-error-color);--banner-border-color:var(--banner-error-border-color)}
package/dist/banner.js CHANGED
@@ -5,36 +5,40 @@ import { CloseButton as t } from "./close-button.js";
5
5
  import { forwardRef as n } from "react";
6
6
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
7
7
  //#region src/stories/molecules/Banner/Banner.tsx
8
- var a = n(function({ variant: n = "info", children: a, actions: o, onDismiss: s, dismissLabel: c, className: l, role: u, "aria-live": d, ...f }, p) {
9
- let m = e("banner"), h = [
8
+ var a = {
9
+ info: "status",
10
+ warning: "alert",
11
+ error: "alert"
12
+ }, o = n(function({ variant: n = "info", children: o, actions: s, onDismiss: c, dismissLabel: l, className: u, role: d, "aria-live": f, ...p }, m) {
13
+ let h = e("banner"), g = d ?? a[n], _ = [
10
14
  "banner",
11
15
  `banner--${n}`,
12
- n === "info" ? "surface-dark" : "",
13
- s ? "banner--dismissible" : "",
14
- l ?? ""
15
- ].filter(Boolean).join(" ");
16
+ n === "info" || n === "error" ? "surface-dark" : "",
17
+ c ? "banner--dismissible" : "",
18
+ u ?? ""
19
+ ].filter(Boolean).join(" "), v = n === "warning" ? " surface-light" : "";
16
20
  return /* @__PURE__ */ i("div", {
17
- ref: p,
18
- role: u ?? "status",
19
- "aria-live": d ?? "polite",
20
- className: h,
21
- ...f,
21
+ ref: m,
22
+ role: g,
23
+ "aria-live": f ?? (g === "alert" ? "assertive" : "polite"),
24
+ className: _,
25
+ ...p,
22
26
  children: [
23
27
  /* @__PURE__ */ r("div", {
24
- className: "banner__content",
25
- children: a
26
- }),
27
- o && /* @__PURE__ */ r("div", {
28
- className: "banner__actions",
28
+ className: `banner__content${v}`,
29
29
  children: o
30
30
  }),
31
- s && /* @__PURE__ */ r(t, {
32
- className: "banner__close",
33
- label: m("dismiss", c),
34
- onClick: s
31
+ s && /* @__PURE__ */ r("div", {
32
+ className: `banner__actions${v}`,
33
+ children: s
34
+ }),
35
+ c && /* @__PURE__ */ r(t, {
36
+ className: `banner__close${v}`,
37
+ label: h("dismiss", l),
38
+ onClick: c
35
39
  })
36
40
  ]
37
41
  });
38
42
  });
39
43
  //#endregion
40
- export { a as Banner };
44
+ export { o as Banner };