@marianmeres/stuic 3.90.0 → 3.92.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/dist/components/ColorScheme/ColorSchemeLocal.svelte +16 -3
- package/dist/components/ColorScheme/ColorSchemeLocal.svelte.d.ts +2 -17
- package/dist/components/ColorScheme/ColorSchemeSystemAware.svelte +15 -2
- package/dist/components/ColorScheme/ColorSchemeSystemAware.svelte.d.ts +2 -17
- package/dist/components/ColorScheme/color-scheme.svelte.d.ts +51 -16
- package/dist/components/ColorScheme/color-scheme.svelte.js +81 -30
- package/package.json +1 -1
|
@@ -3,13 +3,26 @@
|
|
|
3
3
|
export interface Props {}
|
|
4
4
|
</script>
|
|
5
5
|
|
|
6
|
+
<script lang="ts">
|
|
7
|
+
import { ColorScheme } from "./color-scheme.svelte.js";
|
|
8
|
+
$effect(() => {
|
|
9
|
+
// Bootstrap <script> below has run by the time this effect fires;
|
|
10
|
+
// re-seed the runtime from whatever the DOM is now showing.
|
|
11
|
+
ColorScheme.syncFromDom();
|
|
12
|
+
});
|
|
13
|
+
</script>
|
|
14
|
+
|
|
6
15
|
<!--
|
|
7
|
-
|
|
8
|
-
|
|
16
|
+
Similar to ColorSchemeSystemAware, except that it never reads window.matchMedia and only
|
|
17
|
+
relies on the local userland setting.
|
|
18
|
+
|
|
19
|
+
Uses the hardcoded default storage key "stuic-color-scheme". Apps that
|
|
20
|
+
override the runtime key via `ColorScheme.configure({ key })` should ship
|
|
21
|
+
their own inline bootstrap in `app.html` if FOUC-free hydration matters.
|
|
9
22
|
-->
|
|
10
23
|
<svelte:head>
|
|
11
24
|
<script>
|
|
12
|
-
const KEY = "stuic-color-scheme";
|
|
25
|
+
const KEY = window.__COLOR_SCHEME_KEY__ ?? "stuic-color-scheme";
|
|
13
26
|
const cls = window.document.documentElement.classList;
|
|
14
27
|
localStorage.getItem(KEY) === "dark" ? cls.add("dark") : cls.remove("dark");
|
|
15
28
|
</script>
|
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
/** ColorSchemeLocal has no props - it's a pure hydration component */
|
|
2
2
|
export interface Props {
|
|
3
3
|
}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
$$bindings?: Bindings;
|
|
7
|
-
} & Exports;
|
|
8
|
-
(internal: unknown, props: {
|
|
9
|
-
$$events?: Events;
|
|
10
|
-
$$slots?: Slots;
|
|
11
|
-
}): Exports & {
|
|
12
|
-
$set?: any;
|
|
13
|
-
$on?: any;
|
|
14
|
-
};
|
|
15
|
-
z_$$bindings?: Bindings;
|
|
16
|
-
}
|
|
17
|
-
declare const ColorSchemeLocal: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
18
|
-
[evt: string]: CustomEvent<any>;
|
|
19
|
-
}, {}, {}, string>;
|
|
20
|
-
type ColorSchemeLocal = InstanceType<typeof ColorSchemeLocal>;
|
|
4
|
+
declare const ColorSchemeLocal: import("svelte").Component<Record<string, never>, {}, "">;
|
|
5
|
+
type ColorSchemeLocal = ReturnType<typeof ColorSchemeLocal>;
|
|
21
6
|
export default ColorSchemeLocal;
|
|
@@ -3,12 +3,25 @@
|
|
|
3
3
|
export interface Props {}
|
|
4
4
|
</script>
|
|
5
5
|
|
|
6
|
+
<script lang="ts">
|
|
7
|
+
import { ColorScheme } from "./color-scheme.svelte.js";
|
|
8
|
+
$effect(() => {
|
|
9
|
+
// Bootstrap <script> below has run by the time this effect fires;
|
|
10
|
+
// re-seed the runtime from whatever the DOM is now showing.
|
|
11
|
+
ColorScheme.syncFromDom();
|
|
12
|
+
});
|
|
13
|
+
</script>
|
|
14
|
+
|
|
6
15
|
<!--
|
|
7
|
-
If you do not wish to take the system preference into account use
|
|
16
|
+
If you do not wish to take the system preference into account use ColorSchemeLocal sibling.
|
|
17
|
+
|
|
18
|
+
Uses the hardcoded default storage key "stuic-color-scheme". Apps that
|
|
19
|
+
override the runtime key via `ColorScheme.configure({ key })` should ship
|
|
20
|
+
their own inline bootstrap in `app.html` if FOUC-free hydration matters.
|
|
8
21
|
-->
|
|
9
22
|
<svelte:head>
|
|
10
23
|
<script>
|
|
11
|
-
const KEY = "stuic-color-scheme";
|
|
24
|
+
const KEY = window.__COLOR_SCHEME_KEY__ ?? "stuic-color-scheme";
|
|
12
25
|
const cls = window.document.documentElement.classList;
|
|
13
26
|
if (KEY in localStorage) {
|
|
14
27
|
localStorage.getItem(KEY) === "dark" ? cls.add("dark") : cls.remove("dark");
|
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
/** ColorSchemeSystemAware has no props - it's a pure hydration component */
|
|
2
2
|
export interface Props {
|
|
3
3
|
}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
$$bindings?: Bindings;
|
|
7
|
-
} & Exports;
|
|
8
|
-
(internal: unknown, props: {
|
|
9
|
-
$$events?: Events;
|
|
10
|
-
$$slots?: Slots;
|
|
11
|
-
}): Exports & {
|
|
12
|
-
$set?: any;
|
|
13
|
-
$on?: any;
|
|
14
|
-
};
|
|
15
|
-
z_$$bindings?: Bindings;
|
|
16
|
-
}
|
|
17
|
-
declare const ColorSchemeSystemAware: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
18
|
-
[evt: string]: CustomEvent<any>;
|
|
19
|
-
}, {}, {}, string>;
|
|
20
|
-
type ColorSchemeSystemAware = InstanceType<typeof ColorSchemeSystemAware>;
|
|
4
|
+
declare const ColorSchemeSystemAware: import("svelte").Component<Record<string, never>, {}, "">;
|
|
5
|
+
type ColorSchemeSystemAware = ReturnType<typeof ColorSchemeSystemAware>;
|
|
21
6
|
export default ColorSchemeSystemAware;
|
|
@@ -1,47 +1,81 @@
|
|
|
1
1
|
type Scheme = "dark" | "light";
|
|
2
|
+
declare global {
|
|
3
|
+
interface Window {
|
|
4
|
+
/**
|
|
5
|
+
* Optional global override for the localStorage key the inline bootstrap
|
|
6
|
+
* `<script>` in `<ColorSchemeLocal />` / `<ColorSchemeSystemAware />` reads
|
|
7
|
+
* from. Set this before the hydration component mounts (e.g. in
|
|
8
|
+
* `app.html` or at the very top of the root layout's `<script>`) to use a
|
|
9
|
+
* custom key with FOUC-free hydration. `ColorScheme.configure({ key })`
|
|
10
|
+
* also writes this global to keep runtime and bootstrap in sync.
|
|
11
|
+
*/
|
|
12
|
+
__COLOR_SCHEME_KEY__?: string;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
2
15
|
/**
|
|
3
16
|
* A utility class for managing light/dark color scheme preferences.
|
|
4
17
|
*
|
|
5
|
-
* Handles
|
|
18
|
+
* Handles localStorage persistence and DOM class toggling.
|
|
6
19
|
* Works with Tailwind CSS dark mode (class-based strategy).
|
|
7
20
|
*
|
|
8
21
|
* The `ColorScheme.current` getter is reactive (Svelte 5 `$state`): reading it
|
|
9
|
-
* inside a `$derived`/`$effect`/template will react to toggles
|
|
10
|
-
* `storage` events
|
|
22
|
+
* inside a `$derived`/`$effect`/template will react to toggles and cross-tab
|
|
23
|
+
* `storage` events.
|
|
11
24
|
*
|
|
12
25
|
* @example
|
|
13
26
|
* ```ts
|
|
14
27
|
* // Reactive current value (use in templates / $derived / $effect):
|
|
15
28
|
* const scheme = ColorScheme.current; // 'light' or 'dark'
|
|
16
29
|
*
|
|
17
|
-
* // Backward-compatible non-reactive read:
|
|
18
|
-
* const v = ColorScheme.getValue();
|
|
19
|
-
*
|
|
20
30
|
* // Toggle between light and dark
|
|
21
31
|
* ColorScheme.toggle();
|
|
22
32
|
*
|
|
23
|
-
* // Check system preference only
|
|
24
|
-
* const systemPref = ColorScheme.getSystemValue();
|
|
25
|
-
*
|
|
26
33
|
* // Reset to system preference
|
|
27
34
|
* ColorScheme.reset();
|
|
35
|
+
*
|
|
36
|
+
* // Use a custom localStorage key (call early in app boot):
|
|
37
|
+
* ColorScheme.configure({ key: "myapp:color-scheme" });
|
|
28
38
|
* ```
|
|
29
39
|
*
|
|
30
40
|
* @remarks
|
|
31
|
-
* -
|
|
41
|
+
* - Default localStorage key: "stuic-color-scheme" (override via `configure`)
|
|
32
42
|
* - Adds/removes "dark" class on `<html>` element
|
|
33
43
|
* - Works with Tailwind's `darkMode: 'class'` configuration
|
|
44
|
+
* - Pair with `<ColorSchemeLocal />` or `<ColorSchemeSystemAware />` for
|
|
45
|
+
* FOUC-free initial paint
|
|
34
46
|
*/
|
|
35
47
|
export declare class ColorScheme {
|
|
36
|
-
static readonly KEY: "stuic-color-scheme";
|
|
37
48
|
static readonly DARK: "dark";
|
|
38
49
|
static readonly LIGHT: "light";
|
|
50
|
+
/**
|
|
51
|
+
* The active localStorage key. Default is `"stuic-color-scheme"`. Override via
|
|
52
|
+
* `ColorScheme.configure({ key })` or the `key` prop on the hydration components.
|
|
53
|
+
*/
|
|
54
|
+
static get KEY(): string;
|
|
55
|
+
/**
|
|
56
|
+
* Configure the runtime. Call early in app boot, before any consumer reads
|
|
57
|
+
* `ColorScheme.current`. Mutates module state; safe to call more than once
|
|
58
|
+
* (last write wins). Calling without changes is a no-op.
|
|
59
|
+
*
|
|
60
|
+
* Also writes `window.__COLOR_SCHEME_KEY__` so a subsequent hydration
|
|
61
|
+
* component mount (or any external bootstrap script that reads the global)
|
|
62
|
+
* stays in sync with the runtime.
|
|
63
|
+
*/
|
|
64
|
+
static configure(opts: {
|
|
65
|
+
key?: string;
|
|
66
|
+
}): void;
|
|
39
67
|
/**
|
|
40
68
|
* Reactive current value. Read inside `$derived`, `$effect`, or a Svelte
|
|
41
|
-
* template to react to scheme changes (including cross-tab `storage`
|
|
42
|
-
* events and OS-level system-preference changes).
|
|
69
|
+
* template to react to scheme changes (including cross-tab `storage` events).
|
|
43
70
|
*/
|
|
44
71
|
static get current(): Scheme;
|
|
72
|
+
/**
|
|
73
|
+
* Re-seed `current` from the actual `<html>` class state. Used by the
|
|
74
|
+
* hydration components after their inline bootstrap `<script>` has run, so
|
|
75
|
+
* the runtime matches whichever strategy actually painted the DOM. Does NOT
|
|
76
|
+
* write to the DOM.
|
|
77
|
+
*/
|
|
78
|
+
static syncFromDom(): void;
|
|
45
79
|
/**
|
|
46
80
|
* Reads the `prefers-color-scheme` system setting
|
|
47
81
|
*/
|
|
@@ -51,15 +85,16 @@ export declare class ColorScheme {
|
|
|
51
85
|
*/
|
|
52
86
|
static getLocalValue(fallback?: Scheme): Scheme;
|
|
53
87
|
/**
|
|
54
|
-
*
|
|
88
|
+
* Backward-compatible alias for `current`.
|
|
55
89
|
*/
|
|
56
90
|
static getValue(): Scheme;
|
|
57
91
|
/**
|
|
58
|
-
*
|
|
92
|
+
* Toggles between light and dark, persists to localStorage, and updates the DOM.
|
|
59
93
|
*/
|
|
60
94
|
static toggle(): void;
|
|
61
95
|
/**
|
|
62
|
-
* Resets color scheme to system preference by removing localStorage value
|
|
96
|
+
* Resets color scheme to system preference by removing the localStorage value
|
|
97
|
+
* and re-applying the resolved scheme.
|
|
63
98
|
*/
|
|
64
99
|
static reset(): void;
|
|
65
100
|
}
|
|
@@ -1,57 +1,103 @@
|
|
|
1
|
+
const DEFAULT_KEY = "stuic-color-scheme";
|
|
2
|
+
let _key = DEFAULT_KEY;
|
|
1
3
|
let _current = $state("light");
|
|
2
4
|
function _compute() {
|
|
3
|
-
|
|
5
|
+
const local = globalThis.localStorage?.getItem(_key);
|
|
6
|
+
if (local === "dark" || local === "light")
|
|
7
|
+
return local;
|
|
8
|
+
return ColorScheme.getSystemValue();
|
|
9
|
+
}
|
|
10
|
+
function _applyDom(scheme) {
|
|
11
|
+
globalThis?.document?.documentElement.classList.toggle(ColorScheme.DARK, scheme === ColorScheme.DARK);
|
|
4
12
|
}
|
|
5
13
|
function _sync() {
|
|
6
14
|
const next = _compute();
|
|
7
|
-
if (next !== _current)
|
|
15
|
+
if (next !== _current) {
|
|
8
16
|
_current = next;
|
|
17
|
+
_applyDom(next);
|
|
18
|
+
}
|
|
9
19
|
}
|
|
10
20
|
/**
|
|
11
21
|
* A utility class for managing light/dark color scheme preferences.
|
|
12
22
|
*
|
|
13
|
-
* Handles
|
|
23
|
+
* Handles localStorage persistence and DOM class toggling.
|
|
14
24
|
* Works with Tailwind CSS dark mode (class-based strategy).
|
|
15
25
|
*
|
|
16
26
|
* The `ColorScheme.current` getter is reactive (Svelte 5 `$state`): reading it
|
|
17
|
-
* inside a `$derived`/`$effect`/template will react to toggles
|
|
18
|
-
* `storage` events
|
|
27
|
+
* inside a `$derived`/`$effect`/template will react to toggles and cross-tab
|
|
28
|
+
* `storage` events.
|
|
19
29
|
*
|
|
20
30
|
* @example
|
|
21
31
|
* ```ts
|
|
22
32
|
* // Reactive current value (use in templates / $derived / $effect):
|
|
23
33
|
* const scheme = ColorScheme.current; // 'light' or 'dark'
|
|
24
34
|
*
|
|
25
|
-
* // Backward-compatible non-reactive read:
|
|
26
|
-
* const v = ColorScheme.getValue();
|
|
27
|
-
*
|
|
28
35
|
* // Toggle between light and dark
|
|
29
36
|
* ColorScheme.toggle();
|
|
30
37
|
*
|
|
31
|
-
* // Check system preference only
|
|
32
|
-
* const systemPref = ColorScheme.getSystemValue();
|
|
33
|
-
*
|
|
34
38
|
* // Reset to system preference
|
|
35
39
|
* ColorScheme.reset();
|
|
40
|
+
*
|
|
41
|
+
* // Use a custom localStorage key (call early in app boot):
|
|
42
|
+
* ColorScheme.configure({ key: "myapp:color-scheme" });
|
|
36
43
|
* ```
|
|
37
44
|
*
|
|
38
45
|
* @remarks
|
|
39
|
-
* -
|
|
46
|
+
* - Default localStorage key: "stuic-color-scheme" (override via `configure`)
|
|
40
47
|
* - Adds/removes "dark" class on `<html>` element
|
|
41
48
|
* - Works with Tailwind's `darkMode: 'class'` configuration
|
|
49
|
+
* - Pair with `<ColorSchemeLocal />` or `<ColorSchemeSystemAware />` for
|
|
50
|
+
* FOUC-free initial paint
|
|
42
51
|
*/
|
|
43
52
|
export class ColorScheme {
|
|
44
|
-
static KEY = "stuic-color-scheme";
|
|
45
53
|
static DARK = "dark";
|
|
46
54
|
static LIGHT = "light";
|
|
55
|
+
/**
|
|
56
|
+
* The active localStorage key. Default is `"stuic-color-scheme"`. Override via
|
|
57
|
+
* `ColorScheme.configure({ key })` or the `key` prop on the hydration components.
|
|
58
|
+
*/
|
|
59
|
+
static get KEY() {
|
|
60
|
+
return _key;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Configure the runtime. Call early in app boot, before any consumer reads
|
|
64
|
+
* `ColorScheme.current`. Mutates module state; safe to call more than once
|
|
65
|
+
* (last write wins). Calling without changes is a no-op.
|
|
66
|
+
*
|
|
67
|
+
* Also writes `window.__COLOR_SCHEME_KEY__` so a subsequent hydration
|
|
68
|
+
* component mount (or any external bootstrap script that reads the global)
|
|
69
|
+
* stays in sync with the runtime.
|
|
70
|
+
*/
|
|
71
|
+
static configure(opts) {
|
|
72
|
+
if (opts?.key && opts.key !== _key) {
|
|
73
|
+
_key = opts.key;
|
|
74
|
+
if (typeof window !== "undefined")
|
|
75
|
+
window.__COLOR_SCHEME_KEY__ = opts.key;
|
|
76
|
+
_sync();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
47
79
|
/**
|
|
48
80
|
* Reactive current value. Read inside `$derived`, `$effect`, or a Svelte
|
|
49
|
-
* template to react to scheme changes (including cross-tab `storage`
|
|
50
|
-
* events and OS-level system-preference changes).
|
|
81
|
+
* template to react to scheme changes (including cross-tab `storage` events).
|
|
51
82
|
*/
|
|
52
83
|
static get current() {
|
|
53
84
|
return _current;
|
|
54
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Re-seed `current` from the actual `<html>` class state. Used by the
|
|
88
|
+
* hydration components after their inline bootstrap `<script>` has run, so
|
|
89
|
+
* the runtime matches whichever strategy actually painted the DOM. Does NOT
|
|
90
|
+
* write to the DOM.
|
|
91
|
+
*/
|
|
92
|
+
static syncFromDom() {
|
|
93
|
+
if (typeof document === "undefined")
|
|
94
|
+
return;
|
|
95
|
+
const next = document.documentElement.classList.contains(ColorScheme.DARK)
|
|
96
|
+
? ColorScheme.DARK
|
|
97
|
+
: ColorScheme.LIGHT;
|
|
98
|
+
if (next !== _current)
|
|
99
|
+
_current = next;
|
|
100
|
+
}
|
|
55
101
|
/**
|
|
56
102
|
* Reads the `prefers-color-scheme` system setting
|
|
57
103
|
*/
|
|
@@ -64,39 +110,44 @@ export class ColorScheme {
|
|
|
64
110
|
* Reads locally (localStorage) saved value
|
|
65
111
|
*/
|
|
66
112
|
static getLocalValue(fallback = "light") {
|
|
67
|
-
return
|
|
113
|
+
return globalThis.localStorage?.getItem(_key) || fallback;
|
|
68
114
|
}
|
|
69
115
|
/**
|
|
70
|
-
*
|
|
116
|
+
* Backward-compatible alias for `current`.
|
|
71
117
|
*/
|
|
72
118
|
static getValue() {
|
|
73
|
-
return
|
|
119
|
+
return _current;
|
|
74
120
|
}
|
|
75
121
|
/**
|
|
76
|
-
*
|
|
122
|
+
* Toggles between light and dark, persists to localStorage, and updates the DOM.
|
|
77
123
|
*/
|
|
78
124
|
static toggle() {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
125
|
+
const next = _current === ColorScheme.DARK ? ColorScheme.LIGHT : ColorScheme.DARK;
|
|
126
|
+
globalThis.localStorage?.setItem(_key, next);
|
|
127
|
+
_applyDom(next);
|
|
128
|
+
_current = next;
|
|
83
129
|
}
|
|
84
130
|
/**
|
|
85
|
-
* Resets color scheme to system preference by removing localStorage value
|
|
131
|
+
* Resets color scheme to system preference by removing the localStorage value
|
|
132
|
+
* and re-applying the resolved scheme.
|
|
86
133
|
*/
|
|
87
134
|
static reset() {
|
|
88
|
-
globalThis.localStorage?.removeItem(
|
|
89
|
-
globalThis?.document?.documentElement.classList.remove(ColorScheme.DARK, ColorScheme.LIGHT);
|
|
135
|
+
globalThis.localStorage?.removeItem(_key);
|
|
90
136
|
_sync();
|
|
91
137
|
}
|
|
92
138
|
}
|
|
93
139
|
if (typeof window !== "undefined") {
|
|
140
|
+
// If the app declared a custom key via the global (typical place: app.html,
|
|
141
|
+
// before the bootstrap <script> runs), adopt it so the runtime reads/writes
|
|
142
|
+
// the same key the bootstrap painted from.
|
|
143
|
+
if (window.__COLOR_SCHEME_KEY__)
|
|
144
|
+
_key = window.__COLOR_SCHEME_KEY__;
|
|
145
|
+
// Seed from localStorage (with system-pref fallback). Reading from the DOM
|
|
146
|
+
// here is unreliable: module init runs before the hydration component's
|
|
147
|
+
// inline <script> is appended to <head>, so the dark class isn't there yet.
|
|
94
148
|
_current = _compute();
|
|
95
149
|
window.addEventListener("storage", (e) => {
|
|
96
|
-
if (e.key ===
|
|
150
|
+
if (e.key === _key)
|
|
97
151
|
_sync();
|
|
98
152
|
});
|
|
99
|
-
window
|
|
100
|
-
.matchMedia?.(`(prefers-color-scheme: ${ColorScheme.DARK})`)
|
|
101
|
-
.addEventListener("change", () => _sync());
|
|
102
153
|
}
|