@fiestaboard/ui 3.2.0 → 3.4.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.
@@ -1,22 +1,49 @@
1
1
  interface ThemeToggleProps {
2
- /** Current resolved theme. */
3
- theme: "light" | "dark";
2
+ /**
3
+ * Current theme choice. `"light"` / `"dark"` are resolved modes; `"system"`
4
+ * means "follow the OS" and renders a distinct Monitor glyph, so a three-way
5
+ * chooser stays legible at a glance instead of surviving only in `label`.
6
+ * Binary consumers pass `"light"` / `"dark"` and are unaffected — the union
7
+ * was widened, not changed.
8
+ */
9
+ theme: "light" | "dark" | "system";
4
10
  /** Called when the user clicks the toggle. */
5
11
  onToggle: () => void;
6
12
  /** Localized accessible label, e.g. "Toggle theme". */
7
13
  label: string;
14
+ /**
15
+ * Which signal decides Sun vs Moon. Ignored when `theme` is `"system"`.
16
+ *
17
+ * - `"prop"` (default) — the `theme` prop, via `data-resolved-theme`. The
18
+ * component's documented contract: the icon follows what you passed, even
19
+ * where that disagrees with the root `.dark` class. Keep this unless you
20
+ * are the case below; a story hardcoding `theme="dark"` under a light root
21
+ * must still render the dark glyph (issue #89, and VRT caught exactly it).
22
+ * - `"dom"` — the ancestor `.dark` class, the same signal `theme.css` keys
23
+ * dark mode on. For statically rendered sites, where the server cannot
24
+ * know the visitor's theme and so bakes the wrong `data-resolved-theme`
25
+ * into the HTML: an inline `<head>` script that stamps `.dark` before
26
+ * first paint is then enough to paint the correct glyph with no JS and no
27
+ * hydration, killing the light-icon flash a dark-mode visitor sees on
28
+ * every cold load. Only pass this when something stamps `.dark` pre-paint
29
+ * — otherwise the icon is stuck on the light glyph.
30
+ */
31
+ iconSource?: "prop" | "dom";
8
32
  }
9
33
  /**
10
34
  * Controlled presentational theme toggle. Theme state/persistence stays in
11
35
  * the app (FiestaBoard wires this to its use-theme hook).
12
36
  *
13
- * Both icons are always in the DOM; the visible one is selected by CSS keyed
14
- * on the prop-driven `data-resolved-theme` attribute, so the icon still
15
- * follows the `theme` prop (the component's contract) rather than the root
16
- * `.dark` class. Server and client markup differ at most by one attribute
17
- * value when the theme resolves differently server-side — patched cheaply
18
- * during hydration (`suppressHydrationWarning`), so no mounted gate or
19
- * placeholder render is needed.
37
+ * Every icon is always in the DOM and the visible one is selected purely by
38
+ * CSS no icon is conditionally rendered from `theme`. That is what makes the
39
+ * component SSR-safe without a mounted gate (issue #89): server and client
40
+ * markup differ at most by one attribute VALUE, patched cheaply during
41
+ * hydration (`suppressHydrationWarning`). Swapping elements instead would put
42
+ * a real subtree mismatch on the hydration path, which that attribute-level
43
+ * suppression does not cover.
44
+ *
45
+ * Which CSS signal drives Sun vs Moon is the consumer's call — see
46
+ * `iconSource`. The two modes are mutually exclusive by construction.
20
47
  */
21
- export declare const ThemeToggle: import("react").MemoExoticComponent<({ theme, onToggle, label }: ThemeToggleProps) => import("react").JSX.Element>;
48
+ export declare const ThemeToggle: import("react").MemoExoticComponent<({ theme, onToggle, label, iconSource, }: ThemeToggleProps) => import("react").JSX.Element>;
22
49
  export {};
@@ -1,28 +1,41 @@
1
1
  "use client";
2
2
  import { Button as e } from "../forms/button.js";
3
- import { Moon as t, Sun as n } from "lucide-react";
4
- import { memo as r } from "react";
5
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
3
+ import { Monitor as t, Moon as n, Sun as r } from "lucide-react";
4
+ import { memo as i } from "react";
5
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
6
  //#region src/components/chrome/theme-toggle.tsx
