@felleslosninger/minid-elements 0.0.128 → 0.0.130

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.
@@ -9,19 +9,23 @@ declare const MinidCodeInput_base: import('../types/mixin-constructor.ts').Const
9
9
  *
10
10
  * @event mid-change - Emitted when a change to the input value is comitted by the user
11
11
  * @event mid-input - Emitted when the input element recieves input
12
+ * @event mid-complete - Emitted when all characters have been entered.
12
13
  * @event {detail: { validity: ValidityState }} mid-invalid-hide - Emitted when the error message should be hidden
13
14
  * @event {detail: { validity: ValidityState }} mid-invalid-show - Emitted when the error message should be shown
14
15
  *
15
16
  * @slot label - The input's label if you need to use HTML. Alternatively, you can use the `label` attribute.
16
17
  *
17
18
  * @csspart input-container - The wrapper around the input elements. This can be used to adjust font-size.
19
+ * @csspart character-boxes - The container for the visual character boxes.
20
+ * @csspart character-box - An individual character box.
18
21
  *
22
+ * @method focus - Focuses the input element
23
+ * @method clear - Clears the input
19
24
  */
20
25
  export declare class MinidCodeInput extends MinidCodeInput_base {
21
- #private;
22
26
  private readonly hasSlotControler;
23
27
  private readonly labelId;
24
- private inputElements;
28
+ private inputElement;
25
29
  value: string;
26
30
  label: string;
27
31
  type: 'number' | 'text';
@@ -62,17 +66,17 @@ export declare class MinidCodeInput extends MinidCodeInput_base {
62
66
  * A regular expression pattern to validate input against.
63
67
  */
64
68
  pattern?: string;
65
- private internalValues;
69
+ private isFocused;
66
70
  static get formControlValidators(): import('../types/validator.type.ts').Validator[];
67
- get validationTarget(): HTMLInputElement | null;
71
+ get validationTarget(): HTMLInputElement;
68
72
  protected firstUpdated(_changedProperties: PropertyValues): void;
73
+ private handleBoxClick;
69
74
  private handleFocus;
70
75
  private handleBlur;
71
- private handleKeydown;
72
76
  private handleInput;
73
- private handlePaste;
74
- private updateValueAndEmit;
75
- private valueVisualUpdate;
77
+ private handleChange;
78
+ private handleKeydown;
79
+ clear(): void;
76
80
  focus(options?: FocusOptions): void;
77
81
  handleLengthChange(): void;
78
82
  handleValueChange(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"code-input.component.d.ts","sourceRoot":"","sources":["../../src/components/code-input.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAQ5D,OAAO,0BAA0B,CAAC;AASlC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,cAAc,CAAC;KAClC;CACF;;AAqBD;;;;;;;;;;;GAWG;AACH,qBACa,cAAe,SAAQ,mBAEnC;;IACC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAwC;IAEzE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4C;IAGpE,OAAO,CAAC,aAAa,CAAgC;IAGrD,KAAK,SAAM;IAGX,KAAK,SAAM;IAGX,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAU;IAEjC;;OAEG;IAEH,SAAS,EAAE,SAAS,GAAG,MAAM,CAAU;IAEvC;;OAEG;IAEH,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAEhC;;OAEG;IAEH,MAAM,SAAK;IAGX,QAAQ,UAAS;IAEjB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,cAAc,SAAM;IAEpB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,QAAQ,UAAS;IAEjB;;OAEG;IAEH,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,OAAO,CAAC,cAAc,CAAuC;IAE7D,MAAM,KAAK,qBAAqB,qDAO/B;IAED,IAAI,gBAAgB,4BAEnB;IAED,SAAS,CAAC,YAAY,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI;IAIhE,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,aAAa;IAgDrB,OAAO,CAAC,WAAW;IAyBnB,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,iBAAiB;IAOzB,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI;IAOnC,kBAAkB;IAMlB,iBAAiB;IAWR,MAAM;CAiEhB"}
1
+ {"version":3,"file":"code-input.component.d.ts","sourceRoot":"","sources":["../../src/components/code-input.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAQ5D,OAAO,0BAA0B,CAAC;AASlC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,cAAc,CAAC;KAClC;CACF;;AA0FD;;;;;;;;;;;;;;;;GAgBG;AACH,qBACa,cAAe,SAAQ,mBAEnC;IACC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAwC;IACzE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4C;IAGpE,OAAO,CAAC,YAAY,CAAoB;IAGxC,KAAK,SAAM;IAGX,KAAK,SAAM;IAGX,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAY;IAEnC;;OAEG;IAEH,SAAS,EAAE,SAAS,GAAG,MAAM,CAAa;IAE1C;;OAEG;IAEH,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAQ;IAEhC;;OAEG;IAEH,MAAM,SAAK;IAGX,QAAQ,UAAS;IAEjB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IAEH,cAAc,SAAM;IAEpB;;OAEG;IAEH,SAAS,UAAS;IAElB;;OAEG;IAEH,QAAQ,UAAS;IAEjB;;OAEG;IAEH,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,OAAO,CAAC,SAAS,CAAS;IAE1B,MAAM,KAAK,qBAAqB,qDAO/B;IAED,IAAI,gBAAgB,qBAEnB;IAED,SAAS,CAAC,YAAY,CAAC,kBAAkB,EAAE,cAAc,GAAG,IAAI;IAIhE,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,WAAW;IAoBnB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,aAAa;IAiBrB,KAAK;IAIL,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI;IAKnC,kBAAkB;IAOlB,iBAAiB;IAiBR,MAAM;CA8FhB"}
@@ -1,5 +1,5 @@
1
1
  import { css, LitElement, html } from "lit";
2
- import { queryAll, property, state, customElement } from "lit/decorators.js";
2
+ import { query, property, state, customElement } from "lit/decorators.js";
3
3
  import { classMap } from "lit/directives/class-map.js";
4
4
  import { live } from "lit/directives/live.js";
5
5
  import { watch } from "../internal/watch.js";
@@ -11,9 +11,6 @@ import { requiredValidator, maxLengthValidator, minLengthValidator, patternValid
11
11
  import { webOtpApiInit } from "../utilities/web-otp-api.js";
12
12
  var __defProp = Object.defineProperty;
13
13
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
14
- var __typeError = (msg) => {
15
- throw TypeError(msg);
16
- };
17
14
  var __decorateClass = (decorators, target, key, kind) => {
18
15
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
19
16
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
@@ -22,26 +19,90 @@ var __decorateClass = (decorators, target, key, kind) => {
22
19
  if (kind && result) __defProp(target, key, result);
23
20
  return result;
24
21
  };
25
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
26
- var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), member.get(obj));
27
- var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
28
- var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
29
- var _skipValueVisualUpdate;
30
22
  let nextUniqueId = 0;
31
23
  const styles = [
32
24
  css`
33
- :host {
34
- display: block;
35
- }
25
+ :host {
26
+ display: block;
27
+ }
36
28
 
37
- /* Hide increment/decrement buttons on inputs */
38
- input[type='number']::-webkit-outer-spin-button,
39
- input[type='number']::-webkit-inner-spin-button,
40
- input[type='number'] {
41
- -webkit-appearance: none;
42
- margin: 0;
43
- -moz-appearance: textfield !important;
44
- }
29
+ .input-wrapper {
30
+ position: relative;
31
+ cursor: text;
32
+ }
33
+
34
+ .character-boxes {
35
+ display: inline-flex;
36
+ gap: 0.5rem; /* Corresponds to gap-2 in tailwind */
37
+ }
38
+
39
+ .character-box {
40
+ display: inline-flex;
41
+ align-items: center;
42
+ justify-content: center;
43
+ position: relative;
44
+ }
45
+
46
+ .hidden-input {
47
+ position: absolute;
48
+ top: 0;
49
+ left: 0;
50
+ width: 100%;
51
+ height: 100%;
52
+ padding: 0;
53
+ margin: 0;
54
+ background: transparent;
55
+ border: none;
56
+ color: transparent;
57
+ /* Hide the real caret */
58
+ caret-color: transparent;
59
+ /* Make font tiny to avoid visual artifacts */
60
+ font-size: 1px;
61
+ /* Allow clicks to pass through to elements underneath */
62
+ pointer-events: none;
63
+ }
64
+
65
+ .hidden-input:focus {
66
+ outline: none;
67
+ }
68
+
69
+ .hidden-input:disabled {
70
+ cursor: not-allowed;
71
+ }
72
+
73
+ /* Fake caret using a CSS animation */
74
+ @keyframes blink {
75
+ 0%,
76
+ 100% {
77
+ opacity: 1;
78
+ }
79
+ 50% {
80
+ opacity: 0;
81
+ }
82
+ }
83
+
84
+ .character-box--caret::after {
85
+ content: '';
86
+ position: absolute;
87
+ width: 2px;
88
+ height: 60%;
89
+ background-color: var(--color-accent-base, blue);
90
+ animation: blink 1s step-end infinite;
91
+ }
92
+
93
+ /* Hide placeholder circle when the caret is present */
94
+ .character-box--caret.character-box--empty {
95
+ color: transparent;
96
+ }
97
+
98
+ /* Hide increment/decrement buttons on inputs */
99
+ input[type='number']::-webkit-outer-spin-button,
100
+ input[type='number']::-webkit-inner-spin-button,
101
+ input[type='number'] {
102
+ -webkit-appearance: none;
103
+ margin: 0;
104
+ -moz-appearance: textfield !important;
105
+ }
45
106
  `
46
107
  ];
47
108
  let MinidCodeInput = class extends FormControlMixin(
@@ -50,12 +111,11 @@ let MinidCodeInput = class extends FormControlMixin(
50
111
  constructor() {
51
112
  super(...arguments);
52
113
  this.hasSlotControler = new HasSlotController(this, "label");
53
- __privateAdd(this, _skipValueVisualUpdate, false);
54
114
  this.labelId = `mid-code-input-label-${nextUniqueId++}`;
55
115
  this.value = "";
56
116
  this.label = "";
57
- this.type = "text";
58
- this.inputmode = "text";
117
+ this.type = "number";
118
+ this.inputmode = "numeric";
59
119
  this.size = "sm";
60
120
  this.length = 5;
61
121
  this.disabled = false;
@@ -63,7 +123,7 @@ let MinidCodeInput = class extends FormControlMixin(
63
123
  this.invalidmessage = "";
64
124
  this.hidelabel = false;
65
125
  this.required = false;
66
- this.internalValues = Array(this.length).fill("");
126
+ this.isFocused = false;
67
127
  }
68
128
  static get formControlValidators() {
69
129
  return [
@@ -74,141 +134,89 @@ let MinidCodeInput = class extends FormControlMixin(
74
134
  ];
75
135
  }
76
136
  get validationTarget() {
77
- return this.inputElements?.length ? this.inputElements[0] : null;
137
+ return this.inputElement;
78
138
  }
79
139
  firstUpdated(_changedProperties) {
80
140
  webOtpApiInit(this.renderRoot);
81
141
  }
82
- handleFocus(index) {
83
- return () => {
84
- this.inputElements[index].setAttribute("placeholder", "");
85
- this.inputElements[index].select();
86
- };
87
- }
88
- handleBlur(index) {
89
- return () => {
90
- this.inputElements[index].setAttribute("placeholder", "○");
91
- };
142
+ handleBoxClick(index) {
143
+ if (this.disabled) {
144
+ return;
145
+ }
146
+ this.value = this.value.substring(0, index);
147
+ this.focus();
92
148
  }
93
- handleKeydown(index) {
94
- return (event) => {
95
- this.internalValues[index] = event.target.value;
96
- this.value = this.internalValues.join("");
97
- const input = event.target;
98
- const hasModifier = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
99
- if (event.key === "Backspace") {
100
- if (input.value === "" && index > 0) {
101
- this.inputElements[index - 1].focus();
102
- this.internalValues[index - 1] = "";
103
- this.updateValueAndEmit(true);
104
- } else if (input.value !== "") {
105
- input.value = "";
106
- this.internalValues[index] = "";
107
- this.updateValueAndEmit(true);
108
- }
109
- } else if (event.key === "ArrowLeft") {
110
- if (index > 0) {
111
- this.inputElements[index - 1].focus();
112
- }
113
- } else if (event.key === "ArrowRight") {
114
- if (index < this.length - 1) {
115
- this.inputElements[index + 1].focus();
116
- }
117
- } else if (event.key === "Delete") {
118
- input.value = "";
119
- this.internalValues[index] = "";
120
- this.updateValueAndEmit(true);
121
- } else if (event.key === "Enter" && !hasModifier) {
122
- setTimeout(() => {
123
- if (!event.defaultPrevented && !event.isComposing) {
124
- this.form?.requestSubmit();
125
- }
126
- });
127
- }
128
- };
149
+ handleFocus() {
150
+ this.isFocused = true;
129
151
  }
130
- handleInput(index) {
131
- return (event) => {
132
- const input = event.target;
133
- let inputValue = input.value;
134
- if (inputValue.length > 1) {
135
- inputValue = inputValue.charAt(0);
136
- input.value = inputValue;
137
- }
138
- this.internalValues[index] = inputValue;
139
- this.updateValueAndEmit(true);
140
- if (inputValue !== "" && index < this.length - 1) {
141
- this.inputElements[index + 1].focus();
142
- }
143
- this.dispatchEvent(
144
- new Event("mid-input", { bubbles: true, composed: true })
145
- );
146
- };
152
+ handleBlur() {
153
+ this.isFocused = false;
147
154
  }
148
- handlePaste(index) {
149
- return (event) => {
150
- event.preventDefault();
151
- const pasteData = event.clipboardData?.getData("text").trim();
152
- if (pasteData) {
153
- const pasteChars = pasteData.split("");
154
- for (let i = 0; i < this.length; i++) {
155
- if (index + i < this.length && pasteChars[i]) {
156
- this.internalValues[index + i] = pasteChars[i];
157
- }
158
- }
159
- this.updateValueAndEmit();
160
- const lastFilledIndex = Math.min(
161
- index + pasteChars.length - 1,
162
- this.length - 1
163
- );
164
- this.inputElements[lastFilledIndex]?.focus();
165
- }
166
- };
155
+ handleInput(event) {
156
+ const input = event.target;
157
+ const value = input.value.substring(0, this.length);
158
+ if (input.value.length > this.length) {
159
+ input.value = value;
160
+ }
161
+ if (this.value !== value) {
162
+ this.value = value;
163
+ }
164
+ this.dispatchEvent(
165
+ new Event("mid-input", { bubbles: true, composed: true })
166
+ );
167
167
  }
168
- updateValueAndEmit(skipValueUpdate = false) {
169
- __privateSet(this, _skipValueVisualUpdate, skipValueUpdate);
170
- this.value = this.internalValues.join("");
168
+ handleChange() {
171
169
  this.dispatchEvent(
172
170
  new Event("mid-change", {
173
171
  bubbles: true,
174
172
  composed: true
175
173
  })
176
174
  );
177
- if (this.value.length === this.length && this.internalValues.every((digit) => digit !== "")) {
178
- this.dispatchEvent(
179
- new Event("mid-complete", {
180
- bubbles: true,
181
- composed: true
182
- })
183
- );
175
+ }
176
+ handleKeydown(event) {
177
+ const hasModifier = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
178
+ if (event.key === "Enter" && !hasModifier) {
179
+ setTimeout(() => {
180
+ if (!event.defaultPrevented && !event.isComposing) {
181
+ this.form?.requestSubmit();
182
+ }
183
+ });
184
184
  }
185
185
  }
186
- valueVisualUpdate(value) {
187
- const chars = value.split("");
188
- this.internalValues.forEach((_, index) => {
189
- this.internalValues[index] = chars[index];
190
- });
186
+ clear() {
187
+ this.value = "";
191
188
  }
192
189
  focus(options) {
193
- if (this.inputElements.length > 0) {
194
- this.inputElements[0].focus(options);
195
- }
190
+ this.inputElement?.focus(options);
196
191
  }
197
192
  handleLengthChange() {
198
- this.internalValues = Array(this.length).fill("");
199
- this.valueVisualUpdate(this.value);
193
+ if (this.value.length > this.length) {
194
+ this.value = this.value.substring(0, this.length);
195
+ }
200
196
  }
201
197
  handleValueChange() {
202
198
  this.setValue(this.value);
203
- if (__privateGet(this, _skipValueVisualUpdate)) {
204
- __privateSet(this, _skipValueVisualUpdate, false);
205
- return;
199
+ if (this.inputElement && this.inputElement.value !== this.value) {
200
+ this.inputElement.value = this.value;
201
+ }
202
+ if (this.value.length === this.length && this.value.length > 0) {
203
+ this.dispatchEvent(
204
+ new Event("mid-complete", {
205
+ bubbles: true,
206
+ composed: true
207
+ })
208
+ );
206
209
  }
207
- this.valueVisualUpdate(this.value);
208
210
  }
209
211
  render() {
210
212
  const hasLabelSlot = this.hasSlotControler.test("label");
211
213
  const hasLabel = !!this.label || !!hasLabelSlot;
214
+ const chars = this.value.split("");
215
+ const displayValues = Array.from(
216
+ { length: this.length },
217
+ (_, i) => chars[i] || ""
218
+ );
219
+ const caretIndex = this.disabled ? -1 : this.value.length;
212
220
  return html`
213
221
  <label
214
222
  id="${this.labelId}"
@@ -221,42 +229,62 @@ let MinidCodeInput = class extends FormControlMixin(
221
229
  </label>
222
230
  <div
223
231
  part="input-container"
224
- class="${classMap({
232
+ class="input-wrapper ${classMap({
225
233
  "text-heading-sm": this.size === "sm",
226
234
  "text-heading-md": this.size === "md",
227
- "text-heading-lg": this.size === "lg"
228
- })} inline-flex gap-2"
235
+ "text-heading-lg": this.size === "lg",
236
+ "opacity-disabled": this.disabled
237
+ })}"
238
+ @click=${() => this.focus()}
229
239
  >
230
- ${this.internalValues.map((value, index) => {
240
+ <div part="character-boxes" class="character-boxes">
241
+ ${displayValues.map((char, index) => {
242
+ const hasCaret = this.isFocused && index === caretIndex;
231
243
  return html`
232
- <input
233
- .value="${live(value || "")}"
234
- id="mid-code-input-${index}"
235
- class="${classMap({
236
- border: !this.invalidmessage,
244
+ <div
245
+ part="character-box"
246
+ class="character-box ${classMap({
247
+ "border": !this.invalidmessage,
237
248
  "border-2": this.invalidmessage,
238
249
  "border-neutral": !this.invalidmessage,
239
250
  "border-danger": this.invalidmessage,
240
251
  "bg-neutral": !this.invalidmessage,
241
252
  "bg-danger-tinted": this.invalidmessage,
242
- "placeholder:text-neutral-surface-active": !this.invalidmessage,
243
- "placeholder:text-danger-surface-active": this.invalidmessage
244
- })} focus:focus-ring-sm disabled:opacity-disabled size-9 rounded-md text-center font-mono disabled:cursor-not-allowed"
245
- type="${this.type}"
246
- placeholder=""
247
- aria-labelledby="${this.labelId}"
248
- size="1"
249
- ?autofocus="${!index && this.autofocus}"
250
- ?disabled="${this.disabled}"
251
- inputmode="${this.inputmode}"
252
- @keydown="${this.handleKeydown(index)}"
253
- @input="${this.handleInput(index)}"
254
- @paste="${this.handlePaste(index)}"
255
- @focus="${this.handleFocus(index)}"
256
- @blur="${this.handleBlur(index)}"
257
- />
258
- `;
253
+ "text-neutral-surface-active": !char && !this.invalidmessage,
254
+ "text-danger-surface-active": !char && this.invalidmessage,
255
+ "character-box--caret": hasCaret,
256
+ "character-box--empty": !char,
257
+ "focus-ring-sm": hasCaret
258
+ })} size-9 rounded-md text-center font-mono"
259
+ @click=${(e) => {
260
+ e.stopPropagation();
261
+ this.handleBoxClick(index);
262
+ }}
263
+ >
264
+ ${char || "○"}
265
+ </div>
266
+ `;
259
267
  })}
268
+ </div>
269
+ <input
270
+ class="hidden-input"
271
+ .value="${live(this.value)}"
272
+ id="mid-code-input-hidden"
273
+ type="${this.type}"
274
+ aria-labelledby="${this.labelId}"
275
+ maxlength="${this.length}"
276
+ ?autofocus="${this.autofocus}"
277
+ ?disabled="${this.disabled}"
278
+ ?required="${this.required}"
279
+ .pattern="${this.pattern}"
280
+ inputmode="${this.inputmode}"
281
+ autocomplete="one-time-code"
282
+ @input="${this.handleInput}"
283
+ @change="${this.handleChange}"
284
+ @keydown="${this.handleKeydown}"
285
+ @focus="${this.handleFocus}"
286
+ @blur="${this.handleBlur}"
287
+ />
260
288
  </div>
261
289
  <div
262
290
  class="text-danger-subtle mt-2 flex gap-1"
@@ -272,10 +300,9 @@ let MinidCodeInput = class extends FormControlMixin(
272
300
  `;
273
301
  }
274
302
  };
275
- _skipValueVisualUpdate = /* @__PURE__ */ new WeakMap();
276
303
  __decorateClass([
277
- queryAll("input")
278
- ], MinidCodeInput.prototype, "inputElements", 2);
304
+ query(".hidden-input")
305
+ ], MinidCodeInput.prototype, "inputElement", 2);
279
306
  __decorateClass([
280
307
  property({ reflect: true })
281
308
  ], MinidCodeInput.prototype, "value", 2);
@@ -317,7 +344,7 @@ __decorateClass([
317
344
  ], MinidCodeInput.prototype, "pattern", 2);
318
345
  __decorateClass([
319
346
  state()
320
- ], MinidCodeInput.prototype, "internalValues", 2);
347
+ ], MinidCodeInput.prototype, "isFocused", 2);
321
348
  __decorateClass([
322
349
  watch("length")
323
350
  ], MinidCodeInput.prototype, "handleLengthChange", 1);
@@ -1 +1 @@
1
- {"version":3,"file":"code-input.js","sources":["../../src/components/code-input.component.ts"],"sourcesContent":["import { css, html, LitElement, PropertyValues } from 'lit';\nimport { customElement, property, queryAll, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { live } from 'lit/directives/live.js';\nimport { watch } from '../internal/watch.ts';\nimport { FormControlMixin } from '../mixins/form-control.mixin.ts';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { HasSlotController } from '../internal/slot.ts';\nimport './icon/icon.component.ts';\nimport {\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n requiredValidator,\n} from '../mixins/validators.ts';\nimport { webOtpApiInit } from '../utilities/web-otp-api.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-code-input': MinidCodeInput;\n }\n}\n\nlet nextUniqueId = 0;\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n\n /* Hide increment/decrement buttons on inputs */\n input[type='number']::-webkit-outer-spin-button,\n input[type='number']::-webkit-inner-spin-button,\n input[type='number'] {\n -webkit-appearance: none;\n margin: 0;\n -moz-appearance: textfield !important;\n }\n `,\n];\n\n/**\n *\n * @event mid-change - Emitted when a change to the input value is comitted by the user\n * @event mid-input - Emitted when the input element recieves input\n * @event {detail: { validity: ValidityState }} mid-invalid-hide - Emitted when the error message should be hidden\n * @event {detail: { validity: ValidityState }} mid-invalid-show - Emitted when the error message should be shown\n *\n * @slot label - The input's label if you need to use HTML. Alternatively, you can use the `label` attribute.\n *\n * @csspart input-container - The wrapper around the input elements. This can be used to adjust font-size.\n *\n */\n@customElement('mid-code-input')\nexport class MinidCodeInput extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly hasSlotControler = new HasSlotController(this, 'label');\n #skipValueVisualUpdate = false;\n private readonly labelId = `mid-code-input-label-${nextUniqueId++}`;\n\n @queryAll('input')\n private inputElements!: NodeListOf<HTMLInputElement>;\n\n @property({ reflect: true })\n value = '';\n\n @property()\n label = '';\n\n @property()\n type: 'number' | 'text' = 'text';\n\n /**\n * For displaying appropriate virtual keyboard\n */\n @property()\n inputmode: 'numeric' | 'text' = 'text';\n\n /**\n * Adjusts the font-size of the code inputs\n */\n @property()\n size: 'sm' | 'md' | 'lg' = 'sm';\n\n /**\n * Number of input characters or digits\n */\n @property({ type: Number })\n length = 5;\n\n @property({ type: Boolean })\n disabled = false;\n\n /**\n * Focuses the first input element on page load\n */\n @property({ type: Boolean })\n autofocus = false;\n\n /**\n * The minimum length of input that will be considered valid.\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * Error message to display when the input is invalid, also activates invalid styling\n */\n @property()\n invalidmessage = '';\n\n /**\n * Visually hides `label` (still available for screen readers)\n */\n @property({ type: Boolean })\n hidelabel = false;\n\n /**\n * Makes the input required\n */\n @property({ type: Boolean })\n required = false;\n\n /**\n * A regular expression pattern to validate input against.\n */\n @property()\n pattern?: string;\n\n @state()\n private internalValues = Array<string>(this.length).fill('');\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n ];\n }\n\n get validationTarget() {\n return this.inputElements?.length ? this.inputElements[0] : null;\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n webOtpApiInit(this.renderRoot);\n }\n\n private handleFocus(index: number) {\n return () => {\n this.inputElements[index].setAttribute('placeholder', '');\n this.inputElements[index].select();\n };\n }\n\n private handleBlur(index: number) {\n return () => {\n this.inputElements[index].setAttribute('placeholder', '○');\n };\n }\n\n private handleKeydown(index: number) {\n return (event: KeyboardEvent) => {\n this.internalValues[index] = (event.target as HTMLInputElement).value;\n this.value = this.internalValues.join('');\n const input = event.target as HTMLInputElement;\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n if (event.key === 'Backspace') {\n if (input.value === '' && index > 0) {\n // If current input is empty, move to previous and clear it\n this.inputElements[index - 1].focus();\n this.internalValues[index - 1] = '';\n this.updateValueAndEmit(true);\n } else if (input.value !== '') {\n // If current input has a value, clear it\n input.value = '';\n this.internalValues[index] = '';\n this.updateValueAndEmit(true);\n }\n } else if (event.key === 'ArrowLeft') {\n if (index > 0) {\n this.inputElements[index - 1].focus();\n }\n } else if (event.key === 'ArrowRight') {\n if (index < this.length - 1) {\n this.inputElements[index + 1].focus();\n }\n } else if (event.key === 'Delete') {\n // Clear current field without moving\n input.value = '';\n this.internalValues[index] = '';\n this.updateValueAndEmit(true);\n } else if (event.key === 'Enter' && !hasModifier) {\n // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before\n // submitting to allow users to cancel the keydown event if they need to\n setTimeout(() => {\n //\n // When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way\n // to check for this is to look at event.isComposing, which will be true when the IME is open.\n if (!event.defaultPrevented && !event.isComposing) {\n this.form?.requestSubmit();\n }\n });\n }\n };\n }\n\n private handleInput(index: number) {\n return (event: InputEvent) => {\n const input = event.target as HTMLInputElement;\n let inputValue = input.value;\n\n // Only allow single digit input\n if (inputValue.length > 1) {\n inputValue = inputValue.charAt(0);\n input.value = inputValue; // Correct the input value\n }\n\n this.internalValues[index] = inputValue;\n this.updateValueAndEmit(true);\n\n // Auto-focus next input if a digit was entered and it's not the last one\n if (inputValue !== '' && index < this.length - 1) {\n this.inputElements[index + 1].focus();\n }\n\n this.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true })\n );\n };\n }\n\n private handlePaste(index: number) {\n return (event: ClipboardEvent) => {\n event.preventDefault(); // Prevent default paste behavior\n const pasteData = event.clipboardData?.getData('text').trim();\n\n if (pasteData) {\n const pasteChars = pasteData.split('');\n for (let i = 0; i < this.length; i++) {\n if (index + i < this.length && pasteChars[i]) {\n this.internalValues[index + i] = pasteChars[i];\n // Update the actual input element's value directly as well\n // if (this.inputElements[index + i]) {\n // this.inputElements[index + i].value = pasteChars[i];\n // }\n }\n }\n this.updateValueAndEmit();\n\n // Focus the last filled input or the last input if all are filled\n const lastFilledIndex = Math.min(\n index + pasteChars.length - 1,\n this.length - 1\n );\n this.inputElements[lastFilledIndex]?.focus();\n }\n };\n }\n\n private updateValueAndEmit(skipValueUpdate = false) {\n this.#skipValueVisualUpdate = skipValueUpdate;\n this.value = this.internalValues.join('');\n this.dispatchEvent(\n new Event('mid-change', {\n bubbles: true,\n composed: true,\n })\n );\n\n if (\n this.value.length === this.length &&\n this.internalValues.every((digit) => digit !== '')\n ) {\n this.dispatchEvent(\n new Event('mid-complete', {\n bubbles: true,\n composed: true,\n })\n );\n }\n }\n\n private valueVisualUpdate(value: string) {\n const chars = value.split('');\n this.internalValues.forEach((_, index) => {\n this.internalValues[index] = chars[index];\n });\n }\n\n focus(options?: FocusOptions): void {\n if (this.inputElements.length > 0) {\n this.inputElements[0].focus(options);\n }\n }\n\n @watch('length')\n handleLengthChange() {\n this.internalValues = Array(this.length).fill('');\n this.valueVisualUpdate(this.value);\n }\n\n @watch('value')\n handleValueChange() {\n this.setValue(this.value);\n\n if (this.#skipValueVisualUpdate) {\n this.#skipValueVisualUpdate = false;\n return;\n }\n\n this.valueVisualUpdate(this.value);\n }\n\n override render() {\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n return html`\n <label\n id=\"${this.labelId}\"\n class=\"${classMap({\n 'sr-only': this.hidelabel || !hasLabel,\n 'opacity-disabled': this.disabled,\n })} mb-2 block items-center gap-1 font-medium\"\n >\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n <div\n part=\"input-container\"\n class=\"${classMap({\n 'text-heading-sm': this.size === 'sm',\n 'text-heading-md': this.size === 'md',\n 'text-heading-lg': this.size === 'lg',\n })} inline-flex gap-2\"\n >\n ${this.internalValues.map((value, index) => {\n return html`\n <input\n .value=\"${live(value || '')}\"\n id=\"mid-code-input-${index}\"\n class=\"${classMap({\n border: !this.invalidmessage,\n 'border-2': this.invalidmessage,\n 'border-neutral': !this.invalidmessage,\n 'border-danger': this.invalidmessage,\n 'bg-neutral': !this.invalidmessage,\n 'bg-danger-tinted': this.invalidmessage,\n 'placeholder:text-neutral-surface-active': !this.invalidmessage,\n 'placeholder:text-danger-surface-active': this.invalidmessage,\n })} focus:focus-ring-sm disabled:opacity-disabled size-9 rounded-md text-center font-mono disabled:cursor-not-allowed\"\n type=\"${this.type}\"\n placeholder=\"○\"\n aria-labelledby=\"${this.labelId}\"\n size=\"1\"\n ?autofocus=\"${!index && this.autofocus}\"\n ?disabled=\"${this.disabled}\"\n inputmode=\"${this.inputmode}\"\n @keydown=\"${this.handleKeydown(index)}\"\n @input=\"${this.handleInput(index)}\"\n @paste=\"${this.handlePaste(index)}\"\n @focus=\"${this.handleFocus(index)}\"\n @blur=\"${this.handleBlur(index)}\"\n />\n `;\n })}\n </div>\n <div\n class=\"text-danger-subtle mt-2 flex gap-1\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n ${this.invalidmessage}\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"code-input.js","sources":["../../src/components/code-input.component.ts"],"sourcesContent":["import { css, html, LitElement, PropertyValues } from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { live } from 'lit/directives/live.js';\nimport { watch } from '../internal/watch.ts';\nimport { FormControlMixin } from '../mixins/form-control.mixin.ts';\nimport { styled } from '../mixins/tailwind.mixin.ts';\nimport { HasSlotController } from '../internal/slot.ts';\nimport './icon/icon.component.ts';\nimport {\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n requiredValidator,\n} from '../mixins/validators.ts';\nimport { webOtpApiInit } from '../utilities/web-otp-api.ts';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'mid-code-input': MinidCodeInput;\n }\n}\n\nlet nextUniqueId = 0;\n\nconst styles = [\n css`\n :host {\n display: block;\n }\n\n .input-wrapper {\n position: relative;\n cursor: text;\n }\n\n .character-boxes {\n display: inline-flex;\n gap: 0.5rem; /* Corresponds to gap-2 in tailwind */\n }\n\n .character-box {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n }\n\n .hidden-input {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n margin: 0;\n background: transparent;\n border: none;\n color: transparent;\n /* Hide the real caret */\n caret-color: transparent;\n /* Make font tiny to avoid visual artifacts */\n font-size: 1px;\n /* Allow clicks to pass through to elements underneath */\n pointer-events: none;\n }\n\n .hidden-input:focus {\n outline: none;\n }\n\n .hidden-input:disabled {\n cursor: not-allowed;\n }\n\n /* Fake caret using a CSS animation */\n @keyframes blink {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0;\n }\n }\n\n .character-box--caret::after {\n content: '';\n position: absolute;\n width: 2px;\n height: 60%;\n background-color: var(--color-accent-base, blue);\n animation: blink 1s step-end infinite;\n }\n\n /* Hide placeholder circle when the caret is present */\n .character-box--caret.character-box--empty {\n color: transparent;\n }\n\n /* Hide increment/decrement buttons on inputs */\n input[type='number']::-webkit-outer-spin-button,\n input[type='number']::-webkit-inner-spin-button,\n input[type='number'] {\n -webkit-appearance: none;\n margin: 0;\n -moz-appearance: textfield !important;\n }\n `,\n];\n\n/**\n *\n * @event mid-change - Emitted when a change to the input value is comitted by the user\n * @event mid-input - Emitted when the input element recieves input\n * @event mid-complete - Emitted when all characters have been entered.\n * @event {detail: { validity: ValidityState }} mid-invalid-hide - Emitted when the error message should be hidden\n * @event {detail: { validity: ValidityState }} mid-invalid-show - Emitted when the error message should be shown\n *\n * @slot label - The input's label if you need to use HTML. Alternatively, you can use the `label` attribute.\n *\n * @csspart input-container - The wrapper around the input elements. This can be used to adjust font-size.\n * @csspart character-boxes - The container for the visual character boxes.\n * @csspart character-box - An individual character box.\n *\n * @method focus - Focuses the input element\n * @method clear - Clears the input\n */\n@customElement('mid-code-input')\nexport class MinidCodeInput extends FormControlMixin(\n styled(LitElement, styles)\n) {\n private readonly hasSlotControler = new HasSlotController(this, 'label');\n private readonly labelId = `mid-code-input-label-${nextUniqueId++}`;\n\n @query('.hidden-input')\n private inputElement!: HTMLInputElement;\n\n @property({ reflect: true })\n value = '';\n\n @property()\n label = '';\n\n @property()\n type: 'number' | 'text' = 'number';\n\n /**\n * For displaying appropriate virtual keyboard\n */\n @property()\n inputmode: 'numeric' | 'text' = 'numeric';\n\n /**\n * Adjusts the font-size of the code inputs\n */\n @property()\n size: 'sm' | 'md' | 'lg' = 'sm';\n\n /**\n * Number of input characters or digits\n */\n @property({ type: Number })\n length = 5;\n\n @property({ type: Boolean })\n disabled = false;\n\n /**\n * Focuses the first input element on page load\n */\n @property({ type: Boolean })\n autofocus = false;\n\n /**\n * The minimum length of input that will be considered valid.\n */\n @property({ type: Number })\n minlength?: number;\n\n /**\n * Error message to display when the input is invalid, also activates invalid styling\n */\n @property()\n invalidmessage = '';\n\n /**\n * Visually hides `label` (still available for screen readers)\n */\n @property({ type: Boolean })\n hidelabel = false;\n\n /**\n * Makes the input required\n */\n @property({ type: Boolean })\n required = false;\n\n /**\n * A regular expression pattern to validate input against.\n */\n @property()\n pattern?: string;\n\n @state()\n private isFocused = false;\n\n static get formControlValidators() {\n return [\n requiredValidator,\n maxLengthValidator,\n minLengthValidator,\n patternValidator,\n ];\n }\n\n get validationTarget() {\n return this.inputElement;\n }\n\n protected firstUpdated(_changedProperties: PropertyValues): void {\n webOtpApiInit(this.renderRoot);\n }\n\n private handleBoxClick(index: number) {\n if (this.disabled) {\n return;\n }\n\n // Truncate the value to the clicked position\n this.value = this.value.substring(0, index);\n\n // Focus the input to move the caret\n this.focus();\n }\n\n private handleFocus() {\n this.isFocused = true;\n }\n\n private handleBlur() {\n this.isFocused = false;\n }\n\n private handleInput(event: InputEvent) {\n const input = event.target as HTMLInputElement;\n const value = input.value.substring(0, this.length);\n\n // If the browser allowed a value longer than our length (e.g. on type=\"number\"),\n // we need to truncate the underlying input's value directly to keep it in sync.\n if (input.value.length > this.length) {\n input.value = value;\n }\n\n // Update the component's public `value` property if it has changed.\n if (this.value !== value) {\n this.value = value;\n }\n\n this.dispatchEvent(\n new Event('mid-input', { bubbles: true, composed: true }),\n );\n }\n\n private handleChange() {\n this.dispatchEvent(\n new Event('mid-change', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private handleKeydown(event: KeyboardEvent) {\n const hasModifier =\n event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;\n\n if (event.key === 'Enter' && !hasModifier) {\n // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before\n // submitting to allow users to cancel the keydown event if they need to\n setTimeout(() => {\n // When using an Input Method Editor (IME), pressing enter will cause the form to submit unexpectedly. One way\n // to check for this is to look at event.isComposing, which will be true when the IME is open.\n if (!event.defaultPrevented && !event.isComposing) {\n this.form?.requestSubmit();\n }\n });\n }\n }\n\n clear() {\n this.value = '';\n }\n\n focus(options?: FocusOptions): void {\n this.inputElement?.focus(options);\n }\n\n @watch('length')\n handleLengthChange() {\n if (this.value.length > this.length) {\n this.value = this.value.substring(0, this.length);\n }\n }\n\n @watch('value')\n handleValueChange() {\n this.setValue(this.value);\n\n if (this.inputElement && this.inputElement.value !== this.value) {\n this.inputElement.value = this.value;\n }\n\n if (this.value.length === this.length && this.value.length > 0) {\n this.dispatchEvent(\n new Event('mid-complete', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n }\n\n override render() {\n const hasLabelSlot = this.hasSlotControler.test('label');\n const hasLabel = !!this.label || !!hasLabelSlot;\n\n const chars = this.value.split('');\n const displayValues = Array.from(\n { length: this.length },\n (_, i) => chars[i] || '',\n );\n const caretIndex = this.disabled ? -1 : this.value.length;\n\n return html`\n <label\n id=\"${this.labelId}\"\n class=\"${classMap({\n 'sr-only': this.hidelabel || !hasLabel,\n 'opacity-disabled': this.disabled,\n })} mb-2 block items-center gap-1 font-medium\"\n >\n <slot name=\"label\"> ${this.label} </slot>\n </label>\n <div\n part=\"input-container\"\n class=\"input-wrapper ${classMap({\n 'text-heading-sm': this.size === 'sm',\n 'text-heading-md': this.size === 'md',\n 'text-heading-lg': this.size === 'lg',\n 'opacity-disabled': this.disabled,\n })}\"\n @click=${() => this.focus()}\n >\n <div part=\"character-boxes\" class=\"character-boxes\">\n ${displayValues.map((char, index) => {\n const hasCaret = this.isFocused && index === caretIndex;\n return html`\n <div\n part=\"character-box\"\n class=\"character-box ${classMap({\n 'border': !this.invalidmessage,\n 'border-2': this.invalidmessage,\n 'border-neutral': !this.invalidmessage,\n 'border-danger': this.invalidmessage,\n 'bg-neutral': !this.invalidmessage,\n 'bg-danger-tinted': this.invalidmessage,\n 'text-neutral-surface-active':\n !char && !this.invalidmessage,\n 'text-danger-surface-active': !char && this.invalidmessage,\n 'character-box--caret': hasCaret,\n 'character-box--empty': !char,\n 'focus-ring-sm': hasCaret,\n })} size-9 rounded-md text-center font-mono\"\n @click=${(e: MouseEvent) => {\n e.stopPropagation();\n this.handleBoxClick(index);\n }}\n >\n ${char || '○'}\n </div>\n `;\n })}\n </div>\n <input\n class=\"hidden-input\"\n .value=\"${live(this.value)}\"\n id=\"mid-code-input-hidden\"\n type=\"${this.type}\"\n aria-labelledby=\"${this.labelId}\"\n maxlength=\"${this.length}\"\n ?autofocus=\"${this.autofocus}\"\n ?disabled=\"${this.disabled}\"\n ?required=\"${this.required}\"\n .pattern=\"${this.pattern}\"\n inputmode=\"${this.inputmode}\"\n autocomplete=\"one-time-code\"\n @input=\"${this.handleInput}\"\n @change=\"${this.handleChange}\"\n @keydown=\"${this.handleKeydown}\"\n @focus=\"${this.handleFocus}\"\n @blur=\"${this.handleBlur}\"\n />\n </div>\n <div\n class=\"text-danger-subtle mt-2 flex gap-1\"\n aria-live=\"polite\"\n ?hidden=${!this.invalidmessage}\n >\n <mid-icon\n name=\"xmark-octagon-fill\"\n class=\"mt-1 min-h-5 min-w-5\"\n ></mid-icon>\n ${this.invalidmessage}\n </div>\n `;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -348,19 +348,7 @@
348
348
  }
349
349
 
350
350
  .mid-menu-item {
351
- @apply bg-neutral block w-full rounded border-l-[5px] border-transparent px-3 py-2 font-medium;
352
- }
353
-
354
- .mid-menu-item:hover {
355
- @apply border-accent-base bg-accent-tinted;
356
- }
357
-
358
- .mid-menu-item:focus-visible {
359
- @apply border-accent-base bg-accent-tinted outline-0;
360
- }
361
-
362
- .mid-menu-item:active {
363
- @apply border-accent-base bg-accent-tinted;
351
+ @apply active:border-accent-base active:bg-accent-tinted focus-visible:border-accent-base focus-visible:bg-accent-tinted hover:border-accent-base hover:bg-accent-tinted bg-neutral block w-full rounded border-l-[5px] border-transparent px-3 py-2 font-medium outline-0;
364
352
  }
365
353
 
366
354
  .mid-button {
@@ -370,4 +358,8 @@
370
358
  .mid-label {
371
359
  @apply block font-medium;
372
360
  }
361
+
362
+ .mid-link {
363
+ @apply text-accent-subtle visited:text-link-visited focus-visible:bg-focus-outer hover:text-accent inline-flex items-center gap-2 underline decoration-[.0625rem] underline-offset-[.27em] outline-0 hover:decoration-[.125rem] focus-visible:text-white;
364
+ }
373
365
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@felleslosninger/minid-elements",
3
- "version": "0.0.128",
3
+ "version": "0.0.130",
4
4
  "description": "MinID Web Components",
5
5
  "author": "Digitaliseringsdirektoratet",
6
6
  "license": "MIT",