@kern-ux-annex/kern-angular-kit 0.3.4 → 0.3.7
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/.npmignore +2 -0
- package/COMPONENTS.md +816 -0
- package/INTELLISENSE.md +321 -0
- package/README.md +95 -0
- package/fesm2022/kern-ux-annex-kern-angular-kit.mjs +1531 -0
- package/fesm2022/kern-ux-annex-kern-angular-kit.mjs.map +1 -0
- package/index.d.ts +898 -0
- package/package.json +28 -2
- package/schemas/kern-components.schema.json +280 -0
- package/kern-ux-annex-kern-angular-kit-0.3.4.tgz +0 -0
package/COMPONENTS.md
ADDED
|
@@ -0,0 +1,816 @@
|
|
|
1
|
+
# KERN Angular Kit Components
|
|
2
|
+
|
|
3
|
+
This document provides comprehensive documentation for all components available in the `@kern-ux-annex/kern-angular-kit` library. The library follows the KERN Design System and provides Angular 20.1+ compatible components with InputSignal support and modern patterns.
|
|
4
|
+
|
|
5
|
+
**Current Version:** 0.1.2 (July 25, 2025)
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Getting Started](#getting-started)
|
|
11
|
+
- [Form Input Components](#form-input-components)
|
|
12
|
+
- [UI Components](#ui-components)
|
|
13
|
+
- [Services](#services)
|
|
14
|
+
- [Common Patterns](#common-patterns)
|
|
15
|
+
- [Examples](#examples)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Install the library via npm:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @kern-ux-annex/kern-angular-kit
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Getting Started
|
|
26
|
+
|
|
27
|
+
### Import the Module
|
|
28
|
+
|
|
29
|
+
You can import the entire module or individual components:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// Option 1: Import the entire module (NgModule approach)
|
|
33
|
+
import { NgModule } from '@angular/core';
|
|
34
|
+
import { KernAngularKitModule } from '@kern-ux-annex/kern-angular-kit';
|
|
35
|
+
|
|
36
|
+
@NgModule({
|
|
37
|
+
imports: [KernAngularKitModule]
|
|
38
|
+
// ...
|
|
39
|
+
})
|
|
40
|
+
export class AppModule {}
|
|
41
|
+
|
|
42
|
+
// Option 2: Import individual components (Standalone approach - Recommended)
|
|
43
|
+
import { Component } from '@angular/core';
|
|
44
|
+
import {
|
|
45
|
+
KernInputText,
|
|
46
|
+
KernInputCheckbox,
|
|
47
|
+
KernAlert
|
|
48
|
+
} from '@kern-ux-annex/kern-angular-kit';
|
|
49
|
+
|
|
50
|
+
@Component({
|
|
51
|
+
selector: 'app-example',
|
|
52
|
+
imports: [KernInputText, KernInputCheckbox, KernAlert],
|
|
53
|
+
template: `...`
|
|
54
|
+
})
|
|
55
|
+
export class ExampleComponent {}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Required CSS
|
|
59
|
+
|
|
60
|
+
Make sure to include the KERN UX CSS framework:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm install @kern-ux/native
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Add to your `angular.json` or main CSS file:
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
@import '@kern-ux/native/dist/kern.min.css';
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Peer Dependencies
|
|
73
|
+
|
|
74
|
+
The library requires these Angular packages:
|
|
75
|
+
|
|
76
|
+
- `@angular/core`: ^20.1.0
|
|
77
|
+
- `@angular/common`: ^20.1.0
|
|
78
|
+
- `@angular/forms`: ^20.1.0
|
|
79
|
+
|
|
80
|
+
## Form Input Components
|
|
81
|
+
|
|
82
|
+
All form input components implement Angular's `ControlValueAccessor` interface and support Angular Forms (Template-driven and Reactive).
|
|
83
|
+
|
|
84
|
+
### Common Properties
|
|
85
|
+
|
|
86
|
+
All form input components share these common properties:
|
|
87
|
+
|
|
88
|
+
| Property | Type | Required | Default | Description |
|
|
89
|
+
| ----------- | ---------------- | -------- | -------------- | ------------------------------------ |
|
|
90
|
+
| `inputId` | `string` | No | Auto-generated | Custom ID for the input element |
|
|
91
|
+
| `labelText` | `string` | **Yes** | - | Label text for the input |
|
|
92
|
+
| `optional` | `boolean` | No | `false` | Shows "Optional" indicator |
|
|
93
|
+
| `required` | `boolean` | No | `false` | Marks field as required |
|
|
94
|
+
| `readonly` | `boolean` | No | `false` | Makes input read-only |
|
|
95
|
+
| `hintText` | `string \| null` | No | `null` | Helper text below the input |
|
|
96
|
+
| `errorText` | `string \| null` | No | `null` | Error message (triggers error state) |
|
|
97
|
+
|
|
98
|
+
### KernInputText
|
|
99
|
+
|
|
100
|
+
Text input component for general text input.
|
|
101
|
+
|
|
102
|
+
**Selector:** `kern-input-text`
|
|
103
|
+
|
|
104
|
+
**Additional Properties:**
|
|
105
|
+
|
|
106
|
+
| Property | Type | Default | Description |
|
|
107
|
+
| -------------- | -------------------------------- | ------- | ------------------------ |
|
|
108
|
+
| `inputmode` | `'decimal' \| 'numeric' \| null` | `null` | Virtual keyboard hint |
|
|
109
|
+
| `maxlength` | `number \| null` | `null` | Maximum character length |
|
|
110
|
+
| `autocomplete` | `string \| null` | `null` | Autocomplete attribute |
|
|
111
|
+
|
|
112
|
+
**Example:**
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<kern-input-text
|
|
116
|
+
labelText="Full Name"
|
|
117
|
+
hintText="Enter your first and last name"
|
|
118
|
+
[maxlength]="50"
|
|
119
|
+
autocomplete="name"
|
|
120
|
+
[(ngModel)]="fullName"
|
|
121
|
+
>
|
|
122
|
+
</kern-input-text>
|
|
123
|
+
|
|
124
|
+
<!-- With Reactive Forms -->
|
|
125
|
+
<kern-input-text
|
|
126
|
+
labelText="Username"
|
|
127
|
+
autocomplete="username"
|
|
128
|
+
[formControl]="usernameControl"
|
|
129
|
+
>
|
|
130
|
+
</kern-input-text>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### KernInputEmail
|
|
134
|
+
|
|
135
|
+
Email input component with built-in email validation.
|
|
136
|
+
|
|
137
|
+
**Selector:** `kern-input-email`
|
|
138
|
+
|
|
139
|
+
**Additional Properties:**
|
|
140
|
+
|
|
141
|
+
| Property | Type | Default | Description |
|
|
142
|
+
| ----------- | ---------------- | ------- | ------------------------ |
|
|
143
|
+
| `maxlength` | `number \| null` | `null` | Maximum character length |
|
|
144
|
+
|
|
145
|
+
**Example:**
|
|
146
|
+
|
|
147
|
+
```html
|
|
148
|
+
<kern-input-email
|
|
149
|
+
labelText="Email Address"
|
|
150
|
+
autocomplete="email"
|
|
151
|
+
[required]="true"
|
|
152
|
+
[(ngModel)]="email"
|
|
153
|
+
>
|
|
154
|
+
</kern-input-email>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### KernInputPassword
|
|
158
|
+
|
|
159
|
+
Password input component with visibility toggle.
|
|
160
|
+
|
|
161
|
+
**Selector:** `kern-input-password`
|
|
162
|
+
|
|
163
|
+
**Additional Properties:**
|
|
164
|
+
|
|
165
|
+
| Property | Type | Default | Description |
|
|
166
|
+
| -------------- | ---------------- | ------- | ---------------------- |
|
|
167
|
+
| `autocomplete` | `string \| null` | `null` | Autocomplete attribute |
|
|
168
|
+
|
|
169
|
+
**Example:**
|
|
170
|
+
|
|
171
|
+
```html
|
|
172
|
+
<kern-input-password
|
|
173
|
+
labelText="Password"
|
|
174
|
+
autocomplete="current-password"
|
|
175
|
+
[required]="true"
|
|
176
|
+
[(ngModel)]="password"
|
|
177
|
+
>
|
|
178
|
+
</kern-input-password>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### KernInputTextarea
|
|
182
|
+
|
|
183
|
+
Multi-line text input component.
|
|
184
|
+
|
|
185
|
+
**Selector:** `kern-input-textarea`
|
|
186
|
+
|
|
187
|
+
**Additional Properties:**
|
|
188
|
+
|
|
189
|
+
| Property | Type | Default | Description |
|
|
190
|
+
| ----------- | ---------------- | ------- | ------------------------ |
|
|
191
|
+
| `rows` | `number \| null` | `null` | Number of visible rows |
|
|
192
|
+
| `maxlength` | `number \| null` | `null` | Maximum character length |
|
|
193
|
+
|
|
194
|
+
**Example:**
|
|
195
|
+
|
|
196
|
+
```html
|
|
197
|
+
<kern-input-textarea
|
|
198
|
+
labelText="Description"
|
|
199
|
+
hintText="Provide a detailed description"
|
|
200
|
+
[rows]="4"
|
|
201
|
+
[maxlength]="500"
|
|
202
|
+
[(ngModel)]="description"
|
|
203
|
+
>
|
|
204
|
+
</kern-input-textarea>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### KernInputCheckbox
|
|
208
|
+
|
|
209
|
+
Checkbox input component.
|
|
210
|
+
|
|
211
|
+
**Selector:** `kern-input-checkbox`
|
|
212
|
+
|
|
213
|
+
**Properties:**
|
|
214
|
+
|
|
215
|
+
| Property | Type | Required | Default | Description |
|
|
216
|
+
| ----------- | --------- | -------- | -------------- | --------------------------- |
|
|
217
|
+
| `inputId` | `string` | No | Auto-generated | Custom ID for the input |
|
|
218
|
+
| `labelText` | `string` | **Yes** | - | Label text for the checkbox |
|
|
219
|
+
| `error` | `boolean` | No | `false` | Shows error state |
|
|
220
|
+
|
|
221
|
+
**Example:**
|
|
222
|
+
|
|
223
|
+
```html
|
|
224
|
+
<kern-input-checkbox
|
|
225
|
+
labelText="I agree to the terms and conditions"
|
|
226
|
+
[(ngModel)]="agreedToTerms"
|
|
227
|
+
>
|
|
228
|
+
</kern-input-checkbox>
|
|
229
|
+
|
|
230
|
+
<kern-input-checkbox
|
|
231
|
+
labelText="Subscribe to newsletter"
|
|
232
|
+
[error]="newsletterError"
|
|
233
|
+
[formControl]="newsletterControl"
|
|
234
|
+
>
|
|
235
|
+
</kern-input-checkbox>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### KernInputRadio
|
|
239
|
+
|
|
240
|
+
Radio button group component.
|
|
241
|
+
|
|
242
|
+
**Selector:** `kern-input-radio`
|
|
243
|
+
|
|
244
|
+
**Additional Properties:**
|
|
245
|
+
|
|
246
|
+
| Property | Type | Default | Description |
|
|
247
|
+
| --------------------- | --------------------------------------- | ------------ | ----------------- |
|
|
248
|
+
| `options` | `Array<{value: string, label: string}>` | **Required** | Radio options |
|
|
249
|
+
| `horizontalAlignment` | `boolean` | `false` | Horizontal layout |
|
|
250
|
+
|
|
251
|
+
**Example:**
|
|
252
|
+
|
|
253
|
+
```html
|
|
254
|
+
<kern-input-radio
|
|
255
|
+
labelText="Preferred Contact Method"
|
|
256
|
+
[options]="contactOptions"
|
|
257
|
+
[horizontalAlignment]="true"
|
|
258
|
+
[(ngModel)]="contactMethod"
|
|
259
|
+
>
|
|
260
|
+
</kern-input-radio>
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
````typescript
|
|
264
|
+
```typescript
|
|
265
|
+
export class MyComponent {
|
|
266
|
+
contactOptions = [
|
|
267
|
+
{ value: 'email', label: 'Email' },
|
|
268
|
+
{ value: 'phone', label: 'Phone' },
|
|
269
|
+
{ value: 'sms', label: 'SMS' }
|
|
270
|
+
];
|
|
271
|
+
contactMethod = 'email';
|
|
272
|
+
}
|
|
273
|
+
````
|
|
274
|
+
|
|
275
|
+
### KernInputSelect
|
|
276
|
+
|
|
277
|
+
Select dropdown component.
|
|
278
|
+
|
|
279
|
+
**Selector:** `kern-input-select`
|
|
280
|
+
|
|
281
|
+
**Additional Properties:**
|
|
282
|
+
|
|
283
|
+
| Property | Type | Default | Description |
|
|
284
|
+
| --------- | --------------------------------------- | ------------ | -------------- |
|
|
285
|
+
| `options` | `Array<{value: string, label: string}>` | **Required** | Select options |
|
|
286
|
+
|
|
287
|
+
**Example:**
|
|
288
|
+
|
|
289
|
+
```html
|
|
290
|
+
<kern-input-select
|
|
291
|
+
labelText="Country"
|
|
292
|
+
[options]="countryOptions"
|
|
293
|
+
hintText="Select your country of residence"
|
|
294
|
+
[(ngModel)]="selectedCountry"
|
|
295
|
+
>
|
|
296
|
+
</kern-input-select>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
````typescript
|
|
300
|
+
export class MyComponent {
|
|
301
|
+
countryOptions = [
|
|
302
|
+
{ value: 'de', label: 'Germany' },
|
|
303
|
+
{ value: 'at', label: 'Austria' },
|
|
304
|
+
{ value: 'ch', label: 'Switzerland' }
|
|
305
|
+
];
|
|
306
|
+
selectedCountry = 'de';
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
### KernInputDate
|
|
310
|
+
|
|
311
|
+
Date input component with separate fields for day, month, and year.
|
|
312
|
+
|
|
313
|
+
**Selector:** `kern-input-date`
|
|
314
|
+
|
|
315
|
+
**Additional Properties:**
|
|
316
|
+
|
|
317
|
+
| Property | Type | Default | Description |
|
|
318
|
+
| -------- | ---------------- | ------- | ------------------------- |
|
|
319
|
+
| `min` | `string \| null` | `null` | Minimum date (YYYY-MM-DD) |
|
|
320
|
+
| `max` | `string \| null` | `null` | Maximum date (YYYY-MM-DD) |
|
|
321
|
+
|
|
322
|
+
**Example:**
|
|
323
|
+
|
|
324
|
+
```html
|
|
325
|
+
<kern-input-date
|
|
326
|
+
labelText="Birth Date"
|
|
327
|
+
hintText="For example: 17 10 2015"
|
|
328
|
+
[max]="maxDate"
|
|
329
|
+
[(ngModel)]="birthDate"
|
|
330
|
+
>
|
|
331
|
+
</kern-input-date>
|
|
332
|
+
````
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
export class MyComponent {
|
|
336
|
+
maxDate = '2025-12-31';
|
|
337
|
+
birthDate: string | null = null;
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### KernInputTel
|
|
342
|
+
|
|
343
|
+
Telephone number input component with autocomplete support.
|
|
344
|
+
|
|
345
|
+
**Selector:** `kern-input-tel`
|
|
346
|
+
|
|
347
|
+
**Additional Properties:**
|
|
348
|
+
|
|
349
|
+
| Property | Type | Default | Description |
|
|
350
|
+
| ----------- | ---------------- | ------- | ------------------------ |
|
|
351
|
+
| `maxlength` | `number \| null` | `null` | Maximum character length |
|
|
352
|
+
|
|
353
|
+
**Example:**
|
|
354
|
+
|
|
355
|
+
```html
|
|
356
|
+
<kern-input-tel
|
|
357
|
+
labelText="Phone Number"
|
|
358
|
+
autocomplete="tel"
|
|
359
|
+
hintText="Include country code if applicable"
|
|
360
|
+
[(ngModel)]="phoneNumber"
|
|
361
|
+
>
|
|
362
|
+
</kern-input-tel>
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### KernInputUrl
|
|
366
|
+
|
|
367
|
+
URL input component with validation.
|
|
368
|
+
|
|
369
|
+
**Selector:** `kern-input-url`
|
|
370
|
+
|
|
371
|
+
**Additional Properties:**
|
|
372
|
+
|
|
373
|
+
| Property | Type | Default | Description |
|
|
374
|
+
| ----------- | ---------------- | ------- | ------------------------ |
|
|
375
|
+
| `maxlength` | `number \| null` | `null` | Maximum character length |
|
|
376
|
+
|
|
377
|
+
**Example:**
|
|
378
|
+
|
|
379
|
+
```html
|
|
380
|
+
<kern-input-url
|
|
381
|
+
labelText="Website"
|
|
382
|
+
hintText="Enter your website URL (e.g., https://example.com)"
|
|
383
|
+
[(ngModel)]="website"
|
|
384
|
+
>
|
|
385
|
+
</kern-input-url>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### KernInputFile
|
|
389
|
+
|
|
390
|
+
File upload input component.
|
|
391
|
+
|
|
392
|
+
**Selector:** `kern-input-file`
|
|
393
|
+
|
|
394
|
+
**Additional Properties:**
|
|
395
|
+
|
|
396
|
+
| Property | Type | Default | Description |
|
|
397
|
+
| ---------- | ---------------- | ------- | -------------------- |
|
|
398
|
+
| `accept` | `string \| null` | `null` | Accepted file types |
|
|
399
|
+
| `multiple` | `boolean` | `false` | Allow multiple files |
|
|
400
|
+
|
|
401
|
+
**Example:**
|
|
402
|
+
|
|
403
|
+
```html
|
|
404
|
+
<kern-input-file
|
|
405
|
+
labelText="Upload Documents"
|
|
406
|
+
accept=".pdf,.doc,.docx"
|
|
407
|
+
[multiple]="true"
|
|
408
|
+
[(ngModel)]="uploadedFiles"
|
|
409
|
+
>
|
|
410
|
+
</kern-input-file>
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## UI Components
|
|
414
|
+
|
|
415
|
+
### KernAlert
|
|
416
|
+
|
|
417
|
+
Alert/notification component for displaying messages.
|
|
418
|
+
|
|
419
|
+
**Selector:** `kern-alert`
|
|
420
|
+
|
|
421
|
+
**Properties:**
|
|
422
|
+
|
|
423
|
+
| Property | Type | Default | Description |
|
|
424
|
+
| -------- | ---------------------------------------------- | ------------ | ----------- |
|
|
425
|
+
| `title` | `string` | **Required** | Alert title |
|
|
426
|
+
| `type` | `'info' \| 'success' \| 'warning' \| 'danger'` | `'info'` | Alert type |
|
|
427
|
+
|
|
428
|
+
**Example:**
|
|
429
|
+
|
|
430
|
+
```html
|
|
431
|
+
<kern-alert title="Success!" type="success">
|
|
432
|
+
Your form has been submitted successfully.
|
|
433
|
+
</kern-alert>
|
|
434
|
+
|
|
435
|
+
<kern-alert title="Warning" type="warning">
|
|
436
|
+
Please check your input before proceeding.
|
|
437
|
+
</kern-alert>
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### KernAccordion
|
|
441
|
+
|
|
442
|
+
Collapsible content component.
|
|
443
|
+
|
|
444
|
+
**Selector:** `kern-accordion`
|
|
445
|
+
|
|
446
|
+
**Properties:**
|
|
447
|
+
|
|
448
|
+
| Property | Type | Default | Description |
|
|
449
|
+
| -------- | --------- | ------------ | -------------------- |
|
|
450
|
+
| `title` | `string` | **Required** | Accordion title |
|
|
451
|
+
| `open` | `boolean` | `false` | Initially open state |
|
|
452
|
+
|
|
453
|
+
**Example:**
|
|
454
|
+
|
|
455
|
+
```html
|
|
456
|
+
<kern-accordion title="Frequently Asked Questions" [open]="true">
|
|
457
|
+
<p>This is the accordion content that can be collapsed or expanded.</p>
|
|
458
|
+
<ul>
|
|
459
|
+
<li>Item 1</li>
|
|
460
|
+
<li>Item 2</li>
|
|
461
|
+
</ul>
|
|
462
|
+
</kern-accordion>
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### KernDialog
|
|
466
|
+
|
|
467
|
+
Modal dialog component.
|
|
468
|
+
|
|
469
|
+
**Selector:** `kern-dialog`
|
|
470
|
+
|
|
471
|
+
**Properties:**
|
|
472
|
+
|
|
473
|
+
| Property | Type | Default | Description |
|
|
474
|
+
| ----------------------- | ---------------- | -------------- | --------------------- |
|
|
475
|
+
| `dialogId` | `string` | Auto-generated | Custom dialog ID |
|
|
476
|
+
| `title` | `string` | **Required** | Dialog title |
|
|
477
|
+
| `btnCloseLabelText` | `string` | `'Schließen'` | Close button text |
|
|
478
|
+
| `btnPrimaryLabelText` | `string \| null` | `null` | Primary button text |
|
|
479
|
+
| `btnSecondaryLabelText` | `string \| null` | `null` | Secondary button text |
|
|
480
|
+
|
|
481
|
+
**Events:**
|
|
482
|
+
|
|
483
|
+
| Event | Type | Description |
|
|
484
|
+
| ------------------------ | ------- | ------------------------------------- |
|
|
485
|
+
| `cancelEvent` | `Event` | Emitted when dialog is cancelled |
|
|
486
|
+
| `btnPrimaryClickEvent` | `Event` | Emitted when primary button clicked |
|
|
487
|
+
| `btnSecondaryClickEvent` | `Event` | Emitted when secondary button clicked |
|
|
488
|
+
|
|
489
|
+
**Example:**
|
|
490
|
+
|
|
491
|
+
```html
|
|
492
|
+
<kern-dialog
|
|
493
|
+
title="Confirm Action"
|
|
494
|
+
btnPrimaryLabelText="Confirm"
|
|
495
|
+
btnSecondaryLabelText="Cancel"
|
|
496
|
+
(btnPrimaryClickEvent)="onConfirm($event)"
|
|
497
|
+
(btnSecondaryClickEvent)="onCancel($event)"
|
|
498
|
+
>
|
|
499
|
+
<p>Are you sure you want to perform this action?</p>
|
|
500
|
+
</kern-dialog>
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
export class MyComponent {
|
|
505
|
+
onConfirm(event: Event) {
|
|
506
|
+
console.log('User confirmed');
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
onCancel(event: Event) {
|
|
510
|
+
console.log('User cancelled');
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### KernLoader
|
|
516
|
+
|
|
517
|
+
Loading spinner component.
|
|
518
|
+
|
|
519
|
+
**Selector:** `kern-loader`
|
|
520
|
+
|
|
521
|
+
**Properties:**
|
|
522
|
+
|
|
523
|
+
| Property | Type | Default | Description |
|
|
524
|
+
| -------- | -------- | -------------- | ------------------ |
|
|
525
|
+
| `text` | `string` | `'Loading...'` | Screen reader text |
|
|
526
|
+
|
|
527
|
+
**Example:**
|
|
528
|
+
|
|
529
|
+
```html
|
|
530
|
+
<kern-loader text="Loading data..."></kern-loader>
|
|
531
|
+
|
|
532
|
+
<!-- Show conditionally -->
|
|
533
|
+
@if (isLoading) {
|
|
534
|
+
<kern-loader text="Saving your changes..."></kern-loader>
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
## Services
|
|
539
|
+
|
|
540
|
+
### UniqueIdService
|
|
541
|
+
|
|
542
|
+
Service for generating unique IDs for form elements and accessibility.
|
|
543
|
+
|
|
544
|
+
**Methods:**
|
|
545
|
+
|
|
546
|
+
| Method | Parameters | Returns | Description |
|
|
547
|
+
| --------------- | ----------------- | -------- | ---------------------------------------- |
|
|
548
|
+
| `getUniqueId()` | `prefix?: string` | `string` | Generates unique ID with optional prefix |
|
|
549
|
+
|
|
550
|
+
**Example:**
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
import { UniqueIdService } from '@kern-ux-annex/kern-angular-kit';
|
|
554
|
+
|
|
555
|
+
export class MyComponent {
|
|
556
|
+
constructor(private uniqueIdService: UniqueIdService) {
|
|
557
|
+
const id = this.uniqueIdService.getUniqueId('my-component');
|
|
558
|
+
console.log(id); // "my-component_0"
|
|
559
|
+
|
|
560
|
+
const anotherId = this.uniqueIdService.getUniqueId('input');
|
|
561
|
+
console.log(anotherId); // "input_1"
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
## Common Patterns
|
|
567
|
+
|
|
568
|
+
### Form Validation
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
import { Component } from '@angular/core';
|
|
572
|
+
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
|
573
|
+
import { KernInputText, KernInputEmail } from '@kern-ux-annex/kern-angular-kit';
|
|
574
|
+
|
|
575
|
+
@Component({
|
|
576
|
+
selector: 'app-user-form',
|
|
577
|
+
imports: [ReactiveFormsModule, KernInputText, KernInputEmail],
|
|
578
|
+
template: `
|
|
579
|
+
<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
|
|
580
|
+
<kern-input-text
|
|
581
|
+
labelText="Full Name"
|
|
582
|
+
[required]="true"
|
|
583
|
+
[errorText]="getErrorText('name')"
|
|
584
|
+
formControlName="name"
|
|
585
|
+
>
|
|
586
|
+
</kern-input-text>
|
|
587
|
+
|
|
588
|
+
<kern-input-email
|
|
589
|
+
labelText="Email"
|
|
590
|
+
[required]="true"
|
|
591
|
+
[errorText]="getErrorText('email')"
|
|
592
|
+
formControlName="email"
|
|
593
|
+
>
|
|
594
|
+
</kern-input-email>
|
|
595
|
+
|
|
596
|
+
<button type="submit" [disabled]="userForm.invalid">Submit</button>
|
|
597
|
+
</form>
|
|
598
|
+
`
|
|
599
|
+
})
|
|
600
|
+
export class UserFormComponent {
|
|
601
|
+
userForm: FormGroup;
|
|
602
|
+
|
|
603
|
+
constructor(private fb: FormBuilder) {
|
|
604
|
+
this.userForm = this.fb.group({
|
|
605
|
+
name: ['', [Validators.required, Validators.minLength(2)]],
|
|
606
|
+
email: ['', [Validators.required, Validators.email]]
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
getErrorText(fieldName: string): string | null {
|
|
611
|
+
const field = this.userForm.get(fieldName);
|
|
612
|
+
if (field?.invalid && field?.touched) {
|
|
613
|
+
if (field.errors?.['required']) return 'This field is required';
|
|
614
|
+
if (field.errors?.['email']) return 'Please enter a valid email';
|
|
615
|
+
if (field.errors?.['minlength']) return 'Minimum 2 characters required';
|
|
616
|
+
}
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
onSubmit() {
|
|
621
|
+
if (this.userForm.valid) {
|
|
622
|
+
console.log(this.userForm.value);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Dynamic Forms
|
|
629
|
+
|
|
630
|
+
```typescript
|
|
631
|
+
@Component({
|
|
632
|
+
template: `
|
|
633
|
+
@for (field of formFields; track field.name) {
|
|
634
|
+
@switch (field.type) {
|
|
635
|
+
@case ('text') {
|
|
636
|
+
<kern-input-text
|
|
637
|
+
[labelText]="field.label"
|
|
638
|
+
[required]="field.required"
|
|
639
|
+
[(ngModel)]="formData[field.name]"
|
|
640
|
+
>
|
|
641
|
+
</kern-input-text>
|
|
642
|
+
}
|
|
643
|
+
@case ('email') {
|
|
644
|
+
<kern-input-email
|
|
645
|
+
[labelText]="field.label"
|
|
646
|
+
[required]="field.required"
|
|
647
|
+
[(ngModel)]="formData[field.name]"
|
|
648
|
+
>
|
|
649
|
+
</kern-input-email>
|
|
650
|
+
}
|
|
651
|
+
@case ('select') {
|
|
652
|
+
<kern-input-select
|
|
653
|
+
[labelText]="field.label"
|
|
654
|
+
[options]="field.options"
|
|
655
|
+
[required]="field.required"
|
|
656
|
+
[(ngModel)]="formData[field.name]"
|
|
657
|
+
>
|
|
658
|
+
</kern-input-select>
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
`
|
|
663
|
+
})
|
|
664
|
+
export class DynamicFormComponent {
|
|
665
|
+
formFields = [
|
|
666
|
+
{ name: 'firstName', type: 'text', label: 'First Name', required: true },
|
|
667
|
+
{ name: 'email', type: 'email', label: 'Email', required: true },
|
|
668
|
+
{
|
|
669
|
+
name: 'country',
|
|
670
|
+
type: 'select',
|
|
671
|
+
label: 'Country',
|
|
672
|
+
required: false,
|
|
673
|
+
options: [
|
|
674
|
+
{ value: 'de', label: 'Germany' },
|
|
675
|
+
{ value: 'at', label: 'Austria' }
|
|
676
|
+
]
|
|
677
|
+
}
|
|
678
|
+
];
|
|
679
|
+
|
|
680
|
+
formData: Record<string, any> = {};
|
|
681
|
+
}
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
## Examples
|
|
685
|
+
|
|
686
|
+
### Complete Registration Form
|
|
687
|
+
|
|
688
|
+
```typescript
|
|
689
|
+
import { Component } from '@angular/core';
|
|
690
|
+
import {
|
|
691
|
+
KernInputText,
|
|
692
|
+
KernInputEmail,
|
|
693
|
+
KernInputPassword,
|
|
694
|
+
KernInputCheckbox,
|
|
695
|
+
KernInputSelect,
|
|
696
|
+
KernAlert
|
|
697
|
+
} from '@kern-ux-annex/kern-angular-kit';
|
|
698
|
+
|
|
699
|
+
@Component({
|
|
700
|
+
selector: 'app-registration',
|
|
701
|
+
imports: [
|
|
702
|
+
FormsModule,
|
|
703
|
+
KernInputText,
|
|
704
|
+
KernInputEmail,
|
|
705
|
+
KernInputPassword,
|
|
706
|
+
KernInputCheckbox,
|
|
707
|
+
KernInputSelect,
|
|
708
|
+
KernAlert
|
|
709
|
+
],
|
|
710
|
+
template: `
|
|
711
|
+
@if (showSuccess) {
|
|
712
|
+
<kern-alert title="Registration Successful!" type="success">
|
|
713
|
+
Welcome to our platform!
|
|
714
|
+
</kern-alert>
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
<form (ngSubmit)="onSubmit()" #form="ngForm">
|
|
718
|
+
<kern-input-text
|
|
719
|
+
labelText="Full Name"
|
|
720
|
+
[required]="true"
|
|
721
|
+
[(ngModel)]="user.fullName"
|
|
722
|
+
name="fullName"
|
|
723
|
+
>
|
|
724
|
+
</kern-input-text>
|
|
725
|
+
|
|
726
|
+
<kern-input-email
|
|
727
|
+
labelText="Email Address"
|
|
728
|
+
[required]="true"
|
|
729
|
+
[(ngModel)]="user.email"
|
|
730
|
+
name="email"
|
|
731
|
+
>
|
|
732
|
+
</kern-input-email>
|
|
733
|
+
|
|
734
|
+
<kern-input-password
|
|
735
|
+
labelText="Password"
|
|
736
|
+
[required]="true"
|
|
737
|
+
[(ngModel)]="user.password"
|
|
738
|
+
name="password"
|
|
739
|
+
>
|
|
740
|
+
</kern-input-password>
|
|
741
|
+
|
|
742
|
+
<kern-input-select
|
|
743
|
+
labelText="Country"
|
|
744
|
+
[options]="countryOptions"
|
|
745
|
+
[(ngModel)]="user.country"
|
|
746
|
+
name="country"
|
|
747
|
+
>
|
|
748
|
+
</kern-input-select>
|
|
749
|
+
|
|
750
|
+
<kern-input-checkbox
|
|
751
|
+
labelText="I agree to the Terms of Service"
|
|
752
|
+
[required]="true"
|
|
753
|
+
[(ngModel)]="user.agreedToTerms"
|
|
754
|
+
name="agreedToTerms"
|
|
755
|
+
>
|
|
756
|
+
</kern-input-checkbox>
|
|
757
|
+
|
|
758
|
+
<button
|
|
759
|
+
type="submit"
|
|
760
|
+
[disabled]="form.invalid"
|
|
761
|
+
class="kern-btn kern-btn--primary"
|
|
762
|
+
>
|
|
763
|
+
Register
|
|
764
|
+
</button>
|
|
765
|
+
</form>
|
|
766
|
+
`
|
|
767
|
+
})
|
|
768
|
+
export class RegistrationComponent {
|
|
769
|
+
showSuccess = false;
|
|
770
|
+
|
|
771
|
+
user = {
|
|
772
|
+
fullName: '',
|
|
773
|
+
email: '',
|
|
774
|
+
password: '',
|
|
775
|
+
country: '',
|
|
776
|
+
agreedToTerms: false
|
|
777
|
+
};
|
|
778
|
+
|
|
779
|
+
countryOptions = [
|
|
780
|
+
{ value: 'de', label: 'Germany' },
|
|
781
|
+
{ value: 'at', label: 'Austria' },
|
|
782
|
+
{ value: 'ch', label: 'Switzerland' }
|
|
783
|
+
];
|
|
784
|
+
|
|
785
|
+
onSubmit() {
|
|
786
|
+
console.log('User registration:', this.user);
|
|
787
|
+
this.showSuccess = true;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
## Browser Support
|
|
793
|
+
|
|
794
|
+
- Chrome 90+
|
|
795
|
+
- Firefox 90+
|
|
796
|
+
- Safari 14+
|
|
797
|
+
- Edge 90+
|
|
798
|
+
|
|
799
|
+
## Accessibility
|
|
800
|
+
|
|
801
|
+
All components follow WCAG 2.1 AA guidelines and include:
|
|
802
|
+
|
|
803
|
+
- Proper ARIA attributes
|
|
804
|
+
- Keyboard navigation support
|
|
805
|
+
- Screen reader compatibility
|
|
806
|
+
- Focus management
|
|
807
|
+
- High contrast support
|
|
808
|
+
- Unique IDs for form associations
|
|
809
|
+
|
|
810
|
+
## Contributing
|
|
811
|
+
|
|
812
|
+
For contributing guidelines, please see the [CONTRIBUTING.md](./CONTRIBUTING.md) file in the repository.
|
|
813
|
+
|
|
814
|
+
## License
|
|
815
|
+
|
|
816
|
+
This library is licensed under the EUPL-1.2 license.
|