ngx-theme-stack 3.4.0 โ†’ 3.5.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.
package/README.md CHANGED
@@ -1,96 +1,140 @@
1
- # ngx-theme-stack ๐ŸŽจ
1
+ <div align="center">
2
+
3
+ # ๐ŸŽจ ngx-theme-stack
4
+
5
+ **A simple and powerful headless theme manager for Angular.**
6
+ Built for performance and SSR support.
7
+
8
+ [![npm version](https://img.shields.io/npm/v/ngx-theme-stack.svg?style=flat-square)](https://www.npmjs.com/package/ngx-theme-stack)
9
+ [![license](https://img.shields.io/npm/l/ngx-theme-stack.svg?style=flat-square)](https://github.com/WanderleeDev/ngx-theme-stack/blob/main/LICENSE)
10
+ [![angular](https://img.shields.io/badge/angular-v20%20%7C%20v21-dd0031.svg?style=flat-square&logo=angular)](https://angular.dev/)
11
+ [![signals](https://img.shields.io/badge/signals-powered-a78bfa.svg?style=flat-square)](https://angular.dev/guide/signals)
12
+ [![SSR](https://img.shields.io/badge/SSR-ready-4ade80.svg?style=flat-square)](https://angular.dev/guide/ssr)
13
+
14
+ [๐ŸŒ Live Demo](https://demo-ngx-theme-stack.wanderlee.site/) ยท [๐Ÿ“š Documentation](https://ngx-theme-stack-docs.wanderlee.site/) ยท [โญ Star on GitHub](https://github.com/WanderleeDev/ngx-theme-stack)
2
15
 
3
16
  ![ngx-theme-stack banner](https://raw.githubusercontent.com/WanderleeDev/ngx-theme-stack/refs/heads/main/projects/demo-ngx-theme-stack/public/banner.png)
4
17
 
5
- A simple and powerful headless theme manager for **Angular**. Built for performance and SSR support.
18
+ </div>
19
+
20
+ ---
6
21
 
7
- [**๐ŸŒ Live Demo**](https://demo-ngx-theme-stack.wanderlee.site/) | [**๐Ÿ“š Documentation**](https://ngx-theme-stack-docs.wanderlee.site/) | [**โญ Star on GitHub**](https://github.com/WanderleeDev/ngx-theme-stack)
22
+ ## ๐Ÿ“– Table of Contents
23
+
24
+ - [๐Ÿš€ Features](#-features)
25
+ - [๐Ÿ“ฆ Installation](#-installation)
26
+ - [๐Ÿค– What does `ng add` do for you?](#-what-does-ng-add-do-for-you)
27
+ - [๐Ÿ—๏ธ Architecture & Extensibility](#๏ธ-architecture--extensibility)
28
+ - [โš™๏ธ Supported Versions](#๏ธ-supported-versions)
29
+ - [โš™๏ธ Configuration](#๏ธ-configuration)
30
+ - [๐Ÿ› ๏ธ Usage](#๏ธ-usage)
31
+ - [๐Ÿ›ก๏ธ CoreThemeService API](#๏ธ-advanced-corethemeservice-api)
32
+ - [๐ŸŽจ Styling](#-styling)
33
+ - [๐ŸŒช๏ธ Tailwind CSS v4 Integration](#๏ธ-tailwind-css-v4-integration)
34
+ - [โšก Performance Strategies](#-performance-strategies)
35
+ - [๐Ÿ“„ License](#-license)
36
+
37
+ ---
8
38
 
9
39
  ## ๐Ÿš€ Features
10
40
 
11
- - โšก **Single Command Installation**: Automatic configuration via `ng add`.
12
- - ๐ŸŒ“ **System Preference Detection**: Automatic synchronization with OS settings (`prefers-color-scheme`).
13
- - ๐Ÿ”„ **Dynamic Switching**: Multiple ways to toggle themes (toggle, cycle, select).
14
- - ๐Ÿ› ๏ธ **Highly Customizable**: Support for custom themes, class prefixes, and configurable storage.
15
- - ๐Ÿงฑ **Modern Architecture**: Powered by Angular Signals for maximum reactivity and performance.
16
- - ๐ŸŒ **SSR Ready**: Safe to use in Server-Side Rendering environments.
17
- - ๐Ÿšซ **Zero Flicker**: Includes an optimized anti-flash script and the **Critters Trick** strategy to prevent theme jumps and network requests on load.
41
+ | | Feature | Description |
42
+ | --- | ------------------------------- | --------------------------------------------------- |
43
+ | โšก | **Single command setup** | Automatic configuration via `ng add` |
44
+ | ๐ŸŒ“ | **System preference detection** | Auto-syncs with OS via `prefers-color-scheme` |
45
+ | ๐Ÿ”„ | **Dynamic switching** | Toggle, cycle, or select between themes |
46
+ | ๐Ÿ› ๏ธ | **Highly customizable** | Custom themes, class prefixes, configurable storage |
47
+ | ๐Ÿงฑ | **Angular Signals** | Maximum reactivity and performance |
48
+ | ๐ŸŒ | **SSR ready** | Safe in server-side rendering environments |
49
+ | ๐Ÿšซ | **Zero flicker** | Anti-flash script + Critters Trick strategy |
18
50
 
19
- ## ๐Ÿ“ฆ Installation
51
+ ---
20
52
 
21
- To install the library and configure it automatically in your project, run:
53
+ ## ๐Ÿ“ฆ Installation
22
54
 
23
55
  ```bash
24
56
  ng add ngx-theme-stack
25
57
  ```
26
58
 
27
- ### Installation Modes
28
-
29
59
  > [!TIP]
30
60
  > **๐Ÿš€ Using Bun?**
31
- > Since `ng add` is currently not supported for Bun environments, please use this two-step process:
61
+ > Since `ng add` is currently not supported for Bun environments, use this two-step process:
32
62
  >
33
- > 1. **Install:** `bun add ngx-theme-stack`
34
- > 2. **Configure:** `ng generate ngx-theme-stack:ng-add`
35
- >
36
- > This ensures Bun handles the dependency management while the schematic automates the code configuration (providers, index.html, tokens, etc.).
63
+ > ```bash
64
+ > bun add ngx-theme-stack
65
+ > ng generate ngx-theme-stack:ng-add
66
+ > ```
67
+
68
+ ### Installation modes
37
69
 
38
- When running `ng add`, you will be presented with two configuration options:
70
+ When running `ng add`, you choose between two modes:
39
71
 
40
- 1. **Quick Mode**:
41
- - Applies default configuration instantly.
42
- - Initial theme: `system`.
43
- - Apply mode: `class` (adds the theme class to the `<html>` element).
44
- - Available themes: `['light', 'dark', 'system']`.
45
- - **Strategy**: `critters` (Zero-flash via CSS inlining).
72
+ <details>
73
+ <summary><strong>โšก Quick mode</strong> โ€” default, applies instantly</summary>
46
74
 
47
- 2. **Custom Mode**:
48
- - Choose which themes to include (e.g., if you have a `blue` or `high-contrast` theme).
49
- - Configure the default theme upon app startup.
50
- - Change the `localStorage` key where the theme choice is saved.
51
- - Decide how to apply themes: via classes (`class`), attributes (`data-theme`), or both.
52
- - **Pick your strategy**: `critters` for modern SSR/SSG apps or `blocking` for standard CSS loading.
75
+ | Option | Value |
76
+ | ---------------- | ------------------------- |
77
+ | Initial theme | `system` |
78
+ | Apply mode | `class` on `<html>` |
79
+ | Available themes | `light`, `dark`, `system` |
80
+ | Strategy | `critters` โ€” zero flash |
81
+
82
+ </details>
83
+
84
+ <details>
85
+ <summary><strong>๐Ÿ› ๏ธ Custom mode</strong> โ€” full control</summary>
86
+
87
+ - Choose which themes to include (e.g. `blue`, `high-contrast`)
88
+ - Configure the default theme on startup
89
+ - Change the `localStorage` key
90
+ - Apply via `class`, `data-theme` attribute, or both
91
+ - Pick your anti-flash strategy: `critters` or `blocking`
92
+
93
+ </details>
94
+
95
+ ---
53
96
 
54
97
  ## ๐Ÿค– What does `ng add` do for you?
55
98
 
56
- To provide a "Zero Config" experience, the installation command automates the following:
99
+ The installation command automates the following:
57
100
 
58
- 1. **`app.config.ts` (or `main.ts`)**: Injects `provideThemeStack()` into your providers array. It's **Smart**: it uses AST to follow imports and find your providers even if they are delegated to external files.
59
- 2. **`index.html`**: Injects the blocking anti-flash script into the `<head>` to ensure a seamless theme experience.
60
- 3. **`package.json`**: Adds a `"prebuild"` script to automate theme synchronization.
61
- 4. **`angular.json`**: Registers `themes.css` and optimizes build configurations.
62
- 5. **`themes.css`**: Scaffolds your base theme tokens if they don't exist.
101
+ | File | What changes |
102
+ | --------------- | ----------------------------------------------------------------------- |
103
+ | `app.config.ts` | Injects `provideThemeStack()` using AST โ€” follows imports automatically |
104
+ | `index.html` | Injects the blocking anti-flash script into `<head>` |
105
+ | `package.json` | Adds a `"prebuild"` script for theme synchronization |
106
+ | `angular.json` | Registers `themes.css` and optimizes build config |
107
+ | `themes.css` | Scaffolds base theme tokens if they don't exist |
63
108
 
64
109
  > [!TIP]
65
- > **Re-configuration support:** You can run `ng add` multiple times. If you change your mind about the `storageKey` or the `mode`, the schematic will update your existing code and script automatically without duplicating them.
66
-
67
- ## ๐Ÿ—๏ธ Architecture & Extensibility
110
+ > **Re-configuration support:** Run `ng add` multiple times freely. The schematic updates existing code without duplicating it.
68
111
 
69
- The library is designed to be flexible. The **`CoreThemeService`** is the foundation:
112
+ ---
70
113
 
71
- - **Solid Base:** Manages state (`Signal`), persistence (`localStorage`), system detection (`matchMedia`), and safe DOM manipulation (SSR compatible).
72
- - **Extensibility:** You can inject `CoreThemeService` to build your own custom services or components with specific business logic.
114
+ ## ๐Ÿ—๏ธ Architecture & Extensibility
73
115
 
74
- ### Utility Services (Ready to Use)
116
+ The **`CoreThemeService`** is the foundation โ€” it manages state (Signals), persistence (localStorage), system detection (matchMedia), and safe DOM manipulation (SSR compatible).
75
117
 
76
- For common use cases, we include three services with predefined logic:
118
+ ### Utility services
77
119
 
78
- 1. **`ThemeToggleService`**: A simple binary switch between `light` and `dark`.
79
- 2. **`ThemeSelectService`**: Exposes the full list of themes and methods to select them.
80
- 3. **`ThemeCycleService`**: A circular function to cycle through all available themes; exposes `upcoming`, `preceding`, and `cycleIndex` signals for UI feedback.
120
+ | Service | Pattern | Description |
121
+ | -------------------- | ------- | ------------------------------------------------------------------------- |
122
+ | `ThemeToggleService` | Toggle | Binary switch between `light` and `dark` |
123
+ | `ThemeSelectService` | Select | Exposes the full theme list; ideal for dropdowns |
124
+ | `ThemeCycleService` | Cycle | Rotates through all themes; exposes `upcoming`, `preceding`, `cycleIndex` |
81
125
 
82
126
  ---
83
127
 
84
128
  ## โš™๏ธ Supported Versions
85
129
 
86
- | Angular Version | Support |
87
- | :-------------- | :-------- |
88
- | **Angular 21** | โœ… Stable |
89
- | **Angular 20** | โœ… Stable |
130
+ | Angular Version | Status |
131
+ | --------------- | --------- |
132
+ | Angular 21 | โœ… Stable |
133
+ | Angular 20 | โœ… Stable |
90
134
 
91
- ## โš™๏ธ Configuration
135
+ ---
92
136
 
93
- The best way to configure the library is during installation, but you can also manually adjust the providers in your `app.config.ts`:
137
+ ## โš™๏ธ Configuration
94
138
 
95
139
  ```typescript
96
140
  import { provideThemeStack } from 'ngx-theme-stack';
@@ -98,34 +142,38 @@ import { provideThemeStack } from 'ngx-theme-stack';
98
142
  export const appConfig: ApplicationConfig = {
99
143
  providers: [
100
144
  provideThemeStack({
101
- themes: ['light', 'dark', 'sunset'], // Your theme identifiers
102
- defaultTheme: 'system', // Initial fallback ('system' resolves via matchMedia)
103
- mode: 'class', // 'class', 'attribute' or 'both'
104
- strategy: 'critters', // 'critters' (SSR) or 'blocking' (Standard SPA)
105
- storageKey: 'ngx-theme-stack', // LocalStorage key
145
+ themes: ['light', 'dark', 'sunset'], // your theme identifiers
146
+ defaultTheme: 'system', // resolves via matchMedia
147
+ mode: 'class', // 'class' | 'attribute' | 'both'
148
+ strategy: 'critters', // 'critters' | 'blocking'
149
+ storageKey: 'ngx-theme-stack', // localStorage key
106
150
  }),
107
151
  ],
108
152
  };
109
153
  ```
110
154
 
111
- | Option | Type | Default | Description |
112
- | :------------- | :----------- | :---------------------------- | :------------------------------------------------------------------------ |
113
- | `themes` | `string[]` | `['light', 'dark', 'system']` | List of supported theme identifiers. |
114
- | `defaultTheme` | `string` | `'system'` | Theme used on first visit or when no preference is saved. |
115
- | `mode` | `NgMode` | `'class'` | How the theme is applied: `class`, `attribute` (`data-theme`), or `both`. |
116
- | `strategy` | `NgStrategy` | `'critters'` | Anti-flash performance strategy: `critters` (inlined CSS) or `blocking`. |
117
- | `storageKey` | `string` | `'ngx-theme-stack'` | Key used to persist theme preference in `localStorage`. |
155
+ ### Options reference
118
156
 
119
- > [!IMPORTANT]
120
- > Whenever you update these settings, run `ng generate ngx-theme-stack:sync` to ensure your `index.html` is updated with the correct anti-flash script.
157
+ | Option | Type | Default | Description |
158
+ | -------------- | ------------ | ----------------------------- | ------------------------ |
159
+ | `themes` | `string[]` | `['light', 'dark', 'system']` | Merged with built-ins |
160
+ | `defaultTheme` | `string` | `'system'` | Theme on first visit |
161
+ | `mode` | `NgMode` | `'class'` | How the theme is applied |
162
+ | `strategy` | `NgStrategy` | `'critters'` | Anti-flash strategy |
163
+ | `storageKey` | `string` | `'ngx-theme-stack'` | Persistence key |
121
164
 
122
- ## ๐Ÿ› ๏ธ Usage
165
+ > [!NOTE]
166
+ > Custom themes are **merged** with built-ins. Passing `['sepia', 'ocean']` resolves to `['system', 'light', 'dark', 'sepia', 'ocean']`. After config changes, run:
167
+ >
168
+ > ```bash
169
+ > ng generate ngx-theme-stack:sync --project YOUR_PROJECT_NAME
170
+ > ```
123
171
 
124
- For most use cases, we recommend using the built-in **Utility Services**. They provide ready-to-use logic for common patterns.
172
+ ---
125
173
 
126
- ### 1. Simple Toggle (Dark/Light)
174
+ ## ๐Ÿ› ๏ธ Usage
127
175
 
128
- Use `ThemeToggleService` when you only need a simple switch.
176
+ ### 1 โ€” Simple toggle (dark/light)
129
177
 
130
178
  ```typescript
131
179
  import { inject } from '@angular/core';
@@ -143,9 +191,7 @@ export class ThemeToggleComponent {
143
191
  }
144
192
  ```
145
193
 
146
- ### 2. Multi-theme Cycle
147
-
148
- Use `ThemeCycleService` to rotate through all your configured themes in order.
194
+ ### 2 โ€” Multi-theme cycle
149
195
 
150
196
  ```typescript
151
197
  import { inject } from '@angular/core';
@@ -155,7 +201,7 @@ import { ThemeCycleService } from 'ngx-theme-stack';
155
201
  selector: 'app-theme-cycler',
156
202
  standalone: true,
157
203
  template: `
158
- <button (click)="theme.cycle()">Next theme: {{ theme.upcoming() }}</button>
204
+ <button (click)="theme.cycle()">Next: {{ theme.upcoming() }}</button>
159
205
  <p>Theme {{ theme.cycleIndex() + 1 }} of {{ theme.availableThemes.length }}</p>
160
206
  `,
161
207
  })
@@ -164,9 +210,7 @@ export class ThemeCycleComponent {
164
210
  }
165
211
  ```
166
212
 
167
- ### 3. Direct Selection (Dropdowns/Lists)
168
-
169
- Use `ThemeSelectService` to build selection interfaces like dropdowns or radio groups.
213
+ ### 3 โ€” Direct selection (dropdowns/lists)
170
214
 
171
215
  ```typescript
172
216
  import { inject } from '@angular/core';
@@ -192,9 +236,7 @@ export class ThemeSelectComponent {
192
236
 
193
237
  ---
194
238
 
195
- ### ๐Ÿ›ก๏ธ Advanced: CoreThemeService API
196
-
197
- If you need to build custom logic or want full control over the state, use the foundational `CoreThemeService`.
239
+ ## ๐Ÿ›ก๏ธ Advanced: CoreThemeService API
198
240
 
199
241
  ```typescript
200
242
  import { inject } from '@angular/core';
@@ -204,39 +246,37 @@ import { CoreThemeService } from 'ngx-theme-stack';
204
246
  export class MyAdvancedComponent {
205
247
  themeService = inject(CoreThemeService);
206
248
 
207
- /* --- ๐Ÿ“Š Reactive Signals --- */
208
-
209
- // The exact theme chosen by the user ('dark', 'light', 'system', etc.)
210
- selectedTheme = this.themeService.selectedTheme;
211
-
212
- // The theme finally applied to the DOM (resolves 'system' to 'dark' or 'light')
213
- resolvedTheme = this.themeService.resolvedTheme;
214
-
215
- // Helper boolean signals evaluating the applied theme
216
- isDark = this.themeService.isDark;
217
- isLight = this.themeService.isLight;
218
- isSystem = this.themeService.isSystem;
219
-
220
- // True after the first browser render. Great for preventing SSR flickering!
221
- isHydrated = this.themeService.isHydrated;
222
-
223
- /* --- ๐Ÿ› ๏ธ Methods --- */
249
+ // โ”€โ”€ Signals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
250
+ selectedTheme = this.themeService.selectedTheme; // chosen by user
251
+ resolvedTheme = this.themeService.resolvedTheme; // applied to DOM
252
+ isDark = this.themeService.isDark;
253
+ isLight = this.themeService.isLight;
254
+ isSystem = this.themeService.isSystem;
255
+ isHydrated = this.themeService.isHydrated; // true after first render
224
256
 
257
+ // โ”€โ”€ Methods โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
225
258
  changeTheme(newTheme: string) {
226
- // Validates, applies to the DOM, and saves to localStorage
227
- this.themeService.setTheme(newTheme);
259
+ this.themeService.setTheme(newTheme); // validates + applies + persists
228
260
  }
229
261
  }
230
262
  ```
231
263
 
264
+ > [!NOTE]
265
+ > `isDark` and `isLight` are `false` when a custom theme is active (e.g. `'sunset'`). For custom theme guards, use `resolvedTheme()` directly:
266
+ >
267
+ > ```typescript
268
+ > const isSunset = computed(() => themeService.resolvedTheme() === 'sunset');
269
+ > ```
270
+
271
+ ---
272
+
232
273
  ## ๐ŸŽจ Styling
233
274
 
234
- The `ng add` command automatically creates a **`src/themes.css`** file. This is where you should define your theme-specific CSS variables.
275
+ `ng add` creates `src/themes.css` automatically. Define your CSS variables there:
235
276
 
236
277
  ```css
237
278
  /* src/themes.css */
238
279
 
239
- /* Using Classes (Default Mode) */
240
280
  :root,
241
281
  .light {
242
282
  --bg-color: #ffffff;
@@ -254,55 +294,88 @@ The `ng add` command automatically creates a **`src/themes.css`** file. This is
254
294
  }
255
295
  ```
256
296
 
257
- ## ๐ŸŒช๏ธ Tailwind CSS v4 Integration
297
+ ---
258
298
 
259
- If you are using **Tailwind CSS v4**, you can achieve a much cleaner HTML by mapping your `themes.css` variables to your Tailwind theme.
299
+ ## ๐ŸŒช๏ธ Tailwind CSS v4 Integration
260
300
 
261
- ### 1. Configure Custom Variants
301
+ ### Map semantic variables (recommended)
262
302
 
263
303
  ```css
264
304
  /* src/styles.css */
265
305
  @import 'tailwindcss';
266
306
 
267
- /* If using Class mode */
268
- @custom-variant dark (&:where(.dark, .dark *));
269
-
270
- /* If using Attribute mode */
271
- @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
272
- ```
273
-
274
- ### 2. Map Semantic Variables
275
-
276
- ```css
277
307
  @theme {
278
308
  --color-main-bg: var(--bg-color);
279
309
  --color-main-text: var(--text-color);
280
310
  }
281
311
  ```
282
312
 
283
- ### 3. Usage in Components
284
-
285
- Now you can write clean, theme-aware classes:
313
+ ### Use in components โ€” no `dark:` prefix needed
286
314
 
287
315
  ```html
288
316
  <div class="bg-main-bg text-main-text shadow-xl">
289
- <!-- This automatically changes colors based on the active theme -->
317
+ <!-- automatically reflects the active theme -->
290
318
  </div>
291
319
  ```
292
320
 
293
- ## โšก Performance Strategies
321
+ > **Why this works:** CSS variables are set on `<html>` before Angular boots. Tailwind tokens point directly to those variables, covering all themes (dark, light, sunset, etc.) without extra configuration.
294
322
 
295
- `ngx-theme-stack` offers two ways to handle the initial theme application to prevent white flashes:
323
+ <details>
324
+ <summary><strong>Optional: enable the <code>dark:</code> prefix</strong></summary>
296
325
 
297
- 1. **Critters (Default)**: Best for SSR/Static sites. Inlines CSS variables directly in the HTML `<head>`. Result: **Zero network requests for theme variables.**
298
- 2. **Blocking**: Best for standard SPAs. Loads `themes.css` as a traditional blocking resource.
326
+ Only needed if you want `dark:` utilities tied to ngx-theme-stack's toggle:
299
327
 
300
- Use the **Sync Command** to refresh your `index.html` if you change your configuration:
328
+ ```css
329
+ /* Class mode */
330
+ @custom-variant dark (&:where(.dark, .dark *));
301
331
 
302
- ```bash
303
- ng generate ngx-theme-stack:sync --project YOUR_PROJECT_NAME
332
+ /* Attribute mode */
333
+ @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
304
334
  ```
305
335
 
336
+ > **โš ๏ธ** This disconnects `dark:` from OS preference and only covers the built-in `dark` theme. For multi-theme support, prefer the CSS variable approach above.
337
+
338
+ </details>
339
+
340
+ ---
341
+
342
+ ## โšก Performance Strategies
343
+
344
+ ### How the theme is applied on first load
345
+
346
+ `ng add` injects a minimal blocking script as the **first child of `<head>`**. It runs before any stylesheet or Angular bundle:
347
+
348
+ ```
349
+ 1. Read stored theme from localStorage
350
+ 2. If 'system' โ†’ resolve OS preference via matchMedia('prefers-color-scheme: dark')
351
+ 3. Apply theme to <html> (class, attribute, or both)
352
+ 4. Set color-scheme CSS property for native browser adaptation
353
+ ```
354
+
355
+ ### Strategy comparison
356
+
357
+ | | critters (default) | blocking |
358
+ | ------------------------- | ---------------------------------- | ------------------------------------------ |
359
+ | **How it works** | Inlines all CSS vars into `<head>` | Loads `themes.css` as render-blocking file |
360
+ | **Network requests** | Zero | One (then cached) |
361
+ | **Flash risk** | None | None |
362
+ | **Works with CSR** | โœ… | โœ… |
363
+ | **Works with SSR/SSG** | โœ… | โŒ |
364
+ | **Strict CSP compatible** | โŒ requires `unsafe-inline` | โœ… |
365
+ | **Best for** | Most apps | Strict CSP, many themes |
366
+
367
+ <details>
368
+ <summary><strong>When to choose blocking over critters</strong></summary>
369
+
370
+ - **Strict CSP** โ€” Critters generates inline `<style>` tags requiring `'unsafe-inline'` in `style-src`
371
+ - **Many themes** โ€” All theme variables get inlined into HTML on every request; a cached file is more efficient
372
+ - **Critters conflicts** โ€” Complex CSS pipelines (PostCSS, CSS Modules) can conflict with Critters
373
+ - **Simpler debugging** โ€” An explicit stylesheet is easier to inspect in DevTools
374
+
375
+ </details>
376
+
377
+ ---
378
+
306
379
  ## ๐Ÿ“„ License
307
380
 
308
- [MIT](./LICENSE)
381
+ [MIT](https://github.com/WanderleeDev/ngx-theme-stack/blob/main/LICENSE)
@@ -70,8 +70,10 @@ const NGX_THEME_STACK_CONFIG = new InjectionToken('NGX_THEME_STACK_CONFIG', {
70
70
  /**
71
71
  * Provides Theme Stack configuration to Angular's DI system.
72
72
  *
73
- * Custom `themes` are **merged** with the built-in defaults
74
- * (`'light'`, `'dark'`, `'system'`), so you never lose the base themes.
73
+ * The `themes` option accepts **additional** theme identifiers beyond the
74
+ * built-in defaults. They are merged with `'light'`, `'dark'`, and `'system'`
75
+ * so that the resolved {@link NgConfig.themes} array always includes all of
76
+ * them โ€” your custom values are appended after the built-ins.
75
77
  *
76
78
  * **Defaults:**
77
79
  * - `themes`: `['light', 'dark', 'system']`
@@ -99,7 +101,7 @@ const NGX_THEME_STACK_CONFIG = new InjectionToken('NGX_THEME_STACK_CONFIG', {
99
101
  * provideThemeStack()
100
102
  *
101
103
  * @example
102
- * // SSR/SSG Optimization โ€” uses Critters inlining strategy
104
+ * // Critters strategy โ€” inlines all theme CSS in <head> (works for CSR, SSR, and SSG)
103
105
  * provideThemeStack({
104
106
  * strategy: 'critters',
105
107
  * mode: 'class',
@@ -157,10 +159,7 @@ class CoreThemeService {
157
159
  #document = inject(DOCUMENT);
158
160
  #isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
159
161
  // โ”€โ”€ Theme configuration โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
160
- /**
161
- * The initial stored theme read from localStorage.
162
- * This is used to determine the initial theme of the application.
163
- */
162
+ /** The initial stored theme read from localStorage on startup. */
164
163
  #initialStoredTheme = this.readStoredTheme();
165
164
  /** List of available themes for Select/Cycle services. Defaults to ['system', 'light', 'dark']. */
166
165
  availableThemes = this.#config.themes;
@@ -187,9 +186,19 @@ class CoreThemeService {
187
186
  const theme = this.#selectedTheme();
188
187
  return theme === 'system' ? this.#systemPreference() : theme;
189
188
  }, ...(ngDevMode ? [{ debugName: "resolvedTheme" }] : /* istanbul ignore next */ []));
190
- /** Whether the currently applied theme is dark. */
189
+ /**
190
+ * Whether the currently applied theme is dark.
191
+ *
192
+ * Returns `false` when a custom theme (e.g. `'sunset'`) is active โ€” use
193
+ * `resolvedTheme()` directly if you need to inspect the current custom theme.
194
+ */
191
195
  isDark = computed(() => this.resolvedTheme() === 'dark', ...(ngDevMode ? [{ debugName: "isDark" }] : /* istanbul ignore next */ []));
192
- /** Whether the currently applied theme is light. */
196
+ /**
197
+ * Whether the currently applied theme is light.
198
+ *
199
+ * Returns `false` when a custom theme (e.g. `'sepia'`) is active โ€” use
200
+ * `resolvedTheme()` directly if you need to inspect the current custom theme.
201
+ */
193
202
  isLight = computed(() => this.resolvedTheme() === 'light', ...(ngDevMode ? [{ debugName: "isLight" }] : /* istanbul ignore next */ []));
194
203
  /** Whether the currently applied theme is system. */
195
204
  isSystem = computed(() => this.selectedTheme() === 'system', ...(ngDevMode ? [{ debugName: "isSystem" }] : /* istanbul ignore next */ []));