@codenhub/theme 0.1.1 → 0.1.2
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 +7 -10
- package/dist/index.d.ts +10 -9
- package/docs/changelog/0.1.2.md +15 -0
- package/docs/changelog/index.md +9 -0
- package/docs/index.md +30 -22
- package/docs/reference/index.md +381 -0
- package/docs/ssr-and-pre-paint.md +46 -0
- package/docs/tokens-and-persistence.md +51 -0
- package/llms-full.txt +213 -204
- package/llms.txt +19 -13
- package/package.json +25 -22
- package/docs/reference.md +0 -104
package/README.md
CHANGED
|
@@ -26,22 +26,19 @@ theme.destroy({ revertDom: true });
|
|
|
26
26
|
## Documentation
|
|
27
27
|
|
|
28
28
|
- [Documentation overview](docs/index.md)
|
|
29
|
-
- [
|
|
29
|
+
- [Tokens, persistence, and cross-tab sync](docs/tokens-and-persistence.md)
|
|
30
|
+
- [SSR, pre-paint, and Tailwind](docs/ssr-and-pre-paint.md)
|
|
31
|
+
- [API reference](docs/reference/index.md)
|
|
30
32
|
|
|
31
33
|
## Requirements
|
|
32
34
|
|
|
33
|
-
- Browser integration uses `document.documentElement`, `localStorage`,
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
default theme.
|
|
37
|
-
- Consumers provide CSS selectors, variables, visual tokens, and any pre-paint
|
|
38
|
-
script needed to prevent a theme flash.
|
|
35
|
+
- Browser integration uses `document.documentElement`, `localStorage`, `matchMedia`, `storage` events, and `CustomEvent`.
|
|
36
|
+
- SSR is supported by skipping unavailable browser work and using the configured default theme.
|
|
37
|
+
- Consumers provide CSS selectors, variables, visual tokens, and any pre-paint script needed to prevent a theme flash.
|
|
39
38
|
|
|
40
39
|
## Notes
|
|
41
40
|
|
|
42
|
-
Construction validates theme names, mappings, attributes, classes, and token
|
|
43
|
-
schemas and throws on invalid configuration. Storage failures are reported to
|
|
44
|
-
the console and treated as unavailable storage.
|
|
41
|
+
Construction validates theme names, mappings, attributes, classes, and token schemas and throws on invalid configuration. Storage failures are reported to the console and treated as unavailable storage.
|
|
45
42
|
|
|
46
43
|
## License
|
|
47
44
|
|
package/dist/index.d.ts
CHANGED
|
@@ -94,11 +94,10 @@ interface Theme<TSchema extends Record<string, string> = Record<string, string>>
|
|
|
94
94
|
*/
|
|
95
95
|
set(name: string, tokens?: Partial<Record<keyof TSchema, string>>): ThemeDefinition<TSchema>;
|
|
96
96
|
/**
|
|
97
|
-
* Switches
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* the active theme
|
|
101
|
-
* or `systemTheme.dark`.
|
|
97
|
+
* Switches away from the active theme and persists the change. If the active theme configures a
|
|
98
|
+
* `pairedTheme`, that theme is activated. Otherwise the next theme is selected from
|
|
99
|
+
* `systemTheme.light` or `systemTheme.dark` based on the active theme's `colorScheme`, not by
|
|
100
|
+
* cycling the active theme name.
|
|
102
101
|
*
|
|
103
102
|
* @param tokens - Optional runtime override token values to apply. Active overrides persist across subsequent theme changes unless cleared (by passing new overrides or an empty object).
|
|
104
103
|
* @returns The activated `ThemeDefinition` with merged and resolved tokens.
|
|
@@ -140,9 +139,10 @@ interface Theme<TSchema extends Record<string, string> = Record<string, string>>
|
|
|
140
139
|
*/
|
|
141
140
|
getPrePaintScript(): string;
|
|
142
141
|
/**
|
|
143
|
-
* Cleans up the theme instance by removing all in-process change listeners
|
|
144
|
-
* preference media query listener
|
|
145
|
-
* configured `defaultTheme` so the instance can be safely
|
|
142
|
+
* Cleans up the theme instance by removing all in-process change listeners, the system
|
|
143
|
+
* preference media query listener, and the cross-tab storage listener. Resets active tokens
|
|
144
|
+
* and the active theme name to the configured `defaultTheme` so the instance can be safely
|
|
145
|
+
* re-initialized with `init()`.
|
|
146
146
|
*
|
|
147
147
|
* @param options - Optional cleanup options. Set `revertDom: true` to remove configured DOM attributes, classes, and CSS custom properties applied to `document.documentElement`.
|
|
148
148
|
* @sideEffect Removes event listeners from `window` and clears internal subscriber sets. If `revertDom: true`, removes theme attributes, classes, and custom properties from the DOM root.
|
|
@@ -166,7 +166,8 @@ declare const DARK_THEME: ThemeDefinition;
|
|
|
166
166
|
*
|
|
167
167
|
* @param options - Configuration options for theme definitions, persistence keys, DOM attributes, custom class resolvers, and dynamic token schemas.
|
|
168
168
|
* @returns A `Theme` instance.
|
|
169
|
-
* @throws {Error} If configured theme names are empty, duplicated, invalid for CSS class application,
|
|
169
|
+
* @throws {Error} If configured theme names are empty, duplicated, invalid for CSS class application, have an
|
|
170
|
+
* invalid `colorScheme`, or if the default/system themes are not present in the configured list.
|
|
170
171
|
*/
|
|
171
172
|
declare function createTheme<TSchema extends Record<string, string> = Record<string, string>>(options?: ThemeOptions<TSchema>): Theme<TSchema>;
|
|
172
173
|
//#endregion
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 0.1.2
|
|
3
|
+
date: 2026-09-15
|
|
4
|
+
description: A generated API reference and reorganized documentation.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.2
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- A generated API reference, `docs/reference/index.md`, covering every exported symbol from its TSDoc directly — regenerated on every release instead of hand-maintained separately, so it can't drift out of sync with the source.
|
|
12
|
+
|
|
13
|
+
## Changed
|
|
14
|
+
|
|
15
|
+
- Documentation split from one page, `docs/reference.md`, into three focused ones: `docs/index.md` (setup and configuration), `docs/tokens-and-persistence.md` (token resolution, `skipComputed`, persistence, cross-tab sync), and `docs/ssr-and-pre-paint.md` (`getPrePaintScript()`, SSR fallback, Tailwind's `isTailwindCss`, `shouldApplyClass`, `destroy({ revertDom: true })`), plus the generated reference above. Update any link that pointed at `docs/reference.md`.
|
package/docs/index.md
CHANGED
|
@@ -4,13 +4,7 @@ title: Overview
|
|
|
4
4
|
|
|
5
5
|
# Manage Browser Themes
|
|
6
6
|
|
|
7
|
-
`@codenhub/theme`
|
|
8
|
-
state to the document root, synchronizes browser tabs, exposes change events,
|
|
9
|
-
and maps typed tokens to CSS custom properties.
|
|
10
|
-
|
|
11
|
-
It fits browser applications that need one owner for theme preference and DOM
|
|
12
|
-
synchronization while keeping selectors, visual design, and CSS in application
|
|
13
|
-
code.
|
|
7
|
+
`@codenhub/theme` owns one thing for a browser application: deciding which theme is active, keeping it in sync with `localStorage` and the OS `prefers-color-scheme` setting, and reflecting it onto the DOM as an attribute, a class, and CSS custom properties. It fits applications that want one place to own that decision instead of scattering `matchMedia` listeners and `localStorage` reads across the codebase, while keeping selectors, visual design, and CSS entirely in application code.
|
|
14
8
|
|
|
15
9
|
## Setup
|
|
16
10
|
|
|
@@ -29,24 +23,38 @@ const theme = createTheme().init();
|
|
|
29
23
|
theme.set("dark");
|
|
30
24
|
```
|
|
31
25
|
|
|
32
|
-
Call `destroy()` when the manager's owner is
|
|
33
|
-
explicit preference and follows system preference when appropriate.
|
|
26
|
+
`createTheme()` with no arguments configures the built-in `light` and `dark` themes. `init()` resolves the theme to apply — a stored preference if one is valid, otherwise the OS preference — and applies it to `document.documentElement`. Call `destroy()` when the manager's owner is torn down, such as in a framework component's cleanup hook; it stops listening but leaves the DOM and stored preference as they were unless told otherwise (see [Tokens, persistence, and cross-tab sync](tokens-and-persistence.md)).
|
|
34
27
|
|
|
35
|
-
|
|
28
|
+
### Configuration
|
|
29
|
+
|
|
30
|
+
Most applications configure at least `themes` and `tokenSchema` up front:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createTheme } from "@codenhub/theme";
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
const theme = createTheme({
|
|
36
|
+
themes: [
|
|
37
|
+
{ name: "light", colorScheme: "light", tokens: { primary: "#171717" } },
|
|
38
|
+
{ name: "dark", colorScheme: "dark", tokens: { primary: "#f9fafb" } },
|
|
39
|
+
],
|
|
40
|
+
tokenSchema: { primary: "--color-primary" },
|
|
41
|
+
storageKey: "app-theme-preference",
|
|
42
|
+
isTailwindCss: true,
|
|
43
|
+
}).init();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`themes` replaces the built-in list entirely — include `light` and `dark` (or whatever names `defaultTheme` and `systemTheme` point at) when defining custom themes. `tokenSchema` maps the typed token names used in `ThemeDefinition.tokens` and `get()` to the CSS custom property each one writes to `document.documentElement`. See [Tokens, persistence, and cross-tab sync](tokens-and-persistence.md) for how token values are resolved and stored, and [SSR, pre-paint, and Tailwind](ssr-and-pre-paint.md) for flash-of-unstyled-content prevention and OS-preference-only applications like `isTailwindCss`.
|
|
47
|
+
|
|
48
|
+
Construction validates every option and throws on invalid configuration: empty or duplicate theme names, a `defaultTheme` or `systemTheme` name that is not in `themes`, an invalid `colorScheme`, or a `shouldApplyClass` resolver that would produce an empty or whitespace-containing class.
|
|
49
|
+
|
|
50
|
+
## Requirements
|
|
43
51
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
- Browser integration uses `document.documentElement`, `localStorage`, `matchMedia`, `storage` events, and `CustomEvent`. Every one of these is read defensively: an unavailable or throwing API is treated as absent rather than crashing the caller.
|
|
53
|
+
- SSR is supported by skipping unavailable browser work and using the configured `defaultTheme`. The package cannot produce server HTML attributes or prevent a flash on its own — see [SSR, pre-paint, and Tailwind](ssr-and-pre-paint.md).
|
|
54
|
+
- Consumers provide CSS selectors, variables, and visual tokens. The package only ever writes an attribute, optional classes, and CSS custom properties — it ships no CSS or token values beyond the built-in `light`/`dark` definitions' names.
|
|
47
55
|
|
|
48
56
|
## Next steps
|
|
49
57
|
|
|
50
|
-
- [
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
- [Tokens, persistence, and cross-tab sync](tokens-and-persistence.md): How `get()` resolves token values, how preferences persist to `localStorage` and sync across tabs, and how to read or clear the stored preference.
|
|
59
|
+
- [SSR, pre-paint, and Tailwind](ssr-and-pre-paint.md): Preventing a flash of unstyled content before hydration, server-rendering considerations, and toggling Tailwind's `dark` class.
|
|
60
|
+
- [API reference](reference/index.md): Every exported function, type, and interface member with its full signature.
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: /
|
|
3
|
+
group: Reference
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- Generated by `pnpm generate` from packages/theme/src. Do not edit. -->
|
|
7
|
+
|
|
8
|
+
# @codenhub/theme
|
|
9
|
+
|
|
10
|
+
## Functions
|
|
11
|
+
|
|
12
|
+
### createTheme
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
export declare function createTheme<TSchema extends Record<string, string> = Record<string, string>>(options?: ThemeOptions<TSchema>): Theme<TSchema>;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Factory function that creates and returns a `Theme` instance.
|
|
19
|
+
|
|
20
|
+
**Parameters**
|
|
21
|
+
|
|
22
|
+
- `options` — Configuration options for theme definitions, persistence keys, DOM attributes, custom class resolvers, and dynamic token schemas.
|
|
23
|
+
|
|
24
|
+
**Returns** — A `Theme` instance.
|
|
25
|
+
|
|
26
|
+
**Throws** — If configured theme names are empty, duplicated, invalid for CSS class application, have an invalid `colorScheme`, or if the default/system themes are not present in the configured list.
|
|
27
|
+
|
|
28
|
+
### getPrePaintScript
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
export declare function getPrePaintScript<TSchema extends Record<string, string> = Record<string, string>>(options?: ThemeOptions<TSchema>): string;
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Generates a synchronous inline IIFE script string to inject into document `<head>`. Prevents Flash of Unstyled Content (FOUC) by applying storage or system theme before render.
|
|
35
|
+
|
|
36
|
+
**Parameters**
|
|
37
|
+
|
|
38
|
+
- `options` — Configuration options used to determine storage keys, attributes, default/system themes, custom class resolvers, and token schemas.
|
|
39
|
+
|
|
40
|
+
**Returns** — Minified JavaScript script string.
|
|
41
|
+
|
|
42
|
+
## Interfaces
|
|
43
|
+
|
|
44
|
+
### SystemThemeMap
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
export interface SystemThemeMap
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Mapping from OS color-scheme preferences to configured theme names.
|
|
51
|
+
|
|
52
|
+
#### dark
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
dark: string;
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Configured theme name used when the OS preference is dark.
|
|
59
|
+
|
|
60
|
+
#### light
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
light: string;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Configured theme name used when the OS preference is light or no dark preference is detected.
|
|
67
|
+
|
|
68
|
+
### Theme
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
export interface Theme<TSchema extends Record<string, string> = Record<string, string>>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Core theme preference handler. Manages initialization, switching themes, persistence to localStorage, synchronizing with the OS prefers-color-scheme preference, dynamic token mapping to CSS Custom Properties, and dispatching change events.
|
|
75
|
+
|
|
76
|
+
#### clearPreference
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
clearPreference(): ThemeDefinition<TSchema>;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Removes the explicit user theme preference from storage and resets the theme to match the OS system preference.
|
|
83
|
+
|
|
84
|
+
#### destroy
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
destroy(options?: { revertDom?: boolean; }): void;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Cleans up the theme instance by removing all in-process change listeners, the system preference media query listener, and the cross-tab storage listener. Resets active tokens and the active theme name to the configured `defaultTheme` so the instance can be safely re-initialized with `init()`.
|
|
91
|
+
|
|
92
|
+
**Parameters**
|
|
93
|
+
|
|
94
|
+
- `options` — Optional cleanup options. Set `revertDom: true` to remove configured DOM attributes, classes, and CSS custom properties applied to `document.documentElement`.
|
|
95
|
+
|
|
96
|
+
#### get
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
get(options?: { skipComputed?: boolean; }): ThemeDefinition<TSchema>;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Retrieves the active theme configuration including static and computed tokens.
|
|
103
|
+
|
|
104
|
+
Token values are merged in this priority order (last wins):
|
|
105
|
+
|
|
106
|
+
1. CSS computed style — values read from `window.getComputedStyle` for tokens not defined in JS (unless `options.skipComputed` is true).
|
|
107
|
+
2. Theme static tokens — values defined in `ThemeDefinition.tokens` for the active theme.
|
|
108
|
+
3. Runtime overrides — values passed to `init()`, `set()`, `toggle()`, or other methods.
|
|
109
|
+
|
|
110
|
+
**Parameters**
|
|
111
|
+
|
|
112
|
+
- `options` — Optional getter options. Set `skipComputed: true` to avoid reading computed styles from the DOM via `window.getComputedStyle`, preventing potential layout reflows.
|
|
113
|
+
|
|
114
|
+
#### getPrePaintScript
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
getPrePaintScript(): string;
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Generates a synchronous inline IIFE script string to inject into document `<head>`. Prevents Flash of Unstyled Content (FOUC) by applying storage or system theme before render.
|
|
121
|
+
|
|
122
|
+
#### getStored
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
getStored(): string | null;
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Retrieves the currently stored theme preference name from `localStorage`.
|
|
129
|
+
|
|
130
|
+
#### getSystem
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
getSystem(): ThemeDefinition<TSchema>;
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Resolves the configured theme that matches the active OS color-scheme preference.
|
|
137
|
+
|
|
138
|
+
#### init
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
init(tokens?: Partial<Record<keyof TSchema, string>>): this;
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Initializes the theme manager. Resolves the active theme (using the stored preference if valid, falling back to the current OS color-scheme preference), applies classes/attributes to the DOM, and registers the media query listener for automatic system preference updates.
|
|
145
|
+
|
|
146
|
+
**Parameters**
|
|
147
|
+
|
|
148
|
+
- `tokens` — Optional runtime override token values to merge and apply.
|
|
149
|
+
|
|
150
|
+
#### set
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
set(name: string, tokens?: Partial<Record<keyof TSchema, string>>): ThemeDefinition<TSchema>;
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Activates a configured theme by name and updates the stored preference in `localStorage`.
|
|
157
|
+
|
|
158
|
+
**Parameters**
|
|
159
|
+
|
|
160
|
+
- `name` — The name of the configured theme to activate.
|
|
161
|
+
- `tokens` — Optional runtime override token values to apply. Active overrides persist across subsequent theme changes unless cleared (by passing new overrides or an empty object).
|
|
162
|
+
|
|
163
|
+
#### subscribe
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
subscribe(listener: ThemeChangeListener<TSchema>): () => void;
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Registers a callback listener to receive notifications when the theme or its tokens change.
|
|
170
|
+
|
|
171
|
+
**Parameters**
|
|
172
|
+
|
|
173
|
+
- `listener` — Callback function invoked on theme changes.
|
|
174
|
+
|
|
175
|
+
#### toggle
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
toggle(tokens?: Partial<Record<keyof TSchema, string>>): ThemeDefinition<TSchema>;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Switches away from the active theme and persists the change. If the active theme configures a `pairedTheme`, that theme is activated. Otherwise the next theme is selected from `systemTheme.light` or `systemTheme.dark` based on the active theme's `colorScheme`, not by cycling the active theme name.
|
|
182
|
+
|
|
183
|
+
**Parameters**
|
|
184
|
+
|
|
185
|
+
- `tokens` — Optional runtime override token values to apply. Active overrides persist across subsequent theme changes unless cleared (by passing new overrides or an empty object).
|
|
186
|
+
|
|
187
|
+
### ThemeChangeDetail
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
export interface ThemeChangeDetail<TSchema extends Record<string, string> = Record<string, string>>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Payload passed to subscribers and the browser `themechange` event after a theme change.
|
|
194
|
+
|
|
195
|
+
#### name
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
name: string;
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Active theme name after the change.
|
|
202
|
+
|
|
203
|
+
#### source
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
source: ThemeChangeSource;
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Operation or browser signal that caused the change notification.
|
|
210
|
+
|
|
211
|
+
#### theme
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
theme: ThemeDefinition<TSchema>;
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Active theme definition after the change.
|
|
218
|
+
|
|
219
|
+
### ThemeDefinition
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
export interface ThemeDefinition<TSchema extends Record<string, string> = Record<string, string>>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Theme option stored, applied to the configured DOM attribute, and mapped to the browser color scheme.
|
|
226
|
+
|
|
227
|
+
#### colorScheme
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
colorScheme: "light" | "dark";
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Browser color scheme applied to `document.documentElement.style.colorScheme`.
|
|
234
|
+
|
|
235
|
+
#### name
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
name: string;
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Unique configured theme name used for storage, DOM attributes, and generated default classes.
|
|
242
|
+
|
|
243
|
+
#### pairedTheme
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
pairedTheme?: string;
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Optional theme name activated when calling `toggle()` from this theme.
|
|
250
|
+
|
|
251
|
+
#### tokens
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
tokens?: Partial<Record<keyof TSchema, string>>;
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Optional theme-specific static token values.
|
|
258
|
+
|
|
259
|
+
### ThemeOptions
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
export interface ThemeOptions<TSchema extends Record<string, string> = Record<string, string>>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Configuration for theme definitions, persistence, DOM application, and system preference mapping.
|
|
266
|
+
|
|
267
|
+
#### attribute
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
attribute?: string;
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Attribute set on `document.documentElement` with the active theme name.
|
|
274
|
+
|
|
275
|
+
#### defaultTheme
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
defaultTheme?: string;
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Configured theme name used before initialization and when browser APIs are unavailable.
|
|
282
|
+
|
|
283
|
+
#### isTailwindCss
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
isTailwindCss?: boolean;
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Whether to toggle Tailwind CSS's `dark` class for themes with `colorScheme: "dark"`.
|
|
290
|
+
|
|
291
|
+
#### shouldApplyClass
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
shouldApplyClass?: boolean | ThemeClassResolver<TSchema>;
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Whether and how to apply a theme-specific class to `document.documentElement`.
|
|
298
|
+
|
|
299
|
+
#### storageKey
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
storageKey?: string;
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
`localStorage` key used for explicit user preferences.
|
|
306
|
+
|
|
307
|
+
#### systemTheme
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
systemTheme?: SystemThemeMap;
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Configured theme names selected for OS light and dark color-scheme preferences.
|
|
314
|
+
|
|
315
|
+
#### themes
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
themes?: readonly ThemeDefinition<TSchema>[];
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Available themes. Names must be unique, non-empty, and valid default class tokens when `shouldApplyClass` is `true`.
|
|
322
|
+
|
|
323
|
+
#### tokenSchema
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
tokenSchema?: TSchema;
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Schema mapping theme token names to their corresponding CSS Custom Property names.
|
|
330
|
+
|
|
331
|
+
## Type aliases
|
|
332
|
+
|
|
333
|
+
### ThemeChangeListener
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
export type ThemeChangeListener<TSchema extends Record<string, string> = Record<string, string>> = (detail: ThemeChangeDetail<TSchema>) => void;
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
In-process callback registered with `Theme.subscribe()` for applied theme changes.
|
|
340
|
+
|
|
341
|
+
### ThemeChangeSource
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
export type ThemeChangeSource = "init" | "set" | "toggle" | "clearPreference" | "system";
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Reason a theme change notification was emitted.
|
|
348
|
+
|
|
349
|
+
### ThemeClassResolver
|
|
350
|
+
|
|
351
|
+
```ts
|
|
352
|
+
export type ThemeClassResolver<TSchema extends Record<string, string> = Record<string, string>> = (theme: ThemeDefinition<TSchema>) => string;
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Resolves the single DOM class token applied for a theme when custom class application is enabled.
|
|
356
|
+
|
|
357
|
+
## Variables
|
|
358
|
+
|
|
359
|
+
### DARK_THEME
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
export declare const DARK_THEME: ThemeDefinition;
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Built-in dark theme used by default and available for custom theme lists.
|
|
366
|
+
|
|
367
|
+
### LIGHT_THEME
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
export declare const LIGHT_THEME: ThemeDefinition;
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Built-in light theme used by default and available for custom theme lists.
|
|
374
|
+
|
|
375
|
+
### THEME_CHANGE_EVENT
|
|
376
|
+
|
|
377
|
+
```ts
|
|
378
|
+
export declare const THEME_CHANGE_EVENT = "themechange";
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Window event name dispatched with `ThemeChangeDetail` after a theme change is applied in browser environments.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SSR, Pre-Paint, and Tailwind
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# SSR, Pre-Paint, and Tailwind
|
|
6
|
+
|
|
7
|
+
## Preventing a flash of unstyled content
|
|
8
|
+
|
|
9
|
+
A client-side `init()` call runs after the page has already painted once, which is visible as a flash from the default theme to the resolved one. `getPrePaintScript()` — available as a method on an existing manager, or as the standalone `getPrePaintScript(options)` export when no manager exists yet — returns a synchronous, minified inline IIFE string that duplicates the same stored-preference-then-system-preference resolution, and applies the configured attribute, classes, and any static tokens before the browser paints:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { getPrePaintScript } from "@codenhub/theme";
|
|
13
|
+
|
|
14
|
+
const script = getPrePaintScript({ storageKey: "app-theme-preference" });
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Inject the returned string into a blocking `<script>` in the document `<head>`, before any stylesheet or content that depends on the theme:
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<head>
|
|
21
|
+
<script>
|
|
22
|
+
/* inline the string returned by getPrePaintScript() here */
|
|
23
|
+
</script>
|
|
24
|
+
</head>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Pass the same `themes`, `tokenSchema`, `defaultTheme`, `systemTheme`, `storageKey`, `attribute`, `shouldApplyClass`, and `isTailwindCss` options used to construct the manager, so the pre-paint script and the later `init()` call resolve to the same theme. `getPrePaintScript()` only serializes **static** tokens from each theme's `ThemeDefinition.tokens` — and only when `tokenSchema` is passed to it — runtime overrides passed to `init(tokens)` are applied after hydration, during client-side execution, and cannot be part of a script that runs before any application code.
|
|
28
|
+
|
|
29
|
+
## Server-side rendering
|
|
30
|
+
|
|
31
|
+
Without browser APIs, `Theme` methods skip storage reads/writes, DOM updates, and listener registration; `getSystem()` falls back to `defaultTheme`. Every method call remains safe to make during SSR — nothing throws for a missing `window`, `document`, or `localStorage` — but the package cannot produce server-rendered HTML attributes on its own. To avoid a flash on a server-rendered page, either:
|
|
32
|
+
|
|
33
|
+
- Render the server markup with the same attribute/class the pre-paint script would apply (requiring the server to read the same cookie or header a real theme service would use), or
|
|
34
|
+
- Rely on the pre-paint script above to correct the DOM before first paint, accepting that server-rendered markup itself does not carry theme state.
|
|
35
|
+
|
|
36
|
+
Keep any server-side resolution logic — stored names, system mapping, storage key, attribute, classes, color scheme — aligned with the options passed to `createTheme()` and `getPrePaintScript()`; a mismatch reintroduces the flash it exists to prevent.
|
|
37
|
+
|
|
38
|
+
## Tailwind's `dark` class
|
|
39
|
+
|
|
40
|
+
Set `isTailwindCss: true` to toggle Tailwind CSS's `dark` class on `document.documentElement` alongside the configured attribute, for every theme whose `colorScheme` is `"dark"`. This is independent of `shouldApplyClass` (below) — a Tailwind app commonly wants both the `dark` class for Tailwind's `dark:` variant and, when `shouldApplyClass` is left at its default, a `theme-${name}` class for custom per-theme CSS.
|
|
41
|
+
|
|
42
|
+
## Classes and cleanup
|
|
43
|
+
|
|
44
|
+
`shouldApplyClass` controls whether and how a class is applied to `document.documentElement` alongside the attribute: `true` (the default) applies `theme-${name}`, `false` applies no class, and a `ThemeClassResolver` function receives the active `ThemeDefinition` and returns one custom class token — throwing if it returns an empty or whitespace-containing string.
|
|
45
|
+
|
|
46
|
+
`destroy(options?)` removes the media-query and storage listeners and clears in-process subscribers and runtime tokens, leaving the instance safe to `init()` again. By default it does **not** touch the DOM or stored preference. Pass `{ revertDom: true }` to also remove the configured attribute, classes, and CSS custom properties from `document.documentElement` — useful when unmounting a scoped theme manager that should leave no trace, such as in a component test or a preview pane.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tokens, Persistence, and Cross-Tab Sync
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Tokens, Persistence, and Cross-Tab Sync
|
|
6
|
+
|
|
7
|
+
## Token resolution
|
|
8
|
+
|
|
9
|
+
`tokenSchema` maps typed token names to the CSS custom property each one writes, such as `{ primary: "--color-primary" }`. Once configured, `get()` returns the active `ThemeDefinition` with every schema key resolved from three sources, in this priority order (last wins):
|
|
10
|
+
|
|
11
|
+
1. **Computed style** — for a token not defined in JS, the value is read from `window.getComputedStyle(document.documentElement)` in browser environments.
|
|
12
|
+
2. **Theme static tokens** — values set on the active theme's own `ThemeDefinition.tokens`.
|
|
13
|
+
3. **Runtime overrides** — values passed to `init()`, `set()`, or `toggle()`.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
const theme = createTheme({
|
|
17
|
+
themes: [{ name: "brand", colorScheme: "light", tokens: { accent: "#ff6600" } }],
|
|
18
|
+
tokenSchema: { accent: "--color-accent" },
|
|
19
|
+
}).init();
|
|
20
|
+
|
|
21
|
+
theme.set("brand", { accent: "#00c853" }); // runtime override wins over the static "#ff6600"
|
|
22
|
+
theme.get().tokens?.accent; // "#00c853"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Reading computed values can force a synchronous layout reflow. Pass `{ skipComputed: true }` to `get()` to skip that source and avoid the reflow when only the JS-known values are needed.
|
|
26
|
+
|
|
27
|
+
Runtime overrides persist across subsequent theme changes until explicitly replaced — pass a new object, including `{}`, to `init()`, `set()`, or `toggle()` to clear or replace them. Passing a token key that is not in `tokenSchema` throws.
|
|
28
|
+
|
|
29
|
+
## Persistence
|
|
30
|
+
|
|
31
|
+
An explicit preference set through `set()` or `toggle()` is written to `localStorage` under `storageKey` (default `"app-theme-preference"`). `getStored()` returns that value when it names a currently configured theme, or `null` when it is unset, invalid, or storage is unavailable (for example during SSR). `clearPreference()` removes the stored value and re-applies whichever theme `getSystem()` currently resolves to.
|
|
32
|
+
|
|
33
|
+
Storage reads, writes, and removals that throw — a full quota, a disabled storage API, a private-browsing restriction — are logged with `console.error` and treated the same as unavailable storage; they never throw out of `Theme` methods.
|
|
34
|
+
|
|
35
|
+
## Cross-tab sync
|
|
36
|
+
|
|
37
|
+
Every tab running `createTheme().init()` against the same `storageKey` stays in sync: a `storage` event fires in every other tab when one tab writes a new preference, and each one applies the change if it names a valid configured theme. A tab with its own runtime token overrides keeps them — only the active theme name changes from cross-tab sync, not tokens passed in-process.
|
|
38
|
+
|
|
39
|
+
The OS `prefers-color-scheme` media query applies automatically only while no valid stored preference exists. Once a tab (or a previous session) has stored an explicit preference, later system-preference changes are ignored until `clearPreference()` runs.
|
|
40
|
+
|
|
41
|
+
## Reacting to changes
|
|
42
|
+
|
|
43
|
+
`subscribe(listener)` registers a callback invoked after every applied change — from `init()`, `set()`, `toggle()`, `clearPreference()`, or an accepted `system` or cross-tab update — and returns an unsubscribe function:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
const unsubscribe = theme.subscribe(({ name, source }) => {
|
|
47
|
+
console.log(`theme is now "${name}" (${source})`);
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
A subscriber that throws is logged and does not stop other subscribers from running. Browsers also receive a `window` `CustomEvent` named by the exported `THEME_CHANGE_EVENT` constant (`"themechange"`) carrying the same detail, for code that prefers DOM events over `subscribe()`.
|
package/llms-full.txt
CHANGED
|
@@ -1,204 +1,213 @@
|
|
|
1
|
-
<!-- Source: README.md -->
|
|
2
|
-
|
|
3
|
-
# @codenhub/theme
|
|
4
|
-
|
|
5
|
-
Zero-dependency browser theme preference, persistence, DOM, and token manager.
|
|
6
|
-
|
|
7
|
-
## Installation
|
|
8
|
-
|
|
9
|
-
```sh
|
|
10
|
-
pnpm add @codenhub/theme
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Usage
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import { createTheme, getPrePaintScript } from "@codenhub/theme";
|
|
17
|
-
|
|
18
|
-
const theme = createTheme().init();
|
|
19
|
-
theme.set("dark");
|
|
20
|
-
|
|
21
|
-
// Get inline IIFE script string for <head> to prevent FOUC:
|
|
22
|
-
const script = theme.getPrePaintScript(); // or standalone getPrePaintScript()
|
|
23
|
-
|
|
24
|
-
// Remove media-query/storage listeners and subscribers on teardown.
|
|
25
|
-
theme.destroy({ revertDom: true });
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Documentation
|
|
29
|
-
|
|
30
|
-
- [Documentation overview](docs/index.md)
|
|
31
|
-
- [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
- Consumers provide CSS selectors, variables, visual tokens, and any pre-paint
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
- [
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
- `
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
- `
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
- `
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
or
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
1
|
+
<!-- Source: README.md -->
|
|
2
|
+
|
|
3
|
+
# @codenhub/theme
|
|
4
|
+
|
|
5
|
+
Zero-dependency browser theme preference, persistence, DOM, and token manager.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @codenhub/theme
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createTheme, getPrePaintScript } from "@codenhub/theme";
|
|
17
|
+
|
|
18
|
+
const theme = createTheme().init();
|
|
19
|
+
theme.set("dark");
|
|
20
|
+
|
|
21
|
+
// Get inline IIFE script string for <head> to prevent FOUC:
|
|
22
|
+
const script = theme.getPrePaintScript(); // or standalone getPrePaintScript()
|
|
23
|
+
|
|
24
|
+
// Remove media-query/storage listeners and subscribers on teardown.
|
|
25
|
+
theme.destroy({ revertDom: true });
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Documentation
|
|
29
|
+
|
|
30
|
+
- [Documentation overview](docs/index.md)
|
|
31
|
+
- [Tokens, persistence, and cross-tab sync](docs/tokens-and-persistence.md)
|
|
32
|
+
- [SSR, pre-paint, and Tailwind](docs/ssr-and-pre-paint.md)
|
|
33
|
+
- [API reference](docs/reference/index.md)
|
|
34
|
+
|
|
35
|
+
## Requirements
|
|
36
|
+
|
|
37
|
+
- Browser integration uses `document.documentElement`, `localStorage`, `matchMedia`, `storage` events, and `CustomEvent`.
|
|
38
|
+
- SSR is supported by skipping unavailable browser work and using the configured default theme.
|
|
39
|
+
- Consumers provide CSS selectors, variables, visual tokens, and any pre-paint script needed to prevent a theme flash.
|
|
40
|
+
|
|
41
|
+
## Notes
|
|
42
|
+
|
|
43
|
+
Construction validates theme names, mappings, attributes, classes, and token schemas and throws on invalid configuration. Storage failures are reported to the console and treated as unavailable storage.
|
|
44
|
+
|
|
45
|
+
## License
|
|
46
|
+
|
|
47
|
+
Licensed under Apache-2.0.
|
|
48
|
+
|
|
49
|
+
<!-- Source: docs/index.md -->
|
|
50
|
+
|
|
51
|
+
# Manage Browser Themes
|
|
52
|
+
|
|
53
|
+
`@codenhub/theme` owns one thing for a browser application: deciding which theme is active, keeping it in sync with `localStorage` and the OS `prefers-color-scheme` setting, and reflecting it onto the DOM as an attribute, a class, and CSS custom properties. It fits applications that want one place to own that decision instead of scattering `matchMedia` listeners and `localStorage` reads across the codebase, while keeping selectors, visual design, and CSS entirely in application code.
|
|
54
|
+
|
|
55
|
+
## Setup
|
|
56
|
+
|
|
57
|
+
### Installation
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
pnpm add @codenhub/theme
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Quick start
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { createTheme } from "@codenhub/theme";
|
|
67
|
+
|
|
68
|
+
const theme = createTheme().init();
|
|
69
|
+
theme.set("dark");
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`createTheme()` with no arguments configures the built-in `light` and `dark` themes. `init()` resolves the theme to apply — a stored preference if one is valid, otherwise the OS preference — and applies it to `document.documentElement`. Call `destroy()` when the manager's owner is torn down, such as in a framework component's cleanup hook; it stops listening but leaves the DOM and stored preference as they were unless told otherwise (see [Tokens, persistence, and cross-tab sync](docs/tokens-and-persistence.md)).
|
|
73
|
+
|
|
74
|
+
### Configuration
|
|
75
|
+
|
|
76
|
+
Most applications configure at least `themes` and `tokenSchema` up front:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { createTheme } from "@codenhub/theme";
|
|
80
|
+
|
|
81
|
+
const theme = createTheme({
|
|
82
|
+
themes: [
|
|
83
|
+
{ name: "light", colorScheme: "light", tokens: { primary: "#171717" } },
|
|
84
|
+
{ name: "dark", colorScheme: "dark", tokens: { primary: "#f9fafb" } },
|
|
85
|
+
],
|
|
86
|
+
tokenSchema: { primary: "--color-primary" },
|
|
87
|
+
storageKey: "app-theme-preference",
|
|
88
|
+
isTailwindCss: true,
|
|
89
|
+
}).init();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`themes` replaces the built-in list entirely — include `light` and `dark` (or whatever names `defaultTheme` and `systemTheme` point at) when defining custom themes. `tokenSchema` maps the typed token names used in `ThemeDefinition.tokens` and `get()` to the CSS custom property each one writes to `document.documentElement`. See [Tokens, persistence, and cross-tab sync](docs/tokens-and-persistence.md) for how token values are resolved and stored, and [SSR, pre-paint, and Tailwind](docs/ssr-and-pre-paint.md) for flash-of-unstyled-content prevention and OS-preference-only applications like `isTailwindCss`.
|
|
93
|
+
|
|
94
|
+
Construction validates every option and throws on invalid configuration: empty or duplicate theme names, a `defaultTheme` or `systemTheme` name that is not in `themes`, an invalid `colorScheme`, or a `shouldApplyClass` resolver that would produce an empty or whitespace-containing class.
|
|
95
|
+
|
|
96
|
+
## Requirements
|
|
97
|
+
|
|
98
|
+
- Browser integration uses `document.documentElement`, `localStorage`, `matchMedia`, `storage` events, and `CustomEvent`. Every one of these is read defensively: an unavailable or throwing API is treated as absent rather than crashing the caller.
|
|
99
|
+
- SSR is supported by skipping unavailable browser work and using the configured `defaultTheme`. The package cannot produce server HTML attributes or prevent a flash on its own — see [SSR, pre-paint, and Tailwind](docs/ssr-and-pre-paint.md).
|
|
100
|
+
- Consumers provide CSS selectors, variables, and visual tokens. The package only ever writes an attribute, optional classes, and CSS custom properties — it ships no CSS or token values beyond the built-in `light`/`dark` definitions' names.
|
|
101
|
+
|
|
102
|
+
## Next steps
|
|
103
|
+
|
|
104
|
+
- [Tokens, persistence, and cross-tab sync](docs/tokens-and-persistence.md): How `get()` resolves token values, how preferences persist to `localStorage` and sync across tabs, and how to read or clear the stored preference.
|
|
105
|
+
- [SSR, pre-paint, and Tailwind](docs/ssr-and-pre-paint.md): Preventing a flash of unstyled content before hydration, server-rendering considerations, and toggling Tailwind's `dark` class.
|
|
106
|
+
- [API reference](docs/reference/index.md): Every exported function, type, and interface member with its full signature.
|
|
107
|
+
|
|
108
|
+
<!-- Source: docs/ssr-and-pre-paint.md -->
|
|
109
|
+
|
|
110
|
+
# SSR, Pre-Paint, and Tailwind
|
|
111
|
+
|
|
112
|
+
## Preventing a flash of unstyled content
|
|
113
|
+
|
|
114
|
+
A client-side `init()` call runs after the page has already painted once, which is visible as a flash from the default theme to the resolved one. `getPrePaintScript()` — available as a method on an existing manager, or as the standalone `getPrePaintScript(options)` export when no manager exists yet — returns a synchronous, minified inline IIFE string that duplicates the same stored-preference-then-system-preference resolution, and applies the configured attribute, classes, and any static tokens before the browser paints:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import { getPrePaintScript } from "@codenhub/theme";
|
|
118
|
+
|
|
119
|
+
const script = getPrePaintScript({ storageKey: "app-theme-preference" });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Inject the returned string into a blocking `<script>` in the document `<head>`, before any stylesheet or content that depends on the theme:
|
|
123
|
+
|
|
124
|
+
```html
|
|
125
|
+
<head>
|
|
126
|
+
<script>
|
|
127
|
+
/* inline the string returned by getPrePaintScript() here */
|
|
128
|
+
</script>
|
|
129
|
+
</head>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Pass the same `themes`, `tokenSchema`, `defaultTheme`, `systemTheme`, `storageKey`, `attribute`, `shouldApplyClass`, and `isTailwindCss` options used to construct the manager, so the pre-paint script and the later `init()` call resolve to the same theme. `getPrePaintScript()` only serializes **static** tokens from each theme's `ThemeDefinition.tokens` — and only when `tokenSchema` is passed to it — runtime overrides passed to `init(tokens)` are applied after hydration, during client-side execution, and cannot be part of a script that runs before any application code.
|
|
133
|
+
|
|
134
|
+
## Server-side rendering
|
|
135
|
+
|
|
136
|
+
Without browser APIs, `Theme` methods skip storage reads/writes, DOM updates, and listener registration; `getSystem()` falls back to `defaultTheme`. Every method call remains safe to make during SSR — nothing throws for a missing `window`, `document`, or `localStorage` — but the package cannot produce server-rendered HTML attributes on its own. To avoid a flash on a server-rendered page, either:
|
|
137
|
+
|
|
138
|
+
- Render the server markup with the same attribute/class the pre-paint script would apply (requiring the server to read the same cookie or header a real theme service would use), or
|
|
139
|
+
- Rely on the pre-paint script above to correct the DOM before first paint, accepting that server-rendered markup itself does not carry theme state.
|
|
140
|
+
|
|
141
|
+
Keep any server-side resolution logic — stored names, system mapping, storage key, attribute, classes, color scheme — aligned with the options passed to `createTheme()` and `getPrePaintScript()`; a mismatch reintroduces the flash it exists to prevent.
|
|
142
|
+
|
|
143
|
+
## Tailwind's `dark` class
|
|
144
|
+
|
|
145
|
+
Set `isTailwindCss: true` to toggle Tailwind CSS's `dark` class on `document.documentElement` alongside the configured attribute, for every theme whose `colorScheme` is `"dark"`. This is independent of `shouldApplyClass` (below) — a Tailwind app commonly wants both the `dark` class for Tailwind's `dark:` variant and, when `shouldApplyClass` is left at its default, a `theme-${name}` class for custom per-theme CSS.
|
|
146
|
+
|
|
147
|
+
## Classes and cleanup
|
|
148
|
+
|
|
149
|
+
`shouldApplyClass` controls whether and how a class is applied to `document.documentElement` alongside the attribute: `true` (the default) applies `theme-${name}`, `false` applies no class, and a `ThemeClassResolver` function receives the active `ThemeDefinition` and returns one custom class token — throwing if it returns an empty or whitespace-containing string.
|
|
150
|
+
|
|
151
|
+
`destroy(options?)` removes the media-query and storage listeners and clears in-process subscribers and runtime tokens, leaving the instance safe to `init()` again. By default it does **not** touch the DOM or stored preference. Pass `{ revertDom: true }` to also remove the configured attribute, classes, and CSS custom properties from `document.documentElement` — useful when unmounting a scoped theme manager that should leave no trace, such as in a component test or a preview pane.
|
|
152
|
+
|
|
153
|
+
<!-- Source: docs/tokens-and-persistence.md -->
|
|
154
|
+
|
|
155
|
+
# Tokens, Persistence, and Cross-Tab Sync
|
|
156
|
+
|
|
157
|
+
## Token resolution
|
|
158
|
+
|
|
159
|
+
`tokenSchema` maps typed token names to the CSS custom property each one writes, such as `{ primary: "--color-primary" }`. Once configured, `get()` returns the active `ThemeDefinition` with every schema key resolved from three sources, in this priority order (last wins):
|
|
160
|
+
|
|
161
|
+
1. **Computed style** — for a token not defined in JS, the value is read from `window.getComputedStyle(document.documentElement)` in browser environments.
|
|
162
|
+
2. **Theme static tokens** — values set on the active theme's own `ThemeDefinition.tokens`.
|
|
163
|
+
3. **Runtime overrides** — values passed to `init()`, `set()`, or `toggle()`.
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
const theme = createTheme({
|
|
167
|
+
themes: [{ name: "brand", colorScheme: "light", tokens: { accent: "#ff6600" } }],
|
|
168
|
+
tokenSchema: { accent: "--color-accent" },
|
|
169
|
+
}).init();
|
|
170
|
+
|
|
171
|
+
theme.set("brand", { accent: "#00c853" }); // runtime override wins over the static "#ff6600"
|
|
172
|
+
theme.get().tokens?.accent; // "#00c853"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Reading computed values can force a synchronous layout reflow. Pass `{ skipComputed: true }` to `get()` to skip that source and avoid the reflow when only the JS-known values are needed.
|
|
176
|
+
|
|
177
|
+
Runtime overrides persist across subsequent theme changes until explicitly replaced — pass a new object, including `{}`, to `init()`, `set()`, or `toggle()` to clear or replace them. Passing a token key that is not in `tokenSchema` throws.
|
|
178
|
+
|
|
179
|
+
## Persistence
|
|
180
|
+
|
|
181
|
+
An explicit preference set through `set()` or `toggle()` is written to `localStorage` under `storageKey` (default `"app-theme-preference"`). `getStored()` returns that value when it names a currently configured theme, or `null` when it is unset, invalid, or storage is unavailable (for example during SSR). `clearPreference()` removes the stored value and re-applies whichever theme `getSystem()` currently resolves to.
|
|
182
|
+
|
|
183
|
+
Storage reads, writes, and removals that throw — a full quota, a disabled storage API, a private-browsing restriction — are logged with `console.error` and treated the same as unavailable storage; they never throw out of `Theme` methods.
|
|
184
|
+
|
|
185
|
+
## Cross-tab sync
|
|
186
|
+
|
|
187
|
+
Every tab running `createTheme().init()` against the same `storageKey` stays in sync: a `storage` event fires in every other tab when one tab writes a new preference, and each one applies the change if it names a valid configured theme. A tab with its own runtime token overrides keeps them — only the active theme name changes from cross-tab sync, not tokens passed in-process.
|
|
188
|
+
|
|
189
|
+
The OS `prefers-color-scheme` media query applies automatically only while no valid stored preference exists. Once a tab (or a previous session) has stored an explicit preference, later system-preference changes are ignored until `clearPreference()` runs.
|
|
190
|
+
|
|
191
|
+
## Reacting to changes
|
|
192
|
+
|
|
193
|
+
`subscribe(listener)` registers a callback invoked after every applied change — from `init()`, `set()`, `toggle()`, `clearPreference()`, or an accepted `system` or cross-tab update — and returns an unsubscribe function:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
const unsubscribe = theme.subscribe(({ name, source }) => {
|
|
197
|
+
console.log(`theme is now "${name}" (${source})`);
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
A subscriber that throws is logged and does not stop other subscribers from running. Browsers also receive a `window` `CustomEvent` named by the exported `THEME_CHANGE_EVENT` constant (`"themechange"`) carrying the same detail, for code that prefers DOM events over `subscribe()`.
|
|
202
|
+
|
|
203
|
+
<!-- Source: docs/changelog/0.1.2.md -->
|
|
204
|
+
|
|
205
|
+
# 0.1.2
|
|
206
|
+
|
|
207
|
+
## Added
|
|
208
|
+
|
|
209
|
+
- A generated API reference, `docs/reference/index.md`, covering every exported symbol from its TSDoc directly — regenerated on every release instead of hand-maintained separately, so it can't drift out of sync with the source.
|
|
210
|
+
|
|
211
|
+
## Changed
|
|
212
|
+
|
|
213
|
+
- Documentation split from one page, `docs/reference.md`, into three focused ones: `docs/index.md` (setup and configuration), `docs/tokens-and-persistence.md` (token resolution, `skipComputed`, persistence, cross-tab sync), and `docs/ssr-and-pre-paint.md` (`getPrePaintScript()`, SSR fallback, Tailwind's `isTailwindCss`, `shouldApplyClass`, `destroy({ revertDom: true })`), plus the generated reference above. Update any link that pointed at `docs/reference.md`.
|
package/llms.txt
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
# @codenhub/theme
|
|
2
|
-
|
|
3
|
-
> Zero-dependency browser theme preference, persistence, DOM, cross-tab, event,
|
|
4
|
-
> and token manager with SSR-safe fallbacks.
|
|
5
|
-
|
|
6
|
-
Call `init()` in the browser, keep pre-paint logic aligned with configuration,
|
|
7
|
-
and call `destroy()` to release media-query/storage listeners and subscribers.
|
|
8
|
-
|
|
9
|
-
## Documentation
|
|
10
|
-
|
|
11
|
-
- [Documentation overview](docs/index.md): Purpose, status, and starting points.
|
|
12
|
-
- [
|
|
13
|
-
|
|
1
|
+
# @codenhub/theme
|
|
2
|
+
|
|
3
|
+
> Zero-dependency browser theme preference, persistence, DOM, cross-tab, event,
|
|
4
|
+
> and token manager with SSR-safe fallbacks.
|
|
5
|
+
|
|
6
|
+
Call `init()` in the browser, keep pre-paint logic aligned with configuration,
|
|
7
|
+
and call `destroy()` to release media-query/storage listeners and subscribers.
|
|
8
|
+
|
|
9
|
+
## Documentation
|
|
10
|
+
|
|
11
|
+
- [Documentation overview](docs/index.md): Purpose, status, and starting points.
|
|
12
|
+
- [Tokens, persistence, and cross-tab sync](docs/tokens-and-persistence.md): Token
|
|
13
|
+
resolution priority, `localStorage` persistence, and cross-tab sync.
|
|
14
|
+
- [SSR, pre-paint, and Tailwind](docs/ssr-and-pre-paint.md): FOUC prevention, SSR
|
|
15
|
+
fallbacks, and Tailwind `dark` class toggling.
|
|
16
|
+
|
|
17
|
+
## Optional
|
|
18
|
+
|
|
19
|
+
- [API reference](docs/reference/index.md): Generated per-symbol signatures and prose.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codenhub/theme",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Zero-dependency browser theme preference helper for TypeScript apps.",
|
|
6
6
|
"homepage": "https://github.com/codenhub/codenhub/tree/main/packages/theme",
|
|
@@ -29,32 +29,35 @@
|
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
|
-
"devDependencies": {
|
|
33
|
-
"@playwright/test": "^1.61.1",
|
|
34
|
-
"jsdom": "^29.1.1",
|
|
35
|
-
"tsdown": "^0.22.3",
|
|
36
|
-
"typescript": "^6.0.3",
|
|
37
|
-
"vitest": "^4.1.10",
|
|
38
|
-
"@codenhub/styles": "0.1.0",
|
|
39
|
-
"@codenhub/vite-plugin-icons": "0.0.1"
|
|
40
|
-
},
|
|
41
|
-
"codenhub": {
|
|
42
|
-
"docs": {
|
|
43
|
-
"label": "Theme",
|
|
44
|
-
"status": "active"
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
32
|
"scripts": {
|
|
48
33
|
"dev": "pnpm --filter=@codenhub/theme-dev dev",
|
|
49
34
|
"debug": "pnpm build && pnpm --filter=@codenhub/theme-debug dev",
|
|
50
35
|
"build": "tsdown src/index.ts --format esm --dts --clean --no-fixed-extension --minify",
|
|
36
|
+
"prepublishOnly": "pnpm build && pnpm typecheck",
|
|
51
37
|
"status:npm": "npm view @codenhub/theme version dist-tags time --json && npm dist-tag ls @codenhub/theme && npm access get status @codenhub/theme",
|
|
52
|
-
"status:pack": "npm pack --dry-run",
|
|
53
|
-
"test": "vitest run
|
|
38
|
+
"status:pack": "npm pack --dry-run --ignore-scripts",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"test:browser": "playwright test",
|
|
41
|
+
"test:browser:watch": "playwright test --ui",
|
|
54
42
|
"test:coverage": "vitest run --coverage",
|
|
55
|
-
"test:visual": "playwright test",
|
|
56
43
|
"test:watch": "vitest",
|
|
57
|
-
"
|
|
58
|
-
|
|
44
|
+
"typecheck": "tsc -b"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@playwright/test": "catalog:",
|
|
48
|
+
"@vitest/coverage-v8": "catalog:",
|
|
49
|
+
"jsdom": "catalog:",
|
|
50
|
+
"tsdown": "catalog:",
|
|
51
|
+
"typescript": "catalog:",
|
|
52
|
+
"vitest": "catalog:"
|
|
53
|
+
},
|
|
54
|
+
"codenhub": {
|
|
55
|
+
"docs": {
|
|
56
|
+
"label": "ThemeSystem",
|
|
57
|
+
"status": "active",
|
|
58
|
+
"reference": {
|
|
59
|
+
"prose": true
|
|
60
|
+
}
|
|
61
|
+
}
|
|
59
62
|
}
|
|
60
|
-
}
|
|
63
|
+
}
|
package/docs/reference.md
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Reference
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Theme API, Persistence, DOM, and SSR Behavior
|
|
6
|
-
|
|
7
|
-
## Create and Initialize
|
|
8
|
-
|
|
9
|
-
`createTheme<TSchema>(options?): Theme<TSchema>` validates configuration and
|
|
10
|
-
creates a manager. `ThemeOptions` contains:
|
|
11
|
-
|
|
12
|
-
- `themes`: definitions, defaulting to `LIGHT_THEME` and `DARK_THEME`.
|
|
13
|
-
- `defaultTheme`: pre-init and SSR fallback, default `"light"`.
|
|
14
|
-
- `systemTheme`: configured names for light/dark OS preference.
|
|
15
|
-
- `storageKey`: `localStorage` key, default `"app-theme-preference"`.
|
|
16
|
-
- `attribute`: document-root attribute, default `"data-theme"`.
|
|
17
|
-
- `isTailwindCss`: toggle the root `dark` class, default `false`.
|
|
18
|
-
- `shouldApplyClass`: add `theme-${name}` by default, disable classes, or return
|
|
19
|
-
one custom class token with a `ThemeClassResolver`.
|
|
20
|
-
- `tokenSchema`: maps typed token names to CSS custom-property names.
|
|
21
|
-
|
|
22
|
-
`ThemeDefinition` has a unique `name`, `colorScheme` (`light` or `dark`),
|
|
23
|
-
optional static tokens, and optional `pairedTheme` target for `toggle()`.
|
|
24
|
-
`SystemThemeMap` maps OS light and dark preferences.
|
|
25
|
-
|
|
26
|
-
`init(tokens?)` is idempotent until `destroy()`. It registers media-query and
|
|
27
|
-
cross-tab storage listeners, selects valid stored preference before system
|
|
28
|
-
preference, applies the theme, and emits an `"init"` change.
|
|
29
|
-
|
|
30
|
-
## Theme Operations
|
|
31
|
-
|
|
32
|
-
- `get(options?)` returns the active definition. Tokens merge computed CSS values,
|
|
33
|
-
static theme values, then runtime overrides. Reading computed values can force
|
|
34
|
-
style calculation; pass `{ skipComputed: true }` to bypass reading computed DOM styles.
|
|
35
|
-
- `set(name, tokens?)` applies and persists a configured theme; unknown names
|
|
36
|
-
throw.
|
|
37
|
-
- `toggle(tokens?)` switches to `pairedTheme` if defined on the active theme, or
|
|
38
|
-
otherwise by active `colorScheme` between the names in `systemTheme`, then
|
|
39
|
-
persists the choice.
|
|
40
|
-
- `clearPreference()` removes storage and applies the current system theme.
|
|
41
|
-
- `getStored()` returns a valid configured stored name or `null`.
|
|
42
|
-
- `getSystem()` returns the mapped system theme, or `defaultTheme` when media
|
|
43
|
-
queries are unavailable.
|
|
44
|
-
- `getPrePaintScript()` returns a synchronous inline IIFE script string to inject
|
|
45
|
-
into document `<head>` to prevent flash of unstyled content (FOUC). Supports custom
|
|
46
|
-
class resolvers and static token custom properties. Also available as standalone export
|
|
47
|
-
`getPrePaintScript(options?)`.
|
|
48
|
-
|
|
49
|
-
Runtime token overrides persist across theme changes. Passing a new object,
|
|
50
|
-
including `{}`, replaces them. Tokens require a schema and unknown token keys
|
|
51
|
-
throw.
|
|
52
|
-
|
|
53
|
-
## DOM, Persistence, and Events
|
|
54
|
-
|
|
55
|
-
Applying a theme sets the configured root attribute and
|
|
56
|
-
`document.documentElement.style.colorScheme`, updates configured theme classes,
|
|
57
|
-
toggles Tailwind's `dark` class when enabled, and writes mapped token values as
|
|
58
|
-
CSS custom properties. The package supplies no CSS or token values beyond the
|
|
59
|
-
built-in light/dark definitions.
|
|
60
|
-
|
|
61
|
-
Explicit preferences use `localStorage`. `storage` events synchronize valid
|
|
62
|
-
changes from other tabs. OS preference changes apply only while no valid stored
|
|
63
|
-
preference exists. Storage read/write/remove failures are logged with
|
|
64
|
-
`console.error` and treated as unavailable.
|
|
65
|
-
|
|
66
|
-
`subscribe(ThemeChangeListener)` returns an unsubscribe function. Subscribers
|
|
67
|
-
receive `ThemeChangeDetail` with `name`, `theme`, and `ThemeChangeSource`:
|
|
68
|
-
`"init"`, `"set"`, `"toggle"`, `"clearPreference"`, or `"system"`. Subscriber
|
|
69
|
-
errors are logged and do not stop later listeners. Browsers also receive a
|
|
70
|
-
window `CustomEvent` named by `THEME_CHANGE_EVENT` (`"themechange"`).
|
|
71
|
-
|
|
72
|
-
## Validation and Cleanup
|
|
73
|
-
|
|
74
|
-
Creation throws for invalid attributes/storage keys, malformed or duplicate
|
|
75
|
-
themes, invalid color schemes/classes/token schemas, and missing default/system
|
|
76
|
-
theme names. Applying a custom class resolver can throw if it returns an empty
|
|
77
|
-
or whitespace-containing class. Runtime token calls throw without a matching
|
|
78
|
-
schema.
|
|
79
|
-
|
|
80
|
-
`destroy(options?)` removes media-query and storage listeners, clears
|
|
81
|
-
in-process subscribers and runtime tokens, and resets internal active state.
|
|
82
|
-
By default, it does not remove persisted preference or revert attributes,
|
|
83
|
-
classes, custom properties, or `colorScheme` already applied to the document;
|
|
84
|
-
pass `{ revertDom: true }` to remove configured DOM attributes, classes, and
|
|
85
|
-
CSS custom properties from `document.documentElement`.
|
|
86
|
-
|
|
87
|
-
## SSR and Pre-Paint Behavior
|
|
88
|
-
|
|
89
|
-
Without browser APIs, storage, DOM, events, and listeners are skipped;
|
|
90
|
-
`getSystem()` uses `defaultTheme`. Calls remain usable but cannot produce server
|
|
91
|
-
HTML attributes. To avoid a flash, applications must apply equivalent validated
|
|
92
|
-
storage/system logic in a blocking pre-paint script or render matching server
|
|
93
|
-
markup. Keep that logic aligned with custom names, mappings, storage key,
|
|
94
|
-
attribute, classes, and color scheme. Note that `getPrePaintScript()` serializes
|
|
95
|
-
static tokens defined on configured theme definitions (`ThemeDefinition.tokens`);
|
|
96
|
-
runtime token overrides passed to `init(tokens)` or `set(name, tokens)` are applied
|
|
97
|
-
during client-side execution after hydration.
|
|
98
|
-
|
|
99
|
-
## Public Exports
|
|
100
|
-
|
|
101
|
-
The root exports `createTheme`, `getPrePaintScript`, `THEME_CHANGE_EVENT`,
|
|
102
|
-
`LIGHT_THEME`, and `DARK_THEME`, plus `Theme`, `ThemeDefinition`, `SystemThemeMap`,
|
|
103
|
-
`ThemeClassResolver`, `ThemeChangeSource`, `ThemeChangeDetail`,
|
|
104
|
-
`ThemeChangeListener`, and `ThemeOptions` types.
|