@felleslosninger/minid-elements 0.0.129 → 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,21 +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
|
*
|
|
19
|
-
* @method focus - Focuses the
|
|
20
|
-
* @method clear - Clears
|
|
22
|
+
* @method focus - Focuses the input element
|
|
23
|
+
* @method clear - Clears the input
|
|
21
24
|
*/
|
|
22
25
|
export declare class MinidCodeInput extends MinidCodeInput_base {
|
|
23
|
-
#private;
|
|
24
26
|
private readonly hasSlotControler;
|
|
25
27
|
private readonly labelId;
|
|
26
|
-
private
|
|
28
|
+
private inputElement;
|
|
27
29
|
value: string;
|
|
28
30
|
label: string;
|
|
29
31
|
type: 'number' | 'text';
|
|
@@ -64,17 +66,16 @@ export declare class MinidCodeInput extends MinidCodeInput_base {
|
|
|
64
66
|
* A regular expression pattern to validate input against.
|
|
65
67
|
*/
|
|
66
68
|
pattern?: string;
|
|
67
|
-
private
|
|
69
|
+
private isFocused;
|
|
68
70
|
static get formControlValidators(): import('../types/validator.type.ts').Validator[];
|
|
69
|
-
get validationTarget(): HTMLInputElement
|
|
71
|
+
get validationTarget(): HTMLInputElement;
|
|
70
72
|
protected firstUpdated(_changedProperties: PropertyValues): void;
|
|
73
|
+
private handleBoxClick;
|
|
71
74
|
private handleFocus;
|
|
72
75
|
private handleBlur;
|
|
73
|
-
private handleKeydown;
|
|
74
76
|
private handleInput;
|
|
75
|
-
private
|
|
76
|
-
private
|
|
77
|
-
private valueVisualUpdate;
|
|
77
|
+
private handleChange;
|
|
78
|
+
private handleKeydown;
|
|
78
79
|
clear(): void;
|
|
79
80
|
focus(options?: FocusOptions): void;
|
|
80
81
|
handleLengthChange(): 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;;
|
|
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 {
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
:host {
|
|
26
|
+
display: block;
|
|
27
|
+
}
|
|
36
28
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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 = "
|
|
58
|
-
this.inputmode = "
|
|
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.
|
|
126
|
+
this.isFocused = false;
|
|
67
127
|
}
|
|
68
128
|
static get formControlValidators() {
|
|
69
129
|
return [
|
|
@@ -74,145 +134,89 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
74
134
|
];
|
|
75
135
|
}
|
|
76
136
|
get validationTarget() {
|
|
77
|
-
return this.
|
|
137
|
+
return this.inputElement;
|
|
78
138
|
}
|
|
79
139
|
firstUpdated(_changedProperties) {
|
|
80
140
|
webOtpApiInit(this.renderRoot);
|
|
81
141
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
142
|
+
handleBoxClick(index) {
|
|
143
|
+
if (this.disabled) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
this.value = this.value.substring(0, index);
|
|
147
|
+
this.focus();
|
|
87
148
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
this.inputElements[index].setAttribute("placeholder", "○");
|
|
91
|
-
};
|
|
149
|
+
handleFocus() {
|
|
150
|
+
this.isFocused = true;
|
|
92
151
|
}
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
};
|
|
152
|
+
handleBlur() {
|
|
153
|
+
this.isFocused = false;
|
|
129
154
|
}
|
|
130
|
-
handleInput(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
this.dispatchEvent(
|
|
144
|
-
new Event("mid-input", { bubbles: true, composed: true })
|
|
145
|
-
);
|
|
146
|
-
};
|
|
147
|
-
}
|
|
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
|
-
|
|
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
|
-
);
|
|
184
|
-
}
|
|
185
175
|
}
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
+
}
|
|
191
185
|
}
|
|
192
186
|
clear() {
|
|
193
|
-
this.
|
|
194
|
-
this.updateValueAndEmit();
|
|
187
|
+
this.value = "";
|
|
195
188
|
}
|
|
196
189
|
focus(options) {
|
|
197
|
-
|
|
198
|
-
this.inputElements[0].focus(options);
|
|
199
|
-
}
|
|
190
|
+
this.inputElement?.focus(options);
|
|
200
191
|
}
|
|
201
192
|
handleLengthChange() {
|
|
202
|
-
this.
|
|
203
|
-
|
|
193
|
+
if (this.value.length > this.length) {
|
|
194
|
+
this.value = this.value.substring(0, this.length);
|
|
195
|
+
}
|
|
204
196
|
}
|
|
205
197
|
handleValueChange() {
|
|
206
198
|
this.setValue(this.value);
|
|
207
|
-
if (
|
|
208
|
-
|
|
209
|
-
|
|
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
|
+
);
|
|
210
209
|
}
|
|
211
|
-
this.valueVisualUpdate(this.value);
|
|
212
210
|
}
|
|
213
211
|
render() {
|
|
214
212
|
const hasLabelSlot = this.hasSlotControler.test("label");
|
|
215
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;
|
|
216
220
|
return html`
|
|
217
221
|
<label
|
|
218
222
|
id="${this.labelId}"
|
|
@@ -225,42 +229,62 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
225
229
|
</label>
|
|
226
230
|
<div
|
|
227
231
|
part="input-container"
|
|
228
|
-
class="${classMap({
|
|
232
|
+
class="input-wrapper ${classMap({
|
|
229
233
|
"text-heading-sm": this.size === "sm",
|
|
230
234
|
"text-heading-md": this.size === "md",
|
|
231
|
-
"text-heading-lg": this.size === "lg"
|
|
232
|
-
|
|
235
|
+
"text-heading-lg": this.size === "lg",
|
|
236
|
+
"opacity-disabled": this.disabled
|
|
237
|
+
})}"
|
|
238
|
+
@click=${() => this.focus()}
|
|
233
239
|
>
|
|
234
|
-
|
|
240
|
+
<div part="character-boxes" class="character-boxes">
|
|
241
|
+
${displayValues.map((char, index) => {
|
|
242
|
+
const hasCaret = this.isFocused && index === caretIndex;
|
|
235
243
|
return html`
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
border: !this.invalidmessage,
|
|
244
|
+
<div
|
|
245
|
+
part="character-box"
|
|
246
|
+
class="character-box ${classMap({
|
|
247
|
+
"border": !this.invalidmessage,
|
|
241
248
|
"border-2": this.invalidmessage,
|
|
242
249
|
"border-neutral": !this.invalidmessage,
|
|
243
250
|
"border-danger": this.invalidmessage,
|
|
244
251
|
"bg-neutral": !this.invalidmessage,
|
|
245
252
|
"bg-danger-tinted": this.invalidmessage,
|
|
246
|
-
"
|
|
247
|
-
"
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
@blur="${this.handleBlur(index)}"
|
|
261
|
-
/>
|
|
262
|
-
`;
|
|
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
|
+
`;
|
|
263
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
|
+
/>
|
|
264
288
|
</div>
|
|
265
289
|
<div
|
|
266
290
|
class="text-danger-subtle mt-2 flex gap-1"
|
|
@@ -276,10 +300,9 @@ let MinidCodeInput = class extends FormControlMixin(
|
|
|
276
300
|
`;
|
|
277
301
|
}
|
|
278
302
|
};
|
|
279
|
-
_skipValueVisualUpdate = /* @__PURE__ */ new WeakMap();
|
|
280
303
|
__decorateClass([
|
|
281
|
-
|
|
282
|
-
], MinidCodeInput.prototype, "
|
|
304
|
+
query(".hidden-input")
|
|
305
|
+
], MinidCodeInput.prototype, "inputElement", 2);
|
|
283
306
|
__decorateClass([
|
|
284
307
|
property({ reflect: true })
|
|
285
308
|
], MinidCodeInput.prototype, "value", 2);
|
|
@@ -321,7 +344,7 @@ __decorateClass([
|
|
|
321
344
|
], MinidCodeInput.prototype, "pattern", 2);
|
|
322
345
|
__decorateClass([
|
|
323
346
|
state()
|
|
324
|
-
], MinidCodeInput.prototype, "
|
|
347
|
+
], MinidCodeInput.prototype, "isFocused", 2);
|
|
325
348
|
__decorateClass([
|
|
326
349
|
watch("length")
|
|
327
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 * @method focus - Focuses the first input element\n * @method clear - Clears all input elements\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 clear() {\n this.internalValues = Array(this.length).fill('');\n this.updateValueAndEmit();\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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"}
|