@nexub/react 1.8.0 → 2.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.
@@ -36,6 +36,64 @@ function readGlass(key, fallback) {
36
36
  }
37
37
  return fallback;
38
38
  }
39
+ var CONTRAST_QUERY = "(prefers-contrast: more)";
40
+ function readContrast(root) {
41
+ const attr = root.getAttribute("data-contrast");
42
+ if (attr === "standard" || attr === "medium" || attr === "high") return attr;
43
+ return window.matchMedia(CONTRAST_QUERY).matches ? "high" : "standard";
44
+ }
45
+ function useSeedTheme(seed, target) {
46
+ React.useEffect(() => {
47
+ if (!seed) return;
48
+ const color = seed;
49
+ const root = document.documentElement;
50
+ const mq = window.matchMedia(CONTRAST_QUERY);
51
+ const observer = new MutationObserver(() => update());
52
+ let applied = [];
53
+ let create;
54
+ let done = false;
55
+ const clear = () => {
56
+ for (const name of applied) root.style.removeProperty(name);
57
+ applied = [];
58
+ };
59
+ const stop = () => {
60
+ done = true;
61
+ observer.disconnect();
62
+ mq.removeEventListener("change", update);
63
+ };
64
+ function update() {
65
+ if (done || !create) return;
66
+ let vars;
67
+ try {
68
+ vars = create(color, { contrast: readContrast(root), target });
69
+ } catch (error) {
70
+ console.error(error);
71
+ clear();
72
+ stop();
73
+ return;
74
+ }
75
+ clear();
76
+ for (const [name, value] of Object.entries(vars)) root.style.setProperty(name, value);
77
+ applied = Object.keys(vars);
78
+ }
79
+ observer.observe(root, { attributes: true, attributeFilter: ["data-contrast"] });
80
+ mq.addEventListener("change", update);
81
+ import("@nexub/tokens/seed").then(
82
+ (mod) => {
83
+ create = mod.createSeedTheme;
84
+ update();
85
+ },
86
+ (error) => {
87
+ console.error(error);
88
+ stop();
89
+ }
90
+ );
91
+ return () => {
92
+ stop();
93
+ clear();
94
+ };
95
+ }, [seed, target]);
96
+ }
39
97
  function writeStorage(key, value) {
40
98
  if (typeof window === "undefined") return;
41
99
  try {
@@ -48,8 +106,11 @@ function ThemeProvider({
48
106
  defaultTheme = "system",
49
107
  storageKey = "nexub-theme",
50
108
  defaultGlass = "balanced",
51
- glassStorageKey = "nexub-glass"
109
+ glassStorageKey = "nexub-glass",
110
+ seed,
111
+ seedTarget = "primary"
52
112
  }) {
113
+ useSeedTheme(seed, seedTarget);
53
114
  const [theme, setThemeState] = React.useState(defaultTheme);
54
115
  const [systemTheme, setSystemTheme] = React.useState("light");
55
116
  const [glass, setGlassState] = React.useState(defaultGlass);
@@ -1,10 +1,10 @@
1
1
  'use client';
2
2
  import {
3
3
  FormField
4
- } from "../../chunk-G4RLUGE3.js";
5
- import "../../chunk-ZLW7IBXK.js";
6
- import "../../chunk-PGD246WD.js";
4
+ } from "../../chunk-GLQOEW57.js";
7
5
  import "../../chunk-QVTVDL6Y.js";
6
+ import "../../chunk-PGD246WD.js";
7
+ import "../../chunk-ZLW7IBXK.js";
8
8
  import "../../chunk-22BGPRJZ.js";
9
9
  import "../../chunk-5W3AOOYS.js";
10
10
  import "../../chunk-DEIBF3P7.js";
@@ -3,7 +3,7 @@ import {
3
3
  ThemeProvider,
4
4
  ThemeScript,
5
5
  useTheme
6
- } from "../../chunk-AEBYQKLS.js";
6
+ } from "../../chunk-3XX45SUC.js";
7
7
  import "../../chunk-NHUQLIHL.js";
8
8
  export {
9
9
  ThemeProvider,
package/dist/index.d.ts CHANGED
@@ -1788,8 +1788,22 @@ interface ThemeProviderProps {
1788
1788
  defaultGlass?: GlassMode;
1789
1789
  /** localStorage key for the glass intensity. Defaults to 'nexub-glass'. */
1790
1790
  glassStorageKey?: string;
1791
+ /**
1792
+ * Brand seed colour (`#rgb` / `#rrggbb`) for white-label theming. The accent
1793
+ * family named by `seedTarget` is regenerated from it (same HCT tones as the
1794
+ * built-in roles, so WCAG pairs hold) and set on `<html>` via the CSSOM
1795
+ * (strict-CSP safe), following the current `data-contrast` level.
1796
+ *
1797
+ * Runs on the client after `@nexub/tokens/seed` loads (a lazy chunk with
1798
+ * the colour library), so server-rendered pages paint the default brand
1799
+ * first. To avoid that flash, emit `createSeedThemeCss(seed)` from
1800
+ * `@nexub/tokens/seed` into a server-rendered stylesheet instead.
1801
+ */
1802
+ seed?: string;
1803
+ /** Accent family the seed recolours: 'primary' (default) or 'tertiary' (product brand). */
1804
+ seedTarget?: 'primary' | 'tertiary';
1791
1805
  }
1792
- declare function ThemeProvider({ children, defaultTheme, storageKey, defaultGlass, glassStorageKey, }: ThemeProviderProps): React.JSX.Element;
1806
+ declare function ThemeProvider({ children, defaultTheme, storageKey, defaultGlass, glassStorageKey, seed, seedTarget, }: ThemeProviderProps): React.JSX.Element;
1793
1807
  declare function useTheme(): ThemeContextValue;
1794
1808
  interface ThemeScriptProps {
1795
1809
  /** Must match ThemeProvider's `storageKey`. Defaults to 'nexub-theme'. */
package/dist/index.js CHANGED
@@ -1,10 +1,8 @@
1
1
  'use client';
2
- import {
3
- TopNav
4
- } from "./chunk-KRHD7VI6.js";
5
2
  import {
6
3
  Root
7
4
  } from "./chunk-ZXLACKEB.js";
5
+ import "./chunk-XYXMPHND.js";
8
6
  import {
9
7
  Textarea,
10
8
  textareaVariants
@@ -13,7 +11,7 @@ import {
13
11
  ThemeProvider,
14
12
  ThemeScript,
15
13
  useTheme
16
- } from "./chunk-AEBYQKLS.js";
14
+ } from "./chunk-3XX45SUC.js";
17
15
  import {
18
16
  ThinkingIndicator
19
17
  } from "./chunk-ESMIBOF5.js";
@@ -34,7 +32,9 @@ import {
34
32
  import {
35
33
  Toolbar
36
34
  } from "./chunk-2ZBJOUJ7.js";
37
- import "./chunk-XYXMPHND.js";
35
+ import {
36
+ TopNav
37
+ } from "./chunk-KRHD7VI6.js";
38
38
  import {
39
39
  StatusPill,
40
40
  statusPillVariants
@@ -87,13 +87,13 @@ import {
87
87
  import {
88
88
  Stack
89
89
  } from "./chunk-I6CAF7C5.js";
90
- import {
91
- PromptInput
92
- } from "./chunk-O6J6HXVT.js";
93
90
  import {
94
91
  RadioCard,
95
92
  RadioCardGroup
96
93
  } from "./chunk-XTATJMY6.js";
94
+ import {
95
+ PromptInput
96
+ } from "./chunk-O6J6HXVT.js";
97
97
  import {
98
98
  RadioGroup
99
99
  } from "./chunk-Z3HF6XJ3.js";
@@ -180,13 +180,13 @@ import {
180
180
  import {
181
181
  NavigationRail
182
182
  } from "./chunk-5GN2GFW3.js";
183
- import "./chunk-PICMOOAZ.js";
184
183
  import "./chunk-ZT3NWE5U.js";
185
184
  import "./chunk-CAOLGXA5.js";
186
185
  import {
187
186
  IconButton,
188
187
  iconButtonVariants
189
188
  } from "./chunk-NYORXEPS.js";
189
+ import "./chunk-ADO2DB6Q.js";
190
190
  import "./chunk-NZ7UK3G6.js";
191
191
  import {
192
192
  Input,
@@ -209,24 +209,20 @@ import {
209
209
  import {
210
210
  FilterChip
211
211
  } from "./chunk-XHLSYHAV.js";
212
- import "./chunk-BV3U3ATL.js";
213
212
  import {
214
213
  Flex
215
214
  } from "./chunk-7MSIOYJZ.js";
216
- import "./chunk-ADO2DB6Q.js";
215
+ import "./chunk-BV3U3ATL.js";
217
216
  import {
218
217
  FormField
219
- } from "./chunk-G4RLUGE3.js";
218
+ } from "./chunk-GLQOEW57.js";
220
219
  import {
221
- HelperText
222
- } from "./chunk-ZLW7IBXK.js";
220
+ FormError
221
+ } from "./chunk-QVTVDL6Y.js";
223
222
  import {
224
223
  Label,
225
224
  labelVariants
226
225
  } from "./chunk-PGD246WD.js";
227
- import {
228
- FormError
229
- } from "./chunk-QVTVDL6Y.js";
230
226
  import {
231
227
  GradientDivider
232
228
  } from "./chunk-ZC4MZAEX.js";
@@ -238,6 +234,10 @@ import {
238
234
  Heading,
239
235
  headingVariants
240
236
  } from "./chunk-SKIJVVBU.js";
237
+ import "./chunk-PICMOOAZ.js";
238
+ import {
239
+ HelperText
240
+ } from "./chunk-ZLW7IBXK.js";
241
241
  import {
242
242
  DateRangePicker
243
243
  } from "./chunk-6U5WQERX.js";
@@ -272,13 +272,13 @@ import {
272
272
  CommandPalette
273
273
  } from "./chunk-IDIS7Z6H.js";
274
274
  import "./chunk-47UGX37F.js";
275
+ import {
276
+ ContextMenu
277
+ } from "./chunk-ZUGZRXME.js";
275
278
  import {
276
279
  Container,
277
280
  containerVariants
278
281
  } from "./chunk-E4JM3HUM.js";
279
- import {
280
- ContextMenu
281
- } from "./chunk-ZUGZRXME.js";
282
282
  import {
283
283
  CountryBadge
284
284
  } from "./chunk-ZCEUVK2R.js";
@@ -384,12 +384,12 @@ import {
384
384
  NumberTicker
385
385
  } from "./chunk-4MEV2WHD.js";
386
386
  import "./chunk-CIQHFMF6.js";
387
- import {
388
- AppShell
389
- } from "./chunk-56FERRWW.js";
390
387
  import {
391
388
  AspectRatio
392
389
  } from "./chunk-S2CTBFLN.js";
390
+ import {
391
+ AppShell
392
+ } from "./chunk-56FERRWW.js";
393
393
  import {
394
394
  Autocomplete
395
395
  } from "./chunk-GG5HDX7J.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexub/react",
3
- "version": "1.8.0",
3
+ "version": "2.0.0",
4
4
  "description": "React component library for Nexub Design System — 90+ accessible, themeable UI components built on Radix UI primitives.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -68,12 +68,12 @@
68
68
  "date-fns": "^4.4.0",
69
69
  "react-day-picker": "^9.14.0",
70
70
  "tailwind-merge": "^2.6.1",
71
- "@nexub/icons": "1.8.0"
71
+ "@nexub/icons": "2.0.0"
72
72
  },
73
73
  "peerDependencies": {
74
74
  "react": ">=18 <20",
75
75
  "react-dom": ">=18 <20",
76
- "@nexub/tokens": "^1.8.0"
76
+ "@nexub/tokens": "^2.0.0"
77
77
  },
78
78
  "devDependencies": {
79
79
  "@playwright/test": "1.64.0",
@@ -98,8 +98,8 @@
98
98
  "vaul": "1.1.2",
99
99
  "vite": "^7.3.7",
100
100
  "vitest": "^5.0.5",
101
- "@nexub/themes": "1.8.0",
102
- "@nexub/tokens": "1.8.0"
101
+ "@nexub/themes": "2.0.0",
102
+ "@nexub/tokens": "2.0.0"
103
103
  },
104
104
  "scripts": {
105
105
  "build": "tsup && node scripts/check-dts.mjs",
@@ -1,13 +1,13 @@
1
1
  'use client';
2
2
  import {
3
- HelperText
4
- } from "./chunk-ZLW7IBXK.js";
3
+ FormError
4
+ } from "./chunk-QVTVDL6Y.js";
5
5
  import {
6
6
  Label
7
7
  } from "./chunk-PGD246WD.js";
8
8
  import {
9
- FormError
10
- } from "./chunk-QVTVDL6Y.js";
9
+ HelperText
10
+ } from "./chunk-ZLW7IBXK.js";
11
11
  import {
12
12
  cn
13
13
  } from "./chunk-Q7G5WGYV.js";