@helsevestikt/hviktor-angular 0.0.3

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.
@@ -0,0 +1,1776 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Input, Component, booleanAttribute, Directive, CUSTOM_ELEMENTS_SCHEMA, EventEmitter, inject, ElementRef, HostListener, Output, ViewChild, DestroyRef, HostBinding, ViewEncapsulation } from '@angular/core';
3
+ import '@u-elements/u-details';
4
+ import { FormGroupDirective, NgControl, ControlContainer, ReactiveFormsModule } from '@angular/forms';
5
+ import * as i1 from '@angular/common/http';
6
+
7
+ /**
8
+ * Alert provides users with information that is especially important for them to see and understand.
9
+ * The component is designed to capture users' attention.
10
+ * The text in the alert should be short and clear.
11
+ *
12
+ * @example
13
+ * ```html
14
+ * <hvi-alert color="warning">
15
+ * Dette er et advarselsvarsel!
16
+ * </hvi-alert>
17
+ * ```
18
+ *
19
+ * Documentation: https://designsystemet.no/en/components/docs/alert/code/
20
+ */
21
+ class HviAlert {
22
+ /** Sets the type of alert by changing the color and */
23
+ color;
24
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviAlert, deps: [], target: i0.ɵɵFactoryTarget.Component });
25
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviAlert, isStandalone: true, selector: "hvi-alert", inputs: { color: "color" }, host: { properties: { "attr.data-color": "color" }, classAttribute: "ds-alert" }, ngImport: i0, template: `<ng-content />`, isInline: true });
26
+ }
27
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviAlert, decorators: [{
28
+ type: Component,
29
+ args: [{
30
+ selector: 'hvi-alert',
31
+ standalone: true,
32
+ template: `<ng-content />`,
33
+ host: {
34
+ class: 'ds-alert',
35
+ '[attr.data-color]': 'color',
36
+ },
37
+ }]
38
+ }], propDecorators: { color: [{
39
+ type: Input
40
+ }] } });
41
+
42
+ /**
43
+ * Avatar displays an image, initials, or icon for a person, entity, or profile.
44
+ *
45
+ * @example
46
+ * ```html
47
+ * <hvi-avatar
48
+ * ariaLabel="Ola Nordmann"
49
+ * variant="circle"
50
+ * initials="ON"
51
+ * size="md"
52
+ * color="brand1">
53
+ * </hvi-avatar>
54
+ * ```
55
+ *
56
+ * Documentation: https://designsystemet.no/en/components/docs/avatar/code/
57
+ */
58
+ class HviAvatar {
59
+ /** The name of the person the avatar represents */
60
+ ariaLabel;
61
+ /** The shape of the avatar */
62
+ variant;
63
+ /** Initials displayed inside the avatar */
64
+ initials;
65
+ /** The size of the avatar */
66
+ size;
67
+ /** The color theme of the avatar */
68
+ color;
69
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviAvatar, deps: [], target: i0.ɵɵFactoryTarget.Component });
70
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviAvatar, isStandalone: true, selector: "hvi-avatar", inputs: { ariaLabel: "ariaLabel", variant: "variant", initials: "initials", size: "size", color: "color" }, host: { attributes: { "role": "img" }, properties: { "attr.aria-label": "ariaLabel ?? null", "attr.data-variant": "variant ?? null", "attr.data-initials": "initials ?? null", "attr.data-size": "size ?? null", "attr.data-color": "color ?? null" }, classAttribute: "ds-avatar" }, ngImport: i0, template: '<ng-content />', isInline: true });
71
+ }
72
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviAvatar, decorators: [{
73
+ type: Component,
74
+ args: [{
75
+ selector: 'hvi-avatar',
76
+ standalone: true,
77
+ template: '<ng-content />',
78
+ host: {
79
+ class: 'ds-avatar',
80
+ role: 'img',
81
+ '[attr.aria-label]': 'ariaLabel ?? null',
82
+ '[attr.data-variant]': 'variant ?? null',
83
+ '[attr.data-initials]': 'initials ?? null',
84
+ '[attr.data-size]': 'size ?? null',
85
+ '[attr.data-color]': 'color ?? null',
86
+ },
87
+ }]
88
+ }], propDecorators: { ariaLabel: [{
89
+ type: Input
90
+ }], variant: [{
91
+ type: Input
92
+ }], initials: [{
93
+ type: Input
94
+ }], size: [{
95
+ type: Input
96
+ }], color: [{
97
+ type: Input
98
+ }] } });
99
+
100
+ class HviBadgePosition {
101
+ /** Overlap of the badge */
102
+ overlap = 'rectangle';
103
+ /** Placement of the badge */
104
+ placement = 'top-right';
105
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviBadgePosition, deps: [], target: i0.ɵɵFactoryTarget.Component });
106
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviBadgePosition, isStandalone: true, selector: "hvi-badge-position", inputs: { overlap: "overlap", placement: "placement" }, host: { properties: { "attr.data-overlap": "overlap", "attr.data-placement": "placement" }, classAttribute: "ds-badge--position" }, ngImport: i0, template: '<ng-content />', isInline: true });
107
+ }
108
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviBadgePosition, decorators: [{
109
+ type: Component,
110
+ args: [{
111
+ selector: 'hvi-badge-position',
112
+ standalone: true,
113
+ template: '<ng-content />',
114
+ host: {
115
+ class: 'ds-badge--position',
116
+ '[attr.data-overlap]': 'overlap',
117
+ '[attr.data-placement]': 'placement',
118
+ },
119
+ }]
120
+ }], propDecorators: { overlap: [{
121
+ type: Input
122
+ }], placement: [{
123
+ type: Input
124
+ }] } });
125
+
126
+ class HviBadge {
127
+ /** The variants of the badge */
128
+ variant;
129
+ /** count text of the badge*/
130
+ count;
131
+ /** The color theme of the badge */
132
+ color;
133
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviBadge, deps: [], target: i0.ɵɵFactoryTarget.Component });
134
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviBadge, isStandalone: true, selector: "hvi-badge", inputs: { variant: "variant", count: "count", color: "color" }, host: { properties: { "attr.data-variant": "variant ?? null", "attr.data-count": "count ?? null", "attr.data-color": "color ?? null" }, classAttribute: "ds-badge" }, ngImport: i0, template: '<ng-content />', isInline: true });
135
+ }
136
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviBadge, decorators: [{
137
+ type: Component,
138
+ args: [{
139
+ selector: 'hvi-badge',
140
+ standalone: true,
141
+ template: '<ng-content />',
142
+ host: {
143
+ class: 'ds-badge',
144
+ '[attr.data-variant]': 'variant ?? null',
145
+ '[attr.data-count]': 'count ?? null',
146
+ '[attr.data-color]': 'color ?? null',
147
+ },
148
+ }]
149
+ }], propDecorators: { variant: [{
150
+ type: Input
151
+ }], count: [{
152
+ type: Input
153
+ }], color: [{
154
+ type: Input
155
+ }] } });
156
+
157
+ /**
158
+ * Info
159
+ *
160
+ * Eksempel på bruk:
161
+ * ```html
162
+ * <nav hviBreadcrumbs
163
+ * ariaLabel="Du er her:"
164
+ * [backLink]="{
165
+ * label: 'Nivå 3',
166
+ * href: '#',
167
+ * ariaLabel: 'Tilbake til Nivå 3'
168
+ * }"
169
+ * [items]="[
170
+ * { label: 'Nivå 1', href: '#' },
171
+ * { label: 'Nivå 2', href: '#' },
172
+ * { label: 'Nivå 3', href: '#' },
173
+ * { label: 'Nivå 4', href: '#' }
174
+ * ]"
175
+ * ></nav>
176
+ * ```
177
+ *
178
+ * Dokumentasjon: https://designsystemet.no/no/components/docs/breadcrumbs/overview
179
+ */
180
+ class HviBreadcrumbs {
181
+ /** Accessible label for the breadcrumb navigation */
182
+ ariaLabel = 'Du er her:';
183
+ /** Optional back link object */
184
+ backLink;
185
+ /** Array of breadcrumb items */
186
+ items = [];
187
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviBreadcrumbs, deps: [], target: i0.ɵɵFactoryTarget.Component });
188
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: HviBreadcrumbs, isStandalone: true, selector: "nav[hviBreadcrumbs]", inputs: { ariaLabel: "ariaLabel", backLink: "backLink", items: "items" }, host: { attributes: { "role": "navigation" }, properties: { "attr.aria-label": "ariaLabel ?? null" }, classAttribute: "ds-breadcrumbs" }, ngImport: i0, template: `
189
+ <!-- Back link (optional) -->
190
+ @if (backLink) {
191
+ <a class="ds-link" [href]="backLink.href" [attr.aria-label]="backLink.ariaLabel ?? null">
192
+ {{ backLink.label }}
193
+ </a>
194
+ }
195
+
196
+ <ol>
197
+ @for (item of items; let last = $last; track item) {
198
+ <li>
199
+ <a
200
+ class="ds-link"
201
+ [href]="item.href"
202
+ [attr.aria-label]="item.ariaLabel ?? null"
203
+ [attr.aria-current]="last ? 'page' : null"
204
+ >
205
+ {{ item.label }}
206
+ </a>
207
+ </li>
208
+ }
209
+ </ol>
210
+ `, isInline: true });
211
+ }
212
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviBreadcrumbs, decorators: [{
213
+ type: Component,
214
+ args: [{
215
+ selector: 'nav[hviBreadcrumbs]',
216
+ standalone: true,
217
+ template: `
218
+ <!-- Back link (optional) -->
219
+ @if (backLink) {
220
+ <a class="ds-link" [href]="backLink.href" [attr.aria-label]="backLink.ariaLabel ?? null">
221
+ {{ backLink.label }}
222
+ </a>
223
+ }
224
+
225
+ <ol>
226
+ @for (item of items; let last = $last; track item) {
227
+ <li>
228
+ <a
229
+ class="ds-link"
230
+ [href]="item.href"
231
+ [attr.aria-label]="item.ariaLabel ?? null"
232
+ [attr.aria-current]="last ? 'page' : null"
233
+ >
234
+ {{ item.label }}
235
+ </a>
236
+ </li>
237
+ }
238
+ </ol>
239
+ `,
240
+ host: {
241
+ class: 'ds-breadcrumbs',
242
+ role: 'navigation',
243
+ '[attr.aria-label]': 'ariaLabel ?? null',
244
+ },
245
+ }]
246
+ }], propDecorators: { ariaLabel: [{
247
+ type: Input
248
+ }], backLink: [{
249
+ type: Input
250
+ }], items: [{
251
+ type: Input
252
+ }] } });
253
+
254
+ /**
255
+ * @summary
256
+ * Button allows users to perform actions.
257
+ *
258
+ * @example
259
+ * ```html
260
+ * <button hviButton color="brand1" variant="primary" size="md">
261
+ * Click me
262
+ * </button>
263
+ * ```
264
+ *
265
+ * Documentation: https://designsystemet.no/en/components/docs/button/code/
266
+ */
267
+ class HviButton {
268
+ /** The size of the button */
269
+ size;
270
+ /** Used to change the appearance of the button. */
271
+ variant;
272
+ /** The type of button */
273
+ type;
274
+ /** The color of the button */
275
+ color;
276
+ /** If you have only an icon in the button, you can set icon="true" to make it square.
277
+ * If you have other content, such as text, the button will automatically have space around the icon.
278
+ */
279
+ icon = false;
280
+ /** Sets the button in a loading state.
281
+ * Loading indicators such as spinners must be added manually, e.g., with hvi-spinner
282
+ */
283
+ loading = false;
284
+ /** Makes the button full width */
285
+ fullWidth = false;
286
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviButton, deps: [], target: i0.ɵɵFactoryTarget.Directive });
287
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.1.2", type: HviButton, isStandalone: true, selector: "button[hviButton], a[hviButton]", inputs: { size: "size", variant: "variant", type: "type", color: "color", icon: ["icon", "icon", booleanAttribute], loading: ["loading", "loading", booleanAttribute], fullWidth: ["fullWidth", "fullWidth", booleanAttribute] }, host: { properties: { "attr.type": "type", "attr.data-size": "size", "attr.data-variant": "variant", "attr.data-color": "color", "attr.data-fullwidth": "fullWidth ? \"\" : null", "attr.data-icon": "icon ? \"\" : null", "attr.aria-busy": "loading ? \"true\" : null" }, classAttribute: "ds-button" }, ngImport: i0 });
288
+ }
289
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviButton, decorators: [{
290
+ type: Directive,
291
+ args: [{
292
+ selector: 'button[hviButton], a[hviButton]',
293
+ standalone: true,
294
+ host: {
295
+ class: 'ds-button',
296
+ '[attr.type]': 'type',
297
+ '[attr.data-size]': 'size',
298
+ '[attr.data-variant]': 'variant',
299
+ '[attr.data-color]': 'color',
300
+ '[attr.data-fullwidth]': 'fullWidth ? "" : null',
301
+ '[attr.data-icon]': 'icon ? "" : null',
302
+ '[attr.aria-busy]': 'loading ? "true" : null',
303
+ },
304
+ }]
305
+ }], propDecorators: { size: [{
306
+ type: Input
307
+ }], variant: [{
308
+ type: Input
309
+ }], type: [{
310
+ type: Input
311
+ }], color: [{
312
+ type: Input
313
+ }], icon: [{
314
+ type: Input,
315
+ args: [{ transform: booleanAttribute }]
316
+ }], loading: [{
317
+ type: Input,
318
+ args: [{ transform: booleanAttribute }]
319
+ }], fullWidth: [{
320
+ type: Input,
321
+ args: [{ transform: booleanAttribute }]
322
+ }] } });
323
+
324
+ /**
325
+ * Use multiple <div hviCardBlock> elements if you want to divide the card with separators or add images or video that extend to the edge.
326
+ * Note that when you use <div hviCardBlock>, all content must be placed inside a <div hviCardBlock> and not directly in the Card.
327
+ *
328
+ * @example
329
+ * ```html
330
+ * <hvi-card variant="tinted" color="brand1" maxWidth="400px">
331
+ * <div hviCardBlock>
332
+ * <h2>This is a card</h2>
333
+ * <p>The content of the card goes here.</p>
334
+ * </div>
335
+ * </hvi-card>
336
+ * ```
337
+ *
338
+ * Documentation: https://designsystemet.no/en/components/docs/card/code#with-sections
339
+ */
340
+ class HviCardBlock {
341
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviCardBlock, deps: [], target: i0.ɵɵFactoryTarget.Directive });
342
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviCardBlock, isStandalone: true, selector: "[hviCardBlock]", host: { classAttribute: "ds-card__block" }, ngImport: i0 });
343
+ }
344
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviCardBlock, decorators: [{
345
+ type: Directive,
346
+ args: [{
347
+ selector: '[hviCardBlock]',
348
+ standalone: true,
349
+ host: { class: 'ds-card__block' },
350
+ }]
351
+ }] });
352
+
353
+ /**
354
+ * Card highlight information or tasks that are related.
355
+ * The component comes in two variants and can contain text, images, text fields, buttons, and links.
356
+ *
357
+ * @example
358
+ * ```html
359
+ * <hvi-card variant="tinted" color="brand1" maxWidth="400px">
360
+ * <h2>This is a card</h2>
361
+ * <p>The content of the card goes here.</p>
362
+ * </hvi-card>
363
+ * ```
364
+ *
365
+ * Documentation: https://designsystemet.no/en/components/docs/card/overview
366
+ */
367
+ class HviCard {
368
+ /** Sets the background of the card */
369
+ variant;
370
+ /** The color theme of the card */
371
+ color;
372
+ /** Maximum width of the card, for example '320px' or '20rem' */
373
+ maxWidth;
374
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
375
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviCard, isStandalone: true, selector: "hvi-card", inputs: { variant: "variant", color: "color", maxWidth: "maxWidth" }, host: { properties: { "attr.data-variant": "variant", "attr.data-color": "color", "style.max-width": "maxWidth" }, classAttribute: "ds-card" }, ngImport: i0, template: '<ng-content />', isInline: true });
376
+ }
377
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviCard, decorators: [{
378
+ type: Component,
379
+ args: [{
380
+ selector: 'hvi-card',
381
+ standalone: true,
382
+ template: '<ng-content />',
383
+ host: {
384
+ class: 'ds-card',
385
+ '[attr.data-variant]': 'variant',
386
+ '[attr.data-color]': 'color',
387
+ '[style.max-width]': 'maxWidth',
388
+ },
389
+ }]
390
+ }], propDecorators: { variant: [{
391
+ type: Input
392
+ }], color: [{
393
+ type: Input
394
+ }], maxWidth: [{
395
+ type: Input
396
+ }] } });
397
+
398
+ class HviChipButton {
399
+ /** Whether the chip is removable*/
400
+ removable = false;
401
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviChipButton, deps: [], target: i0.ɵɵFactoryTarget.Directive });
402
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.1.2", type: HviChipButton, isStandalone: true, selector: "button[hviChip]", inputs: { removable: ["removable", "removable", booleanAttribute] }, host: { properties: { "attr.data-removable": "removable ? \"true\" : null" }, classAttribute: "ds-chip" }, ngImport: i0 });
403
+ }
404
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviChipButton, decorators: [{
405
+ type: Directive,
406
+ args: [{
407
+ selector: 'button[hviChip]',
408
+ standalone: true,
409
+ host: {
410
+ class: 'ds-chip',
411
+ '[attr.data-removable]': 'removable ? "true" : null',
412
+ },
413
+ }]
414
+ }], propDecorators: { removable: [{
415
+ type: Input,
416
+ args: [{ transform: booleanAttribute }]
417
+ }] } });
418
+
419
+ class HviChipLabel {
420
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviChipLabel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
421
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviChipLabel, isStandalone: true, selector: "label[hviChip]", host: { classAttribute: "ds-chip" }, ngImport: i0 });
422
+ }
423
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviChipLabel, decorators: [{
424
+ type: Directive,
425
+ args: [{
426
+ selector: 'label[hviChip]',
427
+ standalone: true,
428
+ host: {
429
+ class: 'ds-chip',
430
+ },
431
+ }]
432
+ }] });
433
+
434
+ class HviDetailsContent {
435
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDetailsContent, deps: [], target: i0.ɵɵFactoryTarget.Component });
436
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviDetailsContent, isStandalone: true, selector: "hvi-details-content", ngImport: i0, template: `<ng-content />`, isInline: true });
437
+ }
438
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDetailsContent, decorators: [{
439
+ type: Component,
440
+ args: [{
441
+ selector: 'hvi-details-content',
442
+ template: `<ng-content />`,
443
+ }]
444
+ }] });
445
+
446
+ class HviDetailsSummary {
447
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDetailsSummary, deps: [], target: i0.ɵɵFactoryTarget.Component });
448
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviDetailsSummary, isStandalone: true, selector: "hvi-details-summary", ngImport: i0, template: `<ng-content />`, isInline: true });
449
+ }
450
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDetailsSummary, decorators: [{
451
+ type: Component,
452
+ args: [{
453
+ selector: 'hvi-details-summary',
454
+ template: `<ng-content />`,
455
+ }]
456
+ }] });
457
+
458
+ /**
459
+ * Info
460
+ *
461
+ * Eksempel på bruk:
462
+ * ```html
463
+ * <hvi-details>
464
+ * <hvi-details-summary>
465
+ * <p size="md">Detaljer</p>
466
+ * </hvi-details-summary>
467
+ * <hvi-details-content>
468
+ * <p>Her er innholdet i detaljene.</p>
469
+ * </hvi-details-content>
470
+ * </hvi-details>
471
+ * ```
472
+ *
473
+ * Dokumentasjon: https://designsystemet.no/no/components/docs/details/overview
474
+ */
475
+ class HviDetails {
476
+ /** Variant of the details component */
477
+ variant = 'default';
478
+ /** Control open state of the details component */
479
+ open = false;
480
+ /** Set default open state of the details component */
481
+ defaultOpen = false;
482
+ /** Event handler for toggle event */
483
+ onToggle = () => { };
484
+ handleToggle(event) {
485
+ console.log('Toggled!', event);
486
+ }
487
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDetails, deps: [], target: i0.ɵɵFactoryTarget.Component });
488
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviDetails, isStandalone: true, selector: "hvi-details", inputs: { variant: "variant", open: "open", defaultOpen: "defaultOpen", onToggle: "onToggle" }, ngImport: i0, template: ` <u-details
489
+ #detailsRef
490
+ class="ds-details"
491
+ [attr.data-variant]="variant"
492
+ [attr.defaultOpen]="defaultOpen || undefined"
493
+ [attr.open]="open || undefined"
494
+ (toggle)="onToggle($event)"
495
+ >
496
+ <u-summary>
497
+ <ng-content select="hvi-details-summary" />
498
+ </u-summary>
499
+ <div>
500
+ <ng-content select="hvi-details-content" />
501
+ </div>
502
+ </u-details>`, isInline: true });
503
+ }
504
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDetails, decorators: [{
505
+ type: Component,
506
+ args: [{
507
+ selector: 'hvi-details',
508
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
509
+ standalone: true,
510
+ template: ` <u-details
511
+ #detailsRef
512
+ class="ds-details"
513
+ [attr.data-variant]="variant"
514
+ [attr.defaultOpen]="defaultOpen || undefined"
515
+ [attr.open]="open || undefined"
516
+ (toggle)="onToggle($event)"
517
+ >
518
+ <u-summary>
519
+ <ng-content select="hvi-details-summary" />
520
+ </u-summary>
521
+ <div>
522
+ <ng-content select="hvi-details-content" />
523
+ </div>
524
+ </u-details>`,
525
+ host: {},
526
+ }]
527
+ }], propDecorators: { variant: [{
528
+ type: Input
529
+ }], open: [{
530
+ type: Input
531
+ }], defaultOpen: [{
532
+ type: Input
533
+ }], onToggle: [{
534
+ type: Input
535
+ }] } });
536
+
537
+ class HviDialogBlock {
538
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDialogBlock, deps: [], target: i0.ɵɵFactoryTarget.Directive });
539
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviDialogBlock, isStandalone: true, selector: "[hviDialogBlock]", host: { classAttribute: "ds-dialog__block" }, ngImport: i0 });
540
+ }
541
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDialogBlock, decorators: [{
542
+ type: Directive,
543
+ args: [{
544
+ selector: '[hviDialogBlock]',
545
+ standalone: true,
546
+ host: {
547
+ class: 'ds-dialog__block',
548
+ },
549
+ }]
550
+ }] });
551
+
552
+ /**
553
+ * @summary
554
+ * Dialog allows you to create both modal and non-modal dialogs based on the HTML dialog element.
555
+ * You have to connect the <dialog> element to a trigger yourself, and handle opening and closing the dialog with JavaScript.
556
+ *
557
+ * @example
558
+ * HTML:
559
+ * ```html
560
+ * <dialog hviDialog [id]="exampleDialog" [open]="dialogOpen()" (openChange)="toggleDialog($event)">
561
+ * <h3 hviHeading size="md">Example dialog</h3>
562
+ * <p hviParagraph>This is an example of a dialog component.</p>
563
+ * <button hviButton variant="primary" (click)="closeDialog()">Close dialog</button>
564
+ * </dialog>
565
+ * ```
566
+ *
567
+ * TypeScript:
568
+ * ```ts
569
+ * export class DialogExampleComponent {
570
+ * readonly dialogOpen = signal(false);
571
+ * toggleDialog(nextState?: boolean): void {
572
+ * if (typeof nextState === 'boolean') {
573
+ * this.dialogOpen.set(nextState);
574
+ * return;
575
+ * }
576
+ * this.dialogOpen.update((current) => !current);
577
+ * }
578
+ * }
579
+ *
580
+ * Documentation: https://designsystemet.no/en/components/docs/dialog/code/
581
+ */
582
+ class HviDialog {
583
+ id;
584
+ set open(value) {
585
+ this.setOpen(Boolean(value));
586
+ }
587
+ get open() {
588
+ return this.element.open;
589
+ }
590
+ modal = true;
591
+ openChange = new EventEmitter();
592
+ element = inject((ElementRef)).nativeElement;
593
+ openModal() {
594
+ this.setOpen(true);
595
+ }
596
+ close() {
597
+ this.setOpen(false);
598
+ }
599
+ handleClose() {
600
+ this.openChange.emit(false);
601
+ }
602
+ handleCancel(event) {
603
+ event.preventDefault();
604
+ this.setOpen(false);
605
+ }
606
+ setOpen(shouldOpen) {
607
+ if (shouldOpen) {
608
+ if (this.element.open) {
609
+ return;
610
+ }
611
+ if (this.modal) {
612
+ this.element.showModal();
613
+ }
614
+ else {
615
+ this.element.show();
616
+ }
617
+ this.openChange.emit(true);
618
+ return;
619
+ }
620
+ if (!this.element.open) {
621
+ return;
622
+ }
623
+ this.element.close();
624
+ }
625
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDialog, deps: [], target: i0.ɵɵFactoryTarget.Directive });
626
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviDialog, isStandalone: true, selector: "dialog[hviDialog]", inputs: { id: "id", open: "open", modal: "modal" }, outputs: { openChange: "openChange" }, host: { attributes: { "id": "{{ id }}" }, listeners: { "close": "handleClose()", "cancel": "handleCancel($event)" }, classAttribute: "ds-dialog" }, ngImport: i0 });
627
+ }
628
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDialog, decorators: [{
629
+ type: Directive,
630
+ args: [{
631
+ selector: 'dialog[hviDialog]',
632
+ standalone: true,
633
+ host: {
634
+ class: 'ds-dialog',
635
+ id: '{{ id }}',
636
+ },
637
+ }]
638
+ }], propDecorators: { id: [{
639
+ type: Input
640
+ }], open: [{
641
+ type: Input
642
+ }], modal: [{
643
+ type: Input
644
+ }], openChange: [{
645
+ type: Output
646
+ }], handleClose: [{
647
+ type: HostListener,
648
+ args: ['close']
649
+ }], handleCancel: [{
650
+ type: HostListener,
651
+ args: ['cancel', ['$event']]
652
+ }] } });
653
+
654
+ /**
655
+ * Info
656
+ *
657
+ * Eksempel på bruk:
658
+ * ```html
659
+ * <hr hviDivider />
660
+ * ```
661
+ *
662
+ * Dokumentasjon: https://designsystemet.no/no/components/docs/divider/overview
663
+ */
664
+ class HviDivider {
665
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDivider, deps: [], target: i0.ɵɵFactoryTarget.Directive });
666
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviDivider, isStandalone: true, selector: "hr[hviDivider]", host: { attributes: { "aria-hidden": "true" }, classAttribute: "ds-divider" }, ngImport: i0 });
667
+ }
668
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviDivider, decorators: [{
669
+ type: Directive,
670
+ args: [{
671
+ selector: 'hr[hviDivider]',
672
+ standalone: true,
673
+ host: {
674
+ class: 'ds-divider',
675
+ 'aria-hidden': 'true',
676
+ },
677
+ }]
678
+ }] });
679
+
680
+ /**
681
+ * @summary
682
+ * Adds submit handling for Angular reactive forms:
683
+ * - Tracks submitted state
684
+ * - Marks all controls as touched on submit
685
+ * - Optionally focuses an ErrorSummary when invalid
686
+ *
687
+ * @example
688
+ * ```html
689
+ * <[hviForm]></[hviForm]>
690
+ * ```
691
+ *
692
+ * Documentation: https://designsystemet.no/en/components/docs/form/code
693
+ */
694
+ class HviForm {
695
+ /** Emits when the form has been submitted */
696
+ hviSubmitted = new EventEmitter();
697
+ /** True after first submit attempt */
698
+ submitted = false;
699
+ /** Optional focus target (e.g. HviErrorSummaryComponent) */
700
+ focusOnInvalid;
701
+ // Optional injection: present when the form uses [formGroup] and ReactiveFormsModule is in scope
702
+ formGroupDir = inject(FormGroupDirective, { optional: true });
703
+ onSubmit(event) {
704
+ this.submitted = true;
705
+ this.hviSubmitted.emit();
706
+ const form = this.formGroupDir?.form;
707
+ if (!form)
708
+ return;
709
+ form.markAllAsTouched();
710
+ if (form.invalid) {
711
+ event.preventDefault();
712
+ queueMicrotask(() => this.focusOnInvalid?.focus?.());
713
+ }
714
+ }
715
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviForm, deps: [], target: i0.ɵɵFactoryTarget.Directive });
716
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviForm, isStandalone: true, selector: "form[hviForm]", inputs: { focusOnInvalid: "focusOnInvalid" }, outputs: { hviSubmitted: "hviSubmitted" }, host: { listeners: { "submit": "onSubmit($event)" } }, ngImport: i0 });
717
+ }
718
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviForm, decorators: [{
719
+ type: Directive,
720
+ args: [{
721
+ selector: 'form[hviForm]',
722
+ standalone: true,
723
+ }]
724
+ }], propDecorators: { hviSubmitted: [{
725
+ type: Output
726
+ }], focusOnInvalid: [{
727
+ type: Input
728
+ }], onSubmit: [{
729
+ type: HostListener,
730
+ args: ['submit', ['$event']]
731
+ }] } });
732
+
733
+ const DEFAULT_ERROR_PRIORITY$1 = [
734
+ 'required',
735
+ 'minlength',
736
+ 'maxlength',
737
+ 'email',
738
+ 'pattern',
739
+ 'min',
740
+ 'max',
741
+ ];
742
+ let errorSummaryIdCounter = 0;
743
+ const nextErrorSummaryHeadingId = () => `hvi-error-summary-heading-${++errorSummaryIdCounter}`;
744
+ /**
745
+ * @summary
746
+ * ErrorSummary lists blocking validation errors so users can quickly find and fix them.
747
+ *
748
+ * @remarks
749
+ * Modes:
750
+ * - Manual: provide `[errors]` as `{ message, href }[]`.
751
+ * - Auto (recommended): provide `[form]` + `[messages]` (and optionally `[idMap]`) to derive errors from invalid
752
+ * controls in a reactive form.
753
+ *
754
+ * Auto mode should be rendered inside `<form hviForm ...>` so it can follow submit visibility (`showWhen`) and
755
+ * be focused automatically via `[focusOnInvalid]`.
756
+ *
757
+ * Each item link must point to a field id (e.g. `href="#firstName"`). Prefer `id === formControlName`.
758
+ *
759
+ * @example
760
+ * Manual mode:
761
+ * ```html
762
+ * <hvi-error-summary
763
+ * [errors]="[
764
+ * { message: 'Fornavn må være minst 2 tegn', href: '#firstName' },
765
+ * { message: 'Telefonnummer kan kun inneholde siffer', href: '#phone' }
766
+ * ]"
767
+ * />
768
+ * ```
769
+ *
770
+ * @example
771
+ * Auto mode (HTML + TS):
772
+ *
773
+ * ```html
774
+ * HTML:
775
+ * <form hviForm [formGroup]="form" [focusOnInvalid]="summary">
776
+ * <hvi-error-summary #summary [form]="form" [messages]="messages" showWhen="submitted" />
777
+ *
778
+ * <hvi-field>
779
+ * <label hviLabel for="firstName" weight="medium">Fornavn</label>
780
+ * <input hviInput id="firstName" formControlName="firstName" hviControlInvalid />
781
+ * <p hviFieldValidation hviValidationMessage="firstName" [messages]="messages.firstName"></p>
782
+ * </hvi-field>
783
+ *
784
+ * <hvi-field>
785
+ * <label hviLabel for="phone" weight="medium">Telefon</label>
786
+ * <input hviInput id="phone" type="tel" formControlName="phone" hviControlInvalid />
787
+ * <p hviFieldValidation hviValidationMessage="phone" [messages]="messages.phone"></p>
788
+ * </hvi-field>
789
+ *
790
+ * <button hviButton type="submit" variant="primary">Send inn</button>
791
+ * </form>
792
+ * ```
793
+ *
794
+ * ```ts
795
+ * TS:
796
+ * form = new FormGroup({
797
+ * firstName: new FormControl('', [Validators.required, Validators.minLength(2)]),
798
+ * phone: new FormControl('', [Validators.required, Validators.pattern(/^\d+$/)]),
799
+ * });
800
+ *
801
+ * messages = {
802
+ * firstName: { required: 'Fornavn er påkrevd', minlength: 'Fornavn må være minst 2 tegn' },
803
+ * phone: { required: 'Telefon er påkrevd', pattern: 'Telefonnummer kan kun inneholde siffer' },
804
+ * } as const;
805
+ * ```
806
+ *
807
+ * Documentation: https://designsystemet.no/en/components/docs/error-summary/code
808
+ */
809
+ class HviErrorSummary {
810
+ /** Heading text shown above the list */
811
+ heading = 'For å gå videre må du rette opp følgende feil:';
812
+ /** Heading level for the heading element (1-6). Defaults to 2 per DS */
813
+ headingLevel = 2;
814
+ /**
815
+ * Manual mode: items displayed in the summary.
816
+ * If non-empty, manual mode takes precedence over auto mode.
817
+ */
818
+ errors = [];
819
+ /** Auto mode: reactive form to derive errors from */
820
+ form;
821
+ /**
822
+ * Auto mode: messages per controlName.
823
+ * Example:
824
+ * {
825
+ * firstName: { required: 'Fornavn er påkrevd', minlength: 'Fornavn må være minst 2 tegn' },
826
+ * phone: { required: 'Telefon er påkrevd', pattern: 'Telefonnummer kan kun inneholde siffer' }
827
+ * }
828
+ */
829
+ messages;
830
+ /**
831
+ * Auto mode: map controlName -> element id.
832
+ * Default is `id === controlName`.
833
+ */
834
+ idMap;
835
+ /** Auto mode: error key priority (first match wins) */
836
+ errorPriority = DEFAULT_ERROR_PRIORITY$1;
837
+ /** Used for aria-labelledby on the container */
838
+ headingId = nextErrorSummaryHeadingId();
839
+ /** When to show errors from the form controls */
840
+ showWhen = 'submitted';
841
+ container;
842
+ focus() {
843
+ this.container?.nativeElement.focus();
844
+ }
845
+ get computedErrors() {
846
+ // 1) Manual mode wins
847
+ if (this.errors?.length)
848
+ return this.errors;
849
+ // 2) Auto mode
850
+ const form = this.form;
851
+ const messages = this.messages;
852
+ if (!form || !messages)
853
+ return [];
854
+ const items = [];
855
+ for (const controlName of Object.keys(form.controls)) {
856
+ const ctrl = form.controls[controlName];
857
+ if (!ctrl?.invalid)
858
+ continue;
859
+ const errs = ctrl.errors ?? {};
860
+ const msgMap = messages[controlName] ?? {};
861
+ const message = this.pickMessage(errs, msgMap);
862
+ if (!message)
863
+ continue;
864
+ const id = this.idMap?.[controlName] ?? controlName;
865
+ items.push({ message, href: `#${id}` });
866
+ }
867
+ return items;
868
+ }
869
+ pickMessage(errors, messages) {
870
+ for (const key of this.errorPriority) {
871
+ if (errors[key] && messages[key])
872
+ return messages[key];
873
+ }
874
+ for (const key of Object.keys(errors)) {
875
+ if (messages[key])
876
+ return messages[key];
877
+ }
878
+ return Object.keys(errors).length ? 'Ugyldig verdi' : '';
879
+ }
880
+ hviForm = inject(HviForm, { optional: true });
881
+ get shouldShow() {
882
+ if (this.computedErrors.length === 0)
883
+ return false;
884
+ switch (this.showWhen) {
885
+ case 'always':
886
+ return true;
887
+ case 'touched':
888
+ // show when any invalid control is touched OR the form has been submitted
889
+ return (this.hviForm?.submitted ?? false) || this.anyInvalidTouched();
890
+ case 'submitted':
891
+ default:
892
+ return this.hviForm?.submitted ?? false;
893
+ }
894
+ }
895
+ anyInvalidTouched() {
896
+ const form = this.form;
897
+ if (!form)
898
+ return false;
899
+ for (const name of Object.keys(form.controls)) {
900
+ const c = form.controls[name];
901
+ if (c?.invalid && c.touched)
902
+ return true;
903
+ }
904
+ return false;
905
+ }
906
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviErrorSummary, deps: [], target: i0.ɵɵFactoryTarget.Component });
907
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: HviErrorSummary, isStandalone: true, selector: "hvi-error-summary", inputs: { heading: "heading", headingLevel: "headingLevel", errors: "errors", form: "form", messages: "messages", idMap: "idMap", errorPriority: "errorPriority", headingId: "headingId", showWhen: "showWhen" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, static: true }], ngImport: i0, template: `
908
+ <div
909
+ #container
910
+ class="ds-error-summary"
911
+ tabindex="-1"
912
+ [attr.aria-labelledby]="headingId"
913
+ [hidden]="!shouldShow"
914
+ >
915
+ @switch (headingLevel) {
916
+ @case (1) {
917
+ <h1 class="ds-heading" [id]="headingId">{{ heading }}</h1>
918
+ }
919
+ @case (2) {
920
+ <h2 class="ds-heading" [id]="headingId">{{ heading }}</h2>
921
+ }
922
+ @case (3) {
923
+ <h3 class="ds-heading" [id]="headingId">{{ heading }}</h3>
924
+ }
925
+ @case (4) {
926
+ <h4 class="ds-heading" [id]="headingId">{{ heading }}</h4>
927
+ }
928
+ @case (5) {
929
+ <h5 class="ds-heading" [id]="headingId">{{ heading }}</h5>
930
+ }
931
+ @default {
932
+ <h6 class="ds-heading" [id]="headingId">{{ heading }}</h6>
933
+ }
934
+ }
935
+
936
+ <ul class="ds-list">
937
+ @for (err of computedErrors; track err.href) {
938
+ <li>
939
+ <a class="ds-link" data-color="neutral" [href]="err.href">{{ err.message }}</a>
940
+ </li>
941
+ }
942
+ </ul>
943
+ </div>
944
+ `, isInline: true });
945
+ }
946
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviErrorSummary, decorators: [{
947
+ type: Component,
948
+ args: [{
949
+ selector: 'hvi-error-summary',
950
+ standalone: true,
951
+ template: `
952
+ <div
953
+ #container
954
+ class="ds-error-summary"
955
+ tabindex="-1"
956
+ [attr.aria-labelledby]="headingId"
957
+ [hidden]="!shouldShow"
958
+ >
959
+ @switch (headingLevel) {
960
+ @case (1) {
961
+ <h1 class="ds-heading" [id]="headingId">{{ heading }}</h1>
962
+ }
963
+ @case (2) {
964
+ <h2 class="ds-heading" [id]="headingId">{{ heading }}</h2>
965
+ }
966
+ @case (3) {
967
+ <h3 class="ds-heading" [id]="headingId">{{ heading }}</h3>
968
+ }
969
+ @case (4) {
970
+ <h4 class="ds-heading" [id]="headingId">{{ heading }}</h4>
971
+ }
972
+ @case (5) {
973
+ <h5 class="ds-heading" [id]="headingId">{{ heading }}</h5>
974
+ }
975
+ @default {
976
+ <h6 class="ds-heading" [id]="headingId">{{ heading }}</h6>
977
+ }
978
+ }
979
+
980
+ <ul class="ds-list">
981
+ @for (err of computedErrors; track err.href) {
982
+ <li>
983
+ <a class="ds-link" data-color="neutral" [href]="err.href">{{ err.message }}</a>
984
+ </li>
985
+ }
986
+ </ul>
987
+ </div>
988
+ `,
989
+ }]
990
+ }], propDecorators: { heading: [{
991
+ type: Input
992
+ }], headingLevel: [{
993
+ type: Input
994
+ }], errors: [{
995
+ type: Input
996
+ }], form: [{
997
+ type: Input
998
+ }], messages: [{
999
+ type: Input
1000
+ }], idMap: [{
1001
+ type: Input
1002
+ }], errorPriority: [{
1003
+ type: Input
1004
+ }], headingId: [{
1005
+ type: Input
1006
+ }], showWhen: [{
1007
+ type: Input
1008
+ }], container: [{
1009
+ type: ViewChild,
1010
+ args: ['container', { static: true }]
1011
+ }] } });
1012
+
1013
+ /**
1014
+ * Decorative affix container displayed alongside a text input.
1015
+ *
1016
+ * @remarks
1017
+ * Used together with the `hvi-field-affixes` component to wrap leading and trailing adornments.
1018
+ *
1019
+ * @example
1020
+ * ```html
1021
+ * <hvi-field-affixes>
1022
+ * <hvi-field-affix>NOK</hvi-field-affix>
1023
+ * <input hviInput type="text" placeholder="Amount" />
1024
+ * <hvi-field-affix>per month</hvi-field-affix>
1025
+ * </hvi-field-affixes>
1026
+ * ```
1027
+ *
1028
+ * Documentation: https://designsystemet.no/en/components/docs/field/code#prefixsuffix
1029
+ */
1030
+ class HviFieldAffix {
1031
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldAffix, deps: [], target: i0.ɵɵFactoryTarget.Component });
1032
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviFieldAffix, isStandalone: true, selector: "hvi-field-affix", host: { properties: { "aria-hidden": "true" }, classAttribute: "ds-field-affix" }, ngImport: i0, template: `<ng-content />`, isInline: true });
1033
+ }
1034
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldAffix, decorators: [{
1035
+ type: Component,
1036
+ args: [{
1037
+ selector: 'hvi-field-affix',
1038
+ template: `<ng-content />`,
1039
+ host: {
1040
+ class: 'ds-field-affix',
1041
+ '[aria-hidden]': 'true',
1042
+ },
1043
+ }]
1044
+ }] });
1045
+
1046
+ /**
1047
+ * Container for decorative affixes displayed alongside a text input.
1048
+ *
1049
+ * @remarks
1050
+ * Wraps leading and trailing adornments provided by `hvi-field-affix` components.
1051
+ *
1052
+ * @example
1053
+ * ```html
1054
+ * <hvi-field-affixes>
1055
+ * <hvi-field-affix>NOK</hvi-field-affix>
1056
+ * <input hviInput type="text" placeholder="Amount" />
1057
+ * <hvi-field-affix>per month</hvi-field-affix>
1058
+ * </hvi-field-affixes>
1059
+ * ```
1060
+ *
1061
+ * Documentation: https://designsystemet.no/en/components/docs/field/code#prefixsuffix
1062
+ */
1063
+ class HviFieldAffixes {
1064
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldAffixes, deps: [], target: i0.ɵɵFactoryTarget.Component });
1065
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviFieldAffixes, isStandalone: true, selector: "hvi-field-affixes", host: { classAttribute: "ds-field-affixes" }, ngImport: i0, template: `<ng-content />`, isInline: true });
1066
+ }
1067
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldAffixes, decorators: [{
1068
+ type: Component,
1069
+ args: [{
1070
+ selector: 'hvi-field-affixes',
1071
+ template: `<ng-content />`,
1072
+ host: {
1073
+ class: 'ds-field-affixes',
1074
+ },
1075
+ }]
1076
+ }] });
1077
+
1078
+ class HviFieldDescription {
1079
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldDescription, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1080
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviFieldDescription, isStandalone: true, selector: "[hviFieldDescription]", host: { attributes: { "data-field": "description" } }, ngImport: i0 });
1081
+ }
1082
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldDescription, decorators: [{
1083
+ type: Directive,
1084
+ args: [{
1085
+ selector: '[hviFieldDescription]',
1086
+ standalone: true,
1087
+ host: {
1088
+ 'data-field': 'description',
1089
+ },
1090
+ }]
1091
+ }] });
1092
+
1093
+ class HviFieldOptional {
1094
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldOptional, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1095
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviFieldOptional, isStandalone: true, selector: "[hviFieldOptional]", host: { attributes: { "data-field": "optional" } }, ngImport: i0 });
1096
+ }
1097
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldOptional, decorators: [{
1098
+ type: Directive,
1099
+ args: [{
1100
+ selector: '[hviFieldOptional]',
1101
+ standalone: true,
1102
+ host: {
1103
+ 'data-field': 'optional',
1104
+ },
1105
+ }]
1106
+ }] });
1107
+
1108
+ class HviFieldValidation {
1109
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldValidation, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1110
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviFieldValidation, isStandalone: true, selector: "[hviFieldValidation]", host: { attributes: { "data-field": "validation" }, classAttribute: "ds-validation-message" }, ngImport: i0 });
1111
+ }
1112
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldValidation, decorators: [{
1113
+ type: Directive,
1114
+ args: [{
1115
+ selector: '[hviFieldValidation]',
1116
+ standalone: true,
1117
+ host: {
1118
+ class: 'ds-validation-message',
1119
+ 'data-field': 'validation',
1120
+ },
1121
+ }]
1122
+ }] });
1123
+
1124
+ // Copied from https://github.com/digdir/designsystemet/blob/main/packages/react/src/components/field/field-observer.ts
1125
+ function fieldObserver(fieldElement) {
1126
+ if (!fieldElement)
1127
+ return;
1128
+ const elements = new Map();
1129
+ const typeCounter = new Map(); // Track count for each data-field type
1130
+ const uuid = `:${Date.now().toString(36)}${Math.random().toString(36).slice(2, 5)}`;
1131
+ let input = null;
1132
+ let describedby = '';
1133
+ const process = (mutations) => {
1134
+ const changed = [];
1135
+ const removed = [];
1136
+ // Merge MutationRecords
1137
+ for (const mutation of mutations) {
1138
+ if (mutation.attributeName)
1139
+ changed.push(mutation.target ?? fieldElement);
1140
+ changed.push(...(mutation.addedNodes || []));
1141
+ removed.push(...(mutation.removedNodes || []));
1142
+ }
1143
+ // Register elements
1144
+ for (const el of changed) {
1145
+ if (!isElement(el))
1146
+ continue;
1147
+ if (isLabel(el))
1148
+ elements.set(el, el.htmlFor);
1149
+ else if (el.hasAttribute('data-field'))
1150
+ elements.set(el, el.id);
1151
+ else if (isInputLike(el) && !el.hidden) {
1152
+ input = el;
1153
+ describedby = el.getAttribute('aria-describedby') || '';
1154
+ }
1155
+ }
1156
+ // Reset removed elements
1157
+ for (const el of removed) {
1158
+ if (!isElement(el))
1159
+ continue;
1160
+ if (input === el)
1161
+ input = null;
1162
+ if (elements.has(el)) {
1163
+ setAttr(el, isLabel(el) ? 'for' : 'id', elements.get(el));
1164
+ elements.delete(el);
1165
+ }
1166
+ }
1167
+ // Connect elements
1168
+ const describedbyIds = describedby ? describedby.split(' ') : []; // Keep original aria-describedby
1169
+ const inputId = input?.id || uuid;
1170
+ // Reset type counters since we reprocess all elements
1171
+ typeCounter.clear();
1172
+ for (const [el, value] of elements) {
1173
+ const descriptionType = el.getAttribute('data-field');
1174
+ let id;
1175
+ if (descriptionType) {
1176
+ // Increment type counter for this type
1177
+ const count = (typeCounter.get(descriptionType) || 0) + 1;
1178
+ typeCounter.set(descriptionType, count);
1179
+ id = `${inputId}:${descriptionType}:${count}`;
1180
+ }
1181
+ else {
1182
+ id = inputId;
1183
+ }
1184
+ if (!value)
1185
+ setAttr(el, isLabel(el) ? 'for' : 'id', id); // Ensure we have a value
1186
+ if (!describedbyIds.includes(el.id)) {
1187
+ if (descriptionType === 'validation')
1188
+ describedbyIds.unshift(el.id); // Validations to the front
1189
+ else if (descriptionType)
1190
+ describedbyIds.push(el.id); // Other descriptions to the back
1191
+ }
1192
+ }
1193
+ // Prune aria-describedby so it does not reference removed elements
1194
+ const prunedDescribedbyIds = describedbyIds.filter((id) => {
1195
+ if (!id)
1196
+ return false;
1197
+ if (id === inputId)
1198
+ return true;
1199
+ // Keep if it still exists anywhere in the document.
1200
+ // This preserves "original aria-describedby" entries that live outside the field subtree.
1201
+ return !!fieldElement.ownerDocument?.getElementById(id);
1202
+ });
1203
+ setAttr(input, 'id', inputId);
1204
+ setAttr(input, 'aria-describedby', prunedDescribedbyIds.join(' ').trim());
1205
+ };
1206
+ const observer = createOptimizedMutationObserver(process);
1207
+ observer.observe(fieldElement, {
1208
+ attributeFilter: ['id', 'for', 'aria-describedby'],
1209
+ attributes: true,
1210
+ childList: true,
1211
+ subtree: true,
1212
+ });
1213
+ process([{ addedNodes: fieldElement.querySelectorAll('*') }]); // Initial setup
1214
+ observer.takeRecords(); // Clear initial setup queue
1215
+ return () => observer.disconnect();
1216
+ }
1217
+ // Utilities
1218
+ const isElement = (node) => node instanceof Element;
1219
+ const isLabel = (node) => node instanceof HTMLLabelElement;
1220
+ const isInputLike = (node) => node instanceof HTMLElement && 'validity' in node && !(node instanceof HTMLButtonElement); // Matches input, textarea, select and form accosiated custom elements
1221
+ const setAttr = (el, name, value) => value ? el?.setAttribute(name, value) : el?.removeAttribute(name);
1222
+ // Speed up MutationObserver by debouncing, clearing internal queue after changes and only running when page is visible
1223
+ function createOptimizedMutationObserver(callback) {
1224
+ const queue = [];
1225
+ const observer = new MutationObserver((mutations) => {
1226
+ if (!queue.length)
1227
+ requestAnimationFrame(process);
1228
+ queue.push(...mutations);
1229
+ });
1230
+ const process = () => {
1231
+ callback(queue, observer);
1232
+ queue.length = 0; // Reset queue
1233
+ observer.takeRecords(); // Clear queue due to DOM changes in callback
1234
+ };
1235
+ return observer;
1236
+ }
1237
+
1238
+ /**
1239
+ * Field is a helper component to automatically associate a field with hviLabel, hviFieldDescription and hviFieldValidation.
1240
+ *
1241
+ * @example
1242
+ * ```html
1243
+ * <hvi-field>
1244
+ * <label hviLabel>Name</label>
1245
+ * <span hviFieldDescription>Fill in your full name.</span>
1246
+ * <input type="text" />
1247
+ * <span hviFieldValidation>This field is required.</span>
1248
+ * </hvi-field>
1249
+ * ```
1250
+ *
1251
+ * Documentation: https://designsystemet.no/en/components/docs/field/overview
1252
+ */
1253
+ class HviField {
1254
+ /** Position of toggle inputs (radio, checkbox, switch) in field */
1255
+ position;
1256
+ el = inject((ElementRef));
1257
+ destroyRef = inject(DestroyRef);
1258
+ ngAfterViewInit() {
1259
+ const stop = fieldObserver(this.el.nativeElement);
1260
+ this.destroyRef.onDestroy(() => stop?.());
1261
+ }
1262
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviField, deps: [], target: i0.ɵɵFactoryTarget.Component });
1263
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviField, isStandalone: true, selector: "hvi-field", inputs: { position: "position" }, host: { properties: { "attr.data-position": "position ?? null" }, classAttribute: "ds-field" }, ngImport: i0, template: '<ng-content />', isInline: true });
1264
+ }
1265
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviField, decorators: [{
1266
+ type: Component,
1267
+ args: [{
1268
+ selector: 'hvi-field',
1269
+ standalone: true,
1270
+ template: '<ng-content />',
1271
+ host: {
1272
+ class: 'ds-field',
1273
+ '[attr.data-position]': 'position ?? null',
1274
+ },
1275
+ }]
1276
+ }], propDecorators: { position: [{
1277
+ type: Input
1278
+ }] } });
1279
+
1280
+ /**
1281
+ * Fieldset is used to group and label fields that naturally belong together, such as date fields or address fields.
1282
+ * The component helps organize information, make forms more manageable, and improve accessibility for screen readers.
1283
+ *
1284
+ * @example
1285
+ * ```html
1286
+ * <fieldset hviFieldset>
1287
+ * <legend hviLabel>Which framework do you like best?</legend>
1288
+ * <p hviParagraph>Your choice will help us improve the service.</p>
1289
+ * <hvi-field>
1290
+ * <input type="radio" id="angular" name="framework" value="angular" />
1291
+ * <label hviLabel for="angular">Angular</label>
1292
+ * </hvi-field>
1293
+ * <hvi-field>
1294
+ * <input type="radio" id="react" name="framework" value="react" />
1295
+ * <label hviLabel for="react">React</label>
1296
+ * </hvi-field>
1297
+ * <hvi-field>
1298
+ * <input type="radio" id="vue" name="framework" value="vue" />
1299
+ * <label hviLabel for="vue">Vue</label>
1300
+ * </hvi-field>
1301
+ * </fieldset>
1302
+ * ```
1303
+ *
1304
+ * Documentation: https://designsystemet.no/en/components/docs/fieldset/overview
1305
+ */
1306
+ class HviFieldset {
1307
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldset, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1308
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviFieldset, isStandalone: true, selector: "fieldset[hviFieldset]", host: { classAttribute: "ds-fieldset" }, ngImport: i0 });
1309
+ }
1310
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldset, decorators: [{
1311
+ type: Directive,
1312
+ args: [{
1313
+ selector: 'fieldset[hviFieldset]',
1314
+ standalone: true,
1315
+ host: {
1316
+ class: 'ds-fieldset',
1317
+ },
1318
+ }]
1319
+ }] });
1320
+
1321
+ class HviInput {
1322
+ type;
1323
+ size;
1324
+ /** Set role, e.g. `switch` when `checkbox` or `radio` */
1325
+ role;
1326
+ _disabled = false;
1327
+ _readOnly = false;
1328
+ set disabled(value) {
1329
+ this._disabled = value;
1330
+ }
1331
+ get disabled() {
1332
+ return this._disabled;
1333
+ }
1334
+ set readOnly(value) {
1335
+ this._readOnly = value;
1336
+ }
1337
+ get readOnly() {
1338
+ return this._readOnly;
1339
+ }
1340
+ set readonly(value) {
1341
+ this._readOnly = value;
1342
+ }
1343
+ get isToggle() {
1344
+ return this.type === 'checkbox' || this.type === 'radio';
1345
+ }
1346
+ onClick(event) {
1347
+ if (this._readOnly && this.isToggle) {
1348
+ event.preventDefault();
1349
+ event.stopImmediatePropagation();
1350
+ }
1351
+ }
1352
+ onChange(event) {
1353
+ if (this._readOnly && this.isToggle) {
1354
+ event.preventDefault();
1355
+ event.stopImmediatePropagation();
1356
+ }
1357
+ }
1358
+ onKeydown(event) {
1359
+ if (!this._readOnly || !this.isToggle)
1360
+ return;
1361
+ if (event.key === ' ' || event.key === 'Spacebar' || event.key === 'Enter') {
1362
+ event.preventDefault();
1363
+ event.stopImmediatePropagation();
1364
+ }
1365
+ }
1366
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviInput, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1367
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.1.2", type: HviInput, isStandalone: true, selector: "input[hviInput]", inputs: { type: "type", size: "size", role: "role", disabled: ["disabled", "disabled", booleanAttribute], readOnly: ["readOnly", "readOnly", booleanAttribute], readonly: ["readonly", "readonly", booleanAttribute] }, host: { listeners: { "click": "onClick($event)", "change": "onChange($event)", "keydown": "onKeydown($event)" }, properties: { "attr.type": "type ?? null", "attr.size": "size ?? null", "attr.disabled": "_disabled ? \"\" : null", "attr.readonly": "_readOnly ? \"\" : null", "attr.role": "role ?? null" }, classAttribute: "ds-input" }, ngImport: i0 });
1368
+ }
1369
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviInput, decorators: [{
1370
+ type: Directive,
1371
+ args: [{
1372
+ selector: 'input[hviInput]',
1373
+ standalone: true,
1374
+ host: {
1375
+ class: 'ds-input',
1376
+ '[attr.type]': 'type ?? null',
1377
+ '[attr.size]': 'size ?? null',
1378
+ '[attr.disabled]': '_disabled ? "" : null',
1379
+ '[attr.readonly]': '_readOnly ? "" : null',
1380
+ '[attr.role]': 'role ?? null',
1381
+ },
1382
+ }]
1383
+ }], propDecorators: { type: [{
1384
+ type: Input
1385
+ }], size: [{
1386
+ type: Input
1387
+ }], role: [{
1388
+ type: Input
1389
+ }], disabled: [{
1390
+ type: Input,
1391
+ args: [{ transform: booleanAttribute }]
1392
+ }], readOnly: [{
1393
+ type: Input,
1394
+ args: [{ transform: booleanAttribute }]
1395
+ }], readonly: [{
1396
+ type: Input,
1397
+ args: [{ transform: booleanAttribute }]
1398
+ }], onClick: [{
1399
+ type: HostListener,
1400
+ args: ['click', ['$event']]
1401
+ }], onChange: [{
1402
+ type: HostListener,
1403
+ args: ['change', ['$event']]
1404
+ }], onKeydown: [{
1405
+ type: HostListener,
1406
+ args: ['keydown', ['$event']]
1407
+ }] } });
1408
+
1409
+ /**
1410
+ * @summary
1411
+ * Directive to set `aria-invalid` on form controls based on their validation state.
1412
+ *
1413
+ * Usage:
1414
+ * ```html
1415
+ * <input hviControlInvalid formControlName="email" />
1416
+ * ```
1417
+ */
1418
+ class HviControlInvalid {
1419
+ ngControl = inject(NgControl, { self: true, optional: true });
1420
+ hviForm = inject(HviForm, { optional: true });
1421
+ get ariaInvalid() {
1422
+ const control = this.ngControl?.control;
1423
+ if (!control)
1424
+ return null;
1425
+ const submitted = this.hviForm?.submitted ?? false;
1426
+ const show = control.invalid && (control.touched || submitted);
1427
+ return show ? 'true' : null;
1428
+ }
1429
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviControlInvalid, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1430
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviControlInvalid, isStandalone: true, selector: "[hviControlInvalid]", host: { properties: { "attr.aria-invalid": "this.ariaInvalid" } }, ngImport: i0 });
1431
+ }
1432
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviControlInvalid, decorators: [{
1433
+ type: Directive,
1434
+ args: [{
1435
+ selector: '[hviControlInvalid]',
1436
+ standalone: true,
1437
+ }]
1438
+ }], propDecorators: { ariaInvalid: [{
1439
+ type: HostBinding,
1440
+ args: ['attr.aria-invalid']
1441
+ }] } });
1442
+
1443
+ const DEFAULT_ERROR_PRIORITY = [
1444
+ 'required',
1445
+ 'minlength',
1446
+ 'maxlength',
1447
+ 'email',
1448
+ 'pattern',
1449
+ 'min',
1450
+ 'max',
1451
+ ];
1452
+ class HviValidationMessage {
1453
+ /**
1454
+ * Control name in the nearest parent FormGroup (matches formControlName).
1455
+ * Example: hviValidationMessage="firstName"
1456
+ */
1457
+ controlName;
1458
+ /**
1459
+ * Map errorKey -> message, e.g. { required: 'Påkrevd', minlength: 'Minst 2 tegn' }
1460
+ */
1461
+ messages = {};
1462
+ /**
1463
+ * Optional error priority order. Defaults to a sensible order.
1464
+ */
1465
+ errorPriority = DEFAULT_ERROR_PRIORITY;
1466
+ container = inject(ControlContainer, { optional: true });
1467
+ hviForm = inject(HviForm, { optional: true });
1468
+ get control() {
1469
+ const group = this.container?.control;
1470
+ if (!group || !this.controlName)
1471
+ return null;
1472
+ return group.get(this.controlName);
1473
+ }
1474
+ get message() {
1475
+ const ctrl = this.control;
1476
+ if (!ctrl)
1477
+ return '';
1478
+ const submitted = this.hviForm?.submitted ?? false;
1479
+ const show = ctrl.invalid && (ctrl.touched || submitted);
1480
+ if (!show)
1481
+ return '';
1482
+ const errors = ctrl.errors ?? {};
1483
+ // 1) Prioritized keys first
1484
+ for (const key of this.errorPriority) {
1485
+ if (errors[key] && this.messages[key])
1486
+ return this.messages[key];
1487
+ }
1488
+ // 2) Any remaining mapped key
1489
+ for (const key of Object.keys(errors)) {
1490
+ if (this.messages[key])
1491
+ return this.messages[key];
1492
+ }
1493
+ return 'Ugyldig verdi';
1494
+ }
1495
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviValidationMessage, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1496
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviValidationMessage, isStandalone: true, selector: "[hviValidationMessage]", inputs: { controlName: ["hviValidationMessage", "controlName"], messages: "messages", errorPriority: "errorPriority" }, host: { properties: { "textContent": "message", "hidden": "!message" } }, ngImport: i0 });
1497
+ }
1498
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviValidationMessage, decorators: [{
1499
+ type: Directive,
1500
+ args: [{
1501
+ selector: '[hviValidationMessage]',
1502
+ standalone: true,
1503
+ host: {
1504
+ // Sett tekstinnhold direkte på elementet (typisk <p hviFieldValidation ...>)
1505
+ '[textContent]': 'message',
1506
+ // Skjul elementet når det ikke er noen feilmelding
1507
+ '[hidden]': '!message',
1508
+ },
1509
+ }]
1510
+ }], propDecorators: { controlName: [{
1511
+ type: Input,
1512
+ args: ['hviValidationMessage']
1513
+ }], messages: [{
1514
+ type: Input
1515
+ }], errorPriority: [{
1516
+ type: Input
1517
+ }] } });
1518
+
1519
+ // 1) Bare field-byggesteiner
1520
+ const HviFieldKit = [
1521
+ HviField,
1522
+ HviFieldValidation,
1523
+ HviFieldDescription,
1524
+ HviFieldOptional,
1525
+ HviFieldAffix,
1526
+ HviFieldAffixes,
1527
+ ];
1528
+ // 2) Reactive forms + invalid/validation glue + submit behavior
1529
+ const HviValidationKit = [
1530
+ ReactiveFormsModule,
1531
+ HviForm,
1532
+ HviControlInvalid,
1533
+ HviValidationMessage,
1534
+ ];
1535
+ // 3) “Alt du trenger for DS forms”
1536
+ const HviForms = [
1537
+ ...HviValidationKit,
1538
+ ...HviFieldKit,
1539
+ HviInput,
1540
+ HviFieldset,
1541
+ HviErrorSummary,
1542
+ ];
1543
+
1544
+ /**
1545
+ * Heading is used to structure content and create hierarchy on a page.
1546
+ *
1547
+ * @example
1548
+ * ```html
1549
+ * <h1 hviHeading size="xl">This is a heading</h1>
1550
+ * ```
1551
+ *
1552
+ * Documentation: https://designsystemet.no/en/components/docs/heading/overview
1553
+ */
1554
+ class HviHeading {
1555
+ /** The size of the heading */
1556
+ size;
1557
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviHeading, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1558
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviHeading, isStandalone: true, selector: "h1[hviHeading], h2[hviHeading], h3[hviHeading], h4[hviHeading], h5[hviHeading], h6[hviHeading]", inputs: { size: "size" }, host: { properties: { "attr.data-size": "size" }, classAttribute: "ds-heading" }, ngImport: i0 });
1559
+ }
1560
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviHeading, decorators: [{
1561
+ type: Directive,
1562
+ args: [{
1563
+ selector: 'h1[hviHeading], h2[hviHeading], h3[hviHeading], h4[hviHeading], h5[hviHeading], h6[hviHeading]',
1564
+ standalone: true,
1565
+ host: {
1566
+ class: 'ds-heading',
1567
+ '[attr.data-size]': 'size',
1568
+ },
1569
+ }]
1570
+ }], propDecorators: { size: [{
1571
+ type: Input
1572
+ }] } });
1573
+
1574
+ class HviIcon {
1575
+ http;
1576
+ elementRef;
1577
+ cdr;
1578
+ icon;
1579
+ color;
1580
+ size = 'md';
1581
+ ariaHidden = false;
1582
+ constructor(http, elementRef, cdr) {
1583
+ this.http = http;
1584
+ this.elementRef = elementRef;
1585
+ this.cdr = cdr;
1586
+ }
1587
+ ngOnChanges() {
1588
+ this.loadIcon();
1589
+ }
1590
+ loadIcon() {
1591
+ this.http
1592
+ .get(`/assets/icons/${this.icon}.svg`, {
1593
+ responseType: 'text',
1594
+ })
1595
+ .subscribe({
1596
+ next: (svg) => {
1597
+ this.elementRef.nativeElement.innerHTML = svg;
1598
+ this.cdr.markForCheck();
1599
+ },
1600
+ error: (err) => {
1601
+ console.error('Failed to load icon:', this.icon, err);
1602
+ },
1603
+ });
1604
+ }
1605
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviIcon, deps: [{ token: i1.HttpClient }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1606
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "21.1.2", type: HviIcon, isStandalone: true, selector: "hvi-icon", inputs: { icon: "icon", color: "color", size: "size", ariaHidden: ["ariaHidden", "ariaHidden", booleanAttribute] }, host: { properties: { "attr.data-size": "size", "attr.data-color": "color", "attr.aria-hidden": "ariaHidden" }, classAttribute: "hvi-icon" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, styles: ["hvi-icon{display:inline-block}svg{display:inline-block}hvi-icon[data-size=sm] svg{width:16px;height:16px}hvi-icon[data-size=md] svg{width:24px;height:24px}hvi-icon[data-size=lg] svg{width:32px;height:32px}hvi-icon[data-size=xl] svg{width:40px;height:40px}hvi-icon svg path{fill:currentColor}hvi-icon[data-color=danger] svg path{fill:var(--ds-color-danger-base-default)}\n"], encapsulation: i0.ViewEncapsulation.None });
1607
+ }
1608
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviIcon, decorators: [{
1609
+ type: Component,
1610
+ args: [{ selector: 'hvi-icon', standalone: true, template: '', encapsulation: ViewEncapsulation.None, host: {
1611
+ class: 'hvi-icon',
1612
+ '[attr.data-size]': 'size',
1613
+ '[attr.data-color]': 'color',
1614
+ '[attr.aria-hidden]': 'ariaHidden',
1615
+ }, styles: ["hvi-icon{display:inline-block}svg{display:inline-block}hvi-icon[data-size=sm] svg{width:16px;height:16px}hvi-icon[data-size=md] svg{width:24px;height:24px}hvi-icon[data-size=lg] svg{width:32px;height:32px}hvi-icon[data-size=xl] svg{width:40px;height:40px}hvi-icon svg path{fill:currentColor}hvi-icon[data-color=danger] svg path{fill:var(--ds-color-danger-base-default)}\n"] }]
1616
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { icon: [{
1617
+ type: Input,
1618
+ args: [{ required: true }]
1619
+ }], color: [{
1620
+ type: Input
1621
+ }], size: [{
1622
+ type: Input
1623
+ }], ariaHidden: [{
1624
+ type: Input,
1625
+ args: [{ transform: booleanAttribute }]
1626
+ }] } });
1627
+
1628
+ /**
1629
+ * Label functions as a clear and accessible text label that tells the user what an associated form element is about.
1630
+ *
1631
+ * @example
1632
+ * ```html
1633
+ * <label hviLabel weight="semibold">Name</label>
1634
+ * ```
1635
+ *
1636
+ * Documentation: https://designsystemet.no/en/components/docs/label/overview
1637
+ */
1638
+ class HviLabel {
1639
+ /** The font weight of the label */
1640
+ weight;
1641
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviLabel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1642
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviLabel, isStandalone: true, selector: "label[hviLabel], legend[hviLabel]", inputs: { weight: "weight" }, host: { properties: { "attr.data-weight": "weight ?? null" }, classAttribute: "ds-label" }, ngImport: i0 });
1643
+ }
1644
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviLabel, decorators: [{
1645
+ type: Directive,
1646
+ args: [{
1647
+ selector: 'label[hviLabel], legend[hviLabel]',
1648
+ standalone: true,
1649
+ host: {
1650
+ class: 'ds-label',
1651
+ '[attr.data-weight]': 'weight ?? null',
1652
+ },
1653
+ }]
1654
+ }], propDecorators: { weight: [{
1655
+ type: Input
1656
+ }] } });
1657
+
1658
+ /**
1659
+ * Info
1660
+ *
1661
+ * Eksempel på bruk:
1662
+ * ```html
1663
+ * <a hviLink />
1664
+ * ```
1665
+ *
1666
+ * Dokumentasjon: https://designsystemet.no/no/components/docs/input/overview
1667
+ */
1668
+ class HviLink {
1669
+ /** Used to change the appearance of the link. */
1670
+ color = 'default';
1671
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviLink, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1672
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviLink, isStandalone: true, selector: "a[hviLink]", inputs: { color: "color" }, host: { properties: { "attr.data-color": "color" }, classAttribute: "ds-link" }, ngImport: i0 });
1673
+ }
1674
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviLink, decorators: [{
1675
+ type: Directive,
1676
+ args: [{
1677
+ selector: 'a[hviLink]',
1678
+ standalone: true,
1679
+ host: {
1680
+ class: 'ds-link',
1681
+ '[attr.data-color]': 'color',
1682
+ },
1683
+ }]
1684
+ }], propDecorators: { color: [{
1685
+ type: Input
1686
+ }] } });
1687
+
1688
+ /**
1689
+ * Paragraph is used for continuous text and is typically applied in articles, components, help text, and similar content.
1690
+ *
1691
+ * @example
1692
+ * ```html
1693
+ * <p hviParagraph variant="long" size="md">
1694
+ * This is a paragraph with body text that can be adjusted in size and variant.
1695
+ * </p>
1696
+ * ```
1697
+ *
1698
+ * Documentation: https://designsystemet.no/en/components/docs/paragraph/overview
1699
+ */
1700
+ class HviParagraph {
1701
+ /** Adjusts the style for the length of the paragraph */
1702
+ variant;
1703
+ /** Paragraph is available in several text sizes to suit different needs */
1704
+ size;
1705
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviParagraph, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1706
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.2", type: HviParagraph, isStandalone: true, selector: "p[hviParagraph]", inputs: { variant: "variant", size: "size" }, host: { properties: { "attr.data-variant": "variant ?? null", "attr.data-size": "size ?? null" }, classAttribute: "ds-paragraph" }, ngImport: i0 });
1707
+ }
1708
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviParagraph, decorators: [{
1709
+ type: Directive,
1710
+ args: [{
1711
+ selector: 'p[hviParagraph]',
1712
+ standalone: true,
1713
+ host: {
1714
+ class: 'ds-paragraph',
1715
+ '[attr.data-variant]': 'variant ?? null',
1716
+ '[attr.data-size]': 'size ?? null',
1717
+ },
1718
+ }]
1719
+ }], propDecorators: { variant: [{
1720
+ type: Input
1721
+ }], size: [{
1722
+ type: Input
1723
+ }] } });
1724
+
1725
+ /**
1726
+ * @summary
1727
+ * Tag is a label that can be used to categorize items or communicate progress, status, or process. Tags can provide users with a quicker overview of content.
1728
+ *
1729
+ * @example
1730
+ * ```html
1731
+ * <hvi-tag variant="outline" size="sm" color="info">Small info tag</hvi-tag>
1732
+ * ```
1733
+ *
1734
+ * Documentation: https://designsystemet.no/en/components/docs/tag/code
1735
+ */
1736
+ class HviTag {
1737
+ /** The variants of the tag */
1738
+ variant;
1739
+ /** The sizes of the tag */
1740
+ size;
1741
+ /** The color theme of the tag */
1742
+ color;
1743
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviTag, deps: [], target: i0.ɵɵFactoryTarget.Component });
1744
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviTag, isStandalone: true, selector: "hvi-tag", inputs: { variant: "variant", size: "size", color: "color" }, host: { properties: { "attr.data-variant": "variant ?? null", "attr.data-size": "size ?? null", "attr.data-color": "color ?? null" }, classAttribute: "ds-tag" }, ngImport: i0, template: '<ng-content />', isInline: true });
1745
+ }
1746
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviTag, decorators: [{
1747
+ type: Component,
1748
+ args: [{
1749
+ selector: 'hvi-tag',
1750
+ standalone: true,
1751
+ template: '<ng-content />',
1752
+ host: {
1753
+ class: 'ds-tag',
1754
+ '[attr.data-variant]': 'variant ?? null',
1755
+ '[attr.data-size]': 'size ?? null',
1756
+ '[attr.data-color]': 'color ?? null',
1757
+ },
1758
+ }]
1759
+ }], propDecorators: { variant: [{
1760
+ type: Input
1761
+ }], size: [{
1762
+ type: Input
1763
+ }], color: [{
1764
+ type: Input
1765
+ }] } });
1766
+
1767
+ /*
1768
+ * Public API Surface of hviktor
1769
+ */
1770
+
1771
+ /**
1772
+ * Generated bundle index. Do not edit.
1773
+ */
1774
+
1775
+ export { HviAlert, HviAvatar, HviBadge, HviBadgePosition, HviBreadcrumbs, HviButton, HviCard, HviCardBlock, HviChipButton, HviChipLabel, HviControlInvalid, HviDetails, HviDetailsContent, HviDetailsSummary, HviDialog, HviDialogBlock, HviDivider, HviErrorSummary, HviField, HviFieldAffix, HviFieldAffixes, HviFieldDescription, HviFieldKit, HviFieldOptional, HviFieldValidation, HviFieldset, HviForm, HviForms, HviHeading, HviIcon, HviInput, HviLabel, HviLink, HviParagraph, HviTag, HviValidationKit, HviValidationMessage, fieldObserver, isElement, isInputLike, isLabel };
1776
+ //# sourceMappingURL=helsevestikt-hviktor-angular.mjs.map