@ttoss/fsl-theme 1.1.21 → 1.1.22

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 (54) hide show
  1. package/README.md +3 -3
  2. package/dist/{baseBundle-BXvPJYzj.cjs → baseBundle-BWbICg4p.cjs} +1 -1
  3. package/dist/{baseBundle-BLvD8XVS.mjs → baseBundle-DiYlHNG5.mjs} +1 -1
  4. package/dist/{createTheme-JOu16Shb.cjs → createTheme-BHGc1IFI.cjs} +111 -14
  5. package/dist/{createTheme-DzLnsknT.mjs → createTheme-C1r5nJco.mjs} +110 -13
  6. package/dist/css.cjs +2 -2
  7. package/dist/css.mjs +2 -2
  8. package/dist/dataviz/index.cjs +2 -2
  9. package/dist/dataviz/index.mjs +1 -1
  10. package/dist/dtcg.cjs +1 -1
  11. package/dist/dtcg.mjs +1 -1
  12. package/dist/{helpers-C29fy-Ad.cjs → helpers-CIqeJ8yd.cjs} +0 -73
  13. package/dist/{helpers-CA4Qkxct.mjs → helpers-Dz7NfNK6.mjs} +1 -68
  14. package/dist/{index-nJrjI0BA.d.mts → index-BuszkWMy.d.mts} +27 -0
  15. package/dist/{index-CsIjfw86.d.cts → index-Djro6G4e.d.cts} +27 -0
  16. package/dist/index.cjs +1 -1
  17. package/dist/index.d.cts +2 -2
  18. package/dist/index.d.mts +2 -2
  19. package/dist/index.mjs +1 -1
  20. package/dist/{react-CoWIQYx_.cjs → react-BKLEzIN8.cjs} +16 -2
  21. package/dist/{react-CGa6FlNL.d.cts → react-BXqSYnmk.d.cts} +29 -0
  22. package/dist/{react-DnKxR2gK.d.mts → react-D2J482kx.d.mts} +29 -0
  23. package/dist/react.cjs +1 -1
  24. package/dist/react.d.cts +1 -1
  25. package/dist/react.d.mts +1 -1
  26. package/dist/react.mjs +16 -2
  27. package/dist/runtime-entry.cjs +1 -1
  28. package/dist/runtime-entry.mjs +1 -1
  29. package/dist/{ssrScript-DOpLExaG.cjs → ssrScript-D3mYscp1.cjs} +2 -1
  30. package/dist/{ssrScript-CoRE6jjq.mjs → ssrScript-DfmopH-w.mjs} +2 -1
  31. package/dist/themes/bruttal.cjs +3 -3
  32. package/dist/themes/bruttal.d.cts +1 -1
  33. package/dist/themes/bruttal.d.mts +1 -1
  34. package/dist/themes/bruttal.mjs +3 -3
  35. package/dist/themes/corporate.cjs +2 -2
  36. package/dist/themes/corporate.d.cts +1 -1
  37. package/dist/themes/corporate.d.mts +1 -1
  38. package/dist/themes/corporate.mjs +2 -2
  39. package/dist/themes/oca.cjs +2 -2
  40. package/dist/themes/oca.d.cts +1 -1
  41. package/dist/themes/oca.d.mts +1 -1
  42. package/dist/themes/oca.mjs +2 -2
  43. package/dist/themes/ventures.cjs +2 -2
  44. package/dist/themes/ventures.d.cts +1 -1
  45. package/dist/themes/ventures.d.mts +1 -1
  46. package/dist/themes/ventures.mjs +2 -2
  47. package/dist/{toCssVars-BHRiSykR.mjs → toCssVars-CeckLjW1.mjs} +1 -1
  48. package/dist/{toCssVars-CUiqx2kh.cjs → toCssVars-DDowz4wU.cjs} +1 -1
  49. package/dist/vars.cjs +3 -3
  50. package/dist/vars.mjs +3 -3
  51. package/dist/{withDataviz-BlJcYhcw.cjs → withDataviz-BzZwFV2e.cjs} +1 -1
  52. package/dist/{withDataviz-DYV1S_xr.mjs → withDataviz-CrgXLR5A.mjs} +1 -1
  53. package/llms.txt +1 -1
  54. package/package.json +1 -1
package/README.md CHANGED
@@ -11,7 +11,7 @@ pnpm add @ttoss/fsl-theme
11
11
  ## Entry points
12
12
 
13
13
  | Import | Exports |
14
- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
14
+ | :------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
15
15
  | `@ttoss/fsl-theme` | `createTheme`, `darkAlternate`, built-in themes (`bruttal`, `corporate`, `oca`, `ventures`), types (`ThemeTokens`, `ThemeBundle`, `SemanticTokens`, `ModeOverride`, `DeepPartial`, `ThemeMode`) |
16
16
  | `@ttoss/fsl-theme/react` | `ThemeProvider`, `ThemeHead`, `ThemeScript`, `ThemeStyles`, `useColorMode`, `useTokens`, `useResolvedTokens` |
17
17
  | `@ttoss/fsl-theme/dataviz` | `withDataviz`, `useDatavizTokens` |
@@ -164,9 +164,9 @@ Find the CSS property you are setting, then follow the branch to the leaf.
164
164
 
165
165
  ## Per-family specs
166
166
 
167
- Full grammar rules, decision matrices, and anti-patterns live in the family specs. Each file follows the pattern `02-families/{family}.md`:
167
+ Full grammar rules, decision matrices, and anti-patterns live in the family specs. Each file follows the pattern `families/{family}.md`:
168
168
 
