@reliability-design/web 1.0.3 → 1.0.6

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.
Files changed (114) hide show
  1. package/dist/components/rel-accordion/README.md +132 -0
  2. package/dist/components/rel-accordion/rel-accordion.ts +43 -16
  3. package/dist/components/rel-alert/README.md +141 -0
  4. package/dist/components/rel-alert/rel-alert.ts +18 -7
  5. package/dist/components/rel-avatar/README.md +119 -0
  6. package/dist/components/rel-badge/README.md +86 -0
  7. package/dist/components/rel-badge/rel-badge.ts +6 -6
  8. package/dist/components/rel-breadcrumb/README.md +102 -0
  9. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +12 -6
  10. package/dist/components/rel-button/README.md +130 -0
  11. package/dist/components/rel-calendar/README.md +109 -0
  12. package/dist/components/rel-calendar/index.ts +1 -0
  13. package/dist/components/rel-calendar/rel-calendar.ts +467 -0
  14. package/dist/components/rel-card/README.md +94 -0
  15. package/dist/components/rel-card/rel-card.ts +12 -3
  16. package/dist/components/rel-cardmedia/README.md +127 -0
  17. package/dist/components/rel-cardmedia/rel-cardmedia.ts +14 -4
  18. package/dist/components/rel-carousel/README.md +166 -0
  19. package/dist/components/rel-carousel/index.ts +1 -0
  20. package/dist/components/rel-carousel/rel-carousel.ts +469 -0
  21. package/dist/components/rel-chart/README.md +286 -0
  22. package/dist/components/rel-chart/index.ts +1 -0
  23. package/dist/components/rel-chart/rel-chart.ts +736 -0
  24. package/dist/components/rel-checkbox/README.md +77 -0
  25. package/dist/components/rel-checkbox/rel-checkbox.ts +18 -10
  26. package/dist/components/rel-chip/README.md +114 -0
  27. package/dist/components/rel-chip/rel-chip.ts +20 -4
  28. package/dist/components/rel-container/README.md +99 -0
  29. package/dist/components/rel-date-picker/README.md +253 -0
  30. package/dist/components/rel-date-picker/index.ts +1 -0
  31. package/dist/components/rel-date-picker/rel-date-picker.ts +916 -0
  32. package/dist/components/rel-divider/README.md +100 -0
  33. package/dist/components/rel-drawer/README.md +200 -0
  34. package/dist/components/rel-drawer/index.ts +1 -0
  35. package/dist/components/rel-drawer/rel-drawer.ts +621 -0
  36. package/dist/components/rel-kbd/README.md +151 -0
  37. package/dist/components/rel-kbd/rel-kbd.ts +118 -0
  38. package/dist/components/rel-layout/README.md +88 -0
  39. package/dist/components/rel-menu/README.md +151 -0
  40. package/dist/components/rel-menu/rel-menu.ts +18 -10
  41. package/dist/components/rel-menubar/README.md +329 -0
  42. package/dist/components/rel-menubar/index.ts +2 -0
  43. package/dist/components/rel-menubar/rel-menubar-menu.ts +16 -0
  44. package/dist/components/rel-menubar/rel-menubar.ts +576 -0
  45. package/dist/components/rel-nav-menu/README.md +289 -0
  46. package/dist/components/rel-nav-menu/index.ts +3 -0
  47. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +143 -0
  48. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +53 -0
  49. package/dist/components/rel-nav-menu/rel-nav-menu.ts +331 -0
  50. package/dist/components/rel-navbar/README.md +126 -0
  51. package/dist/components/rel-navbar/rel-navbar.ts +91 -0
  52. package/dist/components/rel-otp/README.md +440 -0
  53. package/dist/components/rel-otp/index.ts +1 -0
  54. package/dist/components/rel-otp/rel-otp.ts +504 -0
  55. package/dist/components/rel-pagination/README.md +410 -0
  56. package/dist/components/rel-pagination/index.ts +1 -0
  57. package/dist/components/rel-pagination/rel-pagination.ts +376 -0
  58. package/dist/components/rel-popover/README.md +568 -0
  59. package/dist/components/rel-popover/index.ts +2 -0
  60. package/dist/components/rel-popover/rel-popover-content.ts +55 -0
  61. package/dist/components/rel-popover/rel-popover.ts +327 -0
  62. package/dist/components/rel-progress/README.md +110 -0
  63. package/dist/components/rel-progress/rel-progress.ts +32 -5
  64. package/dist/components/rel-quote-page/README.md +166 -0
  65. package/dist/components/rel-quote-page/rel-quote-page.ts +816 -0
  66. package/dist/components/rel-radio/README.md +120 -0
  67. package/dist/components/rel-radio/rel-radio.ts +13 -5
  68. package/dist/components/rel-resizable/README.md +140 -0
  69. package/dist/components/rel-resizable/index.ts +3 -0
  70. package/dist/components/rel-resizable/rel-resizable-group.ts +374 -0
  71. package/dist/components/rel-resizable/rel-resizable-handle.ts +149 -0
  72. package/dist/components/rel-resizable/rel-resizable-panel.ts +47 -0
  73. package/dist/components/rel-segmented-button/README.md +141 -0
  74. package/dist/components/rel-segmented-button/rel-segmented-button.ts +18 -13
  75. package/dist/components/rel-select/README.md +107 -0
  76. package/dist/components/rel-select/rel-select.ts +14 -14
  77. package/dist/components/rel-sheet/README.md +224 -0
  78. package/dist/components/rel-sheet/rel-sheet.ts +683 -0
  79. package/dist/components/rel-sidebar/README.md +209 -0
  80. package/dist/components/rel-sidebar/rel-sidebar.ts +1158 -0
  81. package/dist/components/rel-slider/README.md +135 -0
  82. package/dist/components/rel-slider/rel-slider.ts +19 -7
  83. package/dist/components/rel-snackbar/README.md +134 -0
  84. package/dist/components/rel-snackbar/rel-snackbar.ts +67 -2
  85. package/dist/components/rel-stepper/README.md +160 -0
  86. package/dist/components/rel-stepper/rel-stepper.ts +6 -6
  87. package/dist/components/rel-switch/README.md +102 -0
  88. package/dist/components/rel-switch/rel-switch.ts +15 -6
  89. package/dist/components/rel-tab/README.md +163 -0
  90. package/dist/components/rel-tab/rel-tab.ts +36 -14
  91. package/dist/components/rel-table/README.md +178 -0
  92. package/dist/components/rel-table/rel-table-body.ts +16 -0
  93. package/dist/components/rel-table/rel-table-caption.ts +22 -0
  94. package/dist/components/rel-table/rel-table-cell.ts +49 -0
  95. package/dist/components/rel-table/rel-table-footer.ts +18 -0
  96. package/dist/components/rel-table/rel-table-head.ts +33 -0
  97. package/dist/components/rel-table/rel-table-header.ts +16 -0
  98. package/dist/components/rel-table/rel-table-row.ts +32 -0
  99. package/dist/components/rel-table/rel-table.ts +47 -0
  100. package/dist/components/rel-textfield/README.md +90 -0
  101. package/dist/components/rel-textfield/rel-textfield.ts +35 -19
  102. package/dist/components/rel-toast/README.md +148 -0
  103. package/dist/components/rel-toast/rel-toast.ts +32 -14
  104. package/dist/components/rel-tooltip/README.md +103 -0
  105. package/dist/components/rel-tooltip/rel-tooltip.ts +9 -9
  106. package/dist/index.d.mts +836 -1
  107. package/dist/index.d.ts +836 -1
  108. package/dist/index.js +10658 -1493
  109. package/dist/index.js.map +1 -1
  110. package/dist/index.mjs +10616 -1499
  111. package/dist/index.mjs.map +1 -1
  112. package/dist/styles/vars.css +293 -183
  113. package/dist/{vars-6ZIUPIU4.css → vars-ITL2K3KO.css} +293 -183
  114. package/package.json +1 -1