7
- var o = r(function({ theme: r, onToggle: o, label: s }) {
8
- return /* @__PURE__ */ a(e, {
7
+ var s = {
8
+ prop: {
9
+ sun: "hidden h-4 w-4 [[data-resolved-theme=dark]_&]:block",
10
+ moon: "h-4 w-4 [[data-resolved-theme=dark]_&]:hidden"
11
+ },
12
+ dom: {
13
+ sun: "hidden h-4 w-4 dark:block",
14
+ moon: "h-4 w-4 dark:hidden"
15
+ }
16
+ }, c = i(function({ theme: i, onToggle: c, label: l, iconSource: u = "prop" }) {
17
+ let d = s[u];
18
+ return /* @__PURE__ */ o(e, {
9
19
  variant: "ghost",
10
20
  size: "icon",
11
- onClick: o,
21
+ onClick: c,
12
22
  className: "w-9 h-9",
13
- "data-resolved-theme": r,
23
+ "data-resolved-theme": i,
14
24
  suppressHydrationWarning: !0,
15
25
  children: [
16
- /* @__PURE__ */ i(n, { className: "hidden h-4 w-4 [[data-resolved-theme=dark]_&]:block" }),
17
- /* @__PURE__ */ i(t, { className: "h-4 w-4 [[data-resolved-theme=dark]_&]:hidden" }),
18
- /* @__PURE__ */ i("span", {
26
+ /* @__PURE__ */ o("span", {
27
+ className: "contents [[data-resolved-theme=system]_&]:hidden",
28
+ children: [/* @__PURE__ */ a(r, { className: d.sun }), /* @__PURE__ */ a(n, { className: d.moon })]
29
+ }),
30
+ /* @__PURE__ */ a(t, { className: "hidden h-4 w-4 [[data-resolved-theme=system]_&]:block" }),
31
+ /* @__PURE__ */ a("span", {
19
32
  className: "sr-only",
20
- children: s
33
+ children: l
21
34
  })
22
35
  ]
23
36
  });
24
37
  });
25
38
  //#endregion
26
- export { o as ThemeToggle };
39
+ export { c as ThemeToggle };
27
40
 
28
41
  //# sourceMappingURL=theme-toggle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme-toggle.js","names":[],"sources":["../../../src/components/chrome/theme-toggle.tsx"],"mappings":";;;;;;AA4BA,IAAa,IAAc,EAAK,SAAqB,EAAE,UAAO,aAAU,YAA2B;CACjG,OACE,kBAAC,GAAD;EACE,SAAQ;EACR,MAAK;EACL,SAAS;EACT,WAAU;EACV,uBAAqB;EACrB,0BAAA;EANF,UAAA;GAQE,kBAAC,GAAD,EAAK,WAAU,sDAAuD,CAAA;GACtE,kBAAC,GAAD,EAAM,WAAU,gDAAiD,CAAA;GACjE,kBAAC,QAAD;IAAM,WAAU;IAAW,UAAA;GAAY,CAAA;EACjC;;AAEZ,CAAC"}
1
+ {"version":3,"file":"theme-toggle.js","names":[],"sources":["../../../src/components/chrome/theme-toggle.tsx"],"mappings":";;;;;;AAiBA,IAAM,IAAe;CACnB,MAAM;EACJ,KAAK;EACL,MAAM;CACR;CACA,KAAK;EACH,KAAK;EACL,MAAM;CACR;AACF,GAkDa,IAAc,EAAK,SAAqB,EACnD,UACA,aACA,UACA,gBAAa,UACM;CACnB,IAAM,IAAQ,EAAa;CAC3B,OACE,kBAAC,GAAD;EACE,SAAQ;EACR,MAAK;EACL,SAAS;EACT,WAAU;EACV,uBAAqB;EACrB,0BAAA;EANF,UAAA;GAWE,kBAAC,QAAD;IAAM,WAAU;IAAhB,UAAA,CACE,kBAAC,GAAD,EAAK,WAAW,EAAM,IAAM,CAAA,GAC5B,kBAAC,GAAD,EAAM,WAAW,EAAM,KAAO,CAAA,CAC1B;;GACN,kBAAC,GAAD,EAAS,WAAU,wDAAyD,CAAA;GAC5E,kBAAC,QAAD;IAAM,WAAU;IAAW,UAAA;GAAY,CAAA;EACjC;;AAEZ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiestaboard/ui",
3
- "version": "3.2.0",
3
+ "version": "3.4.0",
4
4
  "description": "FiestaUI — the FiestaBoard design system. React components on Base UI with Tailwind v4 design tokens.",
5
5
  "license": "MIT",
6
6
  "repository": {