169
- [colors](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/colors.md) · [spacing](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/spacing.md) · [typography](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/typography.md) · [sizing](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/sizing.md) · [radii](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/radii.md) · [borders](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/borders.md) · [elevation](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/elevation.md) · [opacity](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/opacity.md) · [motion](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/motion.md) · [z-index](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/z-index.md) · [breakpoints](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/01-design-system/02-design-tokens/02-families/breakpoints.md)
169
+ [colors](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/colors.md) · [spacing](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/spacing.md) · [typography](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/typography.md) · [sizing](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/sizing.md) · [radii](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/radii.md) · [borders](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/borders.md) · [elevation](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/elevation.md) · [opacity](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/opacity.md) · [motion](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/motion.md) · [z-index](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/z-index.md) · [breakpoints](https://github.com/ttoss/ttoss/blob/main/docs/website/docs/design/design-system/design-tokens/families/breakpoints.md)
170
170
 
171
171
  ## createTheme
172
172
 
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- const require_createTheme = require('./createTheme-JOu16Shb.cjs');
2
+ const require_createTheme = require('./createTheme-BHGc1IFI.cjs');
3
3
 
4
4
  //#region src/baseBundle.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { i as darkAlternate, n as createTheme, r as baseTheme } from "./createTheme-DzLnsknT.mjs";
2
+ import { i as darkAlternate, n as createTheme, r as baseTheme } from "./createTheme-C1r5nJco.mjs";
3
3
 
4
4
  //#region src/baseBundle.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- const require_helpers = require('./helpers-C29fy-Ad.cjs');
2
+ const require_helpers = require('./helpers-CIqeJ8yd.cjs');
3
3
 
4
4
  //#region src/baseTheme.ts
5
5
  /**
@@ -7,6 +7,33 @@ const require_helpers = require('./helpers-C29fy-Ad.cjs');
7
7
  *
8
8
  * System fonts, gray palette, and balanced proportions. Serves as the
9
9
  * canonical base that all other themes extend via `createTheme`.
10
+ *
11
+ * ## Theme brief
12
+ *
13
+ * Every value in this file is chosen so that the resolved bundle satisfies
14
+ * this brief. Changes that contradict the brief belong in a different theme,
15
+ * not in `baseTheme`.
16
+ *
17
+ * ```yaml
18
+ * name: base
19
+ * purpose: default built-in foundation for modern product UI
20
+ * primaryPosture: productive
21
+ * secondaryPosture: calm
22
+ * densityProfile: balanced
23
+ * readingMode: mixed
24
+ * pointerProfile: hybrid
25
+ * interactionRisk: medium
26
+ * surfaceModel: lightly-layered
27
+ * brandEnergy: quiet
28
+ * accessibilityTarget: AA+
29
+ * colorModeStrategy: dark-supported
30
+ * platformBias: web
31
+ * ```
32
+ *
33
+ * Intended feel: practical, calm, modern, trustworthy, easy to extend.
34
+ * Avoided feel: flashy, ornamental, cramped, fragile, overly branded.
35
+ *
36
+ * @see /docs/website/docs/design/design-system/design-tokens/theme-authoring.md#recommended-base-theme-brief
10
37
  */
11
38
  var baseTheme = {
12
39
  core: {
@@ -1077,23 +1104,23 @@ var baseTheme = {
1077
1104
  spacing: {
1078
1105
  inset: {
1079
1106
  control: {
1080
- sm: "{core.spacing.2}",
1081
- md: "{core.spacing.3}",
1082
- lg: "{core.spacing.4}"
1083
- },
1084
- surface: {
1085
1107
  sm: "{core.spacing.3}",
1086
1108
  md: "{core.spacing.4}",
1087
1109
  lg: "{core.spacing.6}"
1110
+ },
1111
+ surface: {
1112
+ sm: "{core.spacing.4}",
1113
+ md: "{core.spacing.6}",
1114
+ lg: "{core.spacing.8}"
1088
1115
  }
1089
1116
  },
1090
1117
  gap: {
1091
1118
  stack: {
1092
1119
  xs: "{core.spacing.2}",
1093
- sm: "{core.spacing.3}",
1094
- md: "{core.spacing.4}",
1095
- lg: "{core.spacing.6}",
1096
- xl: "{core.spacing.8}"
1120
+ sm: "{core.spacing.4}",
1121
+ md: "{core.spacing.6}",
1122
+ lg: "{core.spacing.8}",
1123
+ xl: "{core.spacing.12}"
1097
1124
  },
1098
1125
  inline: {
1099
1126
  xs: "{core.spacing.1}",
@@ -1104,12 +1131,12 @@ var baseTheme = {
1104
1131
  }
1105
1132
  },
1106
1133
  gutter: {
1107
- page: "clamp({core.spacing.4}, {core.spacing.6}, {core.spacing.12})",
1108
- section: "clamp({core.spacing.3}, {core.spacing.4}, {core.spacing.12})"
1134
+ page: "clamp({core.spacing.6}, {core.spacing.12}, {core.spacing.16})",
1135
+ section: "clamp({core.spacing.4}, {core.spacing.8}, {core.spacing.16})"
1109
1136
  },
1110
1137
  separation: {
1111
1138
  interactive: {
1112
- min: "clamp(8px, {core.spacing.2}, 12px)"
1139
+ min: "clamp(8px, {core.spacing.3}, 16px)"
1113
1140
  }
1114
1141
  }
1115
1142
  },
@@ -1715,6 +1742,76 @@ var darkAlternate = {
1715
1742
  }
1716
1743
  };
1717
1744
 
1745
+ //#endregion
1746
+ //#region src/roots/validateRefs.ts
1747
+ /**
1748
+ * Compute the Levenshtein edit distance between two strings.
1749
+ * Used exclusively by `validateRefs` to power "did you mean?" suggestions.
1750
+ */
1751
+ var levenshtein = (a, b) => {
1752
+ const m = a.length;
1753
+ const n = b.length;
1754
+ const dp = Array.from({
1755
+ length: m + 1
1756
+ }, () => {
1757
+ return Array.from({
1758
+ length: n + 1
1759
+ }, () => {
1760
+ return 0;
1761
+ });
1762
+ });
1763
+ for (let i = 0; i <= m; i++) dp[i][0] = i;
1764
+ for (let j = 0; j <= n; j++) dp[0][j] = j;
1765
+ for (let i = 1; i <= m; i++) for (let j = 1; j <= n; j++) dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
1766
+ return dp[m][n];
1767
+ };
1768
+ /**
1769
+ * Validate that every `{ref}` in the merged theme points to an existing path.
1770
+ * Emits `console.warn` for each broken reference with a "did you mean?" suggestion.
1771
+ *
1772
+ * **DEV-only** — callers gate this behind `process.env.NODE_ENV !== 'production'`
1773
+ * so bundlers tree-shake the entire call in production builds.
1774
+ */
1775
+ var validateRefs = theme => {
1776
+ const {
1777
+ core,
1778
+ semantic
1779
+ } = require_helpers.flattenTheme(theme);
1780
+ const all = {
1781
+ ...core,
1782
+ ...semantic
1783
+ };
1784
+ const allKeys = Object.keys(all);
1785
+ const findSuggestion = (refPath, candidates) => {
1786
+ if (candidates.length === 0) return "";
1787
+ let bestDist = Infinity;
1788
+ let bestKey = "";
1789
+ for (const candidate of candidates) {
1790
+ const dist = levenshtein(refPath, candidate);
1791
+ if (dist < bestDist) {
1792
+ bestDist = dist;
1793
+ bestKey = candidate;
1794
+ }
1795
+ }
1796
+ if (bestDist <= Math.ceil(refPath.length * .4)) return `\n Did you mean '{${bestKey}}'?`;
1797
+ return "";
1798
+ };
1799
+ for (const [ownerKey, value] of Object.entries(all)) {
1800
+ if (typeof value !== "string" || !value.includes("{")) continue;
1801
+ let match;
1802
+ const re = new RegExp(require_helpers.COMPOUND_REF_RE.source, require_helpers.COMPOUND_REF_RE.flags);
1803
+ while ((match = re.exec(value)) !== null) {
1804
+ const refPath = match[1];
1805
+ if (all[refPath] !== void 0) continue;
1806
+ const prefix = refPath.split(".")[0];
1807
+ const suggestion = findSuggestion(refPath, allKeys.filter(k => {
1808
+ return k.startsWith(prefix + ".");
1809
+ }));
1810
+ console.warn(`[fsl-theme] Invalid token reference '{${refPath}}' at path '${ownerKey}'.${suggestion}`);
1811
+ }
1812
+ }
1813
+ };
1814
+
1718
1815
  //#endregion
1719
1816
  //#region src/createTheme.ts
1720
1817
  /**
@@ -1728,7 +1825,7 @@ var buildTheme = ({
1728
1825
  overrides = {}
1729
1826
  } = {}) => {
1730
1827
  const merged = require_helpers.deepMerge(base, overrides);
1731
- if (process.env.NODE_ENV !== "production") require_helpers.validateRefs(merged);
1828
+ if (process.env.NODE_ENV !== "production") validateRefs(merged);
1732
1829
  return structuredClone(merged);
1733
1830
  };
1734
1831
  var resolveAlternate = (alternate, parentBundle) => {
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { c as validateRefs, r as deepMerge } from "./helpers-CA4Qkxct.mjs";
2
+ import { a as flattenTheme, r as deepMerge, t as COMPOUND_REF_RE } from "./helpers-Dz7NfNK6.mjs";
3
3
 
4
4
  //#region src/baseTheme.ts
5
5
  /**
@@ -7,6 +7,33 @@ import { c as validateRefs, r as deepMerge } from "./helpers-CA4Qkxct.mjs";
7
7
  *
8
8
  * System fonts, gray palette, and balanced proportions. Serves as the
9
9
  * canonical base that all other themes extend via `createTheme`.
10
+ *
11
+ * ## Theme brief
12
+ *
13
+ * Every value in this file is chosen so that the resolved bundle satisfies
14
+ * this brief. Changes that contradict the brief belong in a different theme,
15
+ * not in `baseTheme`.
16
+ *
17
+ * ```yaml
18
+ * name: base
19
+ * purpose: default built-in foundation for modern product UI
20
+ * primaryPosture: productive
21
+ * secondaryPosture: calm
22
+ * densityProfile: balanced
23
+ * readingMode: mixed
24
+ * pointerProfile: hybrid
25
+ * interactionRisk: medium
26
+ * surfaceModel: lightly-layered
27
+ * brandEnergy: quiet
28
+ * accessibilityTarget: AA+
29
+ * colorModeStrategy: dark-supported
30
+ * platformBias: web
31
+ * ```
32
+ *
33
+ * Intended feel: practical, calm, modern, trustworthy, easy to extend.
34
+ * Avoided feel: flashy, ornamental, cramped, fragile, overly branded.
35
+ *
36
+ * @see /docs/website/docs/design/design-system/design-tokens/theme-authoring.md#recommended-base-theme-brief
10
37
  */
11
38
  var baseTheme = {
12
39
  core: {
@@ -1077,23 +1104,23 @@ var baseTheme = {
1077
1104
  spacing: {
1078
1105
  inset: {
1079
1106
  control: {
1080
- sm: "{core.spacing.2}",
1081
- md: "{core.spacing.3}",
1082
- lg: "{core.spacing.4}"
1083
- },
1084
- surface: {
1085
1107
  sm: "{core.spacing.3}",
1086
1108
  md: "{core.spacing.4}",
1087
1109
  lg: "{core.spacing.6}"
1110
+ },
1111
+ surface: {
1112
+ sm: "{core.spacing.4}",
1113
+ md: "{core.spacing.6}",
1114
+ lg: "{core.spacing.8}"
1088
1115
  }
1089
1116
  },
1090
1117
  gap: {
1091
1118
  stack: {
1092
1119
  xs: "{core.spacing.2}",
1093
- sm: "{core.spacing.3}",
1094
- md: "{core.spacing.4}",
1095
- lg: "{core.spacing.6}",
1096
- xl: "{core.spacing.8}"
1120
+ sm: "{core.spacing.4}",
1121
+ md: "{core.spacing.6}",
1122
+ lg: "{core.spacing.8}",
1123
+ xl: "{core.spacing.12}"
1097
1124
  },
1098
1125
  inline: {
1099
1126
  xs: "{core.spacing.1}",
@@ -1104,12 +1131,12 @@ var baseTheme = {
1104
1131
  }
1105
1132
  },
1106
1133
  gutter: {
1107
- page: "clamp({core.spacing.4}, {core.spacing.6}, {core.spacing.12})",
1108
- section: "clamp({core.spacing.3}, {core.spacing.4}, {core.spacing.12})"
1134
+ page: "clamp({core.spacing.6}, {core.spacing.12}, {core.spacing.16})",
1135
+ section: "clamp({core.spacing.4}, {core.spacing.8}, {core.spacing.16})"
1109
1136
  },
1110
1137
  separation: {
1111
1138
  interactive: {
1112
- min: "clamp(8px, {core.spacing.2}, 12px)"
1139
+ min: "clamp(8px, {core.spacing.3}, 16px)"
1113
1140
  }
1114
1141
  }
1115
1142
  },
@@ -1715,6 +1742,76 @@ var darkAlternate = {
1715
1742
  }
1716
1743
  };
1717
1744
 
1745
+ //#endregion
1746
+ //#region src/roots/validateRefs.ts
1747
+ /**
1748
+ * Compute the Levenshtein edit distance between two strings.
1749
+ * Used exclusively by `validateRefs` to power "did you mean?" suggestions.
1750
+ */
1751
+ var levenshtein = (a, b) => {
1752
+ const m = a.length;
1753
+ const n = b.length;
1754
+ const dp = Array.from({
1755
+ length: m + 1
1756
+ }, () => {
1757
+ return Array.from({
1758
+ length: n + 1
1759
+ }, () => {
1760
+ return 0;
1761
+ });
1762
+ });
1763
+ for (let i = 0; i <= m; i++) dp[i][0] = i;
1764
+ for (let j = 0; j <= n; j++) dp[0][j] = j;
1765
+ for (let i = 1; i <= m; i++) for (let j = 1; j <= n; j++) dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
1766
+ return dp[m][n];
1767
+ };
1768
+ /**
1769
+ * Validate that every `{ref}` in the merged theme points to an existing path.
1770
+ * Emits `console.warn` for each broken reference with a "did you mean?" suggestion.
1771
+ *
1772
+ * **DEV-only** — callers gate this behind `process.env.NODE_ENV !== 'production'`
1773
+ * so bundlers tree-shake the entire call in production builds.
1774
+ */
1775
+ var validateRefs = theme => {
1776
+ const {
1777
+ core,
1778
+ semantic
1779
+ } = flattenTheme(theme);
1780
+ const all = {
1781
+ ...core,
1782
+ ...semantic
1783
+ };
1784
+ const allKeys = Object.keys(all);
1785
+ const findSuggestion = (refPath, candidates) => {
1786
+ if (candidates.length === 0) return "";
1787
+ let bestDist = Infinity;
1788
+ let bestKey = "";
1789
+ for (const candidate of candidates) {
1790
+ const dist = levenshtein(refPath, candidate);
1791
+ if (dist < bestDist) {
1792
+ bestDist = dist;
1793
+ bestKey = candidate;
1794
+ }
1795
+ }
1796
+ if (bestDist <= Math.ceil(refPath.length * .4)) return `\n Did you mean '{${bestKey}}'?`;
1797
+ return "";
1798
+ };
1799
+ for (const [ownerKey, value] of Object.entries(all)) {
1800
+ if (typeof value !== "string" || !value.includes("{")) continue;
1801
+ let match;
1802
+ const re = new RegExp(COMPOUND_REF_RE.source, COMPOUND_REF_RE.flags);
1803
+ while ((match = re.exec(value)) !== null) {
1804
+ const refPath = match[1];
1805
+ if (all[refPath] !== void 0) continue;
1806
+ const prefix = refPath.split(".")[0];
1807
+ const suggestion = findSuggestion(refPath, allKeys.filter(k => {
1808
+ return k.startsWith(prefix + ".");
1809
+ }));
1810
+ console.warn(`[fsl-theme] Invalid token reference '{${refPath}}' at path '${ownerKey}'.${suggestion}`);
1811
+ }
1812
+ }
1813
+ };
1814
+
1718
1815
  //#endregion
1719
1816
  //#region src/createTheme.ts
1720
1817
  /**
package/dist/css.cjs CHANGED
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_helpers = require('./helpers-C29fy-Ad.cjs');
6
- const require_toCssVars = require('./toCssVars-CUiqx2kh.cjs');
5
+ const require_helpers = require('./helpers-CIqeJ8yd.cjs');
6
+ const require_toCssVars = require('./toCssVars-DDowz4wU.cjs');
7
7
 
8
8
  //#region src/css.ts
9
9
  /**
package/dist/css.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { s as toFlatTokens } from "./helpers-CA4Qkxct.mjs";
3
- import { n as toCssVars, t as toCssVarName } from "./toCssVars-BHRiSykR.mjs";
2
+ import { s as toFlatTokens } from "./helpers-Dz7NfNK6.mjs";
3
+ import { n as toCssVars, t as toCssVarName } from "./toCssVars-CeckLjW1.mjs";
4
4
 
5
5
  //#region src/css.ts
6
6
  /**
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_react = require('../react-CoWIQYx_.cjs');
6
- const require_withDataviz = require('../withDataviz-BlJcYhcw.cjs');
5
+ const require_react = require('../react-BKLEzIN8.cjs');
6
+ const require_withDataviz = require('../withDataviz-BzZwFV2e.cjs');
7
7
 
8
8
  //#region src/dataviz/useDatavizTokens.ts
9
9
  /**
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { n as coreDataviz, r as semanticDataviz, t as withDataviz } from "../withDataviz-DYV1S_xr.mjs";
2
+ import { n as coreDataviz, r as semanticDataviz, t as withDataviz } from "../withDataviz-CrgXLR5A.mjs";
3
3
  import { useTokens } from "../react.mjs";
4
4
 
5
5
  //#region src/dataviz/useDatavizTokens.ts
package/dist/dtcg.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_helpers = require('./helpers-C29fy-Ad.cjs');
5
+ const require_helpers = require('./helpers-CIqeJ8yd.cjs');
6
6
  const require_tokenRegistry = require('./tokenRegistry-B9zMRjpL.cjs');
7
7
 
8
8
  //#region src/roots/toDTCG.ts
package/dist/dtcg.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { s as toFlatTokens } from "./helpers-CA4Qkxct.mjs";
2
+ import { s as toFlatTokens } from "./helpers-Dz7NfNK6.mjs";
3
3
  import { n as DTCG_TYPE_PREFIXES } from "./tokenRegistry-DolhB5Vf.mjs";
4
4
 
5
5
  //#region src/roots/toDTCG.ts
@@ -69,73 +69,6 @@ var flattenTheme = theme => {
69
69
  };
70
70
  };
71
71
  /**
72
- * Compute the Levenshtein edit distance between two strings.
73
- * Used exclusively by `validateRefs` to power "did you mean?" suggestions.
74
- */
75
- var levenshtein = (a, b) => {
76
- const m = a.length;
77
- const n = b.length;
78
- const dp = Array.from({
79
- length: m + 1
80
- }, () => {
81
- return Array.from({
82
- length: n + 1
83
- }, () => {
84
- return 0;
85
- });
86
- });
87
- for (let i = 0; i <= m; i++) dp[i][0] = i;
88
- for (let j = 0; j <= n; j++) dp[0][j] = j;
89
- for (let i = 1; i <= m; i++) for (let j = 1; j <= n; j++) dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
90
- return dp[m][n];
91
- };
92
- /**
93
- * Validate that every `{ref}` in the merged theme points to an existing path.
94
- * Emits `console.warn` for each broken reference with a "did you mean?" suggestion.
95
- *
96
- * **DEV-only** — callers gate this behind `process.env.NODE_ENV !== 'production'`
97
- * so bundlers tree-shake the entire call in production builds.
98
- */
99
- var validateRefs = theme => {
100
- const {
101
- core,
102
- semantic
103
- } = flattenTheme(theme);
104
- const all = {
105
- ...core,
106
- ...semantic
107
- };
108
- const allKeys = Object.keys(all);
109
- const findSuggestion = (refPath, candidates) => {
110
- if (candidates.length === 0) return "";
111
- let bestDist = Infinity;
112
- let bestKey = "";
113
- for (const candidate of candidates) {
114
- const dist = levenshtein(refPath, candidate);
115
- if (dist < bestDist) {
116
- bestDist = dist;
117
- bestKey = candidate;
118
- }
119
- }
120
- if (bestDist <= Math.ceil(refPath.length * .4)) return `\n Did you mean '{${bestKey}}'?`;
121
- return "";
122
- };
123
- for (const [ownerKey, value] of Object.entries(all)) {
124
- if (typeof value !== "string" || !value.includes("{")) continue;
125
- let match;
126
- const re = new RegExp(COMPOUND_REF_RE.source, COMPOUND_REF_RE.flags);
127
- while ((match = re.exec(value)) !== null) {
128
- const refPath = match[1];
129
- if (all[refPath] !== void 0) continue;
130
- const prefix = refPath.split(".")[0];
131
- const suggestion = findSuggestion(refPath, allKeys.filter(k => {
132
- return k.startsWith(prefix + ".");
133
- }));
134
- console.warn(`[fsl-theme] Invalid token reference '{${refPath}}' at path '${ownerKey}'.${suggestion}`);
135
- }
136
- }
137
- };
138
- /**
139
72
  * Flatten a `ThemeTokens` into a `Record<string, string | number>` with
140
73
  * every `{ref}` recursively resolved to its final raw value where possible.
141
74
  *
@@ -249,10 +182,4 @@ Object.defineProperty(exports, 'toFlatTokens', {
249
182
  get: function () {
250
183
  return toFlatTokens;
251
184
  }
252
- });
253
- Object.defineProperty(exports, 'validateRefs', {
254
- enumerable: true,
255
- get: function () {
256
- return validateRefs;
257
- }
258
185
  });
@@ -69,73 +69,6 @@ var flattenTheme = theme => {
69
69
  };
70
70
  };
71
71
  /**
72
- * Compute the Levenshtein edit distance between two strings.
73
- * Used exclusively by `validateRefs` to power "did you mean?" suggestions.
74
- */
75
- var levenshtein = (a, b) => {
76
- const m = a.length;
77
- const n = b.length;
78
- const dp = Array.from({
79
- length: m + 1
80
- }, () => {
81
- return Array.from({
82
- length: n + 1
83
- }, () => {
84
- return 0;
85
- });
86
- });
87
- for (let i = 0; i <= m; i++) dp[i][0] = i;
88
- for (let j = 0; j <= n; j++) dp[0][j] = j;
89
- for (let i = 1; i <= m; i++) for (let j = 1; j <= n; j++) dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
90
- return dp[m][n];
91
- };
92
- /**
93
- * Validate that every `{ref}` in the merged theme points to an existing path.
94
- * Emits `console.warn` for each broken reference with a "did you mean?" suggestion.
95
- *
96
- * **DEV-only** — callers gate this behind `process.env.NODE_ENV !== 'production'`
97
- * so bundlers tree-shake the entire call in production builds.
98
- */
99
- var validateRefs = theme => {
100
- const {
101
- core,
102
- semantic
103
- } = flattenTheme(theme);
104
- const all = {
105
- ...core,
106
- ...semantic
107
- };
108
- const allKeys = Object.keys(all);
109
- const findSuggestion = (refPath, candidates) => {
110
- if (candidates.length === 0) return "";
111
- let bestDist = Infinity;
112
- let bestKey = "";
113
- for (const candidate of candidates) {
114
- const dist = levenshtein(refPath, candidate);
115
- if (dist < bestDist) {
116
- bestDist = dist;
117
- bestKey = candidate;
118
- }
119
- }
120
- if (bestDist <= Math.ceil(refPath.length * .4)) return `\n Did you mean '{${bestKey}}'?`;
121
- return "";
122
- };
123
- for (const [ownerKey, value] of Object.entries(all)) {
124
- if (typeof value !== "string" || !value.includes("{")) continue;
125
- let match;
126
- const re = new RegExp(COMPOUND_REF_RE.source, COMPOUND_REF_RE.flags);
127
- while ((match = re.exec(value)) !== null) {
128
- const refPath = match[1];
129
- if (all[refPath] !== void 0) continue;
130
- const prefix = refPath.split(".")[0];
131
- const suggestion = findSuggestion(refPath, allKeys.filter(k => {
132
- return k.startsWith(prefix + ".");
133
- }));
134
- console.warn(`[fsl-theme] Invalid token reference '{${refPath}}' at path '${ownerKey}'.${suggestion}`);
135
- }
136
- }
137
- };
138
- /**
139
72
  * Flatten a `ThemeTokens` into a `Record<string, string | number>` with
140
73
  * every `{ref}` recursively resolved to its final raw value where possible.
141
74
  *
@@ -208,4 +141,4 @@ var toFlatTokens = (theme, options = {}) => {
208
141
  };
209
142
 
210
143
  //#endregion
211
- export { flattenTheme as a, validateRefs as c, flattenObject as i, SAFE_ID_RE as n, isPlainObject as o, deepMerge as r, toFlatTokens as s, COMPOUND_REF_RE as t };
144
+ export { flattenTheme as a, flattenObject as i, SAFE_ID_RE as n, isPlainObject as o, deepMerge as r, toFlatTokens as s, COMPOUND_REF_RE as t };
@@ -6,6 +6,33 @@ import { a as DeepPartial, i as ThemeTokens, r as ThemeBundle, t as ModeOverride
6
6
  *
7
7
  * System fonts, gray palette, and balanced proportions. Serves as the
8
8
  * canonical base that all other themes extend via `createTheme`.
9
+ *
10
+ * ## Theme brief
11
+ *
12
+ * Every value in this file is chosen so that the resolved bundle satisfies
13
+ * this brief. Changes that contradict the brief belong in a different theme,
14
+ * not in `baseTheme`.
15
+ *
16
+ * ```yaml
17
+ * name: base
18
+ * purpose: default built-in foundation for modern product UI
19
+ * primaryPosture: productive
20
+ * secondaryPosture: calm
21
+ * densityProfile: balanced
22
+ * readingMode: mixed
23
+ * pointerProfile: hybrid
24
+ * interactionRisk: medium
25
+ * surfaceModel: lightly-layered
26
+ * brandEnergy: quiet
27
+ * accessibilityTarget: AA+
28
+ * colorModeStrategy: dark-supported
29
+ * platformBias: web
30
+ * ```
31
+ *
32
+ * Intended feel: practical, calm, modern, trustworthy, easy to extend.
33
+ * Avoided feel: flashy, ornamental, cramped, fragile, overly branded.
34
+ *
35
+ * @see /docs/website/docs/design/design-system/design-tokens/theme-authoring.md#recommended-base-theme-brief
9
36
  */
10
37
  declare const baseTheme: ThemeTokens;
11
38
  declare const darkAlternate: ModeOverride;
@@ -6,6 +6,33 @@ import { a as DeepPartial, i as ThemeTokens, r as ThemeBundle, t as ModeOverride
6
6
  *
7
7
  * System fonts, gray palette, and balanced proportions. Serves as the
8
8
  * canonical base that all other themes extend via `createTheme`.
9
+ *
10
+ * ## Theme brief
11
+ *
12
+ * Every value in this file is chosen so that the resolved bundle satisfies
13
+ * this brief. Changes that contradict the brief belong in a different theme,
14
+ * not in `baseTheme`.
15
+ *
16
+ * ```yaml
17
+ * name: base
18
+ * purpose: default built-in foundation for modern product UI
19
+ * primaryPosture: productive
20
+ * secondaryPosture: calm
21
+ * densityProfile: balanced
22
+ * readingMode: mixed
23
+ * pointerProfile: hybrid
24
+ * interactionRisk: medium
25
+ * surfaceModel: lightly-layered
26
+ * brandEnergy: quiet
27
+ * accessibilityTarget: AA+
28
+ * colorModeStrategy: dark-supported
29
+ * platformBias: web
30
+ * ```
31
+ *
32
+ * Intended feel: practical, calm, modern, trustworthy, easy to extend.
33
+ * Avoided feel: flashy, ornamental, cramped, fragile, overly branded.
34
+ *
35
+ * @see /docs/website/docs/design/design-system/design-tokens/theme-authoring.md#recommended-base-theme-brief
9
36
  */
10
37
  declare const baseTheme: ThemeTokens;
11
38
  declare const darkAlternate: ModeOverride;
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_createTheme = require('./createTheme-JOu16Shb.cjs');
5
+ const require_createTheme = require('./createTheme-BHGc1IFI.cjs');
6
6
  const require_themes_bruttal = require('./themes/bruttal.cjs');
7
7
  const require_themes_corporate = require('./themes/corporate.cjs');
8
8
  const require_themes_oca = require('./themes/oca.cjs');
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { a as DeepPartial, i as ThemeTokens, n as SemanticTokens, r as ThemeBundle, t as ModeOverride } from "./Types-BiBa17RL.cjs";
3
- import { a as createTheme, i as bruttal, n as oca, o as baseTheme, r as corporate, s as darkAlternate, t as ventures } from "./index-CsIjfw86.cjs";
3
+ import { a as createTheme, i as bruttal, n as oca, o as baseTheme, r as corporate, s as darkAlternate, t as ventures } from "./index-Djro6G4e.cjs";
4
4
  import { o as ThemeMode } from "./ssrScript-BVysxDws.cjs";
5
- import { c as ThemeStylesProps, n as ThemeHeadProps } from "./react-CGa6FlNL.cjs";
5
+ import { c as ThemeStylesProps, n as ThemeHeadProps } from "./react-BXqSYnmk.cjs";
6
6
  export { type DeepPartial, type ModeOverride, type SemanticTokens, type ThemeBundle, type ThemeHeadProps, type ThemeMode, type ThemeStylesProps, type ThemeTokens, baseTheme, bruttal, corporate, createTheme, darkAlternate, oca, ventures };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { a as DeepPartial, i as ThemeTokens, n as SemanticTokens, r as ThemeBundle, t as ModeOverride } from "./Types-BiBa17RL.mjs";
3
- import { a as createTheme, i as bruttal, n as oca, o as baseTheme, r as corporate, s as darkAlternate, t as ventures } from "./index-nJrjI0BA.mjs";
3
+ import { a as createTheme, i as bruttal, n as oca, o as baseTheme, r as corporate, s as darkAlternate, t as ventures } from "./index-BuszkWMy.mjs";
4
4
  import { o as ThemeMode } from "./ssrScript-BVysxDws.mjs";
5
- import { c as ThemeStylesProps, n as ThemeHeadProps } from "./react-DnKxR2gK.mjs";
5
+ import { c as ThemeStylesProps, n as ThemeHeadProps } from "./react-D2J482kx.mjs";
6
6
  export { type DeepPartial, type ModeOverride, type SemanticTokens, type ThemeBundle, type ThemeHeadProps, type ThemeMode, type ThemeStylesProps, type ThemeTokens, baseTheme, bruttal, corporate, createTheme, darkAlternate, oca, ventures };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { i as darkAlternate, n as createTheme, r as baseTheme } from "./createTheme-DzLnsknT.mjs";
2
+ import { i as darkAlternate, n as createTheme, r as baseTheme } from "./createTheme-C1r5nJco.mjs";
3
3
  import { bruttal } from "./themes/bruttal.mjs";
4
4
  import { corporate } from "./themes/corporate.mjs";
5
5
  import { oca } from "./themes/oca.mjs";
@@ -26,9 +26,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  }) : target, mod));
27
27
 
28
28
  //#endregion
29
- const require_helpers = require('./helpers-C29fy-Ad.cjs');
29
+ const require_helpers = require('./helpers-CIqeJ8yd.cjs');
30
30
  const require_css = require('./css.cjs');
31
- const require_ssrScript = require('./ssrScript-DOpLExaG.cjs');
31
+ const require_ssrScript = require('./ssrScript-D3mYscp1.cjs');
32
32
  let react = require("react");
33
33
  react = __toESM(react);
34
34
  let react_jsx_runtime = require("react/jsx-runtime");
@@ -393,6 +393,12 @@ var ThemeStyles = ({
393
393
  * Use in SSR frameworks (Next.js, Remix) where you need explicit `<head>`
394
394
  * injection. In CSR apps, `<ThemeProvider theme={...}>` handles everything.
395
395
  *
396
+ * **`storageKey` invariant:** `ThemeHead` forwards `storageKey` to `ThemeScript`,
397
+ * which reads localStorage before the first paint. `ThemeProvider` reads the
398
+ * same key at runtime. If you pass a custom `storageKey`, pass the **same value**
399
+ * to both `<ThemeHead>` and `<ThemeProvider>` — a mismatch causes a theme flash
400
+ * exactly in the scenario this component was designed to prevent.
401
+ *
396
402
  * @example
397
403
  * ```tsx
398
404
  * // Next.js app/layout.tsx
@@ -414,6 +420,14 @@ var ThemeStyles = ({
414
420
  * );
415
421
  * }
416
422
  * ```
423
+ *
424
+ * @example
425
+ * ```tsx
426
+ * // Custom storageKey — must be identical on both sides
427
+ * <ThemeHead theme={myTheme} storageKey="my-app-theme" />
428
+ * // ...
429
+ * <ThemeProvider theme={myTheme} storageKey="my-app-theme">{children}</ThemeProvider>
430
+ * ```
417
431
  */
418
432
  var ThemeHead = ({
419
433
  theme,
@@ -47,6 +47,21 @@ interface ThemeProviderProps {
47
47
  * `resolvedMode` (actual: `'light' | 'dark'`), covering all integration
48
48
  * needs in one callback.
49
49
  *
50
+ * **System mode:** when `mode` is `'system'`, this callback fires whenever
51
+ * the OS `prefers-color-scheme` changes (e.g. automatic dark mode at sunset)
52
+ * — without any user interaction. Avoid side-effects that should only happen
53
+ * on explicit user action (e.g. API calls, toast notifications):
54
+ *
55
+ * ```tsx
56
+ * onModeChange={(mode, resolvedMode) => {
57
+ * // ✓ safe for system-triggered changes
58
+ * analytics.track('modeChanged', { mode, resolvedMode });
59
+ *
60
+ * // ✗ guard explicit user actions
61
+ * if (mode !== 'system') showToast('Theme updated');
62
+ * }}
63
+ * ```
64
+ *
50
65
  * @example
51
66
  * ```tsx
52
67
  * <ThemeProvider
@@ -337,6 +352,12 @@ interface ThemeHeadProps extends ThemeStylesProps {
337
352
  * Use in SSR frameworks (Next.js, Remix) where you need explicit `<head>`
338
353
  * injection. In CSR apps, `<ThemeProvider theme={...}>` handles everything.
339
354
  *
355
+ * **`storageKey` invariant:** `ThemeHead` forwards `storageKey` to `ThemeScript`,
356
+ * which reads localStorage before the first paint. `ThemeProvider` reads the
357
+ * same key at runtime. If you pass a custom `storageKey`, pass the **same value**
358
+ * to both `<ThemeHead>` and `<ThemeProvider>` — a mismatch causes a theme flash
359
+ * exactly in the scenario this component was designed to prevent.
360
+ *
340
361
  * @example
341
362
  * ```tsx
342
363
  * // Next.js app/layout.tsx
@@ -358,6 +379,14 @@ interface ThemeHeadProps extends ThemeStylesProps {
358
379
  * );
359
380
  * }
360
381
  * ```
382
+ *
383
+ * @example
384
+ * ```tsx
385
+ * // Custom storageKey — must be identical on both sides
386
+ * <ThemeHead theme={myTheme} storageKey="my-app-theme" />
387
+ * // ...
388
+ * <ThemeProvider theme={myTheme} storageKey="my-app-theme">{children}</ThemeProvider>
389
+ * ```
361
390
  */
362
391
  declare const ThemeHead: ({
363
392
  theme,
@@ -47,6 +47,21 @@ interface ThemeProviderProps {
47
47
  * `resolvedMode` (actual: `'light' | 'dark'`), covering all integration
48
48
  * needs in one callback.
49
49
  *
50
+ * **System mode:** when `mode` is `'system'`, this callback fires whenever
51
+ * the OS `prefers-color-scheme` changes (e.g. automatic dark mode at sunset)
52
+ * — without any user interaction. Avoid side-effects that should only happen
53
+ * on explicit user action (e.g. API calls, toast notifications):
54
+ *
55
+ * ```tsx
56
+ * onModeChange={(mode, resolvedMode) => {
57
+ * // ✓ safe for system-triggered changes
58
+ * analytics.track('modeChanged', { mode, resolvedMode });
59
+ *
60
+ * // ✗ guard explicit user actions
61
+ * if (mode !== 'system') showToast('Theme updated');
62
+ * }}
63
+ * ```
64
+ *
50
65
  * @example
51
66
  * ```tsx
52
67
  * <ThemeProvider
@@ -337,6 +352,12 @@ interface ThemeHeadProps extends ThemeStylesProps {
337
352
  * Use in SSR frameworks (Next.js, Remix) where you need explicit `<head>`
338
353
  * injection. In CSR apps, `<ThemeProvider theme={...}>` handles everything.
339
354
  *
355
+ * **`storageKey` invariant:** `ThemeHead` forwards `storageKey` to `ThemeScript`,
356
+ * which reads localStorage before the first paint. `ThemeProvider` reads the
357
+ * same key at runtime. If you pass a custom `storageKey`, pass the **same value**
358
+ * to both `<ThemeHead>` and `<ThemeProvider>` — a mismatch causes a theme flash
359
+ * exactly in the scenario this component was designed to prevent.
360
+ *
340
361
  * @example
341
362
  * ```tsx
342
363
  * // Next.js app/layout.tsx
@@ -358,6 +379,14 @@ interface ThemeHeadProps extends ThemeStylesProps {
358
379
  * );
359
380
  * }
360
381
  * ```
382
+ *
383
+ * @example
384
+ * ```tsx
385
+ * // Custom storageKey — must be identical on both sides
386
+ * <ThemeHead theme={myTheme} storageKey="my-app-theme" />
387
+ * // ...
388
+ * <ThemeProvider theme={myTheme} storageKey="my-app-theme">{children}</ThemeProvider>
389
+ * ```
361
390
  */
362
391
  declare const ThemeHead: ({
363
392
  theme,
package/dist/react.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_react = require('./react-CoWIQYx_.cjs');
5
+ const require_react = require('./react-BKLEzIN8.cjs');
6
6
  exports.ThemeHead = require_react.ThemeHead;
7
7
  exports.ThemeProvider = require_react.ThemeProvider;
8
8
  exports.ThemeScript = require_react.ThemeScript;
package/dist/react.d.cts CHANGED
@@ -1,4 +1,4 @@
1
1
 
2
2
  import { a as ResolvedMode, o as ThemeMode } from "./ssrScript-BVysxDws.cjs";
3
- import { a as ThemeScript, c as ThemeStylesProps, d as useResolvedTokens, f as useTokens, i as ThemeProviderProps, l as UseColorModeResult, n as ThemeHeadProps, o as ThemeScriptProps, r as ThemeProvider, s as ThemeStyles, t as ThemeHead, u as useColorMode } from "./react-CGa6FlNL.cjs";
3
+ import { a as ThemeScript, c as ThemeStylesProps, d as useResolvedTokens, f as useTokens, i as ThemeProviderProps, l as UseColorModeResult, n as ThemeHeadProps, o as ThemeScriptProps, r as ThemeProvider, s as ThemeStyles, t as ThemeHead, u as useColorMode } from "./react-BXqSYnmk.cjs";
4
4
  export { type ResolvedMode, ThemeHead, ThemeHeadProps, type ThemeMode, ThemeProvider, ThemeProviderProps, ThemeScript, ThemeScriptProps, ThemeStyles, ThemeStylesProps, UseColorModeResult, useColorMode, useResolvedTokens, useTokens };
package/dist/react.d.mts CHANGED
@@ -1,4 +1,4 @@
1
1
 
2
2
  import { a as ResolvedMode, o as ThemeMode } from "./ssrScript-BVysxDws.mjs";
3
- import { a as ThemeScript, c as ThemeStylesProps, d as useResolvedTokens, f as useTokens, i as ThemeProviderProps, l as UseColorModeResult, n as ThemeHeadProps, o as ThemeScriptProps, r as ThemeProvider, s as ThemeStyles, t as ThemeHead, u as useColorMode } from "./react-DnKxR2gK.mjs";
3
+ import { a as ThemeScript, c as ThemeStylesProps, d as useResolvedTokens, f as useTokens, i as ThemeProviderProps, l as UseColorModeResult, n as ThemeHeadProps, o as ThemeScriptProps, r as ThemeProvider, s as ThemeStyles, t as ThemeHead, u as useColorMode } from "./react-D2J482kx.mjs";
4
4
  export { type ResolvedMode, ThemeHead, ThemeHeadProps, type ThemeMode, ThemeProvider, ThemeProviderProps, ThemeScript, ThemeScriptProps, ThemeStyles, ThemeStylesProps, UseColorModeResult, useColorMode, useResolvedTokens, useTokens };
package/dist/react.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { r as deepMerge, s as toFlatTokens } from "./helpers-CA4Qkxct.mjs";
2
+ import { r as deepMerge, s as toFlatTokens } from "./helpers-Dz7NfNK6.mjs";
3
3
  import { getThemeStylesContent } from "./css.mjs";
4
- import { i as createThemeRuntime, t as getThemeScriptContent } from "./ssrScript-CoRE6jjq.mjs";
4
+ import { i as createThemeRuntime, t as getThemeScriptContent } from "./ssrScript-DfmopH-w.mjs";
5
5
  import * as React from "react";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
7
 
@@ -365,6 +365,12 @@ var ThemeStyles = ({
365
365
  * Use in SSR frameworks (Next.js, Remix) where you need explicit `<head>`
366
366
  * injection. In CSR apps, `<ThemeProvider theme={...}>` handles everything.
367
367
  *
368
+ * **`storageKey` invariant:** `ThemeHead` forwards `storageKey` to `ThemeScript`,
369
+ * which reads localStorage before the first paint. `ThemeProvider` reads the
370
+ * same key at runtime. If you pass a custom `storageKey`, pass the **same value**
371
+ * to both `<ThemeHead>` and `<ThemeProvider>` — a mismatch causes a theme flash
372
+ * exactly in the scenario this component was designed to prevent.
373
+ *
368
374
  * @example
369
375
  * ```tsx
370
376
  * // Next.js app/layout.tsx
@@ -386,6 +392,14 @@ var ThemeStyles = ({
386
392
  * );
387
393
  * }
388
394
  * ```
395
+ *
396
+ * @example
397
+ * ```tsx
398
+ * // Custom storageKey — must be identical on both sides
399
+ * <ThemeHead theme={myTheme} storageKey="my-app-theme" />
400
+ * // ...
401
+ * <ThemeProvider theme={myTheme} storageKey="my-app-theme">{children}</ThemeProvider>
402
+ * ```
389
403
  */
390
404
  var ThemeHead = ({
391
405
  theme,
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_ssrScript = require('./ssrScript-DOpLExaG.cjs');
5
+ const require_ssrScript = require('./ssrScript-D3mYscp1.cjs');
6
6
  exports.DATA_MODE_ATTR = require_ssrScript.DATA_MODE_ATTR;
7
7
  exports.DATA_THEME_ATTR = require_ssrScript.DATA_THEME_ATTR;
8
8
  exports.createThemeRuntime = require_ssrScript.createThemeRuntime;
@@ -1,3 +1,3 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { i as createThemeRuntime, n as DATA_MODE_ATTR, r as DATA_THEME_ATTR, t as getThemeScriptContent } from "./ssrScript-CoRE6jjq.mjs";
2
+ import { i as createThemeRuntime, n as DATA_MODE_ATTR, r as DATA_THEME_ATTR, t as getThemeScriptContent } from "./ssrScript-DfmopH-w.mjs";
3
3
  export { DATA_MODE_ATTR, DATA_THEME_ATTR, createThemeRuntime, getThemeScriptContent };
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- const require_helpers = require('./helpers-C29fy-Ad.cjs');
2
+ const require_helpers = require('./helpers-CIqeJ8yd.cjs');
3
3
 
4
4
  //#region src/themeBootstrap.ts
5
5
  /**
@@ -96,6 +96,7 @@ var createThemeRuntime = (config = {}) => {
96
96
  };
97
97
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
98
98
  const onSystemChange = () => {
99
+ if (destroyed) return;
99
100
  resolvedMode = mediaQuery.matches ? "dark" : "light";
100
101
  applyState({
101
102
  persist: false
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { n as SAFE_ID_RE } from "./helpers-CA4Qkxct.mjs";
2
+ import { n as SAFE_ID_RE } from "./helpers-Dz7NfNK6.mjs";
3
3
 
4
4
  //#region src/themeBootstrap.ts
5
5
  /**
@@ -96,6 +96,7 @@ var createThemeRuntime = (config = {}) => {
96
96
  };
97
97
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
98
98
  const onSystemChange = () => {
99
+ if (destroyed) return;
99
100
  resolvedMode = mediaQuery.matches ? "dark" : "light";
100
101
  applyState({
101
102
  persist: false
@@ -2,9 +2,9 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_createTheme = require('../createTheme-JOu16Shb.cjs');
6
- const require_helpers = require('../helpers-C29fy-Ad.cjs');
7
- const require_withDataviz = require('../withDataviz-BlJcYhcw.cjs');
5
+ const require_createTheme = require('../createTheme-BHGc1IFI.cjs');
6
+ const require_helpers = require('../helpers-CIqeJ8yd.cjs');
7
+ const require_withDataviz = require('../withDataviz-BzZwFV2e.cjs');
8
8
 
9
9
  //#region src/themes/bruttal.ts
10
10
  /**
@@ -1,3 +1,3 @@
1
1
 
2
- import { i as bruttal } from "../index-CsIjfw86.cjs";
2
+ import { i as bruttal } from "../index-Djro6G4e.cjs";
3
3
  export { bruttal };
@@ -1,3 +1,3 @@
1
1
 
2
- import { i as bruttal } from "../index-nJrjI0BA.mjs";
2
+ import { i as bruttal } from "../index-BuszkWMy.mjs";
3
3
  export { bruttal };
@@ -1,7 +1,7 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { i as darkAlternate, n as createTheme } from "../createTheme-DzLnsknT.mjs";
3
- import { r as deepMerge } from "../helpers-CA4Qkxct.mjs";
4
- import { t as withDataviz } from "../withDataviz-DYV1S_xr.mjs";
2
+ import { i as darkAlternate, n as createTheme } from "../createTheme-C1r5nJco.mjs";
3
+ import { r as deepMerge } from "../helpers-Dz7NfNK6.mjs";
4
+ import { t as withDataviz } from "../withDataviz-CrgXLR5A.mjs";
5
5
 
6
6
  //#region src/themes/bruttal.ts
7
7
  /**
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_createTheme = require('../createTheme-JOu16Shb.cjs');
6
- const require_withDataviz = require('../withDataviz-BlJcYhcw.cjs');
5
+ const require_createTheme = require('../createTheme-BHGc1IFI.cjs');
6
+ const require_withDataviz = require('../withDataviz-BzZwFV2e.cjs');
7
7
 
8
8
  //#region src/themes/corporate.ts
9
9
  var bundle = require_createTheme.createTheme({
@@ -1,3 +1,3 @@
1
1
 
2
- import { r as corporate } from "../index-CsIjfw86.cjs";
2
+ import { r as corporate } from "../index-Djro6G4e.cjs";
3
3
  export { corporate };
@@ -1,3 +1,3 @@
1
1
 
2
- import { r as corporate } from "../index-nJrjI0BA.mjs";
2
+ import { r as corporate } from "../index-BuszkWMy.mjs";
3
3
  export { corporate };
@@ -1,6 +1,6 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { n as createTheme } from "../createTheme-DzLnsknT.mjs";
3
- import { t as withDataviz } from "../withDataviz-DYV1S_xr.mjs";
2
+ import { n as createTheme } from "../createTheme-C1r5nJco.mjs";
3
+ import { t as withDataviz } from "../withDataviz-CrgXLR5A.mjs";
4
4
 
5
5
  //#region src/themes/corporate.ts
6
6
  var bundle = createTheme({
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_createTheme = require('../createTheme-JOu16Shb.cjs');
6
- const require_withDataviz = require('../withDataviz-BlJcYhcw.cjs');
5
+ const require_createTheme = require('../createTheme-BHGc1IFI.cjs');
6
+ const require_withDataviz = require('../withDataviz-BzZwFV2e.cjs');
7
7
 
8
8
  //#region src/themes/oca.ts
9
9
  var bundle = require_createTheme.createTheme({
@@ -1,3 +1,3 @@
1
1
 
2
- import { n as oca } from "../index-CsIjfw86.cjs";
2
+ import { n as oca } from "../index-Djro6G4e.cjs";
3
3
  export { oca };
@@ -1,3 +1,3 @@
1
1
 
2
- import { n as oca } from "../index-nJrjI0BA.mjs";
2
+ import { n as oca } from "../index-BuszkWMy.mjs";
3
3
  export { oca };
@@ -1,6 +1,6 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { n as createTheme } from "../createTheme-DzLnsknT.mjs";
3
- import { t as withDataviz } from "../withDataviz-DYV1S_xr.mjs";
2
+ import { n as createTheme } from "../createTheme-C1r5nJco.mjs";
3
+ import { t as withDataviz } from "../withDataviz-CrgXLR5A.mjs";
4
4
 
5
5
  //#region src/themes/oca.ts
6
6
  var bundle = createTheme({
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_createTheme = require('../createTheme-JOu16Shb.cjs');
6
- const require_withDataviz = require('../withDataviz-BlJcYhcw.cjs');
5
+ const require_createTheme = require('../createTheme-BHGc1IFI.cjs');
6
+ const require_withDataviz = require('../withDataviz-BzZwFV2e.cjs');
7
7
 
8
8
  //#region src/themes/ventures.ts
9
9
  var bundle = require_createTheme.createTheme({
@@ -1,3 +1,3 @@
1
1
 
2
- import { t as ventures } from "../index-CsIjfw86.cjs";
2
+ import { t as ventures } from "../index-Djro6G4e.cjs";
3
3
  export { ventures };
@@ -1,3 +1,3 @@
1
1
 
2
- import { t as ventures } from "../index-nJrjI0BA.mjs";
2
+ import { t as ventures } from "../index-BuszkWMy.mjs";
3
3
  export { ventures };
@@ -1,6 +1,6 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { n as createTheme } from "../createTheme-DzLnsknT.mjs";
3
- import { t as withDataviz } from "../withDataviz-DYV1S_xr.mjs";
2
+ import { n as createTheme } from "../createTheme-C1r5nJco.mjs";
3
+ import { t as withDataviz } from "../withDataviz-CrgXLR5A.mjs";
4
4
 
5
5
  //#region src/themes/ventures.ts
6
6
  var bundle = createTheme({
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { a as flattenTheme, i as flattenObject, n as SAFE_ID_RE, r as deepMerge, t as COMPOUND_REF_RE } from "./helpers-CA4Qkxct.mjs";
2
+ import { a as flattenTheme, i as flattenObject, n as SAFE_ID_RE, r as deepMerge, t as COMPOUND_REF_RE } from "./helpers-Dz7NfNK6.mjs";
3
3
  import { t as CSS_PATH_PREFIXES } from "./tokenRegistry-DolhB5Vf.mjs";
4
4
 
5
5
  //#region src/roots/toCssVars.ts
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- const require_helpers = require('./helpers-C29fy-Ad.cjs');
2
+ const require_helpers = require('./helpers-CIqeJ8yd.cjs');
3
3
  const require_tokenRegistry = require('./tokenRegistry-B9zMRjpL.cjs');
4
4
 
5
5
  //#region src/roots/toCssVars.ts
package/dist/vars.cjs CHANGED
@@ -2,9 +2,9 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, {
3
3
  value: 'Module'
4
4
  });
5
- const require_helpers = require('./helpers-C29fy-Ad.cjs');
6
- const require_baseBundle = require('./baseBundle-BXvPJYzj.cjs');
7
- const require_toCssVars = require('./toCssVars-CUiqx2kh.cjs');
5
+ const require_helpers = require('./helpers-CIqeJ8yd.cjs');
6
+ const require_baseBundle = require('./baseBundle-BWbICg4p.cjs');
7
+ const require_toCssVars = require('./toCssVars-DDowz4wU.cjs');
8
8
 
9
9
  //#region src/roots/toVars.ts
10
10
  /**
package/dist/vars.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { o as isPlainObject } from "./helpers-CA4Qkxct.mjs";
3
- import { t as baseBundle } from "./baseBundle-BLvD8XVS.mjs";
4
- import { t as toCssVarName } from "./toCssVars-BHRiSykR.mjs";
2
+ import { o as isPlainObject } from "./helpers-Dz7NfNK6.mjs";
3
+ import { t as baseBundle } from "./baseBundle-DiYlHNG5.mjs";
4
+ import { t as toCssVarName } from "./toCssVars-CeckLjW1.mjs";
5
5
 
6
6
  //#region src/roots/toVars.ts
7
7
  /**
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- const require_createTheme = require('./createTheme-JOu16Shb.cjs');
2
+ const require_createTheme = require('./createTheme-BHGc1IFI.cjs');
3
3
 
4
4
  //#region src/dataviz/baseTheme.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { t as buildTheme } from "./createTheme-DzLnsknT.mjs";
2
+ import { t as buildTheme } from "./createTheme-C1r5nJco.mjs";
3
3
 
4
4
  //#region src/dataviz/baseTheme.ts
5
5
  /**
package/llms.txt CHANGED
@@ -728,4 +728,4 @@ Cross-token semantic correctness (the rules above) is **not** statically validat
728
728
  - README — full grammar tables, usage examples per import path
729
729
  - `dist/Types-*.d.ts` — every token has co-located JSDoc with semantics + anti-pattern notes
730
730
  - `src/themes/{bruttal,corporate,oca,ventures}.ts` — worked customization patterns
731
- - Family specs (full grammar, decision matrices, ADRs): `docs/design/01-design-system/02-design-tokens/02-families/{family}.md` in the ttoss monorepo
731
+ - Family specs (full grammar, decision matrices, ADRs): `docs/design/design-system/design-tokens/families/{family}.md` in the ttoss monorepo
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/fsl-theme",
3
- "version": "1.1.21",
3
+ "version": "1.1.22",
4
4
  "description": "ttoss theme provider for UI.",
5
5
  "keywords": [
6
6
  "css-variables",