@asteby/metacore-theme 2.21.0 → 2.25.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 +58 -0
- package/dist/boot.d.ts +75 -0
- package/dist/boot.d.ts.map +1 -0
- package/dist/boot.js +218 -0
- package/dist/boot.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +9 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +17 -3
- package/dist/provider.js.map +1 -1
- package/package.json +10 -3
- package/styles/glass.css +49 -7
package/README.md
CHANGED
|
@@ -66,6 +66,37 @@ the brand painted by `applyBranding`. Import it after your tokens:
|
|
|
66
66
|
It includes a near-opaque fallback for browsers without `backdrop-filter`
|
|
67
67
|
and for `prefers-reduced-transparency`.
|
|
68
68
|
|
|
69
|
+
#### Host chrome and mobile floating panel (optional variables)
|
|
70
|
+
|
|
71
|
+
A host with fixed chrome around the shell publishes its sizes on `:root`. All
|
|
72
|
+
variables are optional and default to `0`/flat: without them the compiled CSS
|
|
73
|
+
behaves exactly as before.
|
|
74
|
+
|
|
75
|
+
| Variable | Default | Effect |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `--app-topbar-h` | `0px` | Fixed top bar: pushes the inset (and `@asteby/metacore-ui` `Sidebar`) down |
|
|
78
|
+
| `--app-notice-h` | `0px` | Notice strip under the top bar (0 when hidden) |
|
|
79
|
+
| `--app-bottombar-h` | `0px` | Bottom dock on mobile: bottom margin of the inset and the mobile sidebar sheet |
|
|
80
|
+
| `--glass-inset-max-height` | `none` | Cap for the inset when the wrapper is not height-bound, e.g. `calc(100svh - var(--app-topbar-h) - var(--app-notice-h) - 1rem)` |
|
|
81
|
+
| `--glass-mobile-gutter` | `0px` | Margin around the inset on phones (e.g. `0.5rem`) |
|
|
82
|
+
| `--glass-mobile-radius` | `0px` | Corner radius of the inset on phones (e.g. `var(--glass-radius)`) |
|
|
83
|
+
| `--glass-mobile-border-width` | `0px` | Rim width on phones (e.g. `1px`) |
|
|
84
|
+
| `--glass-mobile-shadow` | `none` | Shadow on phones (e.g. `var(--glass-highlight), var(--glass-shadow)`) |
|
|
85
|
+
|
|
86
|
+
```css
|
|
87
|
+
:root {
|
|
88
|
+
--app-topbar-h: 3rem;
|
|
89
|
+
--app-bottombar-h: 4rem; /* 0 from sm up if the dock is mobile-only */
|
|
90
|
+
--glass-mobile-gutter: 0.5rem;
|
|
91
|
+
--glass-mobile-radius: var(--glass-radius);
|
|
92
|
+
--glass-mobile-border-width: 1px;
|
|
93
|
+
--glass-mobile-shadow: var(--glass-highlight), var(--glass-shadow);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
An inset with no sidebar sibling (chat-like screens) floats on desktop with
|
|
98
|
+
`<SidebarInset data-glass-float>`.
|
|
99
|
+
|
|
69
100
|
## Usage from JS/TS
|
|
70
101
|
|
|
71
102
|
For programmatic access (Storybook, charts, PDF):
|
|
@@ -93,6 +124,33 @@ The bundled `<ThemeProvider>` (light/dark/system, cookie-persisted) is the
|
|
|
93
124
|
recommended entry; consumer apps can drop their local copies and use
|
|
94
125
|
`useTheme()` for the toggle UI.
|
|
95
126
|
|
|
127
|
+
## No flash on reload
|
|
128
|
+
|
|
129
|
+
`<ThemeProvider>` stores what `<html>` ends up painting — light/dark, the
|
|
130
|
+
`data-ui-*` attributes (theme pack, font, density), `font-*` classes, inline
|
|
131
|
+
custom properties (brand color) and the branding surfaces stylesheet. An inline
|
|
132
|
+
script restores it before the first frame, so a returning visitor never sees
|
|
133
|
+
the defaults first. First visits follow `prefers-color-scheme`. Transitions stay
|
|
134
|
+
off until the providers have mounted (`data-boot-transition` opts an element
|
|
135
|
+
out, e.g. a splash that fades).
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
// vite.config.ts
|
|
139
|
+
import { themeBootScript } from '@asteby/metacore-theme/boot'
|
|
140
|
+
|
|
141
|
+
plugins: [
|
|
142
|
+
{
|
|
143
|
+
name: 'metacore-theme-boot',
|
|
144
|
+
transformIndexHtml: () => [
|
|
145
|
+
{ tag: 'script', children: themeBootScript(), injectTo: 'head-prepend' },
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`@asteby/metacore-theme/boot` has no React import, so it loads in a Node
|
|
152
|
+
config. Pass `persistBoot={false}` to the provider to opt out.
|
|
153
|
+
|
|
96
154
|
## License
|
|
97
155
|
|
|
98
156
|
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
|
package/dist/boot.js.map
ADDED
|
@@ -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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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"}
|
package/dist/provider.d.ts
CHANGED
|
@@ -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
|
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"
|
|
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 =
|
|
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
|
-
|
|
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);
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;
|
|
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.
|
|
3
|
+
"version": "2.25.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,
|
|
@@ -190,19 +197,53 @@
|
|
|
190
197
|
width: calc(var(--sidebar-width-icon) + 1rem);
|
|
191
198
|
}
|
|
192
199
|
|
|
200
|
+
/*
|
|
201
|
+
* Host chrome awareness. A host with fixed chrome around the app shell
|
|
202
|
+
* publishes its sizes as CSS variables on :root (all default to 0, so without
|
|
203
|
+
* them nothing changes):
|
|
204
|
+
*
|
|
205
|
+
* --app-topbar-h height of a fixed top bar
|
|
206
|
+
* --app-notice-h height of a notice strip under it (0 when hidden)
|
|
207
|
+
* --app-bottombar-h height of a bottom dock (mobile)
|
|
208
|
+
*
|
|
209
|
+
* The floating inset leaves them free: top margin = topbar + notice + gutter,
|
|
210
|
+
* bottom margin (mobile) = bottombar + gutter. Optionally cap the panel with
|
|
211
|
+
* --glass-inset-max-height: calc(100svh - var(--app-topbar-h) - var(--app-notice-h) - 1rem);
|
|
212
|
+
* when the shell wrapper is not height-bound (min-h-svh) — the SDK
|
|
213
|
+
* SidebarProvider is h-svh, where the panel already stretches to fit.
|
|
214
|
+
*/
|
|
193
215
|
@media (min-width: 768px) {
|
|
194
216
|
[data-ui-theme='glass'] [data-slot='sidebar'][data-variant='sidebar'] ~ [data-slot='sidebar-inset'] {
|
|
195
|
-
margin: 0.5rem;
|
|
217
|
+
margin: calc(var(--app-topbar-h, 0px) + var(--app-notice-h, 0px) + 0.5rem) 0.5rem 0.5rem;
|
|
196
218
|
margin-inline-start: 0;
|
|
219
|
+
max-height: var(--glass-inset-max-height, none);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/*
|
|
223
|
+
* Opt-in: an inset with no sidebar sibling (chat-like screens) floats the
|
|
224
|
+
* same way with <SidebarInset data-glass-float>.
|
|
225
|
+
*/
|
|
226
|
+
[data-ui-theme='glass'] [data-slot='sidebar-inset'][data-glass-float] {
|
|
227
|
+
margin: calc(var(--app-topbar-h, 0px) + var(--app-notice-h, 0px) + 0.5rem) 0.5rem 0.5rem;
|
|
228
|
+
max-height: var(--glass-inset-max-height, none);
|
|
197
229
|
}
|
|
198
230
|
}
|
|
199
231
|
|
|
200
232
|
@media (max-width: 767px) {
|
|
201
|
-
/*
|
|
233
|
+
/*
|
|
234
|
+
* No sidebar panel beside it on phones: by default the inset is the whole
|
|
235
|
+
* screen, flat. Opt in to a floating panel with --glass-mobile-gutter
|
|
236
|
+
* (e.g. 0.5rem), --glass-mobile-radius (e.g. var(--glass-radius)),
|
|
237
|
+
* --glass-mobile-border-width (e.g. 1px) and --glass-mobile-shadow
|
|
238
|
+
* (e.g. var(--glass-highlight), var(--glass-shadow)).
|
|
239
|
+
*/
|
|
202
240
|
[data-ui-theme='glass'] [data-slot='sidebar-inset'] {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
241
|
+
margin: calc(var(--app-topbar-h, 0px) + var(--app-notice-h, 0px) + var(--glass-mobile-gutter, 0px))
|
|
242
|
+
var(--glass-mobile-gutter, 0px) calc(var(--app-bottombar-h, 0px) + var(--glass-mobile-gutter, 0px));
|
|
243
|
+
max-height: var(--glass-inset-max-height, none);
|
|
244
|
+
border-width: var(--glass-mobile-border-width, 0px);
|
|
245
|
+
border-radius: var(--glass-mobile-radius, 0px);
|
|
246
|
+
box-shadow: var(--glass-mobile-shadow, none);
|
|
206
247
|
}
|
|
207
248
|
}
|
|
208
249
|
|
|
@@ -212,7 +253,8 @@
|
|
|
212
253
|
* gutter, over the dimmed overlay, so it takes the denser popover glass.
|
|
213
254
|
*/
|
|
214
255
|
[data-ui-theme='glass'] [data-mobile='true'][data-slot='sidebar'] {
|
|
215
|
-
inset-block: 0.5rem;
|
|
256
|
+
inset-block-start: calc(var(--app-topbar-h, 0px) + var(--app-notice-h, 0px) + 0.5rem);
|
|
257
|
+
inset-block-end: calc(var(--app-bottombar-h, 0px) + 0.5rem);
|
|
216
258
|
inset-inline-start: 0.5rem;
|
|
217
259
|
height: auto;
|
|
218
260
|
background-color: var(--popover);
|