@asteby/metacore-theme 2.21.0 → 2.23.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.
package/README.md CHANGED
@@ -93,6 +93,33 @@ The bundled `<ThemeProvider>` (light/dark/system, cookie-persisted) is the
93
93
  recommended entry; consumer apps can drop their local copies and use
94
94
  `useTheme()` for the toggle UI.
95
95
 
96
+ ## No flash on reload
97
+
98
+ `<ThemeProvider>` stores what `<html>` ends up painting — light/dark, the
99
+ `data-ui-*` attributes (theme pack, font, density), `font-*` classes, inline
100
+ custom properties (brand color) and the branding surfaces stylesheet. An inline
101
+ script restores it before the first frame, so a returning visitor never sees
102
+ the defaults first. First visits follow `prefers-color-scheme`. Transitions stay
103
+ off until the providers have mounted (`data-boot-transition` opts an element
104
+ out, e.g. a splash that fades).
105
+
106
+ ```ts
107
+ // vite.config.ts
108
+ import { themeBootScript } from '@asteby/metacore-theme/boot'
109
+
110
+ plugins: [
111
+ {
112
+ name: 'metacore-theme-boot',
113
+ transformIndexHtml: () => [
114
+ { tag: 'script', children: themeBootScript(), injectTo: 'head-prepend' },
115
+ ],
116
+ },
117
+ ]
118
+ ```
119
+
120
+ `@asteby/metacore-theme/boot` has no React import, so it loads in a Node
121
+ config. Pass `persistBoot={false}` to the provider to opt out.
122
+
96
123
  ## License
97
124
 
98
125
  Apache-2.0