@@ -0,0 +1,504 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement, property, state, query } from "lit/decorators.js";
3
+
4
+ export type OtpType = "numeric" | "alphanumeric";
5
+
6
+ @customElement("rel-otp")
7
+ export class RelOtp extends LitElement {
8
+ @property({ type: String, reflect: true }) value = "";
9
+ @property({ type: Number }) length = 6;
10
+ @property({ type: Number, attribute: "group-size" }) groupSize = 3;
11
+ @property({ type: String }) placeholder = "";
12
+ @property({ type: String }) type: OtpType = "numeric";
13
+ @property({ type: Boolean }) mask = false;
14
+ @property({ type: Boolean, reflect: true }) disabled = false;
15
+ @property({ type: Boolean, reflect: true }) readonly = false;
16
+ @property({ type: Boolean }) required = false;
17
+ @property({ type: String }) name: string | null = null;
18
+ @property({ type: String }) autocomplete = "one-time-code";
19
+ @property({ type: String }) inputmode: "numeric" | "text" | null = null;
20
+ @property({ type: String }) pattern: string | null = null;
21
+ @property({ type: String, attribute: "aria-label" }) ariaLabel: string | null = null;
22
+ @property({ type: Boolean, reflect: true }) invalid = false;
23
+ @property({ type: Boolean, attribute: "show-separator" }) showSeparator = true;
24
+ @property({ type: String }) size: "sm" | "md" | "lg" = "md";
25
+
26
+ @state() private cells: string[] = [];
27
+ @state() private focusedIndex: number = -1;
28
+
29
+ @query(".hidden-input") private hiddenInput?: HTMLInputElement;
30
+
31
+ private isUpdatingFromValue = false;
32
+
33
+ static styles = css`
34
+ :host {
35
+ display: inline-block;
36
+ font-family: var(--rel-fontFamilies-primary);
37
+ }
38
+
39
+ :host([disabled]) {
40
+ opacity: 0.6;
41
+ pointer-events: none;
42
+ }
43
+
44
+ .otp-root {
45
+ display: inline-flex;
46
+ align-items: center;
47
+ gap: var(--rel-spacing-space-2xs, 8px);
48
+ position: relative;
49
+ }
50
+
51
+ .otp-group {
52
+ display: flex;
53
+ gap: var(--rel-spacing-space-2xs, 8px);
54
+ }
55
+
56
+ .otp-separator {
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ color: var(--rel-colors-gray-divider);
61
+ font-size: var(--rel-fontSizes-lg);
62
+ font-weight: var(--rel-fontWeights-semibold);
63
+ user-select: none;
64
+ padding: 0 var(--rel-spacing-space-3xs, 4px);
65
+ }
66
+
67
+ .otp-separator.hidden {
68
+ display: none;
69
+ }
70
+
71
+ .otp-cell {
72
+ width: 40px;
73
+ height: 48px;
74
+ border: var(--rel-borders-width-stroke-100) solid var(--rel-border-default);
75
+ border-radius: var(--rel-borders-radius-border-radius-200);
76
+ background: var(--rel-colors-white);
77
+ font-family: var(--rel-fontFamilies-primary);
78
+ font-size: var(--rel-fontSizes-lg);
79
+ font-weight: var(--rel-fontWeights-medium);
80
+ text-align: center;
81
+ color: var(--rel-text-primary);
82
+ outline: none;
83
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
84
+ caret-color: var(--rel-colors-gray-primary);
85
+ }
86
+
87
+ /* Size variants */
88
+ :host([size="sm"]) .otp-cell {
89
+ width: 36px;
90
+ height: 40px;
91
+ font-size: var(--rel-fontSizes-md);
92
+ }
93
+
94
+ :host([size="lg"]) .otp-cell {
95
+ width: 48px;
96
+ height: 56px;
97
+ font-size: var(--rel-fontSizes-xl);
98
+ }
99
+
100
+ .otp-cell::placeholder {
101
+ color: var(--rel-colors-gray-placeholder);
102
+ opacity: 0.6;
103
+ }
104
+
105
+ .otp-cell:hover:not(:disabled):not(:read-only) {
106
+ border-color: var(--rel-colors-gray-primary);
107
+ }
108
+
109
+ .otp-cell:focus-visible {
110
+ border-color: var(--rel-colors-gray-heading);
111
+ box-shadow: 0 0 0 2px var(--rel-border-default);
112
+ }
113
+
114
+ .otp-cell:disabled {
115
+ background: var(--rel-colors-gray-light);
116
+ color: var(--rel-colors-gray-disabled-text);
117
+ cursor: not-allowed;
118
+ }
119
+
120
+ .otp-cell:read-only {
121
+ background: var(--rel-colors-gray-surface);
122
+ cursor: default;
123
+ }
124
+
125
+ /* Invalid state */
126
+ :host([invalid]) .otp-cell {
127
+ border-color: var(--rel-border-error);
128
+ }
129
+
130
+ :host([invalid]) .otp-cell:focus {
131
+ border-color: var(--rel-border-error);
132
+ box-shadow: 0 0 0 2px var(--rel-background-error-light);
133
+ }
134
+
135
+ .hidden-input {
136
+ position: absolute;
137
+ opacity: 0;
138
+ pointer-events: none;
139
+ width: 1px;
140
+ height: 1px;
141
+ }
142
+
143
+ /* Reduce motion */
144
+ @media (prefers-reduced-motion: reduce) {
145
+ .otp-cell {
146
+ transition: none;
147
+ }
148
+ }
149
+ `;
150
+
151
+ connectedCallback() {
152
+ super.connectedCallback();
153
+ this.initializeCells();
154
+ }
155
+
156
+ updated(changedProperties: Map<string, any>) {
157
+ super.updated(changedProperties);
158
+
159
+ // Only sync from external value changes, not internal updates
160
+ if (changedProperties.has("value") && !this.isUpdatingFromValue) {
161
+ this.syncCellsFromValue();
162
+ }
163
+
164
+ if (changedProperties.has("length")) {
165
+ this.initializeCells();
166
+ }
167
+ }
168
+
169
+ private initializeCells() {
170
+ this.cells = new Array(this.length).fill("");
171
+ this.syncCellsFromValue();
172
+ }
173
+
174
+ private syncCellsFromValue() {
175
+ const chars = this.value.split("").slice(0, this.length);
176
+ this.cells = new Array(this.length).fill("").map((_, i) => chars[i] || "");
177
+ }
178
+
179
+ private updateValue() {
180
+ this.isUpdatingFromValue = true;
181
+ const newValue = this.cells.join("");
182
+ this.value = newValue;
183
+
184
+ // Update hidden input for forms
185
+ if (this.hiddenInput) {
186
+ this.hiddenInput.value = newValue;
187
+ }
188
+
189
+ this.requestUpdate();
190
+
191
+ // Use setTimeout to ensure isUpdatingFromValue is reset after update cycle
192
+ setTimeout(() => {
193
+ this.isUpdatingFromValue = false;
194
+ }, 0);
195
+
196
+ const complete = newValue.length === this.length && this.isValidValue(newValue);
197
+
198
+ this.dispatchEvent(
199
+ new CustomEvent("rel-change", {
200
+ detail: { value: newValue, complete },
201
+ bubbles: true,
202
+ composed: true,
203
+ })
204
+ );
205
+
206
+ if (complete) {
207
+ this.dispatchEvent(
208
+ new CustomEvent("rel-complete", {
209
+ detail: { value: newValue },
210
+ bubbles: true,
211
+ composed: true,
212
+ })
213
+ );
214
+ }
215
+ }
216
+
217
+ private isValidChar(char: string): boolean {
218
+ if (this.type === "numeric") {
219
+ return /^\d$/.test(char);
220
+ } else {
221
+ return /^[0-9a-zA-Z]$/.test(char);
222
+ }
223
+ }
224
+
225
+ private isValidValue(value: string): boolean {
226
+ if (this.type === "numeric") {
227
+ return /^\d+$/.test(value);
228
+ } else {
229
+ return /^[0-9a-zA-Z]+$/.test(value);
230
+ }
231
+ }
232
+
233
+ private getNextEditableIndex(): number {
234
+ // Find first empty cell, or return last index if all filled
235
+ const emptyIndex = this.cells.findIndex((c) => !c);
236
+ return emptyIndex >= 0 ? emptyIndex : this.length - 1;
237
+ }
238
+
239
+ private handlePointerDown(e: PointerEvent) {
240
+ if (this.disabled || this.readonly) return;
241
+
242
+ const input = e.currentTarget as HTMLInputElement;
243
+ const targetIndex = parseInt(input.dataset.index || "0", 10);
244
+ const nextEditableIndex = this.getNextEditableIndex();
245
+
246
+ // Prevent jumping ahead to empty cells
247
+ if (targetIndex > nextEditableIndex) {
248
+ e.preventDefault();
249
+ this.focusCell(nextEditableIndex);
250
+ }
251
+ }
252
+
253
+ private handleInput(e: Event) {
254
+ if (this.disabled || this.readonly) return;
255
+
256
+ const input = e.currentTarget as HTMLInputElement;
257
+ const index = parseInt(input.dataset.index || "0", 10);
258
+ let inputValue = input.value;
259
+
260
+ // Handle autofill/paste on any cell (mobile OTP can inject full code)
261
+ if (inputValue.length > 1) {
262
+ this.handlePasteValue(inputValue, index);
263
+ return;
264
+ }
265
+
266
+ // Get only the last character typed (handles replace-on-type)
267
+ const char = inputValue.slice(-1);
268
+
269
+ if (char && !this.isValidChar(char)) {
270
+ // Invalid character, revert
271
+ input.value = this.cells[index] || "";
272
+ return;
273
+ }
274
+
275
+ // Update cell (replace existing value)
276
+ this.cells[index] = char;
277
+ input.value = char;
278
+
279
+ this.updateValue();
280
+
281
+ // Auto-advance to next cell
282
+ if (char && index < this.length - 1) {
283
+ this.focusCell(index + 1);
284
+ }
285
+ }
286
+
287
+ private handleKeyDown(e: KeyboardEvent) {
288
+ if (this.disabled || this.readonly) return;
289
+
290
+ const input = e.currentTarget as HTMLInputElement;
291
+ const index = parseInt(input.dataset.index || "0", 10);
292
+
293
+ switch (e.key) {
294
+ case "Backspace":
295
+ e.preventDefault();
296
+ if (this.cells[index]) {
297
+ // Clear current cell, keep focus
298
+ this.cells[index] = "";
299
+ input.value = "";
300
+ this.updateValue();
301
+ } else if (index > 0) {
302
+ // Move to previous cell and clear it
303
+ this.cells[index - 1] = "";
304
+ this.updateValue();
305
+ this.focusCell(index - 1);
306
+ }
307
+ break;
308
+
309
+ case "Delete":
310
+ e.preventDefault();
311
+ this.cells[index] = "";
312
+ input.value = "";
313
+ this.updateValue();
314
+ break;
315
+
316
+ case "ArrowLeft":
317
+ e.preventDefault();
318
+ if (index > 0) {
319
+ this.focusCell(index - 1);
320
+ }
321
+ break;
322
+
323
+ case "ArrowRight":
324
+ e.preventDefault();
325
+ if (index < this.length - 1) {
326
+ this.focusCell(index + 1);
327
+ }
328
+ break;
329
+
330
+ case "Home":
331
+ e.preventDefault();
332
+ this.focusCell(0);
333
+ break;
334
+
335
+ case "End":
336
+ e.preventDefault();
337
+ this.focusCell(this.length - 1);
338
+ break;
339
+
340
+ case "ArrowUp":
341
+ case "ArrowDown":
342
+ e.preventDefault();
343
+ break;
344
+ }
345
+ }
346
+
347
+ private handlePaste(e: ClipboardEvent) {
348
+ if (this.disabled || this.readonly) return;
349
+
350
+ e.preventDefault();
351
+
352
+ const input = e.currentTarget as HTMLInputElement;
353
+ const index = parseInt(input.dataset.index || "0", 10);
354
+ const pastedText = e.clipboardData?.getData("text") || "";
355
+
356
+ this.handlePasteValue(pastedText, index);
357
+ }
358
+
359
+ private handlePasteValue(text: string, startIndex: number) {
360
+ // Filter valid characters
361
+ const validChars = text.split("").filter((char) => this.isValidChar(char));
362
+
363
+ // Distribute characters starting from startIndex
364
+ let updateIndex = startIndex;
365
+ validChars.forEach((char) => {
366
+ if (updateIndex < this.length) {
367
+ this.cells[updateIndex] = char;
368
+ updateIndex++;
369
+ }
370
+ });
371
+
372
+ this.updateValue();
373
+
374
+ // Focus next empty cell or last cell
375
+ const nextEmptyIndex = this.cells.findIndex((c, i) => i >= startIndex && !c);
376
+ if (nextEmptyIndex >= 0) {
377
+ this.focusCell(nextEmptyIndex);
378
+ } else {
379
+ this.focusCell(Math.min(updateIndex, this.length - 1));
380
+ }
381
+ }
382
+
383
+ private handleFocus(e: FocusEvent) {
384
+ const input = e.currentTarget as HTMLInputElement;
385
+ const index = parseInt(input.dataset.index || "0", 10);
386
+
387
+ this.focusedIndex = index;
388
+
389
+ // Select all text on focus for easy replacement
390
+ input.select();
391
+ }
392
+
393
+ private handleBlur() {
394
+ this.focusedIndex = -1;
395
+ }
396
+
397
+ private focusCell(index: number) {
398
+ if (index < 0 || index >= this.length) return;
399
+
400
+ const input = this.renderRoot.querySelector(
401
+ `input[data-index="${index}"]`
402
+ ) as HTMLInputElement | null;
403
+
404
+ if (input) {
405
+ input.focus();
406
+ input.select();
407
+ }
408
+ }
409
+
410
+ private getInputMode(): string {
411
+ if (this.inputmode) return this.inputmode;
412
+ return this.type === "numeric" ? "numeric" : "text";
413
+ }
414
+
415
+ private getAriaLabel(index: number): string {
416
+ const total = this.length;
417
+ const position = index + 1;
418
+ const label = this.type === "numeric" ? "Digit" : "Character";
419
+ return `${label} ${position} of ${total}`;
420
+ }
421
+
422
+ private getGroups(): number[][] {
423
+ const groups: number[][] = [];
424
+ if (this.groupSize <= 0 || !this.showSeparator) {
425
+ // Single group with all cells
426
+ groups.push(Array.from({ length: this.length }, (_, i) => i));
427
+ } else {
428
+ // Multiple groups
429
+ for (let i = 0; i < this.length; i += this.groupSize) {
430
+ groups.push(
431
+ Array.from(
432
+ { length: Math.min(this.groupSize, this.length - i) },
433
+ (_, j) => i + j
434
+ )
435
+ );
436
+ }
437
+ }
438
+ return groups;
439
+ }
440
+
441
+ render() {
442
+ const groups = this.getGroups();
443
+
444
+ return html`
445
+ <div
446
+ part="root"
447
+ class="otp-root"
448
+ role="group"
449
+ aria-label="${this.ariaLabel || "One-time password input"}">
450
+ ${groups.map(
451
+ (group, groupIndex) => html`
452
+ <div class="otp-group">
453
+ ${group.map(
454
+ (index) => html`
455
+ <input
456
+ part="cell"
457
+ class="otp-cell"
458
+ data-index="${index}"
459
+ type="${this.mask ? "password" : "text"}"
460
+ inputmode="${this.getInputMode()}"
461
+ autocomplete="${index === 0 ? this.autocomplete : "off"}"
462
+ pattern="${this.pattern || ""}"
463
+ placeholder="${this.placeholder}"
464
+ maxlength="1"
465
+ .value="${this.cells[index] || ""}"
466
+ ?disabled="${this.disabled}"
467
+ ?readonly="${this.readonly}"
468
+ ?required="${this.required && index === 0}"
469
+ aria-label="${this.getAriaLabel(index)}"
470
+ @pointerdown="${this.handlePointerDown}"
471
+ @input="${this.handleInput}"
472
+ @keydown="${this.handleKeyDown}"
473
+ @paste="${this.handlePaste}"
474
+ @focus="${this.handleFocus}"
475
+ @blur="${this.handleBlur}"
476
+ />
477
+ `
478
+ )}
479
+ </div>
480
+ ${groupIndex < groups.length - 1
481
+ ? html`<div part="separator" class="otp-separator">-</div>`
482
+ : ""}
483
+ `
484
+ )}
485
+
486
+ ${this.name
487
+ ? html`<input
488
+ part="hidden-input"
489
+ class="hidden-input"
490
+ type="hidden"
491
+ name="${this.name}"
492
+ .value="${this.value}"
493
+ />`
494
+ : ""}
495
+ </div>
496
+ `;
497
+ }
498
+ }
499
+
500
+ declare global {
501
+ interface HTMLElementTagNameMap {
502
+ "rel-otp": RelOtp;
503
+ }
504
+ }