ps-helix 7.0.0 → 7.0.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
@@ -2,7 +2,7 @@
2
2
 
3
3
  A comprehensive Angular component library built with Angular 22+ featuring modern design patterns, accessibility-first development, and optimal developer experience.
4
4
 
5
- [![npm version](https://img.shields.io/badge/npm-7.0.0-blue.svg)](https://www.npmjs.com/package/ps-helix)
5
+ [![npm version](https://img.shields.io/badge/npm-7.0.1-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-22.0.0-red.svg)](https://angular.dev/)
8
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-6.0.0-blue.svg)](https://www.typescriptlang.org/)
@@ -108,7 +108,7 @@ After installation, verify that ps-helix is in your `package.json`:
108
108
  ```json
109
109
  {
110
110
  "dependencies": {
111
- "ps-helix": "^7.0.0"
111
+ "ps-helix": "^7.0.1"
112
112
  }
113
113
  }
114
114
  ```
@@ -1188,7 +1188,7 @@ Copyright (c) 2025 PACK Solutions
1188
1188
 
1189
1189
  ---
1190
1190
 
1191
- **Version**: 7.0.0
1191
+ **Version**: 7.0.1
1192
1192
  **Built with**: Angular 22.0.0, TypeScript 6.0.0, Phosphor Icons 2.0.3
1193
1193
  **Author**: Fabrice PEREZ | Design Engineer at PACK Solutions
1194
1194
  **Last Updated**: January 2026
package/TOKENS.md CHANGED
@@ -39,7 +39,7 @@ used before 7.0.0 remain available through the opt-in `styles/compat.css`.
39
39
  | `--psh-text-color-secondary` | `var(--psh-surface-600)` | `rgba(255, 255, 255, 0.75)` |
40
40
  | `--psh-text-color-tertiary` | `var(--psh-surface-500)` | `rgba(255, 255, 255, 0.6)` |
41
41
  | `--psh-text-color-disabled` | `var(--psh-surface-400)` | `rgba(255, 255, 255, 0.4)` |
42
- | `--psh-text-on-primary` | `#FFFFFF` | `#FFFFFF` |
42
+ | `--psh-text-on-primary` | `#FFFFFF` | `#000000` |
43
43
  | `--psh-text-on-secondary` | `#FFFFFF` | `#FFFFFF` |
44
44
  | `--psh-text-on-success` | `#FFFFFF` | `#000000` |
45
45
  | `--psh-text-on-warning` | `#FFFFFF` | `#000000` |
@@ -214,23 +214,31 @@ class ThemeService {
214
214
  this.initializeTheme();
215
215
  afterNextRender(() => this.applyCustomerTheme());
216
216
  }
217
+ /**
218
+ * Switches theme *and* remembers the choice — the two halves of what a theme toggle
219
+ * means. They used to be split across two methods: `setDarkTheme` wrote `data-theme`
220
+ * without persisting, `updateTheme` persisted without writing `data-theme`. Whichever
221
+ * one a consumer picked, half the job was missing, and the demo's own toggle reverted
222
+ * on every reload.
223
+ */
217
224
  setDarkTheme(isDark) {
218
- if (this.isBrowser) {
219
- this.document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
220
- }
221
- this.isDarkThemeSignal.set(isDark);
222
- this.themeNameSignal.set(isDark ? 'dark' : 'light');
223
- this.lastChangeSignal.set(new Date());
224
- this.applyCustomerTheme();
225
+ this.applyTheme(isDark);
226
+ this.saveThemePreference(isDark ? 'dark' : 'light');
225
227
  }
226
228
  toggleTheme() {
227
229
  this.setDarkTheme(!this.isDarkThemeSignal());
228
230
  }
229
231
  updateTheme(name) {
230
- this.themeNameSignal.set(name);
231
- this.isDarkThemeSignal.set(name === 'dark');
232
+ this.setDarkTheme(name === 'dark');
233
+ }
234
+ /** The visible half: the attribute the stylesheets read, and the derived palette. */
235
+ applyTheme(isDark) {
236
+ if (this.isBrowser) {
237
+ this.document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
238
+ }
239
+ this.isDarkThemeSignal.set(isDark);
240
+ this.themeNameSignal.set(isDark ? 'dark' : 'light');
232
241
  this.lastChangeSignal.set(new Date());
233
- this.saveThemePreference(name);
234
242
  this.applyCustomerTheme();
235
243
  }
236
244
  /**
@@ -322,7 +330,9 @@ class ThemeService {
322
330
  const isValid = savedTheme === 'light' || savedTheme === 'dark';
323
331
  // No stored preference → honour the OS "prefers-color-scheme" setting.
324
332
  const initial = isValid ? savedTheme : this.prefersDarkScheme() ? 'dark' : 'light';
325
- this.setDarkTheme(initial === 'dark');
333
+ // Applied, not saved: with nothing stored the theme follows the OS, and writing the
334
+ // first value read would pin it there forever.
335
+ this.applyTheme(initial === 'dark');
326
336
  }
327
337
  /** True when the OS/browser requests a dark colour scheme. */
328
338
  prefersDarkScheme() {
@@ -4370,10 +4380,15 @@ class PshInputComponent {
4370
4380
  }
4371
4381
  break;
4372
4382
  case 'Escape':
4373
- event.preventDefault();
4374
- this.suggestionsVisible.set(false);
4375
- this.focusedSuggestionIndex.set(-1);
4376
- this.syncPanel();
4383
+ // Only when suggestions are showing. Otherwise the keypress belongs to whatever
4384
+ // encloses the field — a modal, most often — and must reach it.
4385
+ if (this.suggestionsVisible()) {
4386
+ event.preventDefault();
4387
+ event.stopPropagation();
4388
+ this.suggestionsVisible.set(false);
4389
+ this.focusedSuggestionIndex.set(-1);
4390
+ this.syncPanel();
4391
+ }
4377
4392
  break;
4378
4393
  }
4379
4394
  }
@@ -6859,6 +6874,7 @@ class PshCollapseComponent {
6859
6874
  case 'Escape':
6860
6875
  if (this.expanded()) {
6861
6876
  event.preventDefault();
6877
+ event.stopPropagation();
6862
6878
  this.close();
6863
6879
  }
6864
6880
  break;
@@ -7120,8 +7136,10 @@ class PshDropdownComponent {
7120
7136
  }
7121
7137
  break;
7122
7138
  case 'Escape':
7139
+ // Consumed here, so an enclosing modal does not also close on the same keypress.
7123
7140
  if (this.isOpen()) {
7124
7141
  event.preventDefault();
7142
+ event.stopPropagation();
7125
7143
  this.close();
7126
7144
  }
7127
7145
  break;
@@ -7152,6 +7170,7 @@ class PshDropdownComponent {
7152
7170
  break;
7153
7171
  case 'Escape':
7154
7172
  event.preventDefault();
7173
+ event.stopPropagation();
7155
7174
  this.close();
7156
7175
  break;
7157
7176
  case 'Tab':
@@ -7682,6 +7701,7 @@ class PshMenuComponent {
7682
7701
  case 'Escape':
7683
7702
  if (this.collapsible() && !this.collapsed()) {
7684
7703
  event.preventDefault();
7704
+ event.stopPropagation();
7685
7705
  this.toggleCollapse();
7686
7706
  }
7687
7707
  break;
@@ -8160,7 +8180,14 @@ class PshSelectComponent {
8160
8180
  this.focusLast();
8161
8181
  break;
8162
8182
  case 'Escape':
8163
- this.close();
8183
+ // Only when there is a panel to dismiss, and then the event stops here: a modal
8184
+ // listens for Escape on the document, so letting it through would close the whole
8185
+ // dialog — the user's form — for someone who only wanted the list gone.
8186
+ if (this.isOpen()) {
8187
+ event.preventDefault();
8188
+ event.stopPropagation();
8189
+ this.close();
8190
+ }
8164
8191
  break;
8165
8192
  case 'Tab':
8166
8193
  this.close();