package/dist/boot.d.ts ADDED
@@ -0,0 +1,75 @@
1
+ export type ThemeMode = 'light' | 'dark';
2
+ /** localStorage entry holding the last resolved theme of this origin. */
3
+ export declare const THEME_BOOT_STORAGE_KEY = "mc:theme-boot:v1";
4
+ /** Cookie the ThemeProvider stores the user's light/dark/system choice in. */
5
+ export declare const THEME_MODE_COOKIE = "metacore-ui-theme";
6
+ /**
7
+ * Class on <html> while the boot theme settles. Transitions are off under
8
+ * it, so the providers re-applying the same theme can't animate anything.
9
+ */
10
+ export declare const THEME_BOOTING_CLASS = "mc-theme-booting";
11
+ /** Elements (and their subtree) that keep their transitions during boot. */
12
+ export declare const THEME_BOOT_TRANSITION_ATTRIBUTE = "data-boot-transition";
13
+ /** What one mode paints: inline custom properties and generated stylesheets. */
14
+ export interface ThemeBootModeSnapshot {
15
+ vars: Record<string, string>;
16
+ styles: Record<string, string>;
17
+ /** attrs + classes it was captured under; another value makes it stale. */
18
+ base: string;
19
+ }
20
+ export interface ThemeBootSnapshot {
21
+ v: 1;
22
+ attrs: Record<string, string>;
23
+ classes: string[];
24
+ modes: Partial<Record<ThemeMode, ThemeBootModeSnapshot>>;
25
+ }
26
+ export interface ThemeBootScriptOptions {
27
+ storageKey?: string;
28
+ modeCookie?: string;
29
+ /** Mode for a first visit with no cookie. `system` follows the OS. */
30
+ defaultMode?: ThemeMode | 'system';
31
+ /** Longest the transition lock may last if the app never releases it. */
32
+ maxLockMs?: number;
33
+ }
34
+ export interface ThemeBootWatchOptions {
35
+ storageKey?: string;
36
+ /** <html> attributes to keep. Default: every `data-ui-*`. */
37
+ attributePattern?: RegExp;
38
+ /** <html> classes to keep, besides light/dark. Default: `font-*`. */
39
+ classPattern?: RegExp;
40
+ /** <style id> elements whose text is kept per mode. */
41
+ styleIds?: string[];
42
+ }
43
+ /** The stylesheet the metacore branding provider generates. */
44
+ export declare const BRANDING_STYLE_ID = "metacore-branding-surfaces";
45
+ /**
46
+ * Inline script (no <script> tag) that restores the stored theme. Put it
47
+ * first in <head>, before the stylesheets, as a classic (not module) script.
48
+ */
49
+ export declare function themeBootScript(options?: ThemeBootScriptOptions): string;
50
+ /**
51
+ * Turns transitions back on once the app painted with its theme. Waits two
52
+ * frames so the providers' first effects commit without animating.
53
+ */
54
+ export declare function releaseThemeBoot(): void;
55
+ /** Reads what <html> paints right now. */
56
+ export declare function captureThemeBoot(options?: ThemeBootWatchOptions): {
57
+ mode: ThemeMode;
58
+ attrs: Record<string, string>;
59
+ classes: string[];
60
+ vars: Record<string, string>;
61
+ styles: Record<string, string>;
62
+ };
63
+ /**
64
+ * Stores the current theme for the next load. The other mode's entry is
65
+ * kept only while the pack/font/density it was taken under still holds.
66
+ * Returns false when nothing changed.
67
+ */
68
+ export declare function persistThemeBoot(options?: ThemeBootWatchOptions): boolean;
69
+ /**
70
+ * Keeps the stored theme in sync with <html>: any provider that changes a
71
+ * class, a data-ui-* attribute, an inline custom property or a watched
72
+ * stylesheet triggers one write per task. Returns the unsubscribe.
73
+ */
74
+ export declare function watchThemeBoot(options?: ThemeBootWatchOptions): () => void;
75
+ //# sourceMappingURL=boot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../src/boot.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;AAExC,yEAAyE;AACzE,eAAO,MAAM,sBAAsB,qBAAqB,CAAA;AACxD,8EAA8E;AAC9E,eAAO,MAAM,iBAAiB,sBAAsB,CAAA;AACpD;;;GAGG;AACH,eAAO,MAAM,mBAAmB,qBAAqB,CAAA;AACrD,4EAA4E;AAC5E,eAAO,MAAM,+BAA+B,yBAAyB,CAAA;AAErE,gFAAgF;AAChF,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,EAAE,CAAC,CAAA;IACJ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAC,CAAA;CACzD;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sEAAsE;IACtE,WAAW,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IAClC,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,+DAA+D;AAC/D,eAAO,MAAM,iBAAiB,+BAA+B,CAAA;AA0D7D;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,MAAM,CAU5E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAMD,0CAA0C;AAC1C,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,qBAA0B,GAAG;IACrE,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B,CAoBA;AAYD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAoB7E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,MAAM,IAAI,CAiC9E"}
package/dist/boot.js ADDED
@@ -0,0 +1,218 @@
1
+ // Paints the theme a returning visitor last saw before the first frame.
2
+ //
3
+ // Every theme provider (dark/light, theme pack, font, density, brand color)
4
+ // resolves after the bundle runs, some after a fetch. Until then the page
5
+ // painted the defaults and then switched: a visible flash on every reload.
6
+ // The providers keep writing <html> as they do today; `watchThemeBoot`
7
+ // stores the result, and `themeBootScript()` is a small inline script for
8
+ // the top of <head> that puts it back synchronously, before any CSS or paint.
9
+ //
10
+ // This module has no React import so a Vite config can build the snippet.
11
+ /** localStorage entry holding the last resolved theme of this origin. */
12
+ export const THEME_BOOT_STORAGE_KEY = 'mc:theme-boot:v1';
13
+ /** Cookie the ThemeProvider stores the user's light/dark/system choice in. */
14
+ export const THEME_MODE_COOKIE = 'metacore-ui-theme';
15
+ /**
16
+ * Class on <html> while the boot theme settles. Transitions are off under
17
+ * it, so the providers re-applying the same theme can't animate anything.
18
+ */
19
+ export const THEME_BOOTING_CLASS = 'mc-theme-booting';
20
+ /** Elements (and their subtree) that keep their transitions during boot. */
21
+ export const THEME_BOOT_TRANSITION_ATTRIBUTE = 'data-boot-transition';
22
+ /** The stylesheet the metacore branding provider generates. */
23
+ export const BRANDING_STYLE_ID = 'metacore-branding-surfaces';
24
+ const DEFAULT_ATTRIBUTES = /^data-ui-/;
25
+ const DEFAULT_CLASSES = /^font-/;
26
+ // Serialized into the inline script: no reference to anything outside it,
27
+ // and ES5 syntax only, since it runs before any polyfill.
28
+ function bootTheme(o) {
29
+ var d = document;
30
+ var root = d.documentElement;
31
+ var release = function () {
32
+ root.classList.remove(o.lockClass);
33
+ };
34
+ try {
35
+ var lock = d.createElement('style');
36
+ lock.textContent =
37
+ 'html.' + o.lockClass + ' *:not([' + o.allowAttr + ']):not([' + o.allowAttr + '] *),' +
38
+ 'html.' + o.lockClass + ' *::before,html.' + o.lockClass + ' *::after' +
39
+ '{transition:none!important}';
40
+ d.head.appendChild(lock);
41
+ root.classList.add(o.lockClass);
42
+ setTimeout(release, o.maxLockMs);
43
+ var m = d.cookie.match(new RegExp('(?:^|; )' + encodeURIComponent(o.modeCookie) + '=([^;]*)'));
44
+ var pref = m ? decodeURIComponent(m[1]) : o.defaultMode;
45
+ var dark = pref === 'dark' ||
46
+ (pref !== 'light' && !!window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
47
+ var mode = dark ? 'dark' : 'light';
48
+ root.classList.remove(dark ? 'light' : 'dark');
49
+ root.classList.add(mode);
50
+ var raw = localStorage.getItem(o.storageKey);
51
+ var s = raw ? JSON.parse(raw) : null;
52
+ if (!s || s.v !== 1)
53
+ return;
54
+ var k;
55
+ for (k in s.attrs) {
56
+ // Only data-* from storage: never an event-handler attribute.
57
+ if (/^data-[\w-]+$/.test(k) && typeof s.attrs[k] === 'string')
58
+ root.setAttribute(k, s.attrs[k]);
59
+ }
60
+ for (var i = 0; i < (s.classes || []).length; i++) {
61
+ if (typeof s.classes[i] === 'string')
62
+ root.classList.add(s.classes[i]);
63
+ }
64
+ var ms = s.modes && s.modes[mode];
65
+ if (!ms)
66
+ return;
67
+ for (k in ms.vars) {
68
+ if (/^--[\w-]+$/.test(k))
69
+ root.style.setProperty(k, String(ms.vars[k]));
70
+ }
71
+ for (k in ms.styles) {
72
+ var el = d.getElementById(k) || d.head.appendChild(d.createElement('style'));
73
+ el.id = k;
74
+ el.textContent = String(ms.styles[k]);
75
+ }
76
+ }
77
+ catch (e) {
78
+ // Storage blocked or corrupt entry: the providers paint as before.
79
+ }
80
+ }
81
+ /**
82
+ * Inline script (no <script> tag) that restores the stored theme. Put it
83
+ * first in <head>, before the stylesheets, as a classic (not module) script.
84
+ */
85
+ export function themeBootScript(options = {}) {
86
+ const config = {
87
+ storageKey: options.storageKey ?? THEME_BOOT_STORAGE_KEY,
88
+ modeCookie: options.modeCookie ?? THEME_MODE_COOKIE,
89
+ defaultMode: options.defaultMode ?? 'system',
90
+ maxLockMs: options.maxLockMs ?? 8000,
91
+ lockClass: THEME_BOOTING_CLASS,
92
+ allowAttr: THEME_BOOT_TRANSITION_ATTRIBUTE,
93
+ };
94
+ return `(${bootTheme.toString().replace(/\n\s+/g, '\n')})(${JSON.stringify(config)});`;
95
+ }
96
+ /**
97
+ * Turns transitions back on once the app painted with its theme. Waits two
98
+ * frames so the providers' first effects commit without animating.
99
+ */
100
+ export function releaseThemeBoot() {
101
+ if (typeof document === 'undefined')
102
+ return;
103
+ const done = () => document.documentElement.classList.remove(THEME_BOOTING_CLASS);
104
+ if (typeof requestAnimationFrame !== 'function')
105
+ return done();
106
+ requestAnimationFrame(() => requestAnimationFrame(done));
107
+ }
108
+ function currentMode(root) {
109
+ return root.classList.contains('dark') ? 'dark' : 'light';
110
+ }
111
+ /** Reads what <html> paints right now. */
112
+ export function captureThemeBoot(options = {}) {
113
+ const root = document.documentElement;
114
+ const attrPattern = options.attributePattern ?? DEFAULT_ATTRIBUTES;
115
+ const classPattern = options.classPattern ?? DEFAULT_CLASSES;
116
+ const attrs = {};
117
+ for (const attr of Array.from(root.attributes)) {
118
+ if (attrPattern.test(attr.name))
119
+ attrs[attr.name] = attr.value;
120
+ }
121
+ const classes = Array.from(root.classList).filter((c) => classPattern.test(c)).sort();
122
+ const vars = {};
123
+ for (let i = 0; i < root.style.length; i++) {
124
+ const prop = root.style.item(i);
125
+ if (prop.startsWith('--'))
126
+ vars[prop] = root.style.getPropertyValue(prop).trim();
127
+ }
128
+ const styles = {};
129
+ for (const id of options.styleIds ?? [BRANDING_STYLE_ID]) {
130
+ const el = document.getElementById(id);
131
+ if (el instanceof HTMLStyleElement && el.textContent)
132
+ styles[id] = el.textContent;
133
+ }
134
+ return { mode: currentMode(root), attrs, classes, vars, styles };
135
+ }
136
+ function readSnapshot(key) {
137
+ try {
138
+ const raw = localStorage.getItem(key);
139
+ const parsed = raw ? JSON.parse(raw) : null;
140
+ return parsed && parsed.v === 1 ? parsed : null;
141
+ }
142
+ catch {
143
+ return null;
144
+ }
145
+ }
146
+ /**
147
+ * Stores the current theme for the next load. The other mode's entry is
148
+ * kept only while the pack/font/density it was taken under still holds.
149
+ * Returns false when nothing changed.
150
+ */
151
+ export function persistThemeBoot(options = {}) {
152
+ if (typeof document === 'undefined')
153
+ return false;
154
+ const key = options.storageKey ?? THEME_BOOT_STORAGE_KEY;
155
+ const now = captureThemeBoot(options);
156
+ const base = JSON.stringify([now.attrs, now.classes]);
157
+ const prev = readSnapshot(key);
158
+ const modes = {};
159
+ const other = now.mode === 'dark' ? 'light' : 'dark';
160
+ const kept = prev?.modes[other];
161
+ if (kept && kept.base === base)
162
+ modes[other] = kept;
163
+ modes[now.mode] = { vars: now.vars, styles: now.styles, base };
164
+ const next = { v: 1, attrs: now.attrs, classes: now.classes, modes };
165
+ const serialized = JSON.stringify(next);
166
+ try {
167
+ if (localStorage.getItem(key) === serialized)
168
+ return false;
169
+ localStorage.setItem(key, serialized);
170
+ return true;
171
+ }
172
+ catch {
173
+ return false;
174
+ }
175
+ }
176
+ /**
177
+ * Keeps the stored theme in sync with <html>: any provider that changes a
178
+ * class, a data-ui-* attribute, an inline custom property or a watched
179
+ * stylesheet triggers one write per task. Returns the unsubscribe.
180
+ */
181
+ export function watchThemeBoot(options = {}) {
182
+ if (typeof document === 'undefined' || typeof MutationObserver === 'undefined') {
183
+ return () => { };
184
+ }
185
+ const styleIds = new Set(options.styleIds ?? [BRANDING_STYLE_ID]);
186
+ let scheduled = false;
187
+ const schedule = () => {
188
+ if (scheduled)
189
+ return;
190
+ scheduled = true;
191
+ setTimeout(() => {
192
+ scheduled = false;
193
+ persistThemeBoot(options);
194
+ }, 0);
195
+ };
196
+ const inWatchedStyle = (node) => {
197
+ const el = node instanceof Element ? node : node?.parentElement;
198
+ return !!el && el.tagName === 'STYLE' && styleIds.has(el.id);
199
+ };
200
+ const observer = new MutationObserver((records) => {
201
+ for (const record of records) {
202
+ if (record.target === document.documentElement && record.type === 'attributes') {
203
+ return schedule();
204
+ }
205
+ if (inWatchedStyle(record.target))
206
+ return schedule();
207
+ for (const node of Array.from(record.addedNodes)) {
208
+ if (inWatchedStyle(node))
209
+ return schedule();
210
+ }
211
+ }
212
+ });
213
+ observer.observe(document.documentElement, { attributes: true });
214
+ observer.observe(document.head, { childList: true, subtree: true, characterData: true });
215
+ schedule();
216
+ return () => observer.disconnect();
217
+ }
218
+ //# sourceMappingURL=boot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot.js","sourceRoot":"","sources":["../src/boot.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,2EAA2E;AAC3E,uEAAuE;AACvE,0EAA0E;AAC1E,8EAA8E;AAC9E,EAAE;AACF,0EAA0E;AAI1E,yEAAyE;AACzE,MAAM,CAAC,MAAM,sBAAsB,GAAG,kBAAkB,CAAA;AACxD,8EAA8E;AAC9E,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAAmB,CAAA;AACpD;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CAAA;AACrD,4EAA4E;AAC5E,MAAM,CAAC,MAAM,+BAA+B,GAAG,sBAAsB,CAAA;AAoCrE,+DAA+D;AAC/D,MAAM,CAAC,MAAM,iBAAiB,GAAG,4BAA4B,CAAA;AAE7D,MAAM,kBAAkB,GAAG,WAAW,CAAA;AACtC,MAAM,eAAe,GAAG,QAAQ,CAAA;AAEhC,0EAA0E;AAC1E,0DAA0D;AAC1D,SAAS,SAAS,CAAC,CAA8E;IAC/F,IAAI,CAAC,GAAG,QAAQ,CAAA;IAChB,IAAI,IAAI,GAAG,CAAC,CAAC,eAAe,CAAA;IAC5B,IAAI,OAAO,GAAG;QACZ,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IACpC,CAAC,CAAA;IACD,IAAI,CAAC;QACH,IAAI,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;QACnC,IAAI,CAAC,WAAW;YACd,OAAO,GAAG,CAAC,CAAC,SAAS,GAAG,UAAU,GAAG,CAAC,CAAC,SAAS,GAAG,UAAU,GAAG,CAAC,CAAC,SAAS,GAAG,OAAO;gBACrF,OAAO,GAAG,CAAC,CAAC,SAAS,GAAG,kBAAkB,GAAG,CAAC,CAAC,SAAS,GAAG,WAAW;gBACtE,6BAA6B,CAAA;QAC/B,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;QACxB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAC/B,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,CAAA;QAEhC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,UAAU,GAAG,kBAAkB,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC,CAAC,CAAA;QAC9F,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAA;QACjE,IAAI,IAAI,GACN,IAAI,KAAK,MAAM;YACf,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO,CAAC,CAAA;QACxG,IAAI,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAA;QAClC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;QAC9C,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAExB,IAAI,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;QAC5C,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QACpC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,OAAM;QAC3B,IAAI,CAAC,CAAA;QACL,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YAClB,8DAA8D;YAC9D,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ;gBAAE,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QACjG,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,QAAQ;gBAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;QACxE,CAAC;QACD,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACjC,IAAI,CAAC,EAAE;YAAE,OAAM;QACf,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;YAClB,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACzE,CAAC;QACD,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YACpB,IAAI,EAAE,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAA;YAC5E,EAAE,CAAC,EAAE,GAAG,CAAC,CAAA;YACT,EAAE,CAAC,WAAW,GAAG,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QACvC,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,mEAAmE;IACrE,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkC,EAAE;IAClE,MAAM,MAAM,GAAG;QACb,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,sBAAsB;QACxD,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,iBAAiB;QACnD,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,QAAQ;QAC5C,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI;QACpC,SAAS,EAAE,mBAAmB;QAC9B,SAAS,EAAE,+BAA+B;KAC3C,CAAA;IACD,OAAO,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAA;AACxF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAM;IAC3C,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAA;IACjF,IAAI,OAAO,qBAAqB,KAAK,UAAU;QAAE,OAAO,IAAI,EAAE,CAAA;IAC9D,qBAAqB,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAA;AAC1D,CAAC;AAED,SAAS,WAAW,CAAC,IAAiB;IACpC,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAA;AAC3D,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,gBAAgB,CAAC,UAAiC,EAAE;IAOlE,MAAM,IAAI,GAAG,QAAQ,CAAC,eAAe,CAAA;IACrC,MAAM,WAAW,GAAG,OAAO,CAAC,gBAAgB,IAAI,kBAAkB,CAAA;IAClE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,eAAe,CAAA;IAC5D,MAAM,KAAK,GAA2B,EAAE,CAAA;IACxC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/C,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAA;IAChE,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IACrF,MAAM,IAAI,GAA2B,EAAE,CAAA;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;IAClF,CAAC;IACD,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACzD,MAAM,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAA;QACtC,IAAI,EAAE,YAAY,gBAAgB,IAAI,EAAE,CAAC,WAAW;YAAE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,CAAA;IACnF,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AAClE,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACrC,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAuB,CAAC,CAAC,CAAC,IAAI,CAAA;QAClE,OAAO,MAAM,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAiC,EAAE;IAClE,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO,KAAK,CAAA;IACjD,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,IAAI,sBAAsB,CAAA;IACxD,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;IACrD,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;IAC9B,MAAM,KAAK,GAA+B,EAAE,CAAA;IAC5C,MAAM,KAAK,GAAc,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAA;IAC/D,MAAM,IAAI,GAAG,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IAC/B,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,CAAA;IACnD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAA;IAC9D,MAAM,IAAI,GAAsB,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;IACvF,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IACvC,IAAI,CAAC;QACH,IAAI,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,UAAU;YAAE,OAAO,KAAK,CAAA;QAC1D,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;QACrC,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,UAAiC,EAAE;IAChE,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,OAAO,gBAAgB,KAAK,WAAW,EAAE,CAAC;QAC/E,OAAO,GAAG,EAAE,GAAE,CAAC,CAAA;IACjB,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAA;IACjE,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,IAAI,SAAS;YAAE,OAAM;QACrB,SAAS,GAAG,IAAI,CAAA;QAChB,UAAU,CAAC,GAAG,EAAE;YACd,SAAS,GAAG,KAAK,CAAA;YACjB,gBAAgB,CAAC,OAAO,CAAC,CAAA;QAC3B,CAAC,EAAE,CAAC,CAAC,CAAA;IACP,CAAC,CAAA;IACD,MAAM,cAAc,GAAG,CAAC,IAAiB,EAAE,EAAE;QAC3C,MAAM,EAAE,GAAG,IAAI,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,aAAa,CAAA;QAC/D,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,OAAO,KAAK,OAAO,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IAC9D,CAAC,CAAA;IACD,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,CAAC,OAAO,EAAE,EAAE;QAChD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,eAAe,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC/E,OAAO,QAAQ,EAAE,CAAA;YACnB,CAAC;YACD,IAAI,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC;gBAAE,OAAO,QAAQ,EAAE,CAAA;YACpD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;gBACjD,IAAI,cAAc,CAAC,IAAI,CAAC;oBAAE,OAAO,QAAQ,EAAE,CAAA;YAC7C,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IACF,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAA;IAChE,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;IACxF,QAAQ,EAAE,CAAA;IACV,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAA;AACpC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -4,4 +4,6 @@ export { colorTokens, chartTokens, radiusTokens, shadowTokens, fontTokens, track
4
4
  export type { ThemeConfig } from './preset.js';
5
5
  export { ThemeProvider, useTheme } from './provider.js';
6
6
  export type { ThemeProviderProps, ThemeProviderState } from './provider.js';
7
+ export { themeBootScript, watchThemeBoot, persistThemeBoot, captureThemeBoot, releaseThemeBoot, THEME_BOOT_STORAGE_KEY, THEME_MODE_COOKIE, THEME_BOOTING_CLASS, THEME_BOOT_TRANSITION_ATTRIBUTE, BRANDING_STYLE_ID, } from './boot.js';
8
+ export type { ThemeMode, ThemeBootSnapshot, ThemeBootModeSnapshot, ThemeBootScriptOptions, ThemeBootWatchOptions, } from './boot.js';
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACvD,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAChD,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACvD,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAE3E,OAAO,EACL,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,+BAA+B,EAC/B,iBAAiB,GAClB,MAAM,WAAW,CAAA;AAClB,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,WAAW,CAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { fonts, fontFamilies } from './fonts.js';
2
2
  export { colorTokens, chartTokens, radiusTokens, shadowTokens, fontTokens, trackingTokens, motionTokens, themeConfig, } from './preset.js';
3
3
  export { ThemeProvider, useTheme } from './provider.js';
4
+ export { themeBootScript, watchThemeBoot, persistThemeBoot, captureThemeBoot, releaseThemeBoot, THEME_BOOT_STORAGE_KEY, THEME_MODE_COOKIE, THEME_BOOTING_CLASS, THEME_BOOT_TRANSITION_ATTRIBUTE, BRANDING_STYLE_ID, } from './boot.js';
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAGhD,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAGhD,OAAO,EACL,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAGvD,OAAO,EACL,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,+BAA+B,EAC/B,iBAAiB,GAClB,MAAM,WAAW,CAAA"}
@@ -1,9 +1,17 @@
1
+ import { type ThemeBootWatchOptions } from './boot.js';
1
2
  type Theme = 'dark' | 'light' | 'system';
2
3
  type ResolvedTheme = Exclude<Theme, 'system'>;
3
4
  export type ThemeProviderProps = {
4
5
  children: React.ReactNode;
5
6
  defaultTheme?: Theme;
6
7
  storageKey?: string;
8
+ /**
9
+ * Stores the resolved theme of <html> for `themeBootScript()`, so the next
10
+ * load paints it before the first frame. On by default; pass options to
11
+ * change what is kept. A custom `storageKey` must also be given to the
12
+ * script as `modeCookie`.
13
+ */
14
+ persistBoot?: boolean | ThemeBootWatchOptions;
7
15
  };
8
16
  export type ThemeProviderState = {
9
17
  defaultTheme: Theme;
@@ -12,7 +20,7 @@ export type ThemeProviderState = {
12
20
  setTheme: (theme: Theme) => void;
13
21
  resetTheme: () => void;
14
22
  };
15
- export declare function ThemeProvider({ children, defaultTheme, storageKey, }: ThemeProviderProps): import("react").JSX.Element;
23
+ export declare function ThemeProvider({ children, defaultTheme, storageKey, persistBoot, }: ThemeProviderProps): import("react").JSX.Element;
16
24
  export declare function useTheme(): ThemeProviderState;
17
25
  export {};
18
26
  //# sourceMappingURL=provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAEA,KAAK,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AACxC,KAAK,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AAM7C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,KAAK,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,EAAE,KAAK,CAAA;IACnB,aAAa,EAAE,aAAa,CAAA;IAC5B,KAAK,EAAE,KAAK,CAAA;IACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,UAAU,EAAE,MAAM,IAAI,CAAA;CACvB,CAAA;AAgCD,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,YAA4B,EAC5B,UAAgC,GACjC,EAAE,kBAAkB,+BAuDpB;AAGD,wBAAgB,QAAQ,IAAI,kBAAkB,CAI7C"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,WAAW,CAAA;AAElB,KAAK,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AACxC,KAAK,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;AAM7C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,YAAY,CAAC,EAAE,KAAK,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,GAAG,qBAAqB,CAAA;CAC9C,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,EAAE,KAAK,CAAA;IACnB,aAAa,EAAE,aAAa,CAAA;IAC5B,KAAK,EAAE,KAAK,CAAA;IACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,UAAU,EAAE,MAAM,IAAI,CAAA;CACvB,CAAA;AAgCD,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,YAA4B,EAC5B,UAAgC,EAChC,WAAkB,GACnB,EAAE,kBAAkB,+BAoEpB;AAGD,wBAAgB,QAAQ,IAAI,kBAAkB,CAI7C"}
package/dist/provider.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useContext, useEffect, useMemo, useState } from 'react';
3
+ import { THEME_MODE_COOKIE, releaseThemeBoot, watchThemeBoot, } from './boot.js';
3
4
  const DEFAULT_THEME = 'system';
4
- const DEFAULT_STORAGE_KEY = 'metacore-ui-theme';
5
+ const DEFAULT_STORAGE_KEY = THEME_MODE_COOKIE;
5
6
  const THEME_COOKIE_MAX_AGE = 60 * 60 * 24 * 365;
6
7
  const initialState = {
7
8
  defaultTheme: DEFAULT_THEME,
@@ -32,7 +33,7 @@ function clearCookie(name) {
32
33
  return;
33
34
  document.cookie = `${encodeURIComponent(name)}=; path=/; max-age=0; SameSite=Lax`;
34
35
  }
35
- export function ThemeProvider({ children, defaultTheme = DEFAULT_THEME, storageKey = DEFAULT_STORAGE_KEY, }) {
36
+ export function ThemeProvider({ children, defaultTheme = DEFAULT_THEME, storageKey = DEFAULT_STORAGE_KEY, persistBoot = true, }) {
36
37
  const [theme, _setTheme] = useState(() => readCookie(storageKey) || defaultTheme);
37
38
  const resolvedTheme = useMemo(() => {
38
39
  if (theme === 'system') {
@@ -49,8 +50,13 @@ export function ThemeProvider({ children, defaultTheme = DEFAULT_THEME, storageK
49
50
  return;
50
51
  const root = window.document.documentElement;
51
52
  const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
53
+ // Unchanged classes are left alone: every class mutation makes the
54
+ // branding provider repaint its tokens.
52
55
  const applyTheme = (current) => {
53
- root.classList.remove('light', 'dark');
56
+ const other = current === 'dark' ? 'light' : 'dark';
57
+ if (root.classList.contains(current) && !root.classList.contains(other))
58
+ return;
59
+ root.classList.remove(other);
54
60
  root.classList.add(current);
55
61
  };
56
62
  const handleChange = () => {
@@ -62,6 +68,14 @@ export function ThemeProvider({ children, defaultTheme = DEFAULT_THEME, storageK
62
68
  mediaQuery.addEventListener('change', handleChange);
63
69
  return () => mediaQuery.removeEventListener('change', handleChange);
64
70
  }, [theme, resolvedTheme]);
71
+ const bootOptions = typeof persistBoot === 'object' ? persistBoot : undefined;
72
+ useEffect(() => {
73
+ const stop = persistBoot === false ? () => { } : watchThemeBoot(bootOptions);
74
+ releaseThemeBoot();
75
+ return stop;
76
+ // Options are read once: the watcher lives as long as the app.
77
+ // eslint-disable-next-line react-hooks/exhaustive-deps
78
+ }, [persistBoot === false]);
65
79
  const setTheme = (next) => {
66
80
  writeCookie(storageKey, next, THEME_COOKIE_MAX_AGE);
67
81
  _setTheme(next);
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-theme",
3
- "version": "2.21.0",
3
+ "version": "2.23.0",
4
4
  "description": "Metacore design tokens + Tailwind 4 preset (oklch, shadows, fonts, dark mode)",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -28,6 +28,10 @@
28
28
  "types": "./dist/fonts.d.ts",
29
29
  "import": "./dist/fonts.js"
30
30
  },
31
+ "./boot": {
32
+ "types": "./dist/boot.d.ts",
33
+ "import": "./dist/boot.js"
34
+ },
31
35
  "./preset": {
32
36
  "types": "./dist/preset.d.ts",
33
37
  "import": "./dist/preset.js"
@@ -44,9 +48,11 @@
44
48
  "devDependencies": {
45
49
  "@types/react": "^19.0.0",
46
50
  "@types/react-dom": "^19.0.0",
51
+ "happy-dom": "^20.11.2",
47
52
  "react": "^19.2.4",
48
53
  "react-dom": "^19.2.4",
49
- "typescript": "^6.0.0"
54
+ "typescript": "^6.0.0",
55
+ "vitest": "^4.0.0"
50
56
  },
51
57
  "publishConfig": {
52
58
  "access": "public"
@@ -55,6 +61,7 @@
55
61
  "build": "tsc -p tsconfig.json",
56
62
  "dev": "tsc -w -p tsconfig.json",
57
63
  "typecheck": "tsc -p tsconfig.json --noEmit",
58
- "clean": "rm -rf dist"
64
+ "clean": "rm -rf dist",
65
+ "test": "vitest run"
59
66
  }
60
67
  }
package/styles/glass.css CHANGED
@@ -134,7 +134,14 @@
134
134
  background-attachment: fixed;
135
135
  }
136
136
 
137
- /* ─── Blur behind every translucent surface ─── */
137
+ /* ─── Blur behind every translucent surface ───
138
+ * A backdrop-filter makes its element the containing block of every
139
+ * position:fixed descendant, the main inset included. A fixed layer rendered
140
+ * inline inside the page (a drag overlay, a full-screen editor, a loading
141
+ * veil) is then placed and clipped by the panel, not the viewport. Render such
142
+ * layers through a portal to <body>: Radix primitives already do, and
143
+ * @asteby/metacore-runtime-react ships PortalDragOverlay for dnd-kit.
144
+ */
138
145
  [data-ui-theme='glass'] .bg-background,
139
146
  [data-ui-theme='glass'] .bg-card,
140
147
  [data-ui-theme='glass'] .bg-popover,