ps-helix 4.1.0 → 5.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A comprehensive Angular component library built with Angular 21+ featuring modern design patterns, accessibility-first development, and optimal developer experience.
4
4
 
5
- [![npm version](https://img.shields.io/badge/npm-4.1.0-blue.svg)](https://www.npmjs.com/package/ps-helix)
5
+ [![npm version](https://img.shields.io/badge/npm-5.0.0-blue.svg)](https://www.npmjs.com/package/ps-helix)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
  [![Angular](https://img.shields.io/badge/Angular-21.0.3-red.svg)](https://angular.dev/)
8
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9.0-blue.svg)](https://www.typescriptlang.org/)
@@ -106,7 +106,7 @@ After installation, verify that ps-helix is in your `package.json`:
106
106
  ```json
107
107
  {
108
108
  "dependencies": {
109
- "ps-helix": "^4.1.0"
109
+ "ps-helix": "^5.0.0"
110
110
  }
111
111
  }
112
112
  ```
@@ -1182,7 +1182,7 @@ Copyright (c) 2025 PACK Solutions
1182
1182
 
1183
1183
  ---
1184
1184
 
1185
- **Version**: 4.1.0
1185
+ **Version**: 5.0.0
1186
1186
  **Built with**: Angular 21.0.3, TypeScript 5.9.0, Phosphor Icons 2.0.3
1187
1187
  **Author**: Fabrice PEREZ | Product Designer at PACK Solutions
1188
1188
  **Last Updated**: January 2026
package/THEME.md CHANGED
@@ -8,19 +8,21 @@ This guide explains how to customize the colors and theme of the Helix Design Sy
8
8
  - [Quick Start](#quick-start)
9
9
  - [Theme Service](#theme-service)
10
10
  - [Custom Colors with Injection Token](#custom-colors-with-injection-token)
11
+ - [Accessibility Safeguard (WCAG)](#accessibility-safeguard-wcag)
11
12
  - [Available CSS Variables](#available-css-variables)
12
13
  - [Dynamic Color Changes](#dynamic-color-changes)
13
14
  - [Examples](#examples)
14
15
 
15
16
  ## Overview
16
17
 
17
- The Helix Design System uses a sophisticated theming system that supports:
18
+ The Helix Design System uses a signal-based theming system that supports:
18
19
 
19
20
  - Light and dark themes
20
- - Custom primary and secondary colors
21
- - Automatic color variant generation (lighter, darker)
22
- - Automatic text color calculation for accessibility
21
+ - Custom primary and secondary brand colors (customer context)
22
+ - Automatic variant generation in OKLCH (hue and chroma preserved, lightness adjusted per mode)
23
+ - WCAG contrast safeguard: a brand color that does not meet the target contrast ratio against the current theme background is silently adjusted before being applied to UI components
23
24
  - Dynamic theme switching at runtime
25
+ - Theme preference persistence in `localStorage` (key: `helix-theme-preference`)
24
26
 
25
27
  ## Quick Start
26
28
 
@@ -34,7 +36,6 @@ import { ThemeService } from 'ps-helix';
34
36
 
35
37
  @Component({
36
38
  selector: 'app-root',
37
- standalone: true,
38
39
  template: `
39
40
  <button (click)="toggleTheme()">
40
41
  Current theme: {{ themeService.themeName() }}
@@ -58,59 +59,67 @@ The `ThemeService` provides the following API:
58
59
 
59
60
  - `setDarkTheme(isDark: boolean)` - Set the theme to dark or light
60
61
  - `toggleTheme()` - Toggle between light and dark themes
61
- - `updateTheme(name: Theme)` - Update theme by name ('light' or 'dark')
62
- - `applyInsurerTheme()` - Apply custom colors (usually called automatically)
62
+ - `updateTheme(name: Theme)` - Update theme by name (`'light'` or `'dark'`) and persist it in localStorage
63
+ - `applyCustomerTheme()` - Re-apply brand colors from the customer context (usually called automatically after theme changes or when the context updates)
63
64
 
64
65
  ### Computed Signals
65
66
 
66
- - `themeName()` - Returns current theme name ('light' or 'dark')
67
- - `isDarkTheme()` - Returns boolean indicating if dark theme is active
68
- - `themeInfo()` - Returns complete theme information including last change date
67
+ - `themeName()` - Returns current theme name (`'light'` or `'dark'`)
68
+ - `isDarkTheme()` - Returns a boolean indicating whether dark theme is active
69
+ - `themeInfo()` - Returns complete theme information including the last change date
69
70
 
70
- ## Default Colors
71
+ ### Types
71
72
 
72
- If you don't provide custom colors, the design system uses the following default theme colors:
73
+ ```typescript
74
+ export type Theme = 'light' | 'dark';
75
+
76
+ export interface ThemeConfig {
77
+ isDark: boolean;
78
+ name: Theme;
79
+ customerTheme?: {
80
+ primaryColor: string;
81
+ secondaryColor?: string;
82
+ };
83
+ }
84
+ ```
73
85
 
74
- - **Primary Color**: `#0F02C4` (Deep Blue)
75
- - **Secondary Color**: `#7B3AEC` (Purple)
86
+ ## Default Colors
76
87
 
77
- These colors are used across all components and automatically generate variants (lighter/darker shades) and accessible text colors.
88
+ If you don't provide custom colors, the design system falls back to the CSS defaults defined in the theme files:
78
89
 
79
- ## Custom Colors with Injection Token
90
+ - Light mode primary: `#0B0191`
91
+ - Dark mode primary: `#8178F7`
92
+ - Light mode secondary: `#5E5E5E`
93
+ - Dark mode secondary: `#5B5A5A`
80
94
 
81
- To customize the primary and secondary colors of your design system to match your brand, you need to provide a service that implements the color interface using Angular's dependency injection system.
95
+ These defaults are defined in `projects/ps-helix/src/lib/styles/themes/light.css` and `dark.css`.
82
96
 
83
- ### Why Not Just CSS Variables?
97
+ ## Custom Colors with Injection Token
84
98
 
85
- The design system uses an **injection token system** instead of simple CSS variable overrides because:
99
+ To customize the primary and secondary colors of your design system to match your brand, provide a service that implements `CustomerContextService` through the `CUSTOMER_CONTEXT_SERVICE` injection token.
86
100
 
87
- 1. Colors are dynamically calculated with variants (lighter, darker, etc.)
88
- 2. Text colors are automatically determined based on background luminance for accessibility
89
- 3. Changes can be reactive and propagate through the application
90
- 4. It provides type safety and better Angular integration
101
+ ### Why an Injection Token and not just CSS variables?
91
102
 
92
- ### Step 1: Create a Theme Context Service
103
+ 1. Variants (light, lighter, dark, darker) are computed in OKLCH at runtime and depend on the current theme (light vs dark).
104
+ 2. Text color on top of brand colors is computed from real WCAG contrast ratios.
105
+ 3. Brand colors are verified against a minimum contrast ratio and silently adjusted for UI usage when needed; the original color is still exposed as `-source` for decorative contexts.
106
+ 4. The token keeps everything type-safe and reactive via Angular DI.
93
107
 
94
- Create a service in your application that implements the `InsurerContextService` interface:
108
+ ### Step 1: Create a Customer Context Service
95
109
 
96
110
  ```typescript
97
111
  // src/app/services/app-theme-context.service.ts
98
112
  import { Injectable, signal } from '@angular/core';
99
- import { InsurerContextService } from 'ps-helix';
113
+ import { CustomerContextService } from 'ps-helix';
100
114
 
101
- @Injectable({
102
- providedIn: 'root'
103
- })
104
- export class AppThemeContextService implements InsurerContextService {
105
- // Define your custom colors using signals for reactivity
106
- private primaryColorSignal = signal('#FF0000'); // Your primary color
107
- private secondaryColorSignal = signal('#00AA00'); // Your secondary color
115
+ @Injectable({ providedIn: 'root' })
116
+ export class AppThemeContextService implements CustomerContextService {
117
+ private primaryColorSignal = signal('#FF0000');
118
+ private secondaryColorSignal = signal('#00AA00');
108
119
 
109
- // Expose as readonly signals - required by InsurerContextService interface
110
120
  primaryColor = this.primaryColorSignal.asReadonly();
111
121
  secondaryColor = this.secondaryColorSignal.asReadonly();
112
122
 
113
- // Optional: Methods to change colors dynamically
114
123
  setPrimaryColor(color: string) {
115
124
  this.primaryColorSignal.set(color);
116
125
  }
@@ -121,121 +130,143 @@ export class AppThemeContextService implements InsurerContextService {
121
130
  }
122
131
  ```
123
132
 
124
- The `InsurerContextService` interface requires two methods:
125
- - `primaryColor(): string` - Returns the primary brand color
126
- - `secondaryColor(): string` - Returns the secondary brand color
133
+ The `CustomerContextService` interface requires two methods:
127
134
 
128
- ### Step 2: Provide the Service with the Injection Token
135
+ - `primaryColor(): string` - Returns the primary brand color (hex)
136
+ - `secondaryColor(): string` - Returns the secondary brand color (hex)
129
137
 
130
- In your application configuration (usually `app.config.ts` or `main.ts`), provide your service using the `INSURER_CONTEXT_SERVICE` token:
138
+ ### Step 2: Provide the Service with the Injection Token
131
139
 
132
140
  ```typescript
133
141
  // src/app/app.config.ts
134
142
  import { ApplicationConfig } from '@angular/core';
135
143
  import { provideRouter } from '@angular/router';
136
- import { INSURER_CONTEXT_SERVICE } from 'ps-helix';
144
+ import { CUSTOMER_CONTEXT_SERVICE } from 'ps-helix';
137
145
  import { AppThemeContextService } from './services/app-theme-context.service';
138
146
  import { routes } from './app.routes';
139
147
 
140
148
  export const appConfig: ApplicationConfig = {
141
149
  providers: [
142
150
  provideRouter(routes),
143
- // Connect your service to the design system's injection token
144
151
  {
145
- provide: INSURER_CONTEXT_SERVICE,
152
+ provide: CUSTOMER_CONTEXT_SERVICE,
146
153
  useExisting: AppThemeContextService
147
154
  }
148
155
  ]
149
156
  };
150
157
  ```
151
158
 
152
- ### Step 3: Initialize the Theme (Optional)
153
-
154
- In your root component, you can inject the `ThemeService` to ensure the theme is applied:
159
+ ### Step 3: Re-apply the Theme (Optional)
155
160
 
156
161
  ```typescript
157
- // src/app/app.component.ts
158
162
  import { Component, inject, OnInit } from '@angular/core';
159
163
  import { ThemeService } from 'ps-helix';
160
164
 
161
165
  @Component({
162
166
  selector: 'app-root',
163
- standalone: true,
164
167
  template: `<router-outlet />`
165
168
  })
166
169
  export class AppComponent implements OnInit {
167
170
  private themeService = inject(ThemeService);
168
171
 
169
172
  ngOnInit() {
170
- // Theme is applied automatically, but you can force it if needed
171
- this.themeService.applyInsurerTheme();
173
+ this.themeService.applyCustomerTheme();
172
174
  }
173
175
  }
174
176
  ```
175
177
 
176
178
  ### Alternative: Simple Non-Reactive Service
177
179
 
178
- If you don't need dynamic color changes, you can use a simpler implementation without signals:
179
-
180
180
  ```typescript
181
181
  import { Injectable } from '@angular/core';
182
- import { InsurerContextService } from 'ps-helix';
183
-
184
- @Injectable({
185
- providedIn: 'root'
186
- })
187
- export class AppThemeContextService implements InsurerContextService {
188
- primaryColor() {
189
- return '#FF0000';
190
- }
182
+ import { CustomerContextService } from 'ps-helix';
191
183
 
192
- secondaryColor() {
193
- return '#00AA00';
194
- }
184
+ @Injectable({ providedIn: 'root' })
185
+ export class AppThemeContextService implements CustomerContextService {
186
+ primaryColor() { return '#FF0000'; }
187
+ secondaryColor() { return '#00AA00'; }
195
188
  }
196
189
  ```
197
190
 
198
- This approach returns static colors and is perfect when you don't need runtime color changes.
191
+ ## Accessibility Safeguard (WCAG)
192
+
193
+ When `applyCustomerTheme()` runs, each brand color is evaluated against the current theme background:
194
+
195
+ - Contrast is computed using the true WCAG 2.1 relative luminance formula.
196
+ - If the ratio is below the target (AA by default, AAA if configured), the color is adjusted in OKLCH: the luminance is shifted (darker on light backgrounds, lighter on dark backgrounds) while hue and chroma are preserved as much as possible.
197
+ - The adjusted color is written into `--customer-primary-color` / `--customer-secondary-color` and consumed by every UI component.
198
+ - The original, unmodified brand color is written into `--customer-primary-color-source` / `--customer-secondary-color-source`, available for decorative surfaces (logos, marketing images) where the contrast rule does not apply.
199
+ - The service never logs or warns: the adjustment is silent by design.
200
+
201
+ ### Configuring the Target Ratio
202
+
203
+ Use the `PSH_THEME_OPTIONS` injection token to opt into AAA:
204
+
205
+ ```typescript
206
+ import { PSH_THEME_OPTIONS, PshThemeOptions } from 'ps-helix';
207
+
208
+ export const appConfig: ApplicationConfig = {
209
+ providers: [
210
+ {
211
+ provide: PSH_THEME_OPTIONS,
212
+ useValue: { targetContrast: 'AAA' } satisfies PshThemeOptions
213
+ }
214
+ ]
215
+ };
216
+ ```
217
+
218
+ Default is `'AA'` (ratio 4.5:1). `'AAA'` raises the requirement to 7:1.
219
+
220
+ ### OKLCH Variant Derivation
221
+
222
+ The four tonal variants (`light`, `lighter`, `dark`, `darker`) are generated by shifting the OKLCH lightness of the accessible base color with mode-aware deltas:
223
+
224
+ | Mode | light | lighter | dark | darker |
225
+ |-------|-------|---------|-------|--------|
226
+ | Light | +0.08 | +0.18 | -0.08 | -0.16 |
227
+ | Dark | +0.06 | +0.14 | -0.06 | -0.14 |
228
+
229
+ Hue and chroma are preserved so the color palette stays perceptually consistent. Fixed percentage RGB lightening/darkening is no longer used.
199
230
 
200
231
  ## Available CSS Variables
201
232
 
202
- Once configured, the `ThemeService` automatically generates the following CSS variables:
233
+ Once configured, `ThemeService` writes the following CSS variables on `:root`:
203
234
 
204
235
  ### Primary Color Variables
205
236
 
206
- - `--insurer-primary-color` - Your primary color
207
- - `--insurer-primary-color-light` - Lightened by 20%
208
- - `--insurer-primary-color-lighter` - Lightened by 40%
209
- - `--insurer-primary-color-dark` - Darkened by 20%
210
- - `--insurer-primary-color-darker` - Darkened by 40%
211
- - `--insurer-primary-color-text` - Calculated text color (black or white) for accessibility
212
- - `--insurer-primary-color-rgb` - RGB values for transparency usage
237
+ - `--customer-primary-color` - Accessibility-adjusted primary color (used by components)
238
+ - `--customer-primary-color-source` - Original brand color, unmodified (for decorative use only)
239
+ - `--customer-primary-color-light` - OKLCH-derived lighter variant
240
+ - `--customer-primary-color-lighter` - OKLCH-derived extra light variant
241
+ - `--customer-primary-color-dark` - OKLCH-derived darker variant
242
+ - `--customer-primary-color-darker` - OKLCH-derived extra dark variant
243
+ - `--customer-primary-color-text` - Readable text color (black or white) picked via WCAG contrast against the adjusted primary
244
+ - `--customer-primary-color-rgb` - `r, g, b` triplet of the adjusted primary for `rgba()` usage
213
245
 
214
246
  ### Secondary Color Variables
215
247
 
216
- - `--insurer-secondary-color`
217
- - `--insurer-secondary-color-light`
218
- - `--insurer-secondary-color-lighter`
219
- - `--insurer-secondary-color-dark`
220
- - `--insurer-secondary-color-darker`
221
- - `--insurer-secondary-color-text`
222
- - `--insurer-secondary-color-rgb`
248
+ - `--customer-secondary-color`
249
+ - `--customer-secondary-color-source`
250
+ - `--customer-secondary-color-light`
251
+ - `--customer-secondary-color-lighter`
252
+ - `--customer-secondary-color-dark`
253
+ - `--customer-secondary-color-darker`
254
+ - `--customer-secondary-color-text`
255
+ - `--customer-secondary-color-rgb`
223
256
 
224
257
  ### Component Usage
225
258
 
226
- These variables are automatically used by design system components through fallback chains:
259
+ Design system components consume the stable abstract variables, which fall back to the defaults when no customer context is provided:
227
260
 
228
261
  ```css
229
- /* Example from the design system */
230
- --primary-color: var(--insurer-primary-color, #1002C5);
231
- --primary-color-light: var(--insurer-primary-color-light, #8080FF);
262
+ /* From projects/ps-helix/src/lib/styles/themes/light.css */
263
+ --primary-color: var(--customer-primary-color, #0B0191);
264
+ --primary-color-light: var(--customer-primary-color-light, #0F02C4);
232
265
  ```
233
266
 
234
- If you provide a custom color through the injection token, it takes precedence. Otherwise, the default color is used.
235
-
236
267
  ### Using in Your Custom Styles
237
268
 
238
- You can also use these variables in your own components:
269
+ Use the abstract variables (`--primary-color`, `--secondary-color`, ...) in your own components so you automatically inherit the accessibility-adjusted palette:
239
270
 
240
271
  ```css
241
272
  .my-custom-button {
@@ -248,9 +279,17 @@ You can also use these variables in your own components:
248
279
  }
249
280
  ```
250
281
 
282
+ For decorative brand elements that must match the literal brand color (e.g. a logo background), use the `-source` variable:
283
+
284
+ ```css
285
+ .brand-logo-surface {
286
+ background-color: var(--customer-primary-color-source);
287
+ }
288
+ ```
289
+
251
290
  ## Dynamic Color Changes
252
291
 
253
- Since the theme context service uses signals, you can change colors dynamically at runtime:
292
+ Since the customer context service uses signals, you can change colors at runtime:
254
293
 
255
294
  ```typescript
256
295
  import { Component, inject } from '@angular/core';
@@ -259,13 +298,10 @@ import { AppThemeContextService } from './services/app-theme-context.service';
259
298
 
260
299
  @Component({
261
300
  selector: 'app-theme-switcher',
262
- standalone: true,
263
301
  template: `
264
- <div>
265
- <button (click)="setRedTheme()">Red Theme</button>
266
- <button (click)="setBlueTheme()">Blue Theme</button>
267
- <button (click)="setGreenTheme()">Green Theme</button>
268
- </div>
302
+ <button (click)="setRedTheme()">Red</button>
303
+ <button (click)="setBlueTheme()">Blue</button>
304
+ <button (click)="setGreenTheme()">Green</button>
269
305
  `
270
306
  })
271
307
  export class ThemeSwitcherComponent {
@@ -275,19 +311,19 @@ export class ThemeSwitcherComponent {
275
311
  setRedTheme() {
276
312
  this.themeContext.setPrimaryColor('#DC2626');
277
313
  this.themeContext.setSecondaryColor('#EF4444');
278
- this.themeService.applyInsurerTheme();
314
+ this.themeService.applyCustomerTheme();
279
315
  }
280
316
 
281
317
  setBlueTheme() {
282
318
  this.themeContext.setPrimaryColor('#2563EB');
283
319
  this.themeContext.setSecondaryColor('#3B82F6');
284
- this.themeService.applyInsurerTheme();
320
+ this.themeService.applyCustomerTheme();
285
321
  }
286
322
 
287
323
  setGreenTheme() {
288
324
  this.themeContext.setPrimaryColor('#16A34A');
289
325
  this.themeContext.setSecondaryColor('#22C55E');
290
- this.themeService.applyInsurerTheme();
326
+ this.themeService.applyCustomerTheme();
291
327
  }
292
328
  }
293
329
  ```
@@ -296,15 +332,11 @@ export class ThemeSwitcherComponent {
296
332
 
297
333
  ### Example 1: Brand Colors from Configuration
298
334
 
299
- Load colors from a configuration file or environment:
300
-
301
335
  ```typescript
302
336
  import { Injectable, signal } from '@angular/core';
303
337
  import { environment } from '../environments/environment';
304
338
 
305
- @Injectable({
306
- providedIn: 'root'
307
- })
339
+ @Injectable({ providedIn: 'root' })
308
340
  export class AppThemeContextService {
309
341
  private primaryColorSignal = signal(environment.brandPrimaryColor);
310
342
  private secondaryColorSignal = signal(environment.brandSecondaryColor);
@@ -316,51 +348,36 @@ export class AppThemeContextService {
316
348
 
317
349
  ### Example 2: User-Selected Theme
318
350
 
319
- Allow users to customize their theme:
320
-
321
351
  ```typescript
322
352
  import { Injectable, signal, effect } from '@angular/core';
323
353
 
324
- @Injectable({
325
- providedIn: 'root'
326
- })
354
+ @Injectable({ providedIn: 'root' })
327
355
  export class AppThemeContextService {
328
- private primaryColorSignal = signal(this.loadFromStorage('primaryColor', '#1002C5'));
329
- private secondaryColorSignal = signal(this.loadFromStorage('secondaryColor', '#7B3AEC'));
356
+ private primaryColorSignal = signal(this.loadFromStorage('primaryColor', '#0B0191'));
357
+ private secondaryColorSignal = signal(this.loadFromStorage('secondaryColor', '#5E5E5E'));
330
358
 
331
359
  primaryColor = this.primaryColorSignal.asReadonly();
332
360
  secondaryColor = this.secondaryColorSignal.asReadonly();
333
361
 
334
362
  constructor() {
335
- // Save to localStorage when colors change
336
363
  effect(() => {
337
364
  localStorage.setItem('primaryColor', this.primaryColorSignal());
338
365
  localStorage.setItem('secondaryColor', this.secondaryColorSignal());
339
366
  });
340
367
  }
341
368
 
342
- setPrimaryColor(color: string) {
343
- this.primaryColorSignal.set(color);
344
- }
345
-
346
- setSecondaryColor(color: string) {
347
- this.secondaryColorSignal.set(color);
348
- }
369
+ setPrimaryColor(color: string) { this.primaryColorSignal.set(color); }
370
+ setSecondaryColor(color: string) { this.secondaryColorSignal.set(color); }
349
371
 
350
372
  private loadFromStorage(key: string, defaultValue: string): string {
351
- try {
352
- return localStorage.getItem(key) || defaultValue;
353
- } catch {
354
- return defaultValue;
355
- }
373
+ try { return localStorage.getItem(key) || defaultValue; }
374
+ catch { return defaultValue; }
356
375
  }
357
376
  }
358
377
  ```
359
378
 
360
379
  ### Example 3: Multi-Tenant Application
361
380
 
362
- Different colors per tenant/client:
363
-
364
381
  ```typescript
365
382
  import { Injectable, signal } from '@angular/core';
366
383
 
@@ -375,9 +392,7 @@ const TENANT_THEMES: Record<string, TenantTheme> = {
375
392
  'tenant-c': { primary: '#16A34A', secondary: '#22C55E' }
376
393
  };
377
394
 
378
- @Injectable({
379
- providedIn: 'root'
380
- })
395
+ @Injectable({ providedIn: 'root' })
381
396
  export class AppThemeContextService {
382
397
  private currentTenantId = signal<string>('tenant-a');
383
398
  private primaryColorSignal = signal(TENANT_THEMES['tenant-a'].primary);
@@ -399,45 +414,33 @@ export class AppThemeContextService {
399
414
 
400
415
  ## Troubleshooting
401
416
 
402
- ### Colors Not Applying
403
-
404
- 1. **Check if the service is provided correctly**: Verify that you've provided your service with the `INSURER_CONTEXT_SERVICE` token in your app config.
405
-
406
- 2. **Check the console**: The `ThemeService` logs information about color application. Look for messages like:
407
- ```
408
- Applying theme colors: { primaryColor: '#FF0000', ... }
409
- Applied insurer theme with primary color: #FF0000
410
- ```
411
-
412
- 3. **Verify the service implementation**: Make sure your service has `primaryColor()` and `secondaryColor()` methods that return strings.
413
-
414
- ### Default Colors Showing Instead of Custom Colors
417
+ ### Colors not applying
415
418
 
416
- If you see the default blue colors (`#1002C5`) instead of your custom colors:
419
+ 1. Verify that your service is provided with the `CUSTOMER_CONTEXT_SERVICE` token in your app config.
420
+ 2. Confirm your service implements `primaryColor()` and `secondaryColor()` returning valid hex strings.
421
+ 3. `ThemeService` is silent by design; if a brand color looks different from the one you provided, it is because the WCAG safeguard adjusted it. Read the adjusted color via `getComputedStyle(document.documentElement).getPropertyValue('--customer-primary-color')` and the original via `--customer-primary-color-source`.
417
422
 
418
- 1. The service might not be injected properly
419
- 2. The methods might not be returning valid hex color codes
420
- 3. Check the browser console for error messages
423
+ ### Default colors showing instead of custom colors
421
424
 
422
- ### Colors Not Updating Dynamically
425
+ - The context service is not provided, or
426
+ - `primaryColor()` / `secondaryColor()` return an invalid hex string.
423
427
 
424
- If colors don't update when you call `setPrimaryColor()`:
428
+ ### Colors not updating dynamically
425
429
 
426
- 1. Make sure you're calling `this.themeService.applyInsurerTheme()` after changing the colors
427
- 2. Verify that your signals are updating correctly
428
- 3. Check that the ThemeService is injected in your component
430
+ 1. Make sure you call `this.themeService.applyCustomerTheme()` after changing a color.
431
+ 2. Verify that your signals are actually updating.
432
+ 3. Confirm `ThemeService` is injected in the component driving the change.
429
433
 
430
434
  ## Best Practices
431
435
 
432
- 1. **Use Signals**: Always use Angular signals for reactive color management
433
- 2. **Validate Colors**: Ensure color values are valid hex codes (e.g., `#FF0000`)
434
- 3. **Accessibility**: Let the ThemeService calculate text colors automatically for proper contrast
435
- 4. **Persistence**: Consider saving user color preferences to localStorage
436
- 5. **Defaults**: Always provide sensible default colors as fallbacks
437
- 6. **Documentation**: Document your color choices and brand guidelines
436
+ 1. Use signals in your customer context service for reactivity.
437
+ 2. Provide valid hex colors (`#RRGGBB`).
438
+ 3. Trust the WCAG safeguard; do not hand-tune base colors for contrast.
439
+ 4. For decorative brand surfaces, use `--customer-*-color-source`. For every other UI use case, use the abstract variables (`--primary-color`, ...).
440
+ 5. Persist user preferences in `localStorage` when relevant.
441
+ 6. Document brand color choices alongside your app's style guide.
438
442
 
439
443
  ## Related Documentation
440
444
 
441
445
  - [Component Documentation](./README.md)
442
446
  - [Translation Guide](./lib/services/translation/README.md)
443
- - [Accessibility Guidelines](./ACCESSIBILITY.md)