@codenhub/theme 0.1.0 → 0.1.1

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.
@@ -0,0 +1,104 @@
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.
package/llms-full.txt ADDED
@@ -0,0 +1,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
+ - [API, persistence, DOM, and SSR behavior](docs/reference.md)
32
+
33
+ ## Requirements
34
+
35
+ - Browser integration uses `document.documentElement`, `localStorage`,
36
+ `matchMedia`, `storage` events, and `CustomEvent`.
37
+ - SSR is supported by skipping unavailable browser work and using the configured
38
+ default theme.
39
+ - Consumers provide CSS selectors, variables, visual tokens, and any pre-paint
40
+ script needed to prevent a theme flash.
41
+
42
+ ## Notes
43
+
44
+ Construction validates theme names, mappings, attributes, classes, and token
45
+ schemas and throws on invalid configuration. Storage failures are reported to
46
+ the console and treated as unavailable storage.
47
+
48
+ ## License
49
+
50
+ Licensed under Apache-2.0.
51
+
52
+ <!-- Source: docs/index.md -->
53
+
54
+ # Manage Browser Themes
55
+
56
+ `@codenhub/theme` resolves stored and system theme preferences, applies theme
57
+ state to the document root, synchronizes browser tabs, exposes change events,
58
+ and maps typed tokens to CSS custom properties.
59
+
60
+ It fits browser applications that need one owner for theme preference and DOM
61
+ synchronization while keeping selectors, visual design, and CSS in application
62
+ code.
63
+
64
+ ## Setup
65
+
66
+ ### Installation
67
+
68
+ ```sh
69
+ pnpm add @codenhub/theme
70
+ ```
71
+
72
+ ### Quick start
73
+
74
+ ```ts
75
+ import { createTheme } from "@codenhub/theme";
76
+
77
+ const theme = createTheme().init();
78
+ theme.set("dark");
79
+ ```
80
+
81
+ Call `destroy()` when the manager's owner is removed. The package persists an
82
+ explicit preference and follows system preference when appropriate.
83
+
84
+ ## Requirements
85
+
86
+ - Browser integration uses `document.documentElement`, `localStorage`,
87
+ `matchMedia`, `storage` events, and `CustomEvent`.
88
+ - SSR is supported by skipping unavailable browser work and using the configured
89
+ default theme.
90
+ - Consumers provide CSS selectors, variables, visual tokens, and any pre-paint
91
+ script needed to prevent a theme flash.
92
+
93
+ The package cannot produce server HTML attributes or prevent a flash before
94
+ initialization. Applications that need pre-paint consistency must apply matching
95
+ theme logic before rendering.
96
+
97
+ ## Next steps
98
+
99
+ - [API, persistence, DOM, and SSR behavior](docs/reference.md): Complete exports,
100
+ configuration, tokens, browser synchronization, validation, pre-paint
101
+ concerns, and cleanup.
102
+
103
+ <!-- Source: docs/reference.md -->
104
+
105
+ # Theme API, Persistence, DOM, and SSR Behavior
106
+
107
+ ## Create and Initialize
108
+
109
+ `createTheme<TSchema>(options?): Theme<TSchema>` validates configuration and
110
+ creates a manager. `ThemeOptions` contains:
111
+
112
+ - `themes`: definitions, defaulting to `LIGHT_THEME` and `DARK_THEME`.
113
+ - `defaultTheme`: pre-init and SSR fallback, default `"light"`.
114
+ - `systemTheme`: configured names for light/dark OS preference.
115
+ - `storageKey`: `localStorage` key, default `"app-theme-preference"`.
116
+ - `attribute`: document-root attribute, default `"data-theme"`.
117
+ - `isTailwindCss`: toggle the root `dark` class, default `false`.
118
+ - `shouldApplyClass`: add `theme-${name}` by default, disable classes, or return
119
+ one custom class token with a `ThemeClassResolver`.
120
+ - `tokenSchema`: maps typed token names to CSS custom-property names.
121
+
122
+ `ThemeDefinition` has a unique `name`, `colorScheme` (`light` or `dark`),
123
+ optional static tokens, and optional `pairedTheme` target for `toggle()`.
124
+ `SystemThemeMap` maps OS light and dark preferences.
125
+
126
+ `init(tokens?)` is idempotent until `destroy()`. It registers media-query and
127
+ cross-tab storage listeners, selects valid stored preference before system
128
+ preference, applies the theme, and emits an `"init"` change.
129
+
130
+ ## Theme Operations
131
+
132
+ - `get(options?)` returns the active definition. Tokens merge computed CSS values,
133
+ static theme values, then runtime overrides. Reading computed values can force
134
+ style calculation; pass `{ skipComputed: true }` to bypass reading computed DOM styles.
135
+ - `set(name, tokens?)` applies and persists a configured theme; unknown names
136
+ throw.
137
+ - `toggle(tokens?)` switches to `pairedTheme` if defined on the active theme, or
138
+ otherwise by active `colorScheme` between the names in `systemTheme`, then
139
+ persists the choice.
140
+ - `clearPreference()` removes storage and applies the current system theme.
141
+ - `getStored()` returns a valid configured stored name or `null`.
142
+ - `getSystem()` returns the mapped system theme, or `defaultTheme` when media
143
+ queries are unavailable.
144
+ - `getPrePaintScript()` returns a synchronous inline IIFE script string to inject
145
+ into document `<head>` to prevent flash of unstyled content (FOUC). Supports custom
146
+ class resolvers and static token custom properties. Also available as standalone export
147
+ `getPrePaintScript(options?)`.
148
+
149
+ Runtime token overrides persist across theme changes. Passing a new object,
150
+ including `{}`, replaces them. Tokens require a schema and unknown token keys
151
+ throw.
152
+
153
+ ## DOM, Persistence, and Events
154
+
155
+ Applying a theme sets the configured root attribute and
156
+ `document.documentElement.style.colorScheme`, updates configured theme classes,
157
+ toggles Tailwind's `dark` class when enabled, and writes mapped token values as
158
+ CSS custom properties. The package supplies no CSS or token values beyond the
159
+ built-in light/dark definitions.
160
+
161
+ Explicit preferences use `localStorage`. `storage` events synchronize valid
162
+ changes from other tabs. OS preference changes apply only while no valid stored
163
+ preference exists. Storage read/write/remove failures are logged with
164
+ `console.error` and treated as unavailable.
165
+
166
+ `subscribe(ThemeChangeListener)` returns an unsubscribe function. Subscribers
167
+ receive `ThemeChangeDetail` with `name`, `theme`, and `ThemeChangeSource`:
168
+ `"init"`, `"set"`, `"toggle"`, `"clearPreference"`, or `"system"`. Subscriber
169
+ errors are logged and do not stop later listeners. Browsers also receive a
170
+ window `CustomEvent` named by `THEME_CHANGE_EVENT` (`"themechange"`).
171
+
172
+ ## Validation and Cleanup
173
+
174
+ Creation throws for invalid attributes/storage keys, malformed or duplicate
175
+ themes, invalid color schemes/classes/token schemas, and missing default/system
176
+ theme names. Applying a custom class resolver can throw if it returns an empty
177
+ or whitespace-containing class. Runtime token calls throw without a matching
178
+ schema.
179
+
180
+ `destroy(options?)` removes media-query and storage listeners, clears
181
+ in-process subscribers and runtime tokens, and resets internal active state.
182
+ By default, it does not remove persisted preference or revert attributes,
183
+ classes, custom properties, or `colorScheme` already applied to the document;
184
+ pass `{ revertDom: true }` to remove configured DOM attributes, classes, and
185
+ CSS custom properties from `document.documentElement`.
186
+
187
+ ## SSR and Pre-Paint Behavior
188
+
189
+ Without browser APIs, storage, DOM, events, and listeners are skipped;
190
+ `getSystem()` uses `defaultTheme`. Calls remain usable but cannot produce server
191
+ HTML attributes. To avoid a flash, applications must apply equivalent validated
192
+ storage/system logic in a blocking pre-paint script or render matching server
193
+ markup. Keep that logic aligned with custom names, mappings, storage key,
194
+ attribute, classes, and color scheme. Note that `getPrePaintScript()` serializes
195
+ static tokens defined on configured theme definitions (`ThemeDefinition.tokens`);
196
+ runtime token overrides passed to `init(tokens)` or `set(name, tokens)` are applied
197
+ during client-side execution after hydration.
198
+
199
+ ## Public Exports
200
+
201
+ The root exports `createTheme`, `getPrePaintScript`, `THEME_CHANGE_EVENT`,
202
+ `LIGHT_THEME`, and `DARK_THEME`, plus `Theme`, `ThemeDefinition`, `SystemThemeMap`,
203
+ `ThemeClassResolver`, `ThemeChangeSource`, `ThemeChangeDetail`,
204
+ `ThemeChangeListener`, and `ThemeOptions` types.
package/llms.txt ADDED
@@ -0,0 +1,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
+ - [API, persistence, DOM, and SSR behavior](docs/reference.md): Complete exports,
13
+ configuration, tokens, listeners, failures, pre-paint behavior, and cleanup.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codenhub/theme",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
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",
@@ -11,7 +11,10 @@
11
11
  "directory": "packages/theme"
12
12
  },
13
13
  "files": [
14
- "dist"
14
+ "dist",
15
+ "docs",
16
+ "llms.txt",
17
+ "llms-full.txt"
15
18
  ],
16
19
  "type": "module",
17
20
  "main": "./dist/index.js",
@@ -32,9 +35,15 @@
32
35
  "tsdown": "^0.22.3",
33
36
  "typescript": "^6.0.3",
34
37
  "vitest": "^4.1.10",
35
- "@codenhub/styles": "0.0.4",
38
+ "@codenhub/styles": "0.1.0",
36
39
  "@codenhub/vite-plugin-icons": "0.0.1"
37
40
  },
41
+ "codenhub": {
42
+ "docs": {
43
+ "label": "Theme",
44
+ "status": "active"
45
+ }
46
+ },
38
47
  "scripts": {
39
48
  "dev": "pnpm --filter=@codenhub/theme-dev dev",
40
49
  "debug": "pnpm build && pnpm --filter=@codenhub/theme-debug dev",