ngx-theme-stack 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -22
- package/fesm2022/ngx-theme-stack.mjs +203 -39
- package/fesm2022/ngx-theme-stack.mjs.map +1 -1
- package/package.json +1 -1
- package/schematics/collection.json +6 -1
- package/schematics/ng-add/anti-flash.d.ts +24 -0
- package/schematics/ng-add/anti-flash.js +98 -0
- package/schematics/ng-add/anti-flash.js.map +1 -0
- package/schematics/ng-add/app-config.d.ts +3 -3
- package/schematics/ng-add/app-config.js +4 -4
- package/schematics/ng-add/app-config.js.map +1 -1
- package/schematics/ng-add/constants.d.ts +4 -5
- package/schematics/ng-add/constants.js +4 -5
- package/schematics/ng-add/constants.js.map +1 -1
- package/schematics/ng-add/index.js +35 -12
- package/schematics/ng-add/index.js.map +1 -1
- package/schematics/ng-add/utils.d.ts +1 -1
- package/schematics/ng-add/utils.js +6 -6
- package/schematics/ng-add/utils.js.map +1 -1
- package/schematics/sync/index.d.ts +12 -0
- package/schematics/sync/index.js +153 -0
- package/schematics/sync/index.js.map +1 -0
- package/schematics/sync/schema.d.ts +4 -0
- package/schematics/sync/schema.js +3 -0
- package/schematics/sync/schema.js.map +1 -0
- package/schematics/sync/schema.json +16 -0
- package/types/ngx-theme-stack.d.ts +168 -33
|
@@ -2,17 +2,53 @@ import * as _angular_core from '@angular/core';
|
|
|
2
2
|
import { InjectionToken } from '@angular/core';
|
|
3
3
|
import * as ngx_theme_stack from 'ngx-theme-stack';
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Runtime list of built-in themes.
|
|
7
|
+
*
|
|
8
|
+
* Lives here (and not in config/index.ts) because it defines a type:
|
|
9
|
+
* config/index.ts already imports from types.ts, so placing DEFAULT_THEMES
|
|
10
|
+
* here avoids any circular dependency.
|
|
11
|
+
*
|
|
12
|
+
* ⚠ KEEP IN SYNC with the duplicate in:
|
|
13
|
+
* projects/ngx-theme-stack/schematics/ng-add/constants.ts → DEFAULT_THEMES
|
|
14
|
+
*
|
|
15
|
+
* Schematics compile to CommonJS and cannot import from this ESM file,
|
|
16
|
+
* so the values are intentionally duplicated. Change both at the same time.
|
|
17
|
+
*/
|
|
6
18
|
declare const DEFAULT_THEMES: readonly ["system", "light", "dark"];
|
|
7
|
-
/**
|
|
8
|
-
type
|
|
9
|
-
|
|
19
|
+
/** Literal union of built-in themes: `'system' | 'light' | 'dark'`. */
|
|
20
|
+
type DefaultNgTheme = (typeof DEFAULT_THEMES)[number];
|
|
21
|
+
/**
|
|
22
|
+
* Theme type.
|
|
23
|
+
*
|
|
24
|
+
* - **Without** `T`: open union — accepts any `string` with IDE autocomplete
|
|
25
|
+
* hints for the built-in themes (`'system' | 'light' | 'dark'`).
|
|
26
|
+
* - **With** `T`: closed union — exactly `DefaultNgTheme | T`, enabling
|
|
27
|
+
* full type-safety for custom theme sets.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* NgTheme // 'system' | 'light' | 'dark' | (string & {})
|
|
31
|
+
* NgTheme<'sepia'> // 'system' | 'light' | 'dark' | 'sepia'
|
|
32
|
+
*/
|
|
33
|
+
type NgTheme<T extends string = string & {}> = DefaultNgTheme | T;
|
|
34
|
+
/**
|
|
35
|
+
* Resolved theme — always `'light'` or `'dark'`, never `'system'`.
|
|
36
|
+
* Represents the value that comes from `matchMedia`, not user selection.
|
|
37
|
+
*/
|
|
38
|
+
type NgSystemTheme = Exclude<DefaultNgTheme, 'system'>;
|
|
10
39
|
type NgMode = 'attribute' | 'class' | 'both';
|
|
11
|
-
|
|
12
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Library configuration.
|
|
42
|
+
*
|
|
43
|
+
* @typeParam T - Custom theme literals. Defaults to open `string`, preserving
|
|
44
|
+
* backwards compatibility. Pass specific literals (e.g. `'sepia' | 'ocean'`)
|
|
45
|
+
* via {@link provideThemeStack} to get a closed, type-safe theme union.
|
|
46
|
+
*/
|
|
47
|
+
interface NgConfig<T extends string = string & {}> {
|
|
48
|
+
defaultTheme: NgTheme<T>;
|
|
13
49
|
storageKey: string;
|
|
14
50
|
mode: NgMode;
|
|
15
|
-
themes: NgTheme[];
|
|
51
|
+
themes: NgTheme<T>[];
|
|
16
52
|
}
|
|
17
53
|
|
|
18
54
|
/**
|
|
@@ -23,22 +59,42 @@ interface NgConfig {
|
|
|
23
59
|
*/
|
|
24
60
|
declare class CoreThemeService {
|
|
25
61
|
#private;
|
|
26
|
-
/** List of available themes for Select/Cycle services. Defaults to ['
|
|
27
|
-
readonly availableThemes:
|
|
62
|
+
/** List of available themes for Select/Cycle services. Defaults to ['system', 'light', 'dark']. */
|
|
63
|
+
readonly availableThemes: string[];
|
|
28
64
|
/** The theme explicitly selected by the user. May be `'system'`. */
|
|
29
65
|
readonly selectedTheme: _angular_core.Signal<NgTheme>;
|
|
30
66
|
/** Resolved theme applied to the DOM. Always `'dark'` or `'light'` (or custom) — never `'system'`. */
|
|
31
|
-
readonly
|
|
67
|
+
readonly resolvedTheme: _angular_core.Signal<(string & {}) | NgSystemTheme>;
|
|
32
68
|
/** Whether the currently applied theme is dark. */
|
|
33
69
|
readonly isDark: _angular_core.Signal<boolean>;
|
|
34
70
|
/** Whether the currently applied theme is light. */
|
|
35
71
|
readonly isLight: _angular_core.Signal<boolean>;
|
|
72
|
+
/** Whether the currently applied theme is system. */
|
|
73
|
+
readonly isSystem: _angular_core.Signal<boolean>;
|
|
74
|
+
/**
|
|
75
|
+
* Whether the service has completed client-side initialization.
|
|
76
|
+
*
|
|
77
|
+
* `false` during SSR and on the very first render pass. Becomes `true`
|
|
78
|
+
* immediately after the first browser render, once the real persisted theme
|
|
79
|
+
* has been read from `localStorage`.
|
|
80
|
+
*
|
|
81
|
+
* Use this to guard any template logic that depends on `selectedTheme` or
|
|
82
|
+
* `resolvedTheme` to avoid an SSR hydration-mismatch flash: the server
|
|
83
|
+
* renders the default (`'system'`) while the browser may have a different
|
|
84
|
+
* value stored.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```html
|
|
88
|
+
* {{ themeService.isHydrated() ? selectedTheme() : '—' }}
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
readonly isHydrated: _angular_core.WritableSignal<boolean>;
|
|
36
92
|
constructor();
|
|
37
93
|
/**
|
|
38
94
|
* Changes the active theme.
|
|
39
95
|
*
|
|
40
96
|
* Persists the choice explicitly so that switching e.g. from `'system'` to
|
|
41
|
-
* `'light'` is saved even when the resolved
|
|
97
|
+
* `'light'` is saved even when the resolved theme did not change
|
|
42
98
|
* (system preference was already `'light'`).
|
|
43
99
|
*
|
|
44
100
|
* @param theme - The theme to apply: `'dark'`, `'light'`, `'system'`, or a custom theme name.
|
|
@@ -53,6 +109,7 @@ declare class CoreThemeService {
|
|
|
53
109
|
private applyThemeAttribute;
|
|
54
110
|
private applyThemeClasses;
|
|
55
111
|
private applyColorSchemeHint;
|
|
112
|
+
private captureAntiFlashClass;
|
|
56
113
|
private readStoredTheme;
|
|
57
114
|
private saveTheme;
|
|
58
115
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<CoreThemeService, never>;
|
|
@@ -62,36 +119,69 @@ declare class CoreThemeService {
|
|
|
62
119
|
/**
|
|
63
120
|
* ⚠ ATTENTION: SHARED CONFIGURATION VALUES
|
|
64
121
|
*
|
|
65
|
-
* These
|
|
66
|
-
* projects/ngx-theme-stack/schematics/ng-add/
|
|
122
|
+
* These defaults MUST match the schematic defaults in:
|
|
123
|
+
* projects/ngx-theme-stack/schematics/ng-add/constants.ts → DEFAULTS
|
|
67
124
|
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
125
|
+
* Schematics compile to CommonJS and cannot import from this ESM file,
|
|
126
|
+
* so the values are intentionally duplicated. Change both at the same time.
|
|
127
|
+
*
|
|
128
|
+
* If you change defaults here, also update:
|
|
129
|
+
* schematics/ng-add/constants.ts → DEFAULTS + DEFAULT_THEMES
|
|
70
130
|
*/
|
|
71
131
|
declare const DEFAULT_NG_CONFIG: {
|
|
72
|
-
|
|
132
|
+
defaultTheme: "system";
|
|
73
133
|
storageKey: string;
|
|
74
134
|
mode: "class";
|
|
75
135
|
themes: ("system" | "light" | "dark")[];
|
|
76
136
|
};
|
|
77
|
-
declare const NGX_THEME_STACK_CONFIG: InjectionToken<NgConfig
|
|
137
|
+
declare const NGX_THEME_STACK_CONFIG: InjectionToken<NgConfig<string>>;
|
|
78
138
|
/**
|
|
79
|
-
*
|
|
139
|
+
* Provides Theme Stack configuration to Angular's DI system.
|
|
140
|
+
*
|
|
141
|
+
* Custom `themes` are **merged** with the built-in defaults
|
|
142
|
+
* (`'light'`, `'dark'`, `'system'`), so you never lose the base themes.
|
|
143
|
+
*
|
|
144
|
+
* The type parameter `T` is **inferred automatically** from the `themes` array
|
|
145
|
+
* when passed as a `const` — no need to specify it manually.
|
|
146
|
+
*
|
|
147
|
+
* @typeParam T - Custom theme string literals, inferred from the `themes` option.
|
|
148
|
+
*
|
|
149
|
+
* @param config - Optional partial configuration. Omitted fields fall back to
|
|
150
|
+
* {@link DEFAULT_NG_CONFIG}.
|
|
151
|
+
*
|
|
152
|
+
* @throws {@link NgxThemeStackError}
|
|
153
|
+
* - If any entry in `themes` is an empty or whitespace-only string.
|
|
154
|
+
* - If `defaultTheme` is not present in the resolved (merged) themes array.
|
|
155
|
+
* - If `storageKey` is an empty or whitespace-only string.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* // Default — uses built-in themes and sensible defaults
|
|
159
|
+
* provideThemeStack()
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* // Closed union: TypeScript infers 'sepia' | 'ocean' from the array
|
|
163
|
+
* provideThemeStack({
|
|
164
|
+
* themes: ['sepia', 'ocean'] as const,
|
|
165
|
+
* defaultTheme: 'sepia', // ✅ in resolved themes
|
|
166
|
+
* // defaultTheme: 'nope', // ❌ throws NgxThemeStackError at runtime
|
|
167
|
+
* })
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* // Custom storage key and mode
|
|
171
|
+
* provideThemeStack({
|
|
172
|
+
* storageKey: 'my-app-theme',
|
|
173
|
+
* mode: 'class',
|
|
174
|
+
* })
|
|
80
175
|
*/
|
|
81
|
-
declare function provideThemeStack(config?: Partial<NgConfig
|
|
82
|
-
provide: InjectionToken<NgConfig
|
|
83
|
-
useValue:
|
|
84
|
-
theme: ngx_theme_stack.NgTheme;
|
|
85
|
-
storageKey: string;
|
|
86
|
-
mode: ngx_theme_stack.NgMode;
|
|
87
|
-
themes: ngx_theme_stack.NgTheme[];
|
|
88
|
-
};
|
|
176
|
+
declare function provideThemeStack<const T extends string = DefaultNgTheme>(config?: Partial<NgConfig<T>>): {
|
|
177
|
+
provide: InjectionToken<NgConfig<string>>;
|
|
178
|
+
useValue: NgConfig<string>;
|
|
89
179
|
};
|
|
90
180
|
|
|
91
181
|
/**
|
|
92
182
|
* Convenience service for cycling through themes in a fixed order.
|
|
93
183
|
*
|
|
94
|
-
* Default cycle: `'
|
|
184
|
+
* Default cycle: `'system'` → `'light'` → `'dark'` → `'system'` → ...
|
|
95
185
|
*
|
|
96
186
|
* Use this when you want to offer users a single button that rotates
|
|
97
187
|
* through all available theme options.
|
|
@@ -101,11 +191,18 @@ declare class ThemeCycleService {
|
|
|
101
191
|
/** The theme explicitly selected by the user. May be `'system'`. */
|
|
102
192
|
readonly selectedTheme: _angular_core.Signal<ngx_theme_stack.NgTheme>;
|
|
103
193
|
/** Resolved theme applied to the DOM. Always concrete — never `'system'`. */
|
|
104
|
-
readonly
|
|
194
|
+
readonly resolvedTheme: _angular_core.Signal<(string & {}) | ngx_theme_stack.NgSystemTheme>;
|
|
105
195
|
/** Whether the currently applied theme is dark. */
|
|
106
196
|
readonly isDark: _angular_core.Signal<boolean>;
|
|
107
197
|
/** Whether the currently applied theme is light. */
|
|
108
198
|
readonly isLight: _angular_core.Signal<boolean>;
|
|
199
|
+
/** Whether the currently applied theme is system. */
|
|
200
|
+
readonly isSystem: _angular_core.Signal<boolean>;
|
|
201
|
+
/**
|
|
202
|
+
* Whether the service has completed client-side initialization.
|
|
203
|
+
* `false` during SSR. Becomes `true` after the first browser render.
|
|
204
|
+
*/
|
|
205
|
+
readonly isHydrated: _angular_core.Signal<boolean>;
|
|
109
206
|
/**
|
|
110
207
|
* Advances to the next theme in the cycle.
|
|
111
208
|
*
|
|
@@ -128,15 +225,22 @@ declare class ThemeCycleService {
|
|
|
128
225
|
declare class ThemeSelectService {
|
|
129
226
|
#private;
|
|
130
227
|
/** List of all configured themes. Defaults to ['light', 'dark', 'system']. */
|
|
131
|
-
readonly availableThemes:
|
|
228
|
+
readonly availableThemes: string[];
|
|
132
229
|
/** The theme explicitly selected by the user. May be `'system'`. */
|
|
133
230
|
readonly selectedTheme: _angular_core.Signal<NgTheme>;
|
|
134
231
|
/** Resolved theme applied to the DOM. Always concrete — never `'system'`. */
|
|
135
|
-
readonly
|
|
232
|
+
readonly resolvedTheme: _angular_core.Signal<(string & {}) | ngx_theme_stack.NgSystemTheme>;
|
|
136
233
|
/** Whether the currently applied theme is dark. */
|
|
137
234
|
readonly isDark: _angular_core.Signal<boolean>;
|
|
138
235
|
/** Whether the currently applied theme is light. */
|
|
139
236
|
readonly isLight: _angular_core.Signal<boolean>;
|
|
237
|
+
/** Whether the currently applied theme is system. */
|
|
238
|
+
readonly isSystem: _angular_core.Signal<boolean>;
|
|
239
|
+
/**
|
|
240
|
+
* Whether the service has completed client-side initialization.
|
|
241
|
+
* `false` during SSR. Becomes `true` after the first browser render.
|
|
242
|
+
*/
|
|
243
|
+
readonly isHydrated: _angular_core.Signal<boolean>;
|
|
140
244
|
/**
|
|
141
245
|
* Applies the given theme.
|
|
142
246
|
*
|
|
@@ -157,11 +261,21 @@ declare class ThemeSelectService {
|
|
|
157
261
|
declare class ThemeToggleService {
|
|
158
262
|
#private;
|
|
159
263
|
/** Resolved theme applied to the DOM. Always concrete — never `'system'`. */
|
|
160
|
-
readonly
|
|
264
|
+
readonly resolvedTheme: _angular_core.Signal<(string & {}) | ngx_theme_stack.NgSystemTheme>;
|
|
265
|
+
readonly selectedTheme: _angular_core.Signal<ngx_theme_stack.NgTheme>;
|
|
161
266
|
/** Whether the currently applied theme is dark. */
|
|
162
267
|
readonly isDark: _angular_core.Signal<boolean>;
|
|
163
268
|
/** Whether the currently applied theme is light. */
|
|
164
269
|
readonly isLight: _angular_core.Signal<boolean>;
|
|
270
|
+
/** Whether the currently applied theme is system. */
|
|
271
|
+
readonly isSystem: _angular_core.Signal<boolean>;
|
|
272
|
+
/**
|
|
273
|
+
* Whether the service has completed client-side initialization.
|
|
274
|
+
* `false` during SSR. Becomes `true` after the first browser render.
|
|
275
|
+
* Guard any template logic that shows `selectedTheme` or `resolvedTheme`
|
|
276
|
+
* behind this signal to avoid a hydration-mismatch flash.
|
|
277
|
+
*/
|
|
278
|
+
readonly isHydrated: _angular_core.Signal<boolean>;
|
|
165
279
|
/**
|
|
166
280
|
* Toggles between `'dark'` and `'light'`.
|
|
167
281
|
*
|
|
@@ -173,5 +287,26 @@ declare class ThemeToggleService {
|
|
|
173
287
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ThemeToggleService>;
|
|
174
288
|
}
|
|
175
289
|
|
|
176
|
-
|
|
177
|
-
|
|
290
|
+
/**
|
|
291
|
+
* Base error class for `ngx-theme-stack`.
|
|
292
|
+
*
|
|
293
|
+
* Thrown when the library configuration is invalid.
|
|
294
|
+
* Consumers can use `instanceof NgxThemeStackError` to catch only
|
|
295
|
+
* errors originating from this library.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* try {
|
|
299
|
+
* bootstrapApplication(AppComponent, appConfig);
|
|
300
|
+
* } catch (e) {
|
|
301
|
+
* if (e instanceof NgxThemeStackError) {
|
|
302
|
+
* console.error('Bad ngx-theme-stack config:', e.message);
|
|
303
|
+
* }
|
|
304
|
+
* }
|
|
305
|
+
*/
|
|
306
|
+
declare class NgxThemeStackError extends Error {
|
|
307
|
+
readonly name = "NgxThemeStackError";
|
|
308
|
+
constructor(message: string);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export { CoreThemeService, DEFAULT_NG_CONFIG, DEFAULT_THEMES, NGX_THEME_STACK_CONFIG, NgxThemeStackError, ThemeCycleService, ThemeSelectService, ThemeToggleService, provideThemeStack };
|
|
312
|
+
export type { DefaultNgTheme, NgConfig, NgMode, NgSystemTheme, NgTheme };
|