ngx-theme-stack 3.6.1 → 3.7.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 CHANGED
@@ -105,7 +105,7 @@ The installation command automates the following:
105
105
  | `package.json` | Adds a `"prebuild"` script for theme synchronization |
106
106
  | `angular.json` | Registers `themes.css` and optimizes build config |
107
107
  | `themes.css` | Scaffolds base theme tokens if they don't exist |
108
- | `SKILL.md` | Generates an AI Agent Skill under `.agent/skills/` (optional) |
108
+ | `SKILL.md` | Generates an AI Agent Skill under `.agents/skills/` (optional) |
109
109
 
110
110
  > [!TIP]
111
111
  > **Re-configuration support:** Run `ng add` multiple times freely. The schematic updates existing code without duplicating it.
@@ -372,7 +372,7 @@ The AI Agent Skill tells coding assistants exactly how to implement theme toggle
372
372
 
373
373
  ### Setup
374
374
 
375
- 1. **Automatic:** During `ng add`, you are prompted to generate the skill file. Selecting **Yes** automatically creates `.agent/skills/ngx-theme-stack/SKILL.md` in your project root.
375
+ 1. **Automatic:** During `ng add`, you are prompted to generate the skill file. Selecting **Yes** automatically creates `.agents/skills/ngx-theme-stack/SKILL.md` in your project root.
376
376
  2. **Manual:** If you did not generate it during installation, or deleted it, you can create/re-create the skill by running:
377
377
  ```bash
378
378
  ng generate ngx-theme-stack:skill
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngx-theme-stack",
3
- "version": "3.6.1",
3
+ "version": "3.7.0",
4
4
  "description": "A stack of themes for Angular applications.",
5
5
  "keywords": [
6
6
  "angular",
@@ -36,27 +36,27 @@ Toggle Cycle Select ← Convenience services (pick ONE per component)
36
36
 
37
37
  ## Interaction Rules
38
38
 
39
- When the user asks to implement theme switching but does NOT specify which
40
- service pattern to use, you MUST ask them to choose before writing code.
41
- Present these options clearly:
42
-
43
- 1. **Toggle** A simple on/off switch between dark and light mode.
44
- Best for: apps with only two themes, toggle buttons, icon switches.
45
- 2. **Cycle** — A single button that rotates through all configured themes.
46
- Best for: apps with 3+ themes, minimal UI footprint, "next theme" buttons.
47
- 3. **Select** — A dropdown, radio group, or tab bar showing all theme options.
48
- Best for: settings pages, theme pickers, full visibility of all themes.
49
-
50
- Only proceed after the user confirms their choice.
39
+ > [!IMPORTANT]
40
+ > **MANDATORY INTERACTION RULE**: If the user asks to implement theme switching, configuration, or a theme-related component but does NOT explicitly specify which convenience service to use (\`ThemeToggleService\`, \`ThemeCycleService\`, or \`ThemeSelectService\`), you **MUST NOT** make assumptions or start writing code.
41
+ > You **MUST** stop and ask the user to explicitly choose one of the three patterns before proceeding.
42
+ >
43
+ > Present these options clearly:
44
+ > 1. **Toggle** (\`ThemeToggleService\`) Binary toggle between dark and light themes (best for simple buttons or icon toggles).
45
+ > 2. **Cycle** (\`ThemeCycleService\`) Rotates through all configured themes (best for 3+ themes with a single button).
46
+ > 3. **Select** (\`ThemeSelectService\`) Full dropdown/radio list of all available themes (best for settings pages or explicit pickers).
47
+ >
48
+ > **Custom Themes Inquiry**: In addition to the service choice, you **MUST** ask the user if they want to configure or need any **custom themes** (e.g. \`sunset\`, \`ocean\`, \`sepia\`) beyond the default \`light\`, \`dark\`, and \`system\`. Prompt the user for details on what they are looking for or need (such as specific custom theme names, colors, or CSS variables) to help them scaffold these customizations.
49
+ >
50
+ > **DO NOT** generate any component code or configurations until the user has explicitly responded to these questions.
51
51
 
52
52
  ## Constraints
53
53
 
54
54
  - Always import from \`'ngx-theme-stack'\` — never deep-import internal paths.
55
55
  - Call \`provideThemeStack()\` exactly once, in the root \`app.config.ts\` providers.
56
56
  - Custom themes are **merged** with built-ins. Passing \`['sepia']\` resolves to \`['system', 'light', 'dark', 'sepia']\`.
57
- - After changing themes in \`provideThemeStack()\`, run: \`ng generate ngx-theme-stack:sync --project PROJECT_NAME\`.
57
+ - **Mandatory Theme Synchronization**: After configuring, adding, or modifying themes in \`provideThemeStack()\`, you **MUST** run the synchronization schematic command: \`ng generate ngx-theme-stack:sync --project PROJECT_NAME\` (or explicitly instruct the user to run it if you cannot execute commands). Failing to synchronize themes after modification is a critical violation that breaks theme compilation.
58
58
  - \`isDark()\` and \`isLight()\` return \`false\` for custom themes — use \`resolvedTheme()\` directly.
59
- - Guard theme-dependent template content behind \`isHydrated()\` in SSR to prevent hydration mismatches.
59
+ - **Mandatory SSR Guard**: You MUST guard all theme-dependent template elements (e.g. text, icons, images, styling classes based on theme signals) using \`@if (theme.isHydrated())\`. Using theme signals (\`isDark()\`, \`resolvedTheme()\`, etc.) directly in templates without checking \`isHydrated()\` causes content flickering and critical Angular hydration mismatch errors in SSR.
60
60
  - Never call \`setTheme()\` with a theme name not registered in the \`themes\` array — it throws \`NgxThemeStackError\`.
61
61
  - Pick ONE convenience service per component — do not mix Toggle, Cycle, and Select in the same component.
62
62
 
@@ -114,16 +114,25 @@ All services expose these signals: \`selectedTheme()\`, \`resolvedTheme()\`, \`i
114
114
  For complete component templates, copy from \`assets/\` directory in this skill folder.
115
115
  For full API details, read \`references/api-reference.md\`.
116
116
 
117
- ## SSR Hydration Guard
117
+ ## SSR Hydration Guard & Layout Stability
118
+
119
+ Guard theme-dependent template content behind \`isHydrated()\` in SSR to prevent hydration mismatches and layout flickering.
118
120
 
119
121
  \`\`\`html
120
122
  @if (theme.isHydrated()) {
121
123
  <img [src]="theme.isDark() ? 'dark-logo.png' : 'light-logo.png'">
122
124
  } @else {
123
- <div class="logo-skeleton"></div>
125
+ <!-- The placeholder/skeleton MUST match the exact size and spacing of the hydrated image -->
126
+ <div class="logo-skeleton" style="width: 150px; height: 40px; display: inline-block;"></div>
124
127
  }
125
128
  \`\`\`
126
129
 
130
+ ### Skeleton & Layout Stability Guidelines
131
+
132
+ When designing fallback skeleton loaders/placeholders:
133
+ 1. **Dimension & Spacing Match**: The fallback element (e.g., inside the \`@else\` block) MUST occupy the exact same space, size, margins, padding, positioning, and responsive constraints as the hydrated element. This ensures zero layout shift (preventing CLS issues) and keeps the Largest Contentful Paint (LCP) optimized.
134
+ 2. **Granular Skeletons**: NEVER wrap an entire complex component or large layout block in an \`isHydrated()\` guard if only a single word, label, icon, or sub-element changes dynamically based on the theme. Instead, place the \`isHydrated()\` guard at the most granular level possible (e.g., directly wrapping just the dynamic text or icon inside the button), leaving the surrounding button wrapper and layout static. A full-element skeleton should only be used if the entire component's structure/layout is completely dynamic.
135
+
127
136
  ## CSS Theme Tokens
128
137
 
129
138
  Define in \`src/themes.css\` (scaffolded by \`ng add\`):
@@ -380,7 +389,7 @@ export class ThemeSelect {
380
389
  \`\`\`
381
390
  `;
382
391
  // ── Schematic logic ─────────────────────────────────────────────────────────
383
- const SKILL_ROOT = '.agent/skills/ngx-theme-stack';
392
+ const SKILL_ROOT = '.agents/skills/ngx-theme-stack';
384
393
  const FILES = [
385
394
  { path: `${SKILL_ROOT}/SKILL.md`, content: SKILL_CONTENT },
386
395
  { path: `${SKILL_ROOT}/references/api-reference.md`, content: API_REFERENCE },
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../projects/ngx-theme-stack/schematics/skill/index.ts"],"names":[],"mappings":";;AAgZA,sCAUC;AAED,sBAMC;AA/ZD,+EAA+E;AAE/E,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwJrB,CAAC;AAEF,+EAA+E;AAE/E,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwIrB,CAAC;AAEF,+EAA+E;AAE/E,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBvB,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBtB,CAAC;AAEF,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCvB,CAAC;AAEF,+EAA+E;AAE/E,MAAM,UAAU,GAAG,+BAA+B,CAAC;AAEnD,MAAM,KAAK,GAAwC;IACjD,EAAE,IAAI,EAAE,GAAG,UAAU,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE;IAC1D,EAAE,IAAI,EAAE,GAAG,UAAU,8BAA8B,EAAE,OAAO,EAAE,aAAa,EAAE;IAC7E,EAAE,IAAI,EAAE,GAAG,UAAU,mCAAmC,EAAE,OAAO,EAAE,eAAe,EAAE;IACpF,EAAE,IAAI,EAAE,GAAG,UAAU,kCAAkC,EAAE,OAAO,EAAE,cAAc,EAAE;IAClF,EAAE,IAAI,EAAE,GAAG,UAAU,mCAAmC,EAAE,OAAO,EAAE,eAAe,EAAE;CACrF,CAAC;AAEF,SAAgB,aAAa,CAAC,IAAU,EAAE,OAAyB;IACjE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACxC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,IAAI,YAAY,CAAC,CAAC;QACtE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACrC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAgB,KAAK,CAAC,OAAe;IACnC,OAAO,CAAC,IAAU,EAAE,OAAyB,EAAE,EAAE;QAC/C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACjF,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../projects/ngx-theme-stack/schematics/skill/index.ts"],"names":[],"mappings":";;AAyZA,sCAUC;AAED,sBAMC;AAxaD,+EAA+E;AAE/E,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiKrB,CAAC;AAEF,+EAA+E;AAE/E,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwIrB,CAAC;AAEF,+EAA+E;AAE/E,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBvB,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;CAwBtB,CAAC;AAEF,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCvB,CAAC;AAEF,+EAA+E;AAE/E,MAAM,UAAU,GAAG,gCAAgC,CAAC;AAEpD,MAAM,KAAK,GAAwC;IACjD,EAAE,IAAI,EAAE,GAAG,UAAU,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE;IAC1D,EAAE,IAAI,EAAE,GAAG,UAAU,8BAA8B,EAAE,OAAO,EAAE,aAAa,EAAE;IAC7E,EAAE,IAAI,EAAE,GAAG,UAAU,mCAAmC,EAAE,OAAO,EAAE,eAAe,EAAE;IACpF,EAAE,IAAI,EAAE,GAAG,UAAU,kCAAkC,EAAE,OAAO,EAAE,cAAc,EAAE;IAClF,EAAE,IAAI,EAAE,GAAG,UAAU,mCAAmC,EAAE,OAAO,EAAE,eAAe,EAAE;CACrF,CAAC;AAEF,SAAgB,aAAa,CAAC,IAAU,EAAE,OAAyB;IACjE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACxC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,IAAI,YAAY,CAAC,CAAC;QACtE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACrC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAgB,KAAK,CAAC,OAAe;IACnC,OAAO,CAAC,IAAU,EAAE,OAAyB,EAAE,EAAE;QAC/C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QACjF,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC"}