ps-helix 5.1.2 → 6.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 +1188 -1188
- package/THEME.md +446 -446
- package/fesm2022/ps-helix.mjs +1949 -1012
- package/fesm2022/ps-helix.mjs.map +1 -1
- package/package.json +6 -5
- package/src/lib/styles/base/global.css +48 -32
- package/src/lib/styles/themes/dark.css +200 -200
- package/src/lib/styles/themes/light.css +278 -278
- package/src/lib/styles/tokens/breakpoints.tokens.css +20 -0
- package/src/lib/styles/tokens/sizing.tokens.css +94 -94
- package/src/lib/styles/tokens/spacing.tokens.css +27 -27
- package/src/lib/styles/utilities/animations.utils.css +157 -157
- package/src/lib/styles/utilities/colors.utils.css +223 -223
- package/src/lib/styles/utilities/focus.utils.css +56 -62
- package/src/lib/styles/utilities/layout.utils.css +135 -135
- package/src/lib/styles/utilities/responsive.utils.css +219 -226
- package/src/lib/styles/utilities/spacing.utils.css +150 -150
- package/src/lib/styles/utilities/typography.utils.css +36 -36
- package/styles.css +34 -33
- package/types/ps-helix.d.ts +291 -67
package/README.md
CHANGED
|
@@ -1,1188 +1,1188 @@
|
|
|
1
|
-
# Helix Design System
|
|
2
|
-
|
|
3
|
-
A comprehensive Angular component library built with Angular
|
|
4
|
-
|
|
5
|
-
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[
|
|
13
|
-
- [Prerequisites](#prerequisites)
|
|
14
|
-
- [Installation](#installation)
|
|
15
|
-
- [Quick Start](#quick-start)
|
|
16
|
-
- [Configuration](#configuration)
|
|
17
|
-
- [Global Styles](#global-styles)
|
|
18
|
-
- [Phosphor Icons Setup](#phosphor-icons-setup)
|
|
19
|
-
- [Theme Service](#theme-service)
|
|
20
|
-
- [Translation Service](#translation-service)
|
|
21
|
-
- [Scroll Service](#scroll-service)
|
|
22
|
-
- [Core Concepts](#core-concepts)
|
|
23
|
-
- [Standalone Components](#standalone-components)
|
|
24
|
-
- [Signal-Based Reactivity](#signal-based-reactivity)
|
|
25
|
-
- [Type Safety](#type-safety)
|
|
26
|
-
- [Dependency Injection](#dependency-injection)
|
|
27
|
-
- [Available Components](#available-components)
|
|
28
|
-
- [Service APIs](#service-apis)
|
|
29
|
-
- [ThemeService](#themeservice)
|
|
30
|
-
- [ToastService](#toastservice)
|
|
31
|
-
- [ScrollService](#scrollservice)
|
|
32
|
-
- [TranslationService](#translationservice)
|
|
33
|
-
- [Exported Types](#exported-types)
|
|
34
|
-
- [Theming](#theming)
|
|
35
|
-
- [Best Practices](#best-practices)
|
|
36
|
-
- [Troubleshooting](#troubleshooting)
|
|
37
|
-
- [Browser Support](#browser-support)
|
|
38
|
-
- [Development Scripts](#development-scripts)
|
|
39
|
-
- [Contributing](#contributing)
|
|
40
|
-
- [License](#license)
|
|
41
|
-
- [Resources](#resources)
|
|
42
|
-
|
|
43
|
-
## Overview
|
|
44
|
-
|
|
45
|
-
Helix is a production-ready design system that provides:
|
|
46
|
-
|
|
47
|
-
- **28 Standalone Components** - All components are standalone, no NgModules required
|
|
48
|
-
- **Signal-Based Reactivity** - Built with Angular
|
|
49
|
-
- **Accessibility First** - WCAG 2.1 AA compliant out of the box
|
|
50
|
-
- **TypeScript Strict Mode** - Full type safety and IntelliSense support
|
|
51
|
-
- **Complete Type Exports** - All component types and enums exported for type-safe development
|
|
52
|
-
- **Customizable Theming** - Light/dark modes with brand color customization
|
|
53
|
-
- **Phosphor Icons** - 6000+ icons with multiple weight variants
|
|
54
|
-
- **i18n Support** - Built-in internationalization with ngx-translate
|
|
55
|
-
- **Responsive Design** - Mobile-first approach with comprehensive breakpoint system
|
|
56
|
-
- **Modern Architecture** - Built with Angular
|
|
57
|
-
|
|
58
|
-
## Prerequisites
|
|
59
|
-
|
|
60
|
-
Before installing Helix, ensure your development environment meets these requirements:
|
|
61
|
-
|
|
62
|
-
- **Node.js**: 18.x or higher
|
|
63
|
-
- **npm**: 9.x or higher
|
|
64
|
-
- **Angular**:
|
|
65
|
-
- **Angular CLI**:
|
|
66
|
-
- **TypeScript**: 5.9.0 or higher
|
|
67
|
-
|
|
68
|
-
### Required Peer Dependencies
|
|
69
|
-
|
|
70
|
-
```json
|
|
71
|
-
{
|
|
72
|
-
"@angular/common": "^
|
|
73
|
-
"@angular/core": "^
|
|
74
|
-
"@angular/forms": "^
|
|
75
|
-
"@ngx-translate/core": "^15.0.0",
|
|
76
|
-
"rxjs": "^7.8.0"
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Included Dependencies
|
|
81
|
-
|
|
82
|
-
The following dependencies are bundled with ps-helix:
|
|
83
|
-
|
|
84
|
-
- **@phosphor-icons/web**: 2.0.3 - Icon library
|
|
85
|
-
- **date-fns**: ^3.3.1 - Date utility functions
|
|
86
|
-
- **tslib**: ^2.6.0 - TypeScript runtime library
|
|
87
|
-
|
|
88
|
-
## Installation
|
|
89
|
-
|
|
90
|
-
Install the package:
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
npm install ps-helix
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
All peer dependencies should be automatically installed. If not, install them manually:
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
npm install @angular/common@^
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Verify Installation
|
|
103
|
-
|
|
104
|
-
After installation, verify that ps-helix is in your `package.json`:
|
|
105
|
-
|
|
106
|
-
```json
|
|
107
|
-
{
|
|
108
|
-
"dependencies": {
|
|
109
|
-
"ps-helix": "^
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Quick Start
|
|
115
|
-
|
|
116
|
-
### Step 1: Import Global Styles
|
|
117
|
-
|
|
118
|
-
In your main `styles.css` file, import the Helix stylesheet:
|
|
119
|
-
|
|
120
|
-
```css
|
|
121
|
-
@import 'ps-helix/styles.css';
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
This single import includes:
|
|
125
|
-
- CSS Reset (normalize styles across browsers)
|
|
126
|
-
- Design Tokens (spacing, typography, colors, etc.)
|
|
127
|
-
- Light and Dark theme variables
|
|
128
|
-
- Utility classes (spacing, typography, layout, etc.)
|
|
129
|
-
- Responsive breakpoints and grid system
|
|
130
|
-
- Animation utilities
|
|
131
|
-
- Focus management styles
|
|
132
|
-
|
|
133
|
-
### Step 2: Configure Phosphor Icons
|
|
134
|
-
|
|
135
|
-
Add Phosphor Icons CDN links to your `src/index.html` in the `<head>` section:
|
|
136
|
-
|
|
137
|
-
```html
|
|
138
|
-
<!DOCTYPE html>
|
|
139
|
-
<html lang="en">
|
|
140
|
-
<head>
|
|
141
|
-
<meta charset="UTF-8" />
|
|
142
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
143
|
-
<title>Your App</title>
|
|
144
|
-
|
|
145
|
-
<!-- Phosphor Icons CDN -->
|
|
146
|
-
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/regular/style.css">
|
|
147
|
-
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/fill/style.css">
|
|
148
|
-
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/bold/style.css">
|
|
149
|
-
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/light/style.css">
|
|
150
|
-
</head>
|
|
151
|
-
<body>
|
|
152
|
-
<app-root></app-root>
|
|
153
|
-
</body>
|
|
154
|
-
</html>
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Step 3: Import and Use Components
|
|
158
|
-
|
|
159
|
-
All components are standalone. Import them directly where needed:
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
import { Component } from '@angular/core';
|
|
163
|
-
import { PshButtonComponent } from 'ps-helix';
|
|
164
|
-
|
|
165
|
-
@Component({
|
|
166
|
-
selector: 'app-root',
|
|
167
|
-
imports: [PshButtonComponent],
|
|
168
|
-
template: `
|
|
169
|
-
<psh-button
|
|
170
|
-
variant="primary"
|
|
171
|
-
size="medium"
|
|
172
|
-
(clicked)="handleClick()">
|
|
173
|
-
Click Me
|
|
174
|
-
</psh-button>
|
|
175
|
-
`
|
|
176
|
-
})
|
|
177
|
-
export class AppComponent {
|
|
178
|
-
handleClick() {
|
|
179
|
-
console.log('Button clicked!');
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### Step 4: Initialize Theme Service (Optional)
|
|
185
|
-
|
|
186
|
-
If you want to use theme switching, inject the ThemeService:
|
|
187
|
-
|
|
188
|
-
```typescript
|
|
189
|
-
import { Component, inject, OnInit } from '@angular/core';
|
|
190
|
-
import { ThemeService } from 'ps-helix';
|
|
191
|
-
|
|
192
|
-
@Component({
|
|
193
|
-
selector: 'app-root',
|
|
194
|
-
template: `
|
|
195
|
-
<button (click)="themeService.toggleTheme()">
|
|
196
|
-
Toggle Theme ({{ themeService.themeName() }})
|
|
197
|
-
</button>
|
|
198
|
-
`
|
|
199
|
-
})
|
|
200
|
-
export class AppComponent implements OnInit {
|
|
201
|
-
themeService = inject(ThemeService);
|
|
202
|
-
|
|
203
|
-
ngOnInit() {
|
|
204
|
-
// Theme is initialized automatically
|
|
205
|
-
console.log('Current theme:', this.themeService.themeName());
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Step 5: Verify Everything Works
|
|
211
|
-
|
|
212
|
-
Create a simple test component to ensure the library is working:
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
import { Component } from '@angular/core';
|
|
216
|
-
import { PshButtonComponent, PshCardComponent, PshAlertComponent } from 'ps-helix';
|
|
217
|
-
|
|
218
|
-
@Component({
|
|
219
|
-
selector: 'app-test',
|
|
220
|
-
imports: [PshButtonComponent, PshCardComponent, PshAlertComponent],
|
|
221
|
-
template: `
|
|
222
|
-
<psh-card>
|
|
223
|
-
<h2>Helix Design System</h2>
|
|
224
|
-
<psh-alert type="success" message="Installation successful!" />
|
|
225
|
-
<psh-button variant="primary">Test Button</psh-button>
|
|
226
|
-
</psh-card>
|
|
227
|
-
`
|
|
228
|
-
})
|
|
229
|
-
export class TestComponent {}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## Configuration
|
|
233
|
-
|
|
234
|
-
### Global Styles
|
|
235
|
-
|
|
236
|
-
The design system provides a comprehensive set of CSS custom properties (CSS variables) that you can use in your own styles:
|
|
237
|
-
|
|
238
|
-
```css
|
|
239
|
-
/* Using design tokens in your custom styles */
|
|
240
|
-
.my-custom-component {
|
|
241
|
-
padding: var(--spacing-md);
|
|
242
|
-
margin-bottom: var(--spacing-lg);
|
|
243
|
-
background: var(--surface-card);
|
|
244
|
-
color: var(--text-color);
|
|
245
|
-
border-radius: var(--border-radius);
|
|
246
|
-
box-shadow: var(--shadow-md);
|
|
247
|
-
}
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### Phosphor Icons Setup
|
|
251
|
-
|
|
252
|
-
After adding the CDN links, use icons in your templates:
|
|
253
|
-
|
|
254
|
-
```html
|
|
255
|
-
<!-- Regular weight (default) -->
|
|
256
|
-
<i class="ph ph-heart"></i>
|
|
257
|
-
|
|
258
|
-
<!-- Fill weight -->
|
|
259
|
-
<i class="ph-fill ph-heart"></i>
|
|
260
|
-
|
|
261
|
-
<!-- Bold weight -->
|
|
262
|
-
<i class="ph-bold ph-heart"></i>
|
|
263
|
-
|
|
264
|
-
<!-- Light weight -->
|
|
265
|
-
<i class="ph-light ph-heart"></i>
|
|
266
|
-
|
|
267
|
-
<!-- With accessibility label for icon-only buttons -->
|
|
268
|
-
<button aria-label="Like this item">
|
|
269
|
-
<i class="ph ph-heart" aria-hidden="true"></i>
|
|
270
|
-
</button>
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
Browse all 6000+ icons at: [https://phosphoricons.com/](https://phosphoricons.com/)
|
|
274
|
-
|
|
275
|
-
### Theme Service
|
|
276
|
-
|
|
277
|
-
The `ThemeService` manages light/dark theme switching and custom brand colors.
|
|
278
|
-
|
|
279
|
-
#### Basic Theme Switching
|
|
280
|
-
|
|
281
|
-
```typescript
|
|
282
|
-
import { Component, inject } from '@angular/core';
|
|
283
|
-
import { ThemeService } from 'ps-helix';
|
|
284
|
-
|
|
285
|
-
@Component({
|
|
286
|
-
selector: 'app-root',
|
|
287
|
-
template: `
|
|
288
|
-
<button (click)="toggleTheme()">
|
|
289
|
-
Current theme: {{ themeService.themeName() }}
|
|
290
|
-
</button>
|
|
291
|
-
`
|
|
292
|
-
})
|
|
293
|
-
export class AppComponent {
|
|
294
|
-
themeService = inject(ThemeService);
|
|
295
|
-
|
|
296
|
-
toggleTheme() {
|
|
297
|
-
this.themeService.toggleTheme();
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
For complete theming documentation including custom brand colors, see [THEME.md](./THEME.md).
|
|
303
|
-
|
|
304
|
-
### Translation Service
|
|
305
|
-
|
|
306
|
-
Configure internationalization with ngx-translate:
|
|
307
|
-
|
|
308
|
-
```typescript
|
|
309
|
-
// src/main.ts
|
|
310
|
-
import { bootstrapApplication } from '@angular/platform-browser';
|
|
311
|
-
import { provideHttpClient } from '@angular/common/http';
|
|
312
|
-
import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core';
|
|
313
|
-
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
|
314
|
-
import { HttpClient } from '@angular/common/http';
|
|
315
|
-
import { AppComponent } from './app/app.component';
|
|
316
|
-
|
|
317
|
-
export function HttpLoaderFactory(http: HttpClient) {
|
|
318
|
-
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
bootstrapApplication(AppComponent, {
|
|
322
|
-
providers: [
|
|
323
|
-
provideHttpClient(),
|
|
324
|
-
...TranslateModule.forRoot({
|
|
325
|
-
defaultLanguage: 'en',
|
|
326
|
-
loader: {
|
|
327
|
-
provide: TranslateLoader,
|
|
328
|
-
useFactory: HttpLoaderFactory,
|
|
329
|
-
deps: [HttpClient]
|
|
330
|
-
}
|
|
331
|
-
}).providers || []
|
|
332
|
-
]
|
|
333
|
-
}).then(ref => {
|
|
334
|
-
const translateService = ref.injector.get(TranslateService);
|
|
335
|
-
translateService.use('en');
|
|
336
|
-
});
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
#### Using TranslationService in Components
|
|
340
|
-
|
|
341
|
-
```typescript
|
|
342
|
-
import { Component, inject } from '@angular/core';
|
|
343
|
-
import { TranslationService } from 'ps-helix';
|
|
344
|
-
|
|
345
|
-
@Component({
|
|
346
|
-
selector: 'app-example',
|
|
347
|
-
template: `
|
|
348
|
-
<select (change)="changeLanguage($event)">
|
|
349
|
-
<option value="en">English</option>
|
|
350
|
-
<option value="fr">Français</option>
|
|
351
|
-
<option value="es">Español</option>
|
|
352
|
-
</select>
|
|
353
|
-
`
|
|
354
|
-
})
|
|
355
|
-
export class ExampleComponent {
|
|
356
|
-
private translationService = inject(TranslationService);
|
|
357
|
-
|
|
358
|
-
changeLanguage(event: Event) {
|
|
359
|
-
const lang = (event.target as HTMLSelectElement).value;
|
|
360
|
-
this.translationService.setLanguage(lang);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### Scroll Service
|
|
366
|
-
|
|
367
|
-
The `ScrollService` provides utilities for scroll management:
|
|
368
|
-
|
|
369
|
-
```typescript
|
|
370
|
-
import { Component, inject } from '@angular/core';
|
|
371
|
-
import { ScrollService } from 'ps-helix';
|
|
372
|
-
|
|
373
|
-
@Component({
|
|
374
|
-
selector: 'app-example',
|
|
375
|
-
template: `
|
|
376
|
-
<button (click)="scrollToTop()">Back to Top</button>
|
|
377
|
-
<button (click)="scrollToElement('#section-2')">Go to Section 2</button>
|
|
378
|
-
`
|
|
379
|
-
})
|
|
380
|
-
export class ExampleComponent {
|
|
381
|
-
private scrollService = inject(ScrollService);
|
|
382
|
-
|
|
383
|
-
scrollToTop() {
|
|
384
|
-
this.scrollService.scrollToTop();
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
scrollToElement(selector: string) {
|
|
388
|
-
this.scrollService.scrollToElement(selector);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
## Core Concepts
|
|
394
|
-
|
|
395
|
-
### Standalone Components
|
|
396
|
-
|
|
397
|
-
All Helix components are standalone (no NgModules required):
|
|
398
|
-
|
|
399
|
-
```typescript
|
|
400
|
-
import { Component } from '@angular/core';
|
|
401
|
-
import {
|
|
402
|
-
PshButtonComponent,
|
|
403
|
-
PshInputComponent,
|
|
404
|
-
PshCardComponent
|
|
405
|
-
} from 'ps-helix';
|
|
406
|
-
|
|
407
|
-
@Component({
|
|
408
|
-
selector: 'app-form',
|
|
409
|
-
imports: [
|
|
410
|
-
PshButtonComponent,
|
|
411
|
-
PshInputComponent,
|
|
412
|
-
PshCardComponent
|
|
413
|
-
],
|
|
414
|
-
template: `
|
|
415
|
-
<psh-card>
|
|
416
|
-
<psh-input label="Email" />
|
|
417
|
-
<psh-button variant="primary">Submit</psh-button>
|
|
418
|
-
</psh-card>
|
|
419
|
-
`
|
|
420
|
-
})
|
|
421
|
-
export class FormComponent {}
|
|
422
|
-
```
|
|
423
|
-
|
|
424
|
-
### Signal-Based Reactivity
|
|
425
|
-
|
|
426
|
-
Components use Angular signals for optimal change detection:
|
|
427
|
-
|
|
428
|
-
```typescript
|
|
429
|
-
import { Component, signal } from '@angular/core';
|
|
430
|
-
import { PshModalComponent } from 'ps-helix';
|
|
431
|
-
|
|
432
|
-
@Component({
|
|
433
|
-
selector: 'app-example',
|
|
434
|
-
imports: [PshModalComponent],
|
|
435
|
-
template: `
|
|
436
|
-
<button (click)="isOpen.set(true)">Open Modal</button>
|
|
437
|
-
|
|
438
|
-
<psh-modal [(open)]="isOpen" title="Confirmation">
|
|
439
|
-
<p>Are you sure?</p>
|
|
440
|
-
</psh-modal>
|
|
441
|
-
`
|
|
442
|
-
})
|
|
443
|
-
export class ExampleComponent {
|
|
444
|
-
isOpen = signal(false);
|
|
445
|
-
}
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
### Signal Forms Support
|
|
449
|
-
|
|
450
|
-
Form components natively implement Angular
|
|
451
|
-
|
|
452
|
-
| Component | Signal Forms Interface | Reactive Forms |
|
|
453
|
-
|-----------|----------------------|----------------|
|
|
454
|
-
| `psh-input` | `FormValueControl<string>` | `ControlValueAccessor` |
|
|
455
|
-
| `psh-select` | `FormValueControl<T \| T[] \| null>` | `ControlValueAccessor` |
|
|
456
|
-
| `psh-checkbox` | `FormCheckboxControl` | `ControlValueAccessor` |
|
|
457
|
-
| `psh-switch` | `FormCheckboxControl` | `ControlValueAccessor` |
|
|
458
|
-
| `psh-radio` | - | Property binding only |
|
|
459
|
-
|
|
460
|
-
### Type Safety
|
|
461
|
-
|
|
462
|
-
All components export TypeScript types for type-safe development:
|
|
463
|
-
|
|
464
|
-
```typescript
|
|
465
|
-
import { Component } from '@angular/core';
|
|
466
|
-
import { PshButtonComponent, ButtonVariant, ButtonSize } from 'ps-helix';
|
|
467
|
-
|
|
468
|
-
@Component({
|
|
469
|
-
selector: 'app-example',
|
|
470
|
-
imports: [PshButtonComponent],
|
|
471
|
-
template: `
|
|
472
|
-
<psh-button [variant]="variant" [size]="size">
|
|
473
|
-
{{ buttonText }}
|
|
474
|
-
</psh-button>
|
|
475
|
-
`
|
|
476
|
-
})
|
|
477
|
-
export class ExampleComponent {
|
|
478
|
-
variant: ButtonVariant = 'primary'; // Type-safe
|
|
479
|
-
size: ButtonSize = 'medium'; // Type-safe
|
|
480
|
-
buttonText = 'Click Me';
|
|
481
|
-
}
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
### Dependency Injection
|
|
485
|
-
|
|
486
|
-
Use modern `inject()` function instead of constructor injection:
|
|
487
|
-
|
|
488
|
-
```typescript
|
|
489
|
-
import { Component, inject } from '@angular/core';
|
|
490
|
-
import { ThemeService, ToastService } from 'ps-helix';
|
|
491
|
-
|
|
492
|
-
@Component({
|
|
493
|
-
selector: 'app-example',
|
|
494
|
-
template: `<button (click)="showToast()">Show Toast</button>`
|
|
495
|
-
})
|
|
496
|
-
export class ExampleComponent {
|
|
497
|
-
// Modern injection syntax
|
|
498
|
-
private themeService = inject(ThemeService);
|
|
499
|
-
private toastService = inject(ToastService);
|
|
500
|
-
|
|
501
|
-
showToast() {
|
|
502
|
-
this.toastService.success('Hello from Helix!');
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
## Available Components
|
|
508
|
-
|
|
509
|
-
Helix provides **28 production-ready components** organized by category:
|
|
510
|
-
|
|
511
|
-
### Form Components (6)
|
|
512
|
-
|
|
513
|
-
- **PshButtonComponent** - Versatile button with multiple variants, sizes, and states
|
|
514
|
-
- **PshInputComponent** - Text input with validation, error messages, and form control integration
|
|
515
|
-
- **PshCheckboxComponent** - Checkbox with customizable states and labels
|
|
516
|
-
- **PshRadioComponent** - Radio button for single selection from a group
|
|
517
|
-
- **PshSelectComponent** - Dropdown select with search, filtering, and custom rendering
|
|
518
|
-
- **PshSwitchComponent** - Toggle switch with on/off states
|
|
519
|
-
|
|
520
|
-
### Layout Components (6)
|
|
521
|
-
|
|
522
|
-
- **PshCardComponent** - Flexible content container with header, body, and footer sections
|
|
523
|
-
- **PshModalComponent** - Modal dialog overlay with backdrop and keyboard navigation
|
|
524
|
-
- **PshSidebarComponent** - Collapsible sidebar navigation with responsive behavior
|
|
525
|
-
- **PshCollapseComponent** - Expandable/collapsible content section with animation
|
|
526
|
-
- **PshTabsComponent** + **PshTabComponent** - Tabbed content organization with keyboard navigation
|
|
527
|
-
- **PshTabBarComponent** - Bottom tab bar navigation for mobile-first applications
|
|
528
|
-
|
|
529
|
-
### Feedback Components (5)
|
|
530
|
-
|
|
531
|
-
- **PshAlertComponent** - Alert messages with severity levels (success, info, warning, error)
|
|
532
|
-
- **PshToastComponent** + **ToastService** - Toast notification system with queue management
|
|
533
|
-
- **PshSpinloaderComponent** - Loading spinner with various sizes
|
|
534
|
-
- **PshProgressbarComponent** - Progress indicator with percentage display
|
|
535
|
-
- **PshTooltipComponent** - Contextual tooltips with multiple positions
|
|
536
|
-
|
|
537
|
-
### Data Display Components (7)
|
|
538
|
-
|
|
539
|
-
- **PshTableComponent** - Data table with sorting, pagination, and custom rendering
|
|
540
|
-
- **PshBadgeComponent** - Status badges and indicators with various colors
|
|
541
|
-
- **PshTagComponent** - Removable tags for labels and filters
|
|
542
|
-
- **PshAvatarComponent** - User avatar with image, initials, or icon fallback
|
|
543
|
-
- **PshStatCardComponent** - Statistical card for dashboards
|
|
544
|
-
- **PshInfoCardComponent** - Information card with icon and content
|
|
545
|
-
- **PshHorizontalCardComponent** - Horizontal layout card component
|
|
546
|
-
|
|
547
|
-
### Navigation Components (4)
|
|
548
|
-
|
|
549
|
-
- **PshMenuComponent** - Dropdown menu with nested items, vertical/horizontal modes and collapsible mode; when collapsed, automatic tooltips appear on icons for both root items and sub-items (right position, 300ms delay) with `aria-describedby` linkage
|
|
550
|
-
- **PshPaginationComponent** - Pagination controls with page numbers
|
|
551
|
-
- **PshStepperComponent** + **PshStepComponent** - Step-by-step wizard navigation with validation
|
|
552
|
-
- **PshDropdownComponent** - Dropdown trigger and content container
|
|
553
|
-
|
|
554
|
-
## Service APIs
|
|
555
|
-
|
|
556
|
-
### ThemeService
|
|
557
|
-
|
|
558
|
-
Manage application themes and custom brand colors.
|
|
559
|
-
|
|
560
|
-
**Methods:**
|
|
561
|
-
- `setDarkTheme(isDark: boolean)` - Set theme mode
|
|
562
|
-
- `toggleTheme()` - Toggle between light and dark
|
|
563
|
-
- `updateTheme(name: 'light' | 'dark')` - Update theme by name
|
|
564
|
-
- `applyInsurerTheme()` - Apply custom brand colors
|
|
565
|
-
|
|
566
|
-
**Computed Signals:**
|
|
567
|
-
- `themeName()` - Returns current theme name
|
|
568
|
-
- `isDarkTheme()` - Returns boolean for dark mode
|
|
569
|
-
- `themeInfo()` - Returns complete theme information
|
|
570
|
-
|
|
571
|
-
**Example:**
|
|
572
|
-
|
|
573
|
-
```typescript
|
|
574
|
-
import { inject } from '@angular/core';
|
|
575
|
-
import { ThemeService } from 'ps-helix';
|
|
576
|
-
|
|
577
|
-
export class MyComponent {
|
|
578
|
-
themeService = inject(ThemeService);
|
|
579
|
-
|
|
580
|
-
get currentTheme() {
|
|
581
|
-
return this.themeService.themeName(); // 'light' or 'dark'
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
get isDark() {
|
|
585
|
-
return this.themeService.isDarkTheme(); // boolean
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
switchTheme() {
|
|
589
|
-
this.themeService.toggleTheme();
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
### ToastService
|
|
595
|
-
|
|
596
|
-
Display temporary notification messages.
|
|
597
|
-
|
|
598
|
-
**Methods:**
|
|
599
|
-
- `success(message: string, options?)` - Show success toast
|
|
600
|
-
- `error(message: string, options?)` - Show error toast
|
|
601
|
-
- `warning(message: string, options?)` - Show warning toast
|
|
602
|
-
- `info(message: string, options?)` - Show info toast
|
|
603
|
-
|
|
604
|
-
**Options:**
|
|
605
|
-
- `duration?: number` - Display duration in milliseconds (default: 3000)
|
|
606
|
-
- `position?: ToastPosition` - 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'
|
|
607
|
-
|
|
608
|
-
**Example:**
|
|
609
|
-
|
|
610
|
-
```typescript
|
|
611
|
-
import { inject } from '@angular/core';
|
|
612
|
-
import { ToastService } from 'ps-helix';
|
|
613
|
-
|
|
614
|
-
export class MyComponent {
|
|
615
|
-
private toastService = inject(ToastService);
|
|
616
|
-
|
|
617
|
-
saveData() {
|
|
618
|
-
try {
|
|
619
|
-
// Save logic
|
|
620
|
-
this.toastService.success('Data saved successfully!');
|
|
621
|
-
} catch (error) {
|
|
622
|
-
this.toastService.error('Failed to save data');
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
showCustom() {
|
|
627
|
-
this.toastService.info('Processing...', {
|
|
628
|
-
duration: 5000,
|
|
629
|
-
position: 'bottom-right'
|
|
630
|
-
});
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
```
|
|
634
|
-
|
|
635
|
-
### ScrollService
|
|
636
|
-
|
|
637
|
-
Utility service for scroll management and smooth scrolling.
|
|
638
|
-
|
|
639
|
-
**Methods:**
|
|
640
|
-
- `scrollToTop()` - Scroll to page top smoothly
|
|
641
|
-
- `scrollToElement(selector: string)` - Scroll to specific element
|
|
642
|
-
- `disableScroll()` - Disable page scrolling (useful for modals)
|
|
643
|
-
- `enableScroll()` - Re-enable page scrolling
|
|
644
|
-
|
|
645
|
-
**Example:**
|
|
646
|
-
|
|
647
|
-
```typescript
|
|
648
|
-
import { inject } from '@angular/core';
|
|
649
|
-
import { ScrollService } from 'ps-helix';
|
|
650
|
-
|
|
651
|
-
export class MyComponent {
|
|
652
|
-
private scrollService = inject(ScrollService);
|
|
653
|
-
|
|
654
|
-
backToTop() {
|
|
655
|
-
this.scrollService.scrollToTop();
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
goToSection(sectionId: string) {
|
|
659
|
-
this.scrollService.scrollToElement(`#${sectionId}`);
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
openModal() {
|
|
663
|
-
this.scrollService.disableScroll();
|
|
664
|
-
// Show modal
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
closeModal() {
|
|
668
|
-
this.scrollService.enableScroll();
|
|
669
|
-
// Hide modal
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
```
|
|
673
|
-
|
|
674
|
-
### TranslationService
|
|
675
|
-
|
|
676
|
-
Wrapper service for ngx-translate functionality.
|
|
677
|
-
|
|
678
|
-
**Methods:**
|
|
679
|
-
- `setLanguage(lang: string)` - Change application language
|
|
680
|
-
- `getTranslation(key: string)` - Get translation for a key
|
|
681
|
-
- `instant(key: string)` - Get instant translation (synchronous)
|
|
682
|
-
|
|
683
|
-
**Example:**
|
|
684
|
-
|
|
685
|
-
```typescript
|
|
686
|
-
import { Component, inject } from '@angular/core';
|
|
687
|
-
import { TranslationService } from 'ps-helix';
|
|
688
|
-
|
|
689
|
-
@Component({
|
|
690
|
-
selector: 'app-language-selector',
|
|
691
|
-
template: `
|
|
692
|
-
<select (change)="changeLanguage($event)">
|
|
693
|
-
<option value="en">English</option>
|
|
694
|
-
<option value="fr">Français</option>
|
|
695
|
-
<option value="es">Español</option>
|
|
696
|
-
<option value="de">Deutsch</option>
|
|
697
|
-
</select>
|
|
698
|
-
`
|
|
699
|
-
})
|
|
700
|
-
export class LanguageSelectorComponent {
|
|
701
|
-
private translationService = inject(TranslationService);
|
|
702
|
-
|
|
703
|
-
changeLanguage(event: Event) {
|
|
704
|
-
const selectedLang = (event.target as HTMLSelectElement).value;
|
|
705
|
-
this.translationService.setLanguage(selectedLang);
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
```
|
|
709
|
-
|
|
710
|
-
## Exported Types
|
|
711
|
-
|
|
712
|
-
All component types and enums are exported for type-safe development:
|
|
713
|
-
|
|
714
|
-
### Alert Types
|
|
715
|
-
|
|
716
|
-
```typescript
|
|
717
|
-
import { AlertType, AlertVariant } from 'ps-helix';
|
|
718
|
-
|
|
719
|
-
const type: AlertType = 'success' | 'error' | 'warning' | 'info';
|
|
720
|
-
const variant: AlertVariant = 'solid' | 'outlined' | 'soft';
|
|
721
|
-
```
|
|
722
|
-
|
|
723
|
-
### Avatar Types
|
|
724
|
-
|
|
725
|
-
```typescript
|
|
726
|
-
import { AvatarSize, AvatarShape } from 'ps-helix';
|
|
727
|
-
|
|
728
|
-
const size: AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
729
|
-
const shape: AvatarShape = 'circle' | 'square';
|
|
730
|
-
```
|
|
731
|
-
|
|
732
|
-
### Badge Types
|
|
733
|
-
|
|
734
|
-
```typescript
|
|
735
|
-
import { BadgeSize, BadgeVariant } from 'ps-helix';
|
|
736
|
-
|
|
737
|
-
const size: BadgeSize = 'sm' | 'md' | 'lg';
|
|
738
|
-
const variant: BadgeVariant = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info';
|
|
739
|
-
```
|
|
740
|
-
|
|
741
|
-
### Button Types
|
|
742
|
-
|
|
743
|
-
```typescript
|
|
744
|
-
import { ButtonAppearance, ButtonSize, ButtonVariant } from 'ps-helix';
|
|
745
|
-
|
|
746
|
-
const appearance: ButtonAppearance = 'filled' | 'outlined' | 'text' | 'ghost';
|
|
747
|
-
const size: ButtonSize = 'small' | 'medium' | 'large';
|
|
748
|
-
const variant: ButtonVariant = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info';
|
|
749
|
-
```
|
|
750
|
-
|
|
751
|
-
### Input Types
|
|
752
|
-
|
|
753
|
-
```typescript
|
|
754
|
-
import { InputSize, InputType } from 'ps-helix';
|
|
755
|
-
|
|
756
|
-
const size: InputSize = 'small' | 'medium' | 'large';
|
|
757
|
-
const type: InputType = 'text' | 'password' | 'email' | 'number' | 'tel' | 'url' | 'search';
|
|
758
|
-
```
|
|
759
|
-
|
|
760
|
-
### Modal Types
|
|
761
|
-
|
|
762
|
-
```typescript
|
|
763
|
-
import { ModalSize } from 'ps-helix';
|
|
764
|
-
|
|
765
|
-
const size: ModalSize = 'small' | 'medium' | 'large' | 'fullscreen';
|
|
766
|
-
```
|
|
767
|
-
|
|
768
|
-
### Select Types
|
|
769
|
-
|
|
770
|
-
```typescript
|
|
771
|
-
import { SelectOption, SelectOptionGroup, SelectSize, SearchConfig } from 'ps-helix';
|
|
772
|
-
|
|
773
|
-
interface SelectOption<T> {
|
|
774
|
-
label: string;
|
|
775
|
-
value: T;
|
|
776
|
-
icon?: string;
|
|
777
|
-
disabled?: boolean;
|
|
778
|
-
description?: string;
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
interface SelectOptionGroup<T> {
|
|
782
|
-
label: string;
|
|
783
|
-
options: SelectOption<T>[];
|
|
784
|
-
disabled?: boolean;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
interface SearchConfig {
|
|
788
|
-
debounceTime: number;
|
|
789
|
-
placeholder: string;
|
|
790
|
-
minLength: number;
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
type SelectSize = 'small' | 'medium' | 'large';
|
|
794
|
-
```
|
|
795
|
-
|
|
796
|
-
### Stepper Types
|
|
797
|
-
|
|
798
|
-
```typescript
|
|
799
|
-
import { StepperVariant } from 'ps-helix';
|
|
800
|
-
|
|
801
|
-
const variant: StepperVariant = 'default' | 'numbered' | 'progress';
|
|
802
|
-
```
|
|
803
|
-
|
|
804
|
-
### Table Types
|
|
805
|
-
|
|
806
|
-
```typescript
|
|
807
|
-
import { TableColumn, TableSortDirection } from 'ps-helix';
|
|
808
|
-
|
|
809
|
-
const sortDirection: TableSortDirection = 'asc' | 'desc' | null;
|
|
810
|
-
|
|
811
|
-
interface TableColumn<T> {
|
|
812
|
-
key: string;
|
|
813
|
-
label: string;
|
|
814
|
-
sortable?: boolean;
|
|
815
|
-
width?: string;
|
|
816
|
-
align?: 'left' | 'center' | 'right';
|
|
817
|
-
render?: (item: T) => string;
|
|
818
|
-
}
|
|
819
|
-
```
|
|
820
|
-
|
|
821
|
-
### Toast Types
|
|
822
|
-
|
|
823
|
-
```typescript
|
|
824
|
-
import { ToastPosition, ToastVariant } from 'ps-helix';
|
|
825
|
-
|
|
826
|
-
const position: ToastPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
|
|
827
|
-
const variant: ToastVariant = 'success' | 'error' | 'warning' | 'info';
|
|
828
|
-
```
|
|
829
|
-
|
|
830
|
-
### Tooltip Types
|
|
831
|
-
|
|
832
|
-
```typescript
|
|
833
|
-
import { TooltipPlacement, TooltipTrigger } from 'ps-helix';
|
|
834
|
-
|
|
835
|
-
const placement: TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
836
|
-
const trigger: TooltipTrigger = 'hover' | 'click' | 'focus';
|
|
837
|
-
```
|
|
838
|
-
|
|
839
|
-
For a complete list of all exported types, see the [type definitions](./src/public-api.ts).
|
|
840
|
-
|
|
841
|
-
## Theming
|
|
842
|
-
|
|
843
|
-
### Default Colors
|
|
844
|
-
|
|
845
|
-
Helix provides default theme colors:
|
|
846
|
-
- **Primary**: `#0F02C4` (Deep Blue)
|
|
847
|
-
- **Secondary**: `#7B3AEC` (Purple)
|
|
848
|
-
|
|
849
|
-
### Custom Brand Colors
|
|
850
|
-
|
|
851
|
-
Customize to match your brand identity using the injection token pattern. See the complete guide in [THEME.md](./THEME.md).
|
|
852
|
-
|
|
853
|
-
### Available CSS Variables
|
|
854
|
-
|
|
855
|
-
Once configured, numerous CSS variables are available:
|
|
856
|
-
|
|
857
|
-
**Primary Color:**
|
|
858
|
-
- `--primary-color`
|
|
859
|
-
- `--primary-color-light`
|
|
860
|
-
- `--primary-color-lighter`
|
|
861
|
-
- `--primary-color-dark`
|
|
862
|
-
- `--primary-color-darker`
|
|
863
|
-
- `--primary-color-text`
|
|
864
|
-
- `--primary-color-rgb`
|
|
865
|
-
|
|
866
|
-
**Secondary Color:**
|
|
867
|
-
- `--secondary-color`
|
|
868
|
-
- `--secondary-color-light`
|
|
869
|
-
- `--secondary-color-lighter`
|
|
870
|
-
- `--secondary-color-dark`
|
|
871
|
-
- `--secondary-color-darker`
|
|
872
|
-
- `--secondary-color-text`
|
|
873
|
-
- `--secondary-color-rgb`
|
|
874
|
-
|
|
875
|
-
### Using Custom Variables
|
|
876
|
-
|
|
877
|
-
```css
|
|
878
|
-
.my-button {
|
|
879
|
-
background: var(--primary-color);
|
|
880
|
-
color: var(--primary-color-text);
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
.my-button:hover {
|
|
884
|
-
background: var(--primary-color-light);
|
|
885
|
-
}
|
|
886
|
-
```
|
|
887
|
-
|
|
888
|
-
For complete theming guide including custom colors, dynamic changes, and advanced configurations, see [THEME.md](./THEME.md).
|
|
889
|
-
|
|
890
|
-
## Best Practices
|
|
891
|
-
|
|
892
|
-
### Component Organization
|
|
893
|
-
|
|
894
|
-
```typescript
|
|
895
|
-
// ✅ Good: Import only what you need
|
|
896
|
-
import { PshButtonComponent, PshInputComponent } from 'ps-helix';
|
|
897
|
-
|
|
898
|
-
// ❌ Avoid: Don't import entire module
|
|
899
|
-
import * as Helix from 'ps-helix';
|
|
900
|
-
```
|
|
901
|
-
|
|
902
|
-
### Type Safety
|
|
903
|
-
|
|
904
|
-
```typescript
|
|
905
|
-
// ✅ Good: Use exported types
|
|
906
|
-
import { ButtonVariant, ButtonSize } from 'ps-helix';
|
|
907
|
-
|
|
908
|
-
const variant: ButtonVariant = 'primary';
|
|
909
|
-
const size: ButtonSize = 'medium';
|
|
910
|
-
|
|
911
|
-
// ❌ Avoid: Magic strings without types
|
|
912
|
-
const variant = 'primary'; // No type checking
|
|
913
|
-
```
|
|
914
|
-
|
|
915
|
-
### Signal Usage
|
|
916
|
-
|
|
917
|
-
```typescript
|
|
918
|
-
// ✅ Good: Use signals for reactive state
|
|
919
|
-
import { signal } from '@angular/core';
|
|
920
|
-
|
|
921
|
-
export class MyComponent {
|
|
922
|
-
isVisible = signal(false);
|
|
923
|
-
|
|
924
|
-
toggle() {
|
|
925
|
-
this.isVisible.update(v => !v);
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
// ❌ Avoid: Traditional properties for reactive UI
|
|
930
|
-
export class MyComponent {
|
|
931
|
-
isVisible = false; // Won't trigger change detection optimally
|
|
932
|
-
}
|
|
933
|
-
```
|
|
934
|
-
|
|
935
|
-
### Accessibility
|
|
936
|
-
|
|
937
|
-
```html
|
|
938
|
-
<!-- ✅ Good: Proper ARIA labels for icon-only buttons -->
|
|
939
|
-
<button aria-label="Delete item" (click)="delete()">
|
|
940
|
-
<i class="ph ph-trash" aria-hidden="true"></i>
|
|
941
|
-
</button>
|
|
942
|
-
|
|
943
|
-
<!-- ❌ Avoid: Icon buttons without labels -->
|
|
944
|
-
<button (click)="delete()">
|
|
945
|
-
<i class="ph ph-trash"></i>
|
|
946
|
-
</button>
|
|
947
|
-
```
|
|
948
|
-
|
|
949
|
-
### Form Integration
|
|
950
|
-
|
|
951
|
-
Form components (`psh-input`, `psh-checkbox`, `psh-select`, `psh-switch`) support three integration modes:
|
|
952
|
-
|
|
953
|
-
```typescript
|
|
954
|
-
// ✅ Recommended: Signal Forms (Angular
|
|
955
|
-
import { signal } from '@angular/core';
|
|
956
|
-
import { form, FormField, required, email } from '@angular/forms/signals';
|
|
957
|
-
|
|
958
|
-
export class MyComponent {
|
|
959
|
-
model = signal({ email: '', password: '' });
|
|
960
|
-
loginForm = form(this.model, (p) => {
|
|
961
|
-
required(p.email, { message: 'Email required' });
|
|
962
|
-
email(p.email, { message: 'Invalid email format' });
|
|
963
|
-
});
|
|
964
|
-
}
|
|
965
|
-
```
|
|
966
|
-
|
|
967
|
-
```html
|
|
968
|
-
<psh-input [formField]="loginForm.email" type="email" label="Email" />
|
|
969
|
-
```
|
|
970
|
-
|
|
971
|
-
```typescript
|
|
972
|
-
// ✅ Also supported: Reactive Forms (backward compatible)
|
|
973
|
-
import { FormControl, Validators } from '@angular/forms';
|
|
974
|
-
|
|
975
|
-
export class MyComponent {
|
|
976
|
-
emailControl = new FormControl('', [
|
|
977
|
-
Validators.required,
|
|
978
|
-
Validators.email
|
|
979
|
-
]);
|
|
980
|
-
}
|
|
981
|
-
```
|
|
982
|
-
|
|
983
|
-
```html
|
|
984
|
-
<psh-input label="Email" [formControl]="emailControl" [required]="true" />
|
|
985
|
-
```
|
|
986
|
-
|
|
987
|
-
```html
|
|
988
|
-
<!-- ✅ Also supported: Two-way binding -->
|
|
989
|
-
<psh-input [(value)]="myValue" label="Email" />
|
|
990
|
-
```
|
|
991
|
-
|
|
992
|
-
### Performance Optimization
|
|
993
|
-
|
|
994
|
-
```typescript
|
|
995
|
-
// ✅ Good: Use OnPush change detection
|
|
996
|
-
import { ChangeDetectionStrategy } from '@angular/core';
|
|
997
|
-
|
|
998
|
-
@Component({
|
|
999
|
-
selector: 'app-example',
|
|
1000
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1001
|
-
template: `...`
|
|
1002
|
-
})
|
|
1003
|
-
export class ExampleComponent {}
|
|
1004
|
-
|
|
1005
|
-
// ✅ Good: Use trackBy for lists
|
|
1006
|
-
@Component({
|
|
1007
|
-
template: `
|
|
1008
|
-
@for (item of items(); track item.id) {
|
|
1009
|
-
<psh-card>{{ item.name }}</psh-card>
|
|
1010
|
-
}
|
|
1011
|
-
`
|
|
1012
|
-
})
|
|
1013
|
-
export class ListComponent {
|
|
1014
|
-
items = signal<Item[]>([]);
|
|
1015
|
-
}
|
|
1016
|
-
```
|
|
1017
|
-
|
|
1018
|
-
### Testing
|
|
1019
|
-
|
|
1020
|
-
```typescript
|
|
1021
|
-
// ✅ Good: Test components with TestBed
|
|
1022
|
-
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
1023
|
-
import { PshButtonComponent } from 'ps-helix';
|
|
1024
|
-
|
|
1025
|
-
describe('MyComponent', () => {
|
|
1026
|
-
let component: MyComponent;
|
|
1027
|
-
let fixture: ComponentFixture<MyComponent>;
|
|
1028
|
-
|
|
1029
|
-
beforeEach(async () => {
|
|
1030
|
-
await TestBed.configureTestingModule({
|
|
1031
|
-
imports: [MyComponent, PshButtonComponent]
|
|
1032
|
-
}).compileComponents();
|
|
1033
|
-
|
|
1034
|
-
fixture = TestBed.createComponent(MyComponent);
|
|
1035
|
-
component = fixture.componentInstance;
|
|
1036
|
-
fixture.detectChanges();
|
|
1037
|
-
});
|
|
1038
|
-
|
|
1039
|
-
it('should create', () => {
|
|
1040
|
-
expect(component).toBeTruthy();
|
|
1041
|
-
});
|
|
1042
|
-
});
|
|
1043
|
-
```
|
|
1044
|
-
|
|
1045
|
-
## Troubleshooting
|
|
1046
|
-
|
|
1047
|
-
### Styles Not Applied
|
|
1048
|
-
|
|
1049
|
-
**Problem**: Components appear unstyled or broken.
|
|
1050
|
-
|
|
1051
|
-
**Solution**: Ensure you've imported the global stylesheet:
|
|
1052
|
-
|
|
1053
|
-
```css
|
|
1054
|
-
/* In src/styles.css */
|
|
1055
|
-
@import 'ps-helix/styles.css';
|
|
1056
|
-
```
|
|
1057
|
-
|
|
1058
|
-
### Icons Not Displaying
|
|
1059
|
-
|
|
1060
|
-
**Problem**: Icons show as empty squares or missing glyphs.
|
|
1061
|
-
|
|
1062
|
-
**Solution**: Verify Phosphor Icons CDN links are in `index.html`:
|
|
1063
|
-
|
|
1064
|
-
```html
|
|
1065
|
-
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/regular/style.css">
|
|
1066
|
-
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/fill/style.css">
|
|
1067
|
-
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/bold/style.css">
|
|
1068
|
-
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/light/style.css">
|
|
1069
|
-
```
|
|
1070
|
-
|
|
1071
|
-
### Custom Colors Not Applying
|
|
1072
|
-
|
|
1073
|
-
**Problem**: Brand colors aren't being used.
|
|
1074
|
-
|
|
1075
|
-
**Solution**:
|
|
1076
|
-
1. Verify your theme context service implements `InsurerContextService`
|
|
1077
|
-
2. Check the provider configuration in `main.ts` or `app.config.ts`
|
|
1078
|
-
3. Ensure you're using valid hex color codes (e.g., `#FF0000`)
|
|
1079
|
-
4. Call `themeService.applyInsurerTheme()` after color changes
|
|
1080
|
-
|
|
1081
|
-
See [THEME.md](./THEME.md) for complete theming documentation.
|
|
1082
|
-
|
|
1083
|
-
### TypeScript Errors
|
|
1084
|
-
|
|
1085
|
-
**Problem**: TypeScript compilation errors with component imports.
|
|
1086
|
-
|
|
1087
|
-
**Solution**:
|
|
1088
|
-
1. Verify Angular version is
|
|
1089
|
-
2. Check `tsconfig.json` has `"strict": true`
|
|
1090
|
-
3. Ensure all peer dependencies are installed
|
|
1091
|
-
4. Clear node_modules and reinstall: `rm -rf node_modules && npm install`
|
|
1092
|
-
|
|
1093
|
-
### Performance Issues
|
|
1094
|
-
|
|
1095
|
-
**Problem**: Application feels slow or unresponsive.
|
|
1096
|
-
|
|
1097
|
-
**Solution**:
|
|
1098
|
-
1. Use `OnPush` change detection strategy
|
|
1099
|
-
2. Implement proper signal usage
|
|
1100
|
-
3. Avoid unnecessary component re-renders
|
|
1101
|
-
4. Use `trackBy` functions in `@for` loops
|
|
1102
|
-
5. Lazy load routes and components where possible
|
|
1103
|
-
|
|
1104
|
-
### Build Errors
|
|
1105
|
-
|
|
1106
|
-
**Problem**: Build fails with module resolution errors.
|
|
1107
|
-
|
|
1108
|
-
**Solution**:
|
|
1109
|
-
1. Verify package.json includes ps-helix in dependencies
|
|
1110
|
-
2. Clear Angular cache: `ng cache clean`
|
|
1111
|
-
3. Delete .angular folder and rebuild
|
|
1112
|
-
4. Check that all peer dependencies match required versions
|
|
1113
|
-
|
|
1114
|
-
### Runtime Errors
|
|
1115
|
-
|
|
1116
|
-
**Problem**: Errors in browser console at runtime.
|
|
1117
|
-
|
|
1118
|
-
**Solution**:
|
|
1119
|
-
1. Check browser console for specific error messages
|
|
1120
|
-
2. Verify all required services are provided
|
|
1121
|
-
3. Ensure ThemeService is initialized if using custom themes
|
|
1122
|
-
4. Check that ngx-translate is properly configured if using i18n
|
|
1123
|
-
|
|
1124
|
-
## Browser Support
|
|
1125
|
-
|
|
1126
|
-
Helix Design System supports:
|
|
1127
|
-
|
|
1128
|
-
- **Chrome**: Latest 2 versions
|
|
1129
|
-
- **Firefox**: Latest 2 versions
|
|
1130
|
-
- **Safari**: Latest 2 versions
|
|
1131
|
-
- **Edge**: Latest 2 versions
|
|
1132
|
-
- **Mobile browsers**: iOS Safari 14+, Chrome Android latest
|
|
1133
|
-
|
|
1134
|
-
**Note**: Internet Explorer is not supported.
|
|
1135
|
-
|
|
1136
|
-
## Development Scripts
|
|
1137
|
-
|
|
1138
|
-
The following scripts are available for library development:
|
|
1139
|
-
|
|
1140
|
-
```bash
|
|
1141
|
-
npm run build:lib # Build the library
|
|
1142
|
-
npm run watch:lib # Watch for changes and rebuild
|
|
1143
|
-
npm run publish:lib # Publish to npm registry
|
|
1144
|
-
npm run build # Build demo application
|
|
1145
|
-
npm run dev # Run demo application in dev mode
|
|
1146
|
-
```
|
|
1147
|
-
|
|
1148
|
-
## Contributing
|
|
1149
|
-
|
|
1150
|
-
We welcome contributions! To contribute to Helix Design System:
|
|
1151
|
-
|
|
1152
|
-
1. Fork the repository
|
|
1153
|
-
2. Create a feature branch: `git checkout -b feature/my-feature`
|
|
1154
|
-
3. Make your changes and commit: `git commit -am 'Add new feature'`
|
|
1155
|
-
4. Push to the branch: `git push origin feature/my-feature`
|
|
1156
|
-
5. Submit a pull request
|
|
1157
|
-
|
|
1158
|
-
### Development Guidelines
|
|
1159
|
-
|
|
1160
|
-
- Follow Angular style guide
|
|
1161
|
-
- Use TypeScript strict mode
|
|
1162
|
-
- Write tests for new components
|
|
1163
|
-
- Document all public APIs
|
|
1164
|
-
- Ensure accessibility compliance (WCAG 2.1 AA)
|
|
1165
|
-
- Keep components small and focused
|
|
1166
|
-
- Use signals for reactive state
|
|
1167
|
-
|
|
1168
|
-
## License
|
|
1169
|
-
|
|
1170
|
-
MIT License - see LICENSE file for details.
|
|
1171
|
-
|
|
1172
|
-
Copyright (c) 2025 PACK Solutions
|
|
1173
|
-
|
|
1174
|
-
## Resources
|
|
1175
|
-
|
|
1176
|
-
- **Theme Customization Guide**: [THEME.md](./THEME.md)
|
|
1177
|
-
- **Component Documentation**: Individual component README files in `/lib/components/`
|
|
1178
|
-
- **Phosphor Icons**: [https://phosphoricons.com/](https://phosphoricons.com/)
|
|
1179
|
-
- **Angular Documentation**: [https://angular.dev/](https://angular.dev/)
|
|
1180
|
-
- **TypeScript Documentation**: [https://www.typescriptlang.org/](https://www.typescriptlang.org/)
|
|
1181
|
-
- **ngx-translate**: [https://github.com/ngx-translate/core](https://github.com/ngx-translate/core)
|
|
1182
|
-
|
|
1183
|
-
---
|
|
1184
|
-
|
|
1185
|
-
**Version**:
|
|
1186
|
-
**Built with**: Angular
|
|
1187
|
-
**Author**: Fabrice PEREZ | Product Designer at PACK Solutions
|
|
1188
|
-
**Last Updated**: January 2026
|
|
1
|
+
# Helix Design System
|
|
2
|
+
|
|
3
|
+
A comprehensive Angular component library built with Angular 22+ featuring modern design patterns, accessibility-first development, and optimal developer experience.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/ps-helix)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://angular.dev/)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Overview](#overview)
|
|
13
|
+
- [Prerequisites](#prerequisites)
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Quick Start](#quick-start)
|
|
16
|
+
- [Configuration](#configuration)
|
|
17
|
+
- [Global Styles](#global-styles)
|
|
18
|
+
- [Phosphor Icons Setup](#phosphor-icons-setup)
|
|
19
|
+
- [Theme Service](#theme-service)
|
|
20
|
+
- [Translation Service](#translation-service)
|
|
21
|
+
- [Scroll Service](#scroll-service)
|
|
22
|
+
- [Core Concepts](#core-concepts)
|
|
23
|
+
- [Standalone Components](#standalone-components)
|
|
24
|
+
- [Signal-Based Reactivity](#signal-based-reactivity)
|
|
25
|
+
- [Type Safety](#type-safety)
|
|
26
|
+
- [Dependency Injection](#dependency-injection)
|
|
27
|
+
- [Available Components](#available-components)
|
|
28
|
+
- [Service APIs](#service-apis)
|
|
29
|
+
- [ThemeService](#themeservice)
|
|
30
|
+
- [ToastService](#toastservice)
|
|
31
|
+
- [ScrollService](#scrollservice)
|
|
32
|
+
- [TranslationService](#translationservice)
|
|
33
|
+
- [Exported Types](#exported-types)
|
|
34
|
+
- [Theming](#theming)
|
|
35
|
+
- [Best Practices](#best-practices)
|
|
36
|
+
- [Troubleshooting](#troubleshooting)
|
|
37
|
+
- [Browser Support](#browser-support)
|
|
38
|
+
- [Development Scripts](#development-scripts)
|
|
39
|
+
- [Contributing](#contributing)
|
|
40
|
+
- [License](#license)
|
|
41
|
+
- [Resources](#resources)
|
|
42
|
+
|
|
43
|
+
## Overview
|
|
44
|
+
|
|
45
|
+
Helix is a production-ready design system that provides:
|
|
46
|
+
|
|
47
|
+
- **28 Standalone Components** - All components are standalone, no NgModules required
|
|
48
|
+
- **Signal-Based Reactivity** - Built with Angular 22 signals for optimal performance
|
|
49
|
+
- **Accessibility First** - WCAG 2.1 AA compliant out of the box
|
|
50
|
+
- **TypeScript Strict Mode** - Full type safety and IntelliSense support
|
|
51
|
+
- **Complete Type Exports** - All component types and enums exported for type-safe development
|
|
52
|
+
- **Customizable Theming** - Light/dark modes with brand color customization
|
|
53
|
+
- **Phosphor Icons** - 6000+ icons with multiple weight variants
|
|
54
|
+
- **i18n Support** - Built-in internationalization with ngx-translate
|
|
55
|
+
- **Responsive Design** - Mobile-first approach with comprehensive breakpoint system
|
|
56
|
+
- **Modern Architecture** - Built with Angular 22 standalone components and signals
|
|
57
|
+
|
|
58
|
+
## Prerequisites
|
|
59
|
+
|
|
60
|
+
Before installing Helix, ensure your development environment meets these requirements:
|
|
61
|
+
|
|
62
|
+
- **Node.js**: 18.x or higher
|
|
63
|
+
- **npm**: 9.x or higher
|
|
64
|
+
- **Angular**: 22.0.0 or higher
|
|
65
|
+
- **Angular CLI**: 22.0.0 or higher
|
|
66
|
+
- **TypeScript**: 5.9.0 or higher
|
|
67
|
+
|
|
68
|
+
### Required Peer Dependencies
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"@angular/common": "^22.0.0",
|
|
73
|
+
"@angular/core": "^22.0.0",
|
|
74
|
+
"@angular/forms": "^22.0.0",
|
|
75
|
+
"@ngx-translate/core": "^15.0.0",
|
|
76
|
+
"rxjs": "^7.8.0"
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Included Dependencies
|
|
81
|
+
|
|
82
|
+
The following dependencies are bundled with ps-helix:
|
|
83
|
+
|
|
84
|
+
- **@phosphor-icons/web**: 2.0.3 - Icon library
|
|
85
|
+
- **date-fns**: ^3.3.1 - Date utility functions
|
|
86
|
+
- **tslib**: ^2.6.0 - TypeScript runtime library
|
|
87
|
+
|
|
88
|
+
## Installation
|
|
89
|
+
|
|
90
|
+
Install the package:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm install ps-helix
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
All peer dependencies should be automatically installed. If not, install them manually:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm install @angular/common@^22.0.0 @angular/core@^22.0.0 @angular/forms@^22.0.0 @ngx-translate/core@^15.0.0 rxjs@^7.8.0
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Verify Installation
|
|
103
|
+
|
|
104
|
+
After installation, verify that ps-helix is in your `package.json`:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"dependencies": {
|
|
109
|
+
"ps-helix": "^6.0.0"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Quick Start
|
|
115
|
+
|
|
116
|
+
### Step 1: Import Global Styles
|
|
117
|
+
|
|
118
|
+
In your main `styles.css` file, import the Helix stylesheet:
|
|
119
|
+
|
|
120
|
+
```css
|
|
121
|
+
@import 'ps-helix/styles.css';
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
This single import includes:
|
|
125
|
+
- CSS Reset (normalize styles across browsers)
|
|
126
|
+
- Design Tokens (spacing, typography, colors, etc.)
|
|
127
|
+
- Light and Dark theme variables
|
|
128
|
+
- Utility classes (spacing, typography, layout, etc.)
|
|
129
|
+
- Responsive breakpoints and grid system
|
|
130
|
+
- Animation utilities
|
|
131
|
+
- Focus management styles
|
|
132
|
+
|
|
133
|
+
### Step 2: Configure Phosphor Icons
|
|
134
|
+
|
|
135
|
+
Add Phosphor Icons CDN links to your `src/index.html` in the `<head>` section:
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<!DOCTYPE html>
|
|
139
|
+
<html lang="en">
|
|
140
|
+
<head>
|
|
141
|
+
<meta charset="UTF-8" />
|
|
142
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
143
|
+
<title>Your App</title>
|
|
144
|
+
|
|
145
|
+
<!-- Phosphor Icons CDN -->
|
|
146
|
+
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/regular/style.css">
|
|
147
|
+
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/fill/style.css">
|
|
148
|
+
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/bold/style.css">
|
|
149
|
+
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/light/style.css">
|
|
150
|
+
</head>
|
|
151
|
+
<body>
|
|
152
|
+
<app-root></app-root>
|
|
153
|
+
</body>
|
|
154
|
+
</html>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Step 3: Import and Use Components
|
|
158
|
+
|
|
159
|
+
All components are standalone. Import them directly where needed:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { Component } from '@angular/core';
|
|
163
|
+
import { PshButtonComponent } from 'ps-helix';
|
|
164
|
+
|
|
165
|
+
@Component({
|
|
166
|
+
selector: 'app-root',
|
|
167
|
+
imports: [PshButtonComponent],
|
|
168
|
+
template: `
|
|
169
|
+
<psh-button
|
|
170
|
+
variant="primary"
|
|
171
|
+
size="medium"
|
|
172
|
+
(clicked)="handleClick()">
|
|
173
|
+
Click Me
|
|
174
|
+
</psh-button>
|
|
175
|
+
`
|
|
176
|
+
})
|
|
177
|
+
export class AppComponent {
|
|
178
|
+
handleClick() {
|
|
179
|
+
console.log('Button clicked!');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Step 4: Initialize Theme Service (Optional)
|
|
185
|
+
|
|
186
|
+
If you want to use theme switching, inject the ThemeService:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import { Component, inject, OnInit } from '@angular/core';
|
|
190
|
+
import { ThemeService } from 'ps-helix';
|
|
191
|
+
|
|
192
|
+
@Component({
|
|
193
|
+
selector: 'app-root',
|
|
194
|
+
template: `
|
|
195
|
+
<button (click)="themeService.toggleTheme()">
|
|
196
|
+
Toggle Theme ({{ themeService.themeName() }})
|
|
197
|
+
</button>
|
|
198
|
+
`
|
|
199
|
+
})
|
|
200
|
+
export class AppComponent implements OnInit {
|
|
201
|
+
themeService = inject(ThemeService);
|
|
202
|
+
|
|
203
|
+
ngOnInit() {
|
|
204
|
+
// Theme is initialized automatically
|
|
205
|
+
console.log('Current theme:', this.themeService.themeName());
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Step 5: Verify Everything Works
|
|
211
|
+
|
|
212
|
+
Create a simple test component to ensure the library is working:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { Component } from '@angular/core';
|
|
216
|
+
import { PshButtonComponent, PshCardComponent, PshAlertComponent } from 'ps-helix';
|
|
217
|
+
|
|
218
|
+
@Component({
|
|
219
|
+
selector: 'app-test',
|
|
220
|
+
imports: [PshButtonComponent, PshCardComponent, PshAlertComponent],
|
|
221
|
+
template: `
|
|
222
|
+
<psh-card>
|
|
223
|
+
<h2>Helix Design System</h2>
|
|
224
|
+
<psh-alert type="success" message="Installation successful!" />
|
|
225
|
+
<psh-button variant="primary">Test Button</psh-button>
|
|
226
|
+
</psh-card>
|
|
227
|
+
`
|
|
228
|
+
})
|
|
229
|
+
export class TestComponent {}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Configuration
|
|
233
|
+
|
|
234
|
+
### Global Styles
|
|
235
|
+
|
|
236
|
+
The design system provides a comprehensive set of CSS custom properties (CSS variables) that you can use in your own styles:
|
|
237
|
+
|
|
238
|
+
```css
|
|
239
|
+
/* Using design tokens in your custom styles */
|
|
240
|
+
.my-custom-component {
|
|
241
|
+
padding: var(--spacing-md);
|
|
242
|
+
margin-bottom: var(--spacing-lg);
|
|
243
|
+
background: var(--surface-card);
|
|
244
|
+
color: var(--text-color);
|
|
245
|
+
border-radius: var(--border-radius);
|
|
246
|
+
box-shadow: var(--shadow-md);
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Phosphor Icons Setup
|
|
251
|
+
|
|
252
|
+
After adding the CDN links, use icons in your templates:
|
|
253
|
+
|
|
254
|
+
```html
|
|
255
|
+
<!-- Regular weight (default) -->
|
|
256
|
+
<i class="ph ph-heart"></i>
|
|
257
|
+
|
|
258
|
+
<!-- Fill weight -->
|
|
259
|
+
<i class="ph-fill ph-heart"></i>
|
|
260
|
+
|
|
261
|
+
<!-- Bold weight -->
|
|
262
|
+
<i class="ph-bold ph-heart"></i>
|
|
263
|
+
|
|
264
|
+
<!-- Light weight -->
|
|
265
|
+
<i class="ph-light ph-heart"></i>
|
|
266
|
+
|
|
267
|
+
<!-- With accessibility label for icon-only buttons -->
|
|
268
|
+
<button aria-label="Like this item">
|
|
269
|
+
<i class="ph ph-heart" aria-hidden="true"></i>
|
|
270
|
+
</button>
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Browse all 6000+ icons at: [https://phosphoricons.com/](https://phosphoricons.com/)
|
|
274
|
+
|
|
275
|
+
### Theme Service
|
|
276
|
+
|
|
277
|
+
The `ThemeService` manages light/dark theme switching and custom brand colors.
|
|
278
|
+
|
|
279
|
+
#### Basic Theme Switching
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
import { Component, inject } from '@angular/core';
|
|
283
|
+
import { ThemeService } from 'ps-helix';
|
|
284
|
+
|
|
285
|
+
@Component({
|
|
286
|
+
selector: 'app-root',
|
|
287
|
+
template: `
|
|
288
|
+
<button (click)="toggleTheme()">
|
|
289
|
+
Current theme: {{ themeService.themeName() }}
|
|
290
|
+
</button>
|
|
291
|
+
`
|
|
292
|
+
})
|
|
293
|
+
export class AppComponent {
|
|
294
|
+
themeService = inject(ThemeService);
|
|
295
|
+
|
|
296
|
+
toggleTheme() {
|
|
297
|
+
this.themeService.toggleTheme();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
For complete theming documentation including custom brand colors, see [THEME.md](./THEME.md).
|
|
303
|
+
|
|
304
|
+
### Translation Service
|
|
305
|
+
|
|
306
|
+
Configure internationalization with ngx-translate:
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
// src/main.ts
|
|
310
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
311
|
+
import { provideHttpClient } from '@angular/common/http';
|
|
312
|
+
import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core';
|
|
313
|
+
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
|
314
|
+
import { HttpClient } from '@angular/common/http';
|
|
315
|
+
import { AppComponent } from './app/app.component';
|
|
316
|
+
|
|
317
|
+
export function HttpLoaderFactory(http: HttpClient) {
|
|
318
|
+
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
bootstrapApplication(AppComponent, {
|
|
322
|
+
providers: [
|
|
323
|
+
provideHttpClient(),
|
|
324
|
+
...TranslateModule.forRoot({
|
|
325
|
+
defaultLanguage: 'en',
|
|
326
|
+
loader: {
|
|
327
|
+
provide: TranslateLoader,
|
|
328
|
+
useFactory: HttpLoaderFactory,
|
|
329
|
+
deps: [HttpClient]
|
|
330
|
+
}
|
|
331
|
+
}).providers || []
|
|
332
|
+
]
|
|
333
|
+
}).then(ref => {
|
|
334
|
+
const translateService = ref.injector.get(TranslateService);
|
|
335
|
+
translateService.use('en');
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
#### Using TranslationService in Components
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
import { Component, inject } from '@angular/core';
|
|
343
|
+
import { TranslationService } from 'ps-helix';
|
|
344
|
+
|
|
345
|
+
@Component({
|
|
346
|
+
selector: 'app-example',
|
|
347
|
+
template: `
|
|
348
|
+
<select (change)="changeLanguage($event)">
|
|
349
|
+
<option value="en">English</option>
|
|
350
|
+
<option value="fr">Français</option>
|
|
351
|
+
<option value="es">Español</option>
|
|
352
|
+
</select>
|
|
353
|
+
`
|
|
354
|
+
})
|
|
355
|
+
export class ExampleComponent {
|
|
356
|
+
private translationService = inject(TranslationService);
|
|
357
|
+
|
|
358
|
+
changeLanguage(event: Event) {
|
|
359
|
+
const lang = (event.target as HTMLSelectElement).value;
|
|
360
|
+
this.translationService.setLanguage(lang);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Scroll Service
|
|
366
|
+
|
|
367
|
+
The `ScrollService` provides utilities for scroll management:
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
import { Component, inject } from '@angular/core';
|
|
371
|
+
import { ScrollService } from 'ps-helix';
|
|
372
|
+
|
|
373
|
+
@Component({
|
|
374
|
+
selector: 'app-example',
|
|
375
|
+
template: `
|
|
376
|
+
<button (click)="scrollToTop()">Back to Top</button>
|
|
377
|
+
<button (click)="scrollToElement('#section-2')">Go to Section 2</button>
|
|
378
|
+
`
|
|
379
|
+
})
|
|
380
|
+
export class ExampleComponent {
|
|
381
|
+
private scrollService = inject(ScrollService);
|
|
382
|
+
|
|
383
|
+
scrollToTop() {
|
|
384
|
+
this.scrollService.scrollToTop();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
scrollToElement(selector: string) {
|
|
388
|
+
this.scrollService.scrollToElement(selector);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Core Concepts
|
|
394
|
+
|
|
395
|
+
### Standalone Components
|
|
396
|
+
|
|
397
|
+
All Helix components are standalone (no NgModules required):
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
import { Component } from '@angular/core';
|
|
401
|
+
import {
|
|
402
|
+
PshButtonComponent,
|
|
403
|
+
PshInputComponent,
|
|
404
|
+
PshCardComponent
|
|
405
|
+
} from 'ps-helix';
|
|
406
|
+
|
|
407
|
+
@Component({
|
|
408
|
+
selector: 'app-form',
|
|
409
|
+
imports: [
|
|
410
|
+
PshButtonComponent,
|
|
411
|
+
PshInputComponent,
|
|
412
|
+
PshCardComponent
|
|
413
|
+
],
|
|
414
|
+
template: `
|
|
415
|
+
<psh-card>
|
|
416
|
+
<psh-input label="Email" />
|
|
417
|
+
<psh-button variant="primary">Submit</psh-button>
|
|
418
|
+
</psh-card>
|
|
419
|
+
`
|
|
420
|
+
})
|
|
421
|
+
export class FormComponent {}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Signal-Based Reactivity
|
|
425
|
+
|
|
426
|
+
Components use Angular signals for optimal change detection:
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
import { Component, signal } from '@angular/core';
|
|
430
|
+
import { PshModalComponent } from 'ps-helix';
|
|
431
|
+
|
|
432
|
+
@Component({
|
|
433
|
+
selector: 'app-example',
|
|
434
|
+
imports: [PshModalComponent],
|
|
435
|
+
template: `
|
|
436
|
+
<button (click)="isOpen.set(true)">Open Modal</button>
|
|
437
|
+
|
|
438
|
+
<psh-modal [(open)]="isOpen" title="Confirmation">
|
|
439
|
+
<p>Are you sure?</p>
|
|
440
|
+
</psh-modal>
|
|
441
|
+
`
|
|
442
|
+
})
|
|
443
|
+
export class ExampleComponent {
|
|
444
|
+
isOpen = signal(false);
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Signal Forms Support
|
|
449
|
+
|
|
450
|
+
Form components natively implement Angular 22 Signal Forms interfaces (`FormValueControl`, `FormCheckboxControl`) while maintaining backward compatibility with Reactive Forms via `ControlValueAccessor`:
|
|
451
|
+
|
|
452
|
+
| Component | Signal Forms Interface | Reactive Forms |
|
|
453
|
+
|-----------|----------------------|----------------|
|
|
454
|
+
| `psh-input` | `FormValueControl<string>` | `ControlValueAccessor` |
|
|
455
|
+
| `psh-select` | `FormValueControl<T \| T[] \| null>` | `ControlValueAccessor` |
|
|
456
|
+
| `psh-checkbox` | `FormCheckboxControl` | `ControlValueAccessor` |
|
|
457
|
+
| `psh-switch` | `FormCheckboxControl` | `ControlValueAccessor` |
|
|
458
|
+
| `psh-radio` | - | Property binding only |
|
|
459
|
+
|
|
460
|
+
### Type Safety
|
|
461
|
+
|
|
462
|
+
All components export TypeScript types for type-safe development:
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
import { Component } from '@angular/core';
|
|
466
|
+
import { PshButtonComponent, ButtonVariant, ButtonSize } from 'ps-helix';
|
|
467
|
+
|
|
468
|
+
@Component({
|
|
469
|
+
selector: 'app-example',
|
|
470
|
+
imports: [PshButtonComponent],
|
|
471
|
+
template: `
|
|
472
|
+
<psh-button [variant]="variant" [size]="size">
|
|
473
|
+
{{ buttonText }}
|
|
474
|
+
</psh-button>
|
|
475
|
+
`
|
|
476
|
+
})
|
|
477
|
+
export class ExampleComponent {
|
|
478
|
+
variant: ButtonVariant = 'primary'; // Type-safe
|
|
479
|
+
size: ButtonSize = 'medium'; // Type-safe
|
|
480
|
+
buttonText = 'Click Me';
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Dependency Injection
|
|
485
|
+
|
|
486
|
+
Use modern `inject()` function instead of constructor injection:
|
|
487
|
+
|
|
488
|
+
```typescript
|
|
489
|
+
import { Component, inject } from '@angular/core';
|
|
490
|
+
import { ThemeService, ToastService } from 'ps-helix';
|
|
491
|
+
|
|
492
|
+
@Component({
|
|
493
|
+
selector: 'app-example',
|
|
494
|
+
template: `<button (click)="showToast()">Show Toast</button>`
|
|
495
|
+
})
|
|
496
|
+
export class ExampleComponent {
|
|
497
|
+
// Modern injection syntax
|
|
498
|
+
private themeService = inject(ThemeService);
|
|
499
|
+
private toastService = inject(ToastService);
|
|
500
|
+
|
|
501
|
+
showToast() {
|
|
502
|
+
this.toastService.success('Hello from Helix!');
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
## Available Components
|
|
508
|
+
|
|
509
|
+
Helix provides **28 production-ready components** organized by category:
|
|
510
|
+
|
|
511
|
+
### Form Components (6)
|
|
512
|
+
|
|
513
|
+
- **PshButtonComponent** - Versatile button with multiple variants, sizes, and states
|
|
514
|
+
- **PshInputComponent** - Text input with validation, error messages, and form control integration
|
|
515
|
+
- **PshCheckboxComponent** - Checkbox with customizable states and labels
|
|
516
|
+
- **PshRadioComponent** - Radio button for single selection from a group
|
|
517
|
+
- **PshSelectComponent** - Dropdown select with search, filtering, and custom rendering
|
|
518
|
+
- **PshSwitchComponent** - Toggle switch with on/off states
|
|
519
|
+
|
|
520
|
+
### Layout Components (6)
|
|
521
|
+
|
|
522
|
+
- **PshCardComponent** - Flexible content container with header, body, and footer sections
|
|
523
|
+
- **PshModalComponent** - Modal dialog overlay with backdrop and keyboard navigation
|
|
524
|
+
- **PshSidebarComponent** - Collapsible sidebar navigation with responsive behavior
|
|
525
|
+
- **PshCollapseComponent** - Expandable/collapsible content section with animation
|
|
526
|
+
- **PshTabsComponent** + **PshTabComponent** - Tabbed content organization with keyboard navigation
|
|
527
|
+
- **PshTabBarComponent** - Bottom tab bar navigation for mobile-first applications
|
|
528
|
+
|
|
529
|
+
### Feedback Components (5)
|
|
530
|
+
|
|
531
|
+
- **PshAlertComponent** - Alert messages with severity levels (success, info, warning, error)
|
|
532
|
+
- **PshToastComponent** + **ToastService** - Toast notification system with queue management
|
|
533
|
+
- **PshSpinloaderComponent** - Loading spinner with various sizes
|
|
534
|
+
- **PshProgressbarComponent** - Progress indicator with percentage display
|
|
535
|
+
- **PshTooltipComponent** - Contextual tooltips with multiple positions
|
|
536
|
+
|
|
537
|
+
### Data Display Components (7)
|
|
538
|
+
|
|
539
|
+
- **PshTableComponent** - Data table with sorting, pagination, and custom rendering
|
|
540
|
+
- **PshBadgeComponent** - Status badges and indicators with various colors
|
|
541
|
+
- **PshTagComponent** - Removable tags for labels and filters
|
|
542
|
+
- **PshAvatarComponent** - User avatar with image, initials, or icon fallback
|
|
543
|
+
- **PshStatCardComponent** - Statistical card for dashboards
|
|
544
|
+
- **PshInfoCardComponent** - Information card with icon and content
|
|
545
|
+
- **PshHorizontalCardComponent** - Horizontal layout card component
|
|
546
|
+
|
|
547
|
+
### Navigation Components (4)
|
|
548
|
+
|
|
549
|
+
- **PshMenuComponent** - Dropdown menu with nested items, vertical/horizontal modes and collapsible mode; when collapsed, automatic tooltips appear on icons for both root items and sub-items (right position, 300ms delay) with `aria-describedby` linkage
|
|
550
|
+
- **PshPaginationComponent** - Pagination controls with page numbers
|
|
551
|
+
- **PshStepperComponent** + **PshStepComponent** - Step-by-step wizard navigation with validation
|
|
552
|
+
- **PshDropdownComponent** - Dropdown trigger and content container
|
|
553
|
+
|
|
554
|
+
## Service APIs
|
|
555
|
+
|
|
556
|
+
### ThemeService
|
|
557
|
+
|
|
558
|
+
Manage application themes and custom brand colors.
|
|
559
|
+
|
|
560
|
+
**Methods:**
|
|
561
|
+
- `setDarkTheme(isDark: boolean)` - Set theme mode
|
|
562
|
+
- `toggleTheme()` - Toggle between light and dark
|
|
563
|
+
- `updateTheme(name: 'light' | 'dark')` - Update theme by name
|
|
564
|
+
- `applyInsurerTheme()` - Apply custom brand colors
|
|
565
|
+
|
|
566
|
+
**Computed Signals:**
|
|
567
|
+
- `themeName()` - Returns current theme name
|
|
568
|
+
- `isDarkTheme()` - Returns boolean for dark mode
|
|
569
|
+
- `themeInfo()` - Returns complete theme information
|
|
570
|
+
|
|
571
|
+
**Example:**
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
import { inject } from '@angular/core';
|
|
575
|
+
import { ThemeService } from 'ps-helix';
|
|
576
|
+
|
|
577
|
+
export class MyComponent {
|
|
578
|
+
themeService = inject(ThemeService);
|
|
579
|
+
|
|
580
|
+
get currentTheme() {
|
|
581
|
+
return this.themeService.themeName(); // 'light' or 'dark'
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
get isDark() {
|
|
585
|
+
return this.themeService.isDarkTheme(); // boolean
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
switchTheme() {
|
|
589
|
+
this.themeService.toggleTheme();
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
### ToastService
|
|
595
|
+
|
|
596
|
+
Display temporary notification messages.
|
|
597
|
+
|
|
598
|
+
**Methods:**
|
|
599
|
+
- `success(message: string, options?)` - Show success toast
|
|
600
|
+
- `error(message: string, options?)` - Show error toast
|
|
601
|
+
- `warning(message: string, options?)` - Show warning toast
|
|
602
|
+
- `info(message: string, options?)` - Show info toast
|
|
603
|
+
|
|
604
|
+
**Options:**
|
|
605
|
+
- `duration?: number` - Display duration in milliseconds (default: 3000)
|
|
606
|
+
- `position?: ToastPosition` - 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'
|
|
607
|
+
|
|
608
|
+
**Example:**
|
|
609
|
+
|
|
610
|
+
```typescript
|
|
611
|
+
import { inject } from '@angular/core';
|
|
612
|
+
import { ToastService } from 'ps-helix';
|
|
613
|
+
|
|
614
|
+
export class MyComponent {
|
|
615
|
+
private toastService = inject(ToastService);
|
|
616
|
+
|
|
617
|
+
saveData() {
|
|
618
|
+
try {
|
|
619
|
+
// Save logic
|
|
620
|
+
this.toastService.success('Data saved successfully!');
|
|
621
|
+
} catch (error) {
|
|
622
|
+
this.toastService.error('Failed to save data');
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
showCustom() {
|
|
627
|
+
this.toastService.info('Processing...', {
|
|
628
|
+
duration: 5000,
|
|
629
|
+
position: 'bottom-right'
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### ScrollService
|
|
636
|
+
|
|
637
|
+
Utility service for scroll management and smooth scrolling.
|
|
638
|
+
|
|
639
|
+
**Methods:**
|
|
640
|
+
- `scrollToTop()` - Scroll to page top smoothly
|
|
641
|
+
- `scrollToElement(selector: string)` - Scroll to specific element
|
|
642
|
+
- `disableScroll()` - Disable page scrolling (useful for modals)
|
|
643
|
+
- `enableScroll()` - Re-enable page scrolling
|
|
644
|
+
|
|
645
|
+
**Example:**
|
|
646
|
+
|
|
647
|
+
```typescript
|
|
648
|
+
import { inject } from '@angular/core';
|
|
649
|
+
import { ScrollService } from 'ps-helix';
|
|
650
|
+
|
|
651
|
+
export class MyComponent {
|
|
652
|
+
private scrollService = inject(ScrollService);
|
|
653
|
+
|
|
654
|
+
backToTop() {
|
|
655
|
+
this.scrollService.scrollToTop();
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
goToSection(sectionId: string) {
|
|
659
|
+
this.scrollService.scrollToElement(`#${sectionId}`);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
openModal() {
|
|
663
|
+
this.scrollService.disableScroll();
|
|
664
|
+
// Show modal
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
closeModal() {
|
|
668
|
+
this.scrollService.enableScroll();
|
|
669
|
+
// Hide modal
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### TranslationService
|
|
675
|
+
|
|
676
|
+
Wrapper service for ngx-translate functionality.
|
|
677
|
+
|
|
678
|
+
**Methods:**
|
|
679
|
+
- `setLanguage(lang: string)` - Change application language
|
|
680
|
+
- `getTranslation(key: string)` - Get translation for a key
|
|
681
|
+
- `instant(key: string)` - Get instant translation (synchronous)
|
|
682
|
+
|
|
683
|
+
**Example:**
|
|
684
|
+
|
|
685
|
+
```typescript
|
|
686
|
+
import { Component, inject } from '@angular/core';
|
|
687
|
+
import { TranslationService } from 'ps-helix';
|
|
688
|
+
|
|
689
|
+
@Component({
|
|
690
|
+
selector: 'app-language-selector',
|
|
691
|
+
template: `
|
|
692
|
+
<select (change)="changeLanguage($event)">
|
|
693
|
+
<option value="en">English</option>
|
|
694
|
+
<option value="fr">Français</option>
|
|
695
|
+
<option value="es">Español</option>
|
|
696
|
+
<option value="de">Deutsch</option>
|
|
697
|
+
</select>
|
|
698
|
+
`
|
|
699
|
+
})
|
|
700
|
+
export class LanguageSelectorComponent {
|
|
701
|
+
private translationService = inject(TranslationService);
|
|
702
|
+
|
|
703
|
+
changeLanguage(event: Event) {
|
|
704
|
+
const selectedLang = (event.target as HTMLSelectElement).value;
|
|
705
|
+
this.translationService.setLanguage(selectedLang);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
## Exported Types
|
|
711
|
+
|
|
712
|
+
All component types and enums are exported for type-safe development:
|
|
713
|
+
|
|
714
|
+
### Alert Types
|
|
715
|
+
|
|
716
|
+
```typescript
|
|
717
|
+
import { AlertType, AlertVariant } from 'ps-helix';
|
|
718
|
+
|
|
719
|
+
const type: AlertType = 'success' | 'error' | 'warning' | 'info';
|
|
720
|
+
const variant: AlertVariant = 'solid' | 'outlined' | 'soft';
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
### Avatar Types
|
|
724
|
+
|
|
725
|
+
```typescript
|
|
726
|
+
import { AvatarSize, AvatarShape } from 'ps-helix';
|
|
727
|
+
|
|
728
|
+
const size: AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
729
|
+
const shape: AvatarShape = 'circle' | 'square';
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
### Badge Types
|
|
733
|
+
|
|
734
|
+
```typescript
|
|
735
|
+
import { BadgeSize, BadgeVariant } from 'ps-helix';
|
|
736
|
+
|
|
737
|
+
const size: BadgeSize = 'sm' | 'md' | 'lg';
|
|
738
|
+
const variant: BadgeVariant = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info';
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
### Button Types
|
|
742
|
+
|
|
743
|
+
```typescript
|
|
744
|
+
import { ButtonAppearance, ButtonSize, ButtonVariant } from 'ps-helix';
|
|
745
|
+
|
|
746
|
+
const appearance: ButtonAppearance = 'filled' | 'outlined' | 'text' | 'ghost';
|
|
747
|
+
const size: ButtonSize = 'small' | 'medium' | 'large';
|
|
748
|
+
const variant: ButtonVariant = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info';
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
### Input Types
|
|
752
|
+
|
|
753
|
+
```typescript
|
|
754
|
+
import { InputSize, InputType } from 'ps-helix';
|
|
755
|
+
|
|
756
|
+
const size: InputSize = 'small' | 'medium' | 'large';
|
|
757
|
+
const type: InputType = 'text' | 'password' | 'email' | 'number' | 'tel' | 'url' | 'search';
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
### Modal Types
|
|
761
|
+
|
|
762
|
+
```typescript
|
|
763
|
+
import { ModalSize } from 'ps-helix';
|
|
764
|
+
|
|
765
|
+
const size: ModalSize = 'small' | 'medium' | 'large' | 'fullscreen';
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
### Select Types
|
|
769
|
+
|
|
770
|
+
```typescript
|
|
771
|
+
import { SelectOption, SelectOptionGroup, SelectSize, SearchConfig } from 'ps-helix';
|
|
772
|
+
|
|
773
|
+
interface SelectOption<T> {
|
|
774
|
+
label: string;
|
|
775
|
+
value: T;
|
|
776
|
+
icon?: string;
|
|
777
|
+
disabled?: boolean;
|
|
778
|
+
description?: string;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
interface SelectOptionGroup<T> {
|
|
782
|
+
label: string;
|
|
783
|
+
options: SelectOption<T>[];
|
|
784
|
+
disabled?: boolean;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
interface SearchConfig {
|
|
788
|
+
debounceTime: number;
|
|
789
|
+
placeholder: string;
|
|
790
|
+
minLength: number;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
type SelectSize = 'small' | 'medium' | 'large';
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
### Stepper Types
|
|
797
|
+
|
|
798
|
+
```typescript
|
|
799
|
+
import { StepperVariant } from 'ps-helix';
|
|
800
|
+
|
|
801
|
+
const variant: StepperVariant = 'default' | 'numbered' | 'progress';
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
### Table Types
|
|
805
|
+
|
|
806
|
+
```typescript
|
|
807
|
+
import { TableColumn, TableSortDirection } from 'ps-helix';
|
|
808
|
+
|
|
809
|
+
const sortDirection: TableSortDirection = 'asc' | 'desc' | null;
|
|
810
|
+
|
|
811
|
+
interface TableColumn<T> {
|
|
812
|
+
key: string;
|
|
813
|
+
label: string;
|
|
814
|
+
sortable?: boolean;
|
|
815
|
+
width?: string;
|
|
816
|
+
align?: 'left' | 'center' | 'right';
|
|
817
|
+
render?: (item: T) => string;
|
|
818
|
+
}
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
### Toast Types
|
|
822
|
+
|
|
823
|
+
```typescript
|
|
824
|
+
import { ToastPosition, ToastVariant } from 'ps-helix';
|
|
825
|
+
|
|
826
|
+
const position: ToastPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
|
|
827
|
+
const variant: ToastVariant = 'success' | 'error' | 'warning' | 'info';
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
### Tooltip Types
|
|
831
|
+
|
|
832
|
+
```typescript
|
|
833
|
+
import { TooltipPlacement, TooltipTrigger } from 'ps-helix';
|
|
834
|
+
|
|
835
|
+
const placement: TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
836
|
+
const trigger: TooltipTrigger = 'hover' | 'click' | 'focus';
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
For a complete list of all exported types, see the [type definitions](./src/public-api.ts).
|
|
840
|
+
|
|
841
|
+
## Theming
|
|
842
|
+
|
|
843
|
+
### Default Colors
|
|
844
|
+
|
|
845
|
+
Helix provides default theme colors:
|
|
846
|
+
- **Primary**: `#0F02C4` (Deep Blue)
|
|
847
|
+
- **Secondary**: `#7B3AEC` (Purple)
|
|
848
|
+
|
|
849
|
+
### Custom Brand Colors
|
|
850
|
+
|
|
851
|
+
Customize to match your brand identity using the injection token pattern. See the complete guide in [THEME.md](./THEME.md).
|
|
852
|
+
|
|
853
|
+
### Available CSS Variables
|
|
854
|
+
|
|
855
|
+
Once configured, numerous CSS variables are available:
|
|
856
|
+
|
|
857
|
+
**Primary Color:**
|
|
858
|
+
- `--primary-color`
|
|
859
|
+
- `--primary-color-light`
|
|
860
|
+
- `--primary-color-lighter`
|
|
861
|
+
- `--primary-color-dark`
|
|
862
|
+
- `--primary-color-darker`
|
|
863
|
+
- `--primary-color-text`
|
|
864
|
+
- `--primary-color-rgb`
|
|
865
|
+
|
|
866
|
+
**Secondary Color:**
|
|
867
|
+
- `--secondary-color`
|
|
868
|
+
- `--secondary-color-light`
|
|
869
|
+
- `--secondary-color-lighter`
|
|
870
|
+
- `--secondary-color-dark`
|
|
871
|
+
- `--secondary-color-darker`
|
|
872
|
+
- `--secondary-color-text`
|
|
873
|
+
- `--secondary-color-rgb`
|
|
874
|
+
|
|
875
|
+
### Using Custom Variables
|
|
876
|
+
|
|
877
|
+
```css
|
|
878
|
+
.my-button {
|
|
879
|
+
background: var(--primary-color);
|
|
880
|
+
color: var(--primary-color-text);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.my-button:hover {
|
|
884
|
+
background: var(--primary-color-light);
|
|
885
|
+
}
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
For complete theming guide including custom colors, dynamic changes, and advanced configurations, see [THEME.md](./THEME.md).
|
|
889
|
+
|
|
890
|
+
## Best Practices
|
|
891
|
+
|
|
892
|
+
### Component Organization
|
|
893
|
+
|
|
894
|
+
```typescript
|
|
895
|
+
// ✅ Good: Import only what you need
|
|
896
|
+
import { PshButtonComponent, PshInputComponent } from 'ps-helix';
|
|
897
|
+
|
|
898
|
+
// ❌ Avoid: Don't import entire module
|
|
899
|
+
import * as Helix from 'ps-helix';
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
### Type Safety
|
|
903
|
+
|
|
904
|
+
```typescript
|
|
905
|
+
// ✅ Good: Use exported types
|
|
906
|
+
import { ButtonVariant, ButtonSize } from 'ps-helix';
|
|
907
|
+
|
|
908
|
+
const variant: ButtonVariant = 'primary';
|
|
909
|
+
const size: ButtonSize = 'medium';
|
|
910
|
+
|
|
911
|
+
// ❌ Avoid: Magic strings without types
|
|
912
|
+
const variant = 'primary'; // No type checking
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
### Signal Usage
|
|
916
|
+
|
|
917
|
+
```typescript
|
|
918
|
+
// ✅ Good: Use signals for reactive state
|
|
919
|
+
import { signal } from '@angular/core';
|
|
920
|
+
|
|
921
|
+
export class MyComponent {
|
|
922
|
+
isVisible = signal(false);
|
|
923
|
+
|
|
924
|
+
toggle() {
|
|
925
|
+
this.isVisible.update(v => !v);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
// ❌ Avoid: Traditional properties for reactive UI
|
|
930
|
+
export class MyComponent {
|
|
931
|
+
isVisible = false; // Won't trigger change detection optimally
|
|
932
|
+
}
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
### Accessibility
|
|
936
|
+
|
|
937
|
+
```html
|
|
938
|
+
<!-- ✅ Good: Proper ARIA labels for icon-only buttons -->
|
|
939
|
+
<button aria-label="Delete item" (click)="delete()">
|
|
940
|
+
<i class="ph ph-trash" aria-hidden="true"></i>
|
|
941
|
+
</button>
|
|
942
|
+
|
|
943
|
+
<!-- ❌ Avoid: Icon buttons without labels -->
|
|
944
|
+
<button (click)="delete()">
|
|
945
|
+
<i class="ph ph-trash"></i>
|
|
946
|
+
</button>
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
### Form Integration
|
|
950
|
+
|
|
951
|
+
Form components (`psh-input`, `psh-checkbox`, `psh-select`, `psh-switch`) support three integration modes:
|
|
952
|
+
|
|
953
|
+
```typescript
|
|
954
|
+
// ✅ Recommended: Signal Forms (Angular 22+)
|
|
955
|
+
import { signal } from '@angular/core';
|
|
956
|
+
import { form, FormField, required, email } from '@angular/forms/signals';
|
|
957
|
+
|
|
958
|
+
export class MyComponent {
|
|
959
|
+
model = signal({ email: '', password: '' });
|
|
960
|
+
loginForm = form(this.model, (p) => {
|
|
961
|
+
required(p.email, { message: 'Email required' });
|
|
962
|
+
email(p.email, { message: 'Invalid email format' });
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
```html
|
|
968
|
+
<psh-input [formField]="loginForm.email" type="email" label="Email" />
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
```typescript
|
|
972
|
+
// ✅ Also supported: Reactive Forms (backward compatible)
|
|
973
|
+
import { FormControl, Validators } from '@angular/forms';
|
|
974
|
+
|
|
975
|
+
export class MyComponent {
|
|
976
|
+
emailControl = new FormControl('', [
|
|
977
|
+
Validators.required,
|
|
978
|
+
Validators.email
|
|
979
|
+
]);
|
|
980
|
+
}
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
```html
|
|
984
|
+
<psh-input label="Email" [formControl]="emailControl" [required]="true" />
|
|
985
|
+
```
|
|
986
|
+
|
|
987
|
+
```html
|
|
988
|
+
<!-- ✅ Also supported: Two-way binding -->
|
|
989
|
+
<psh-input [(value)]="myValue" label="Email" />
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
### Performance Optimization
|
|
993
|
+
|
|
994
|
+
```typescript
|
|
995
|
+
// ✅ Good: Use OnPush change detection
|
|
996
|
+
import { ChangeDetectionStrategy } from '@angular/core';
|
|
997
|
+
|
|
998
|
+
@Component({
|
|
999
|
+
selector: 'app-example',
|
|
1000
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1001
|
+
template: `...`
|
|
1002
|
+
})
|
|
1003
|
+
export class ExampleComponent {}
|
|
1004
|
+
|
|
1005
|
+
// ✅ Good: Use trackBy for lists
|
|
1006
|
+
@Component({
|
|
1007
|
+
template: `
|
|
1008
|
+
@for (item of items(); track item.id) {
|
|
1009
|
+
<psh-card>{{ item.name }}</psh-card>
|
|
1010
|
+
}
|
|
1011
|
+
`
|
|
1012
|
+
})
|
|
1013
|
+
export class ListComponent {
|
|
1014
|
+
items = signal<Item[]>([]);
|
|
1015
|
+
}
|
|
1016
|
+
```
|
|
1017
|
+
|
|
1018
|
+
### Testing
|
|
1019
|
+
|
|
1020
|
+
```typescript
|
|
1021
|
+
// ✅ Good: Test components with TestBed
|
|
1022
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
1023
|
+
import { PshButtonComponent } from 'ps-helix';
|
|
1024
|
+
|
|
1025
|
+
describe('MyComponent', () => {
|
|
1026
|
+
let component: MyComponent;
|
|
1027
|
+
let fixture: ComponentFixture<MyComponent>;
|
|
1028
|
+
|
|
1029
|
+
beforeEach(async () => {
|
|
1030
|
+
await TestBed.configureTestingModule({
|
|
1031
|
+
imports: [MyComponent, PshButtonComponent]
|
|
1032
|
+
}).compileComponents();
|
|
1033
|
+
|
|
1034
|
+
fixture = TestBed.createComponent(MyComponent);
|
|
1035
|
+
component = fixture.componentInstance;
|
|
1036
|
+
fixture.detectChanges();
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
it('should create', () => {
|
|
1040
|
+
expect(component).toBeTruthy();
|
|
1041
|
+
});
|
|
1042
|
+
});
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
## Troubleshooting
|
|
1046
|
+
|
|
1047
|
+
### Styles Not Applied
|
|
1048
|
+
|
|
1049
|
+
**Problem**: Components appear unstyled or broken.
|
|
1050
|
+
|
|
1051
|
+
**Solution**: Ensure you've imported the global stylesheet:
|
|
1052
|
+
|
|
1053
|
+
```css
|
|
1054
|
+
/* In src/styles.css */
|
|
1055
|
+
@import 'ps-helix/styles.css';
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
### Icons Not Displaying
|
|
1059
|
+
|
|
1060
|
+
**Problem**: Icons show as empty squares or missing glyphs.
|
|
1061
|
+
|
|
1062
|
+
**Solution**: Verify Phosphor Icons CDN links are in `index.html`:
|
|
1063
|
+
|
|
1064
|
+
```html
|
|
1065
|
+
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/regular/style.css">
|
|
1066
|
+
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/fill/style.css">
|
|
1067
|
+
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/bold/style.css">
|
|
1068
|
+
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.0.3/src/light/style.css">
|
|
1069
|
+
```
|
|
1070
|
+
|
|
1071
|
+
### Custom Colors Not Applying
|
|
1072
|
+
|
|
1073
|
+
**Problem**: Brand colors aren't being used.
|
|
1074
|
+
|
|
1075
|
+
**Solution**:
|
|
1076
|
+
1. Verify your theme context service implements `InsurerContextService`
|
|
1077
|
+
2. Check the provider configuration in `main.ts` or `app.config.ts`
|
|
1078
|
+
3. Ensure you're using valid hex color codes (e.g., `#FF0000`)
|
|
1079
|
+
4. Call `themeService.applyInsurerTheme()` after color changes
|
|
1080
|
+
|
|
1081
|
+
See [THEME.md](./THEME.md) for complete theming documentation.
|
|
1082
|
+
|
|
1083
|
+
### TypeScript Errors
|
|
1084
|
+
|
|
1085
|
+
**Problem**: TypeScript compilation errors with component imports.
|
|
1086
|
+
|
|
1087
|
+
**Solution**:
|
|
1088
|
+
1. Verify Angular version is 22.0.0 or higher
|
|
1089
|
+
2. Check `tsconfig.json` has `"strict": true`
|
|
1090
|
+
3. Ensure all peer dependencies are installed
|
|
1091
|
+
4. Clear node_modules and reinstall: `rm -rf node_modules && npm install`
|
|
1092
|
+
|
|
1093
|
+
### Performance Issues
|
|
1094
|
+
|
|
1095
|
+
**Problem**: Application feels slow or unresponsive.
|
|
1096
|
+
|
|
1097
|
+
**Solution**:
|
|
1098
|
+
1. Use `OnPush` change detection strategy
|
|
1099
|
+
2. Implement proper signal usage
|
|
1100
|
+
3. Avoid unnecessary component re-renders
|
|
1101
|
+
4. Use `trackBy` functions in `@for` loops
|
|
1102
|
+
5. Lazy load routes and components where possible
|
|
1103
|
+
|
|
1104
|
+
### Build Errors
|
|
1105
|
+
|
|
1106
|
+
**Problem**: Build fails with module resolution errors.
|
|
1107
|
+
|
|
1108
|
+
**Solution**:
|
|
1109
|
+
1. Verify package.json includes ps-helix in dependencies
|
|
1110
|
+
2. Clear Angular cache: `ng cache clean`
|
|
1111
|
+
3. Delete .angular folder and rebuild
|
|
1112
|
+
4. Check that all peer dependencies match required versions
|
|
1113
|
+
|
|
1114
|
+
### Runtime Errors
|
|
1115
|
+
|
|
1116
|
+
**Problem**: Errors in browser console at runtime.
|
|
1117
|
+
|
|
1118
|
+
**Solution**:
|
|
1119
|
+
1. Check browser console for specific error messages
|
|
1120
|
+
2. Verify all required services are provided
|
|
1121
|
+
3. Ensure ThemeService is initialized if using custom themes
|
|
1122
|
+
4. Check that ngx-translate is properly configured if using i18n
|
|
1123
|
+
|
|
1124
|
+
## Browser Support
|
|
1125
|
+
|
|
1126
|
+
Helix Design System supports:
|
|
1127
|
+
|
|
1128
|
+
- **Chrome**: Latest 2 versions
|
|
1129
|
+
- **Firefox**: Latest 2 versions
|
|
1130
|
+
- **Safari**: Latest 2 versions
|
|
1131
|
+
- **Edge**: Latest 2 versions
|
|
1132
|
+
- **Mobile browsers**: iOS Safari 14+, Chrome Android latest
|
|
1133
|
+
|
|
1134
|
+
**Note**: Internet Explorer is not supported.
|
|
1135
|
+
|
|
1136
|
+
## Development Scripts
|
|
1137
|
+
|
|
1138
|
+
The following scripts are available for library development:
|
|
1139
|
+
|
|
1140
|
+
```bash
|
|
1141
|
+
npm run build:lib # Build the library
|
|
1142
|
+
npm run watch:lib # Watch for changes and rebuild
|
|
1143
|
+
npm run publish:lib # Publish to npm registry
|
|
1144
|
+
npm run build # Build demo application
|
|
1145
|
+
npm run dev # Run demo application in dev mode
|
|
1146
|
+
```
|
|
1147
|
+
|
|
1148
|
+
## Contributing
|
|
1149
|
+
|
|
1150
|
+
We welcome contributions! To contribute to Helix Design System:
|
|
1151
|
+
|
|
1152
|
+
1. Fork the repository
|
|
1153
|
+
2. Create a feature branch: `git checkout -b feature/my-feature`
|
|
1154
|
+
3. Make your changes and commit: `git commit -am 'Add new feature'`
|
|
1155
|
+
4. Push to the branch: `git push origin feature/my-feature`
|
|
1156
|
+
5. Submit a pull request
|
|
1157
|
+
|
|
1158
|
+
### Development Guidelines
|
|
1159
|
+
|
|
1160
|
+
- Follow Angular style guide
|
|
1161
|
+
- Use TypeScript strict mode
|
|
1162
|
+
- Write tests for new components
|
|
1163
|
+
- Document all public APIs
|
|
1164
|
+
- Ensure accessibility compliance (WCAG 2.1 AA)
|
|
1165
|
+
- Keep components small and focused
|
|
1166
|
+
- Use signals for reactive state
|
|
1167
|
+
|
|
1168
|
+
## License
|
|
1169
|
+
|
|
1170
|
+
MIT License - see LICENSE file for details.
|
|
1171
|
+
|
|
1172
|
+
Copyright (c) 2025 PACK Solutions
|
|
1173
|
+
|
|
1174
|
+
## Resources
|
|
1175
|
+
|
|
1176
|
+
- **Theme Customization Guide**: [THEME.md](./THEME.md)
|
|
1177
|
+
- **Component Documentation**: Individual component README files in `/lib/components/`
|
|
1178
|
+
- **Phosphor Icons**: [https://phosphoricons.com/](https://phosphoricons.com/)
|
|
1179
|
+
- **Angular Documentation**: [https://angular.dev/](https://angular.dev/)
|
|
1180
|
+
- **TypeScript Documentation**: [https://www.typescriptlang.org/](https://www.typescriptlang.org/)
|
|
1181
|
+
- **ngx-translate**: [https://github.com/ngx-translate/core](https://github.com/ngx-translate/core)
|
|
1182
|
+
|
|
1183
|
+
---
|
|
1184
|
+
|
|
1185
|
+
**Version**: 6.0.0
|
|
1186
|
+
**Built with**: Angular 22.0.0, TypeScript 6.0.0, Phosphor Icons 2.0.3
|
|
1187
|
+
**Author**: Fabrice PEREZ | Product Designer at PACK Solutions
|
|
1188
|
+
**Last Updated**: January 2026
|