@helsevestikt/hviktor-angular 0.0.11 → 0.0.13

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.
@@ -1,8 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Input, Component, booleanAttribute, Directive, CUSTOM_ELEMENTS_SCHEMA, EventEmitter, inject, ElementRef, HostListener, Output, ViewChild, DestroyRef, HostBinding, ChangeDetectorRef, ViewEncapsulation } from '@angular/core';
3
3
  import '@u-elements/u-details';
4
- import { FormGroupDirective, NgControl, ControlContainer, ReactiveFormsModule } from '@angular/forms';
4
+ import { FormGroupDirective, NgControl, ControlContainer, Validators, ReactiveFormsModule } from '@angular/forms';
5
5
  import { HttpClient } from '@angular/common/http';
6
+ import { computePosition, offset, flip, shift, autoUpdate } from '@floating-ui/dom';
6
7
 
7
8
  /**
8
9
  * Alert provides users with information that is especially important for them to see and understand.
@@ -1010,117 +1011,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
1010
1011
  args: ['container', { static: true }]
1011
1012
  }] } });
1012
1013
 
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
1014
  // Copied from https://github.com/digdir/designsystemet/blob/main/packages/react/src/components/field/field-observer.ts
1125
1015
  function fieldObserver(fieldElement) {
1126
1016
  if (!fieldElement)
@@ -1235,6 +1125,117 @@ function createOptimizedMutationObserver(callback) {
1235
1125
  return observer;
1236
1126
  }
1237
1127
 
1128
+ /**
1129
+ * Decorative affix container displayed alongside a text input.
1130
+ *
1131
+ * @remarks
1132
+ * Used together with the `hvi-field-affixes` component to wrap leading and trailing adornments.
1133
+ *
1134
+ * @example
1135
+ * ```html
1136
+ * <hvi-field-affixes>
1137
+ * <hvi-field-affix>NOK</hvi-field-affix>
1138
+ * <input hviInput type="text" placeholder="Amount" />
1139
+ * <hvi-field-affix>per month</hvi-field-affix>
1140
+ * </hvi-field-affixes>
1141
+ * ```
1142
+ *
1143
+ * Documentation: https://designsystemet.no/en/components/docs/field/code#prefixsuffix
1144
+ */
1145
+ class HviFieldAffix {
1146
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldAffix, deps: [], target: i0.ɵɵFactoryTarget.Component });
1147
+ 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 });
1148
+ }
1149
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldAffix, decorators: [{
1150
+ type: Component,
1151
+ args: [{
1152
+ selector: 'hvi-field-affix',
1153
+ template: `<ng-content />`,
1154
+ host: {
1155
+ class: 'ds-field-affix',
1156
+ '[aria-hidden]': 'true',
1157
+ },
1158
+ }]
1159
+ }] });
1160
+
1161
+ /**
1162
+ * Container for decorative affixes displayed alongside a text input.
1163
+ *
1164
+ * @remarks
1165
+ * Wraps leading and trailing adornments provided by `hvi-field-affix` components.
1166
+ *
1167
+ * @example
1168
+ * ```html
1169
+ * <hvi-field-affixes>
1170
+ * <hvi-field-affix>NOK</hvi-field-affix>
1171
+ * <input hviInput type="text" placeholder="Amount" />
1172
+ * <hvi-field-affix>per month</hvi-field-affix>
1173
+ * </hvi-field-affixes>
1174
+ * ```
1175
+ *
1176
+ * Documentation: https://designsystemet.no/en/components/docs/field/code#prefixsuffix
1177
+ */
1178
+ class HviFieldAffixes {
1179
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldAffixes, deps: [], target: i0.ɵɵFactoryTarget.Component });
1180
+ 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 });
1181
+ }
1182
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldAffixes, decorators: [{
1183
+ type: Component,
1184
+ args: [{
1185
+ selector: 'hvi-field-affixes',
1186
+ template: `<ng-content />`,
1187
+ host: {
1188
+ class: 'ds-field-affixes',
1189
+ },
1190
+ }]
1191
+ }] });
1192
+
1193
+ class HviFieldDescription {
1194
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldDescription, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1195
+ 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 });
1196
+ }
1197
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldDescription, decorators: [{
1198
+ type: Directive,
1199
+ args: [{
1200
+ selector: '[hviFieldDescription]',
1201
+ standalone: true,
1202
+ host: {
1203
+ 'data-field': 'description',
1204
+ },
1205
+ }]
1206
+ }] });
1207
+
1208
+ class HviFieldOptional {
1209
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldOptional, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1210
+ 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 });
1211
+ }
1212
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldOptional, decorators: [{
1213
+ type: Directive,
1214
+ args: [{
1215
+ selector: '[hviFieldOptional]',
1216
+ standalone: true,
1217
+ host: {
1218
+ 'data-field': 'optional',
1219
+ },
1220
+ }]
1221
+ }] });
1222
+
1223
+ class HviFieldValidation {
1224
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldValidation, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1225
+ 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 });
1226
+ }
1227
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviFieldValidation, decorators: [{
1228
+ type: Directive,
1229
+ args: [{
1230
+ selector: '[hviFieldValidation]',
1231
+ standalone: true,
1232
+ host: {
1233
+ class: 'ds-validation-message',
1234
+ 'data-field': 'validation',
1235
+ },
1236
+ }]
1237
+ }] });
1238
+
1238
1239
  /**
1239
1240
  * Field is a helper component to automatically associate a field with hviLabel, hviFieldDescription and hviFieldValidation.
1240
1241
  *
@@ -1319,7 +1320,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
1319
1320
  }] });
1320
1321
 
1321
1322
  class HviInput {
1323
+ /** Supported input types */
1322
1324
  type;
1325
+ /** Set size attribute on input element */
1323
1326
  size;
1324
1327
  /** Set role, e.g. `switch` when `checkbox` or `radio` */
1325
1328
  role;
@@ -1516,6 +1519,158 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
1516
1519
  type: Input
1517
1520
  }] } });
1518
1521
 
1522
+ /**
1523
+ * Extracts validators and messages from an array of validator bundles.
1524
+ *
1525
+ * @example
1526
+ * ```ts
1527
+ * const config = hviValidators([
1528
+ * hviRequired('Fornavn er påkrevd'),
1529
+ * hviMinLength(2, 'Fornavn må være minst 2 tegn'),
1530
+ * ]);
1531
+ *
1532
+ * form = new FormGroup({
1533
+ * firstName: new FormControl('', config.validators),
1534
+ * });
1535
+ *
1536
+ * // In template: [messages]="config.messages"
1537
+ * ```
1538
+ */
1539
+ function hviValidators(bundles) {
1540
+ return {
1541
+ validators: bundles.map((b) => b.validator),
1542
+ messages: bundles.reduce((acc, b) => ({ ...acc, [b.key]: b.message }), {}),
1543
+ };
1544
+ }
1545
+ /**
1546
+ * Extracts only the validator functions from bundles.
1547
+ * Useful when you need just the validators for a FormControl.
1548
+ */
1549
+ function hviExtractValidators(bundles) {
1550
+ return bundles.map((b) => b.validator);
1551
+ }
1552
+ /**
1553
+ * Extracts only the messages from bundles.
1554
+ * Useful when you need just the messages object.
1555
+ */
1556
+ function hviExtractMessages(bundles) {
1557
+ return bundles.reduce((acc, b) => ({ ...acc, [b.key]: b.message }), {});
1558
+ }
1559
+
1560
+ /**
1561
+ * Creates a required validator bundle.
1562
+ *
1563
+ * @example
1564
+ * ```ts
1565
+ * hviRequired('Dette feltet er påkrevd')
1566
+ * ```
1567
+ */
1568
+ function hviRequired(message) {
1569
+ return { validator: Validators.required, key: 'required', message };
1570
+ }
1571
+ /**
1572
+ * Creates a requiredTrue validator bundle (for checkboxes that must be checked).
1573
+ *
1574
+ * @example
1575
+ * ```ts
1576
+ * hviRequiredTrue('Du må godta vilkårene')
1577
+ * ```
1578
+ */
1579
+ function hviRequiredTrue(message) {
1580
+ return { validator: Validators.requiredTrue, key: 'required', message };
1581
+ }
1582
+ /**
1583
+ * Creates a minLength validator bundle.
1584
+ *
1585
+ * @example
1586
+ * ```ts
1587
+ * hviMinLength(2, 'Må være minst 2 tegn')
1588
+ * ```
1589
+ */
1590
+ function hviMinLength(length, message) {
1591
+ return { validator: Validators.minLength(length), key: 'minlength', message };
1592
+ }
1593
+ /**
1594
+ * Creates a maxLength validator bundle.
1595
+ *
1596
+ * @example
1597
+ * ```ts
1598
+ * hviMaxLength(100, 'Kan ikke være mer enn 100 tegn')
1599
+ * ```
1600
+ */
1601
+ function hviMaxLength(length, message) {
1602
+ return { validator: Validators.maxLength(length), key: 'maxlength', message };
1603
+ }
1604
+ /**
1605
+ * Creates an email validator bundle.
1606
+ *
1607
+ * @example
1608
+ * ```ts
1609
+ * hviEmail('Ugyldig e-postadresse')
1610
+ * ```
1611
+ */
1612
+ function hviEmail(message) {
1613
+ return { validator: Validators.email, key: 'email', message };
1614
+ }
1615
+ /**
1616
+ * Creates a pattern validator bundle.
1617
+ *
1618
+ * @example
1619
+ * ```ts
1620
+ * hviPattern(/^\d+$/, 'Kan kun inneholde tall')
1621
+ * ```
1622
+ */
1623
+ function hviPattern(pattern, message) {
1624
+ return { validator: Validators.pattern(pattern), key: 'pattern', message };
1625
+ }
1626
+ /**
1627
+ * Creates a min value validator bundle.
1628
+ *
1629
+ * @example
1630
+ * ```ts
1631
+ * hviMin(0, 'Må være minst 0')
1632
+ * ```
1633
+ */
1634
+ function hviMin(min, message) {
1635
+ return { validator: Validators.min(min), key: 'min', message };
1636
+ }
1637
+ /**
1638
+ * Creates a max value validator bundle.
1639
+ *
1640
+ * @example
1641
+ * ```ts
1642
+ * hviMax(100, 'Kan ikke være mer enn 100')
1643
+ * ```
1644
+ */
1645
+ function hviMax(max, message) {
1646
+ return { validator: Validators.max(max), key: 'max', message };
1647
+ }
1648
+ /**
1649
+ * Creates a custom validator bundle with a specified error key.
1650
+ * Use this for custom validators or validators not covered by the built-in functions.
1651
+ *
1652
+ * @example
1653
+ * ```ts
1654
+ * // Custom validator that checks if value matches a specific format
1655
+ * const norwegianPhoneValidator: ValidatorFn = (control) => {
1656
+ * const valid = /^(\+47)?\d{8}$/.test(control.value);
1657
+ * return valid ? null : { norwegianPhone: true };
1658
+ * };
1659
+ *
1660
+ * hviCustom('norwegianPhone', norwegianPhoneValidator, 'Ugyldig norsk telefonnummer')
1661
+ * ```
1662
+ */
1663
+ function hviCustom(key, validator, message) {
1664
+ return { validator, key, message };
1665
+ }
1666
+ /**
1667
+ * Creates a nullValidator bundle (always valid, useful for conditional validation).
1668
+ * Note: This validator always passes, so the message will never be shown.
1669
+ */
1670
+ function hviNullValidator() {
1671
+ return { validator: Validators.nullValidator, key: 'null', message: '' };
1672
+ }
1673
+
1519
1674
  // 1) Bare field-byggesteiner
1520
1675
  const HviFieldKit = [
1521
1676
  HviField,
@@ -1753,6 +1908,205 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
1753
1908
  type: Input
1754
1909
  }] } });
1755
1910
 
1911
+ const arrowPseudoElement = {
1912
+ name: 'ArrowPseudoElement',
1913
+ fn(data) {
1914
+ const { elements, rects, placement } = data;
1915
+ let arrowX = `${Math.round(rects.reference.width / 2 + rects.reference.x - data.x)}px`;
1916
+ let arrowY = `${Math.round(rects.reference.height / 2 + rects.reference.y - data.y)}px`;
1917
+ if (rects.reference.width > rects.floating.width) {
1918
+ arrowX = `${Math.round(rects.floating.width / 2)}px`;
1919
+ }
1920
+ if (rects.reference.height > rects.floating.height) {
1921
+ arrowY = `${Math.round(rects.floating.height / 2)}px`;
1922
+ }
1923
+ switch (placement.split('-')[0]) {
1924
+ case 'top':
1925
+ arrowY = '100%';
1926
+ break;
1927
+ case 'right':
1928
+ arrowX = '0';
1929
+ break;
1930
+ case 'bottom':
1931
+ arrowY = '0';
1932
+ break;
1933
+ case 'left':
1934
+ arrowX = '100%';
1935
+ break;
1936
+ }
1937
+ elements.floating.setAttribute('data-placement', placement.split('-')[0]);
1938
+ elements.floating.style.setProperty('--ds-popover-arrow-x', arrowX);
1939
+ elements.floating.style.setProperty('--ds-popover-arrow-y', arrowY);
1940
+ return data;
1941
+ },
1942
+ };
1943
+ /**
1944
+ * @summary
1945
+ * Popover vises over andre elementer i grensesnittet og er koblet til et spesifikt element.
1946
+ * Den brukes til å vise tilleggsinformasjon, interaktive elementer eller korte forklaringer uten å navigere bort fra siden.
1947
+ *
1948
+ * @example
1949
+ * ```html
1950
+ * <button hviButton popovertarget="popover1">Open popover</button>
1951
+ * <hvi-popover id="popover1"> Popover content </hvi-popover>
1952
+ * ```
1953
+ *
1954
+ * @see {@link https://designsystemet.no/en/components/docs/popover/code}
1955
+ */
1956
+ class HviPopover {
1957
+ el = inject((ElementRef));
1958
+ cleanupAutoUpdate;
1959
+ boundHandleClick;
1960
+ boundHandleKeydown;
1961
+ /** Popover type - 'manual' krever manuell lukking, 'auto' lukkes ved klikk utenfor */
1962
+ type = 'manual';
1963
+ /** Visuell variant */
1964
+ variant = 'default';
1965
+ /** Farge-tema */
1966
+ color = 'neutral';
1967
+ /** Plassering av popover relativt til trigger */
1968
+ placement = 'top';
1969
+ /** Aktiver automatisk repositjonering hvis det ikke er plass */
1970
+ autoPlacement = true;
1971
+ /** Event når popover åpnes */
1972
+ opened = new EventEmitter();
1973
+ /** Event når popover lukkes */
1974
+ closed = new EventEmitter();
1975
+ get popoverElement() {
1976
+ return this.el.nativeElement;
1977
+ }
1978
+ get triggerElement() {
1979
+ const id = this.popoverElement.id;
1980
+ return id ? document.querySelector(`[popovertarget="${id}"]`) : null;
1981
+ }
1982
+ ngOnInit() {
1983
+ this.setupEventListeners();
1984
+ }
1985
+ ngOnDestroy() {
1986
+ this.stopAutoUpdate();
1987
+ this.removeEventListeners();
1988
+ }
1989
+ setupEventListeners() {
1990
+ const popover = this.popoverElement;
1991
+ // Click utenfor lukker popover
1992
+ this.boundHandleClick = (event) => {
1993
+ const el = event.target;
1994
+ const isTrigger = el?.closest?.(`[popovertarget="${popover.id}"]`);
1995
+ const isOutside = !isTrigger && !popover.contains(el);
1996
+ if (isTrigger) {
1997
+ event.preventDefault();
1998
+ popover.togglePopover?.();
1999
+ }
2000
+ if (isOutside && popover.matches(':popover-open')) {
2001
+ popover.togglePopover?.();
2002
+ }
2003
+ };
2004
+ // Escape lukker popover
2005
+ this.boundHandleKeydown = (event) => {
2006
+ if (event.key !== 'Escape' || !popover.matches(':popover-open'))
2007
+ return;
2008
+ event.preventDefault();
2009
+ popover.togglePopover?.();
2010
+ };
2011
+ addEventListener('click', this.boundHandleClick);
2012
+ addEventListener('keydown', this.boundHandleKeydown);
2013
+ // Toggle events
2014
+ popover.addEventListener('beforetoggle', this.handleBeforeToggle);
2015
+ popover.addEventListener('toggle', this.handleToggle);
2016
+ }
2017
+ removeEventListeners() {
2018
+ if (this.boundHandleClick) {
2019
+ removeEventListener('click', this.boundHandleClick);
2020
+ }
2021
+ if (this.boundHandleKeydown) {
2022
+ removeEventListener('keydown', this.boundHandleKeydown);
2023
+ }
2024
+ this.popoverElement.removeEventListener('beforetoggle', this.handleBeforeToggle);
2025
+ this.popoverElement.removeEventListener('toggle', this.handleToggle);
2026
+ }
2027
+ handleBeforeToggle = (event) => {
2028
+ const toggleEvent = event;
2029
+ if (toggleEvent.newState === 'open') {
2030
+ this.updatePosition();
2031
+ }
2032
+ };
2033
+ handleToggle = (event) => {
2034
+ const toggleEvent = event;
2035
+ if (toggleEvent.newState === 'open') {
2036
+ this.startAutoUpdate();
2037
+ this.opened.emit();
2038
+ }
2039
+ else {
2040
+ this.stopAutoUpdate();
2041
+ this.closed.emit();
2042
+ }
2043
+ };
2044
+ updatePosition() {
2045
+ const trigger = this.triggerElement;
2046
+ const popover = this.popoverElement;
2047
+ if (!trigger || !popover)
2048
+ return;
2049
+ computePosition(trigger, popover, {
2050
+ placement: this.placement,
2051
+ strategy: 'fixed',
2052
+ middleware: [
2053
+ offset((data) => {
2054
+ const styles = getComputedStyle(data.elements.floating, '::before');
2055
+ return parseFloat(styles.height) || 12;
2056
+ }),
2057
+ ...(this.autoPlacement ? [flip({ fallbackAxisSideDirection: 'start' }), shift()] : []),
2058
+ arrowPseudoElement,
2059
+ ],
2060
+ }).then(({ x, y }) => {
2061
+ popover.style.translate = `${x}px ${y}px`;
2062
+ });
2063
+ }
2064
+ startAutoUpdate() {
2065
+ this.stopAutoUpdate();
2066
+ const trigger = this.triggerElement;
2067
+ const popover = this.popoverElement;
2068
+ if (!trigger || !popover)
2069
+ return;
2070
+ this.cleanupAutoUpdate = autoUpdate(trigger, popover, () => this.updatePosition());
2071
+ }
2072
+ stopAutoUpdate() {
2073
+ if (this.cleanupAutoUpdate) {
2074
+ this.cleanupAutoUpdate();
2075
+ this.cleanupAutoUpdate = undefined;
2076
+ }
2077
+ }
2078
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviPopover, deps: [], target: i0.ɵɵFactoryTarget.Component });
2079
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: HviPopover, isStandalone: true, selector: "hvi-popover", inputs: { type: "type", variant: "variant", color: "color", placement: "placement", autoPlacement: "autoPlacement" }, outputs: { opened: "opened", closed: "closed" }, host: { properties: { "attr.popover": "type", "attr.data-variant": "variant", "attr.data-color": "color" }, classAttribute: "ds-popover" }, ngImport: i0, template: '<ng-content />', isInline: true });
2080
+ }
2081
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: HviPopover, decorators: [{
2082
+ type: Component,
2083
+ args: [{
2084
+ selector: 'hvi-popover',
2085
+ standalone: true,
2086
+ template: '<ng-content />',
2087
+ host: {
2088
+ class: 'ds-popover',
2089
+ '[attr.popover]': 'type',
2090
+ '[attr.data-variant]': 'variant',
2091
+ '[attr.data-color]': 'color',
2092
+ },
2093
+ }]
2094
+ }], propDecorators: { type: [{
2095
+ type: Input
2096
+ }], variant: [{
2097
+ type: Input
2098
+ }], color: [{
2099
+ type: Input
2100
+ }], placement: [{
2101
+ type: Input
2102
+ }], autoPlacement: [{
2103
+ type: Input
2104
+ }], opened: [{
2105
+ type: Output
2106
+ }], closed: [{
2107
+ type: Output
2108
+ }] } });
2109
+
1756
2110
  /**
1757
2111
  * @summary
1758
2112
  * 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.
@@ -1803,5 +2157,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
1803
2157
  * Generated bundle index. Do not edit.
1804
2158
  */
1805
2159
 
1806
- 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, HviList, HviParagraph, HviTag, HviValidationKit, HviValidationMessage, fieldObserver, isElement, isInputLike, isLabel };
2160
+ 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, HviList, HviParagraph, HviPopover, HviTag, HviValidationKit, HviValidationMessage, fieldObserver, hviCustom, hviEmail, hviExtractMessages, hviExtractValidators, hviMax, hviMaxLength, hviMin, hviMinLength, hviNullValidator, hviPattern, hviRequired, hviRequiredTrue, hviValidators, isElement, isInputLike, isLabel };
1807
2161
  //# sourceMappingURL=helsevestikt-hviktor-angular.mjs.map