sprintify-ui 0.12.12 → 0.12.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { PropType } from 'vue';
|
|
2
|
+
import { Size } from '@/utils/sizes';
|
|
3
|
+
declare function focusAction(): void;
|
|
4
|
+
declare function clearAction(): void;
|
|
2
5
|
declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
3
6
|
modelValue: {
|
|
4
7
|
required: true;
|
|
@@ -12,7 +15,30 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
12
15
|
default: string;
|
|
13
16
|
type: PropType<"numeric" | "alphanumeric">;
|
|
14
17
|
};
|
|
15
|
-
|
|
18
|
+
size: {
|
|
19
|
+
default: string;
|
|
20
|
+
type: PropType<Size>;
|
|
21
|
+
};
|
|
22
|
+
hasError: {
|
|
23
|
+
default: boolean;
|
|
24
|
+
type: BooleanConstructor;
|
|
25
|
+
};
|
|
26
|
+
disabled: {
|
|
27
|
+
default: boolean;
|
|
28
|
+
type: BooleanConstructor;
|
|
29
|
+
};
|
|
30
|
+
autofocus: {
|
|
31
|
+
default: boolean;
|
|
32
|
+
type: BooleanConstructor;
|
|
33
|
+
};
|
|
34
|
+
class: {
|
|
35
|
+
default: string;
|
|
36
|
+
type: PropType<string | string[]>;
|
|
37
|
+
};
|
|
38
|
+
}>, {
|
|
39
|
+
focus: typeof focusAction;
|
|
40
|
+
clear: typeof clearAction;
|
|
41
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
16
42
|
"update:modelValue": (...args: any[]) => void;
|
|
17
43
|
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
18
44
|
modelValue: {
|
|
@@ -27,9 +53,34 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
27
53
|
default: string;
|
|
28
54
|
type: PropType<"numeric" | "alphanumeric">;
|
|
29
55
|
};
|
|
56
|
+
size: {
|
|
57
|
+
default: string;
|
|
58
|
+
type: PropType<Size>;
|
|
59
|
+
};
|
|
60
|
+
hasError: {
|
|
61
|
+
default: boolean;
|
|
62
|
+
type: BooleanConstructor;
|
|
63
|
+
};
|
|
64
|
+
disabled: {
|
|
65
|
+
default: boolean;
|
|
66
|
+
type: BooleanConstructor;
|
|
67
|
+
};
|
|
68
|
+
autofocus: {
|
|
69
|
+
default: boolean;
|
|
70
|
+
type: BooleanConstructor;
|
|
71
|
+
};
|
|
72
|
+
class: {
|
|
73
|
+
default: string;
|
|
74
|
+
type: PropType<string | string[]>;
|
|
75
|
+
};
|
|
30
76
|
}>> & Readonly<{
|
|
31
77
|
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
32
78
|
}>, {
|
|
79
|
+
class: string | string[];
|
|
33
80
|
type: "numeric" | "alphanumeric";
|
|
81
|
+
size: "xs" | "sm" | "md" | "lg" | "xl";
|
|
82
|
+
disabled: boolean;
|
|
83
|
+
hasError: boolean;
|
|
84
|
+
autofocus: boolean;
|
|
34
85
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
35
86
|
export default _default;
|
package/package.json
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import { BaseUniqueCode } from "."
|
|
2
2
|
import ShowValue from "@/../.storybook/components/ShowValue.vue";
|
|
3
|
+
import { sizes } from "../../.storybook/utils";
|
|
3
4
|
|
|
4
5
|
export default {
|
|
5
6
|
title: "Form/BaseUniqueCode",
|
|
6
7
|
component: BaseUniqueCode,
|
|
8
|
+
args: {
|
|
9
|
+
numberOfCharacters: 4,
|
|
10
|
+
autofocus: false,
|
|
11
|
+
},
|
|
7
12
|
argTypes: {
|
|
8
13
|
type: {
|
|
9
14
|
control: { type: "select" },
|
|
10
15
|
options: ["numeric", "alphanumeric"],
|
|
11
16
|
},
|
|
17
|
+
size: {
|
|
18
|
+
control: { type: "select" },
|
|
19
|
+
options: sizes,
|
|
20
|
+
},
|
|
12
21
|
},
|
|
13
22
|
};
|
|
14
23
|
|
|
@@ -19,18 +28,76 @@ const Template = (args) => ({
|
|
|
19
28
|
return { args, value };
|
|
20
29
|
},
|
|
21
30
|
template: `
|
|
22
|
-
<BaseUniqueCode v-model="value" v-bind="args"
|
|
31
|
+
<BaseUniqueCode v-model="value" v-bind="args"></BaseUniqueCode>
|
|
23
32
|
<ShowValue :value="value" />
|
|
24
33
|
`,
|
|
25
34
|
});
|
|
26
35
|
|
|
27
36
|
export const Numeric = Template.bind({});
|
|
28
|
-
Numeric.args = {
|
|
29
|
-
numberOfCharacters: 4,
|
|
30
|
-
};
|
|
31
37
|
|
|
32
38
|
export const Alphanumeric = Template.bind({});
|
|
33
39
|
Alphanumeric.args = {
|
|
34
|
-
|
|
35
|
-
type: "text",
|
|
40
|
+
type: "alphanumeric",
|
|
36
41
|
};
|
|
42
|
+
|
|
43
|
+
export const SixCharacters = Template.bind({});
|
|
44
|
+
SixCharacters.args = {
|
|
45
|
+
numberOfCharacters: 6,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const Prefilled = Template.bind({});
|
|
49
|
+
Prefilled.args = {
|
|
50
|
+
modelValue: "1234",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const Error = Template.bind({});
|
|
54
|
+
Error.args = {
|
|
55
|
+
hasError: true,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Disabled = Template.bind({});
|
|
59
|
+
Disabled.args = {
|
|
60
|
+
modelValue: "12",
|
|
61
|
+
disabled: true,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const Autofocus = Template.bind({});
|
|
65
|
+
Autofocus.args = {
|
|
66
|
+
autofocus: true,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const TemplateSizes = (args) => ({
|
|
70
|
+
components: { BaseUniqueCode },
|
|
71
|
+
setup() {
|
|
72
|
+
const value = ref("");
|
|
73
|
+
return { args, value, sizes };
|
|
74
|
+
},
|
|
75
|
+
template: `
|
|
76
|
+
<div v-for="size in sizes" :key="size" class="mb-4">
|
|
77
|
+
<p class="text-xs text-slate-600 leading-tight mb-1">{{ size }}</p>
|
|
78
|
+
<BaseUniqueCode v-model="value" v-bind="args" :size="size"></BaseUniqueCode>
|
|
79
|
+
</div>
|
|
80
|
+
`,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
export const Sizes = TemplateSizes.bind({});
|
|
84
|
+
|
|
85
|
+
const FocusAndClearTemplate = (args) => ({
|
|
86
|
+
components: { BaseUniqueCode, ShowValue },
|
|
87
|
+
setup() {
|
|
88
|
+
const value = ref("");
|
|
89
|
+
const input = ref(null);
|
|
90
|
+
return { args, value, input };
|
|
91
|
+
},
|
|
92
|
+
template: `
|
|
93
|
+
<BaseUniqueCode ref="input" v-model="value" v-bind="args"></BaseUniqueCode>
|
|
94
|
+
<ShowValue :value="value" />
|
|
95
|
+
|
|
96
|
+
<div class="mt-4 flex gap-2">
|
|
97
|
+
<button @click="input.focus()" class="btn btn-sm">Focus</button>
|
|
98
|
+
<button @click="input.clear()" class="btn btn-sm">Clear</button>
|
|
99
|
+
</div>
|
|
100
|
+
`,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
export const FocusAndClear = FocusAndClearTemplate.bind({});
|
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div>
|
|
2
|
+
<div :class="classes">
|
|
3
3
|
<input
|
|
4
|
-
v-for="index in
|
|
4
|
+
v-for="index in numberOfCharacters"
|
|
5
5
|
:key="index"
|
|
6
|
-
ref="
|
|
7
|
-
|
|
8
|
-
text-4xl font-normal text-gray-700 text-center p-0 m-0 mx-2 outline-none
|
|
9
|
-
duration-200 focus:outline-none focus:shadow-none focus:border-b-primary-500 focus:ring-0"
|
|
6
|
+
:ref="(el) => setInputRef(el, index - 1)"
|
|
7
|
+
:value="characters[index - 1] || ''"
|
|
10
8
|
type="text"
|
|
11
9
|
maxlength="1"
|
|
12
10
|
:pattern="pattern"
|
|
13
|
-
:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
:inputmode="type === 'numeric' ? 'numeric' : 'text'"
|
|
12
|
+
:autocomplete="index === 1 ? 'one-time-code' : 'off'"
|
|
13
|
+
:disabled="disabled"
|
|
14
|
+
:class="cellClasses"
|
|
15
|
+
@input="onInput(index - 1, $event)"
|
|
16
|
+
@paste="onPaste(index - 1, $event)"
|
|
17
|
+
@keydown="onKeydown(index - 1, $event)"
|
|
18
|
+
@focus="onFocus($event)"
|
|
17
19
|
>
|
|
18
20
|
</div>
|
|
19
21
|
</template>
|
|
20
22
|
|
|
21
23
|
<script setup lang="ts">
|
|
22
|
-
import {
|
|
24
|
+
import { computed, nextTick, onMounted, PropType, ref, watch } from 'vue';
|
|
25
|
+
import { Size } from '@/utils/sizes';
|
|
26
|
+
import { twMerge } from 'tailwind-merge';
|
|
23
27
|
|
|
24
28
|
const props = defineProps({
|
|
25
29
|
modelValue: {
|
|
@@ -31,153 +35,224 @@ const props = defineProps({
|
|
|
31
35
|
type: Number,
|
|
32
36
|
},
|
|
33
37
|
type: {
|
|
34
|
-
default:
|
|
38
|
+
default: 'numeric',
|
|
35
39
|
type: String as PropType<'numeric' | 'alphanumeric'>,
|
|
36
|
-
}
|
|
40
|
+
},
|
|
41
|
+
size: {
|
|
42
|
+
default: 'md',
|
|
43
|
+
type: String as PropType<Size>,
|
|
44
|
+
},
|
|
45
|
+
hasError: {
|
|
46
|
+
default: false,
|
|
47
|
+
type: Boolean,
|
|
48
|
+
},
|
|
49
|
+
disabled: {
|
|
50
|
+
default: false,
|
|
51
|
+
type: Boolean,
|
|
52
|
+
},
|
|
53
|
+
autofocus: {
|
|
54
|
+
default: true,
|
|
55
|
+
type: Boolean,
|
|
56
|
+
},
|
|
57
|
+
class: {
|
|
58
|
+
default: '',
|
|
59
|
+
type: [String, Array] as PropType<string | string[]>,
|
|
60
|
+
},
|
|
37
61
|
});
|
|
38
62
|
|
|
39
63
|
const emit = defineEmits(['update:modelValue']);
|
|
40
64
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
return "[A-Za-z0-9]+";
|
|
44
|
-
}
|
|
65
|
+
const codeInputs = ref<(HTMLInputElement | null)[]>([]);
|
|
66
|
+
const characters = ref<string[]>(Array(props.numberOfCharacters).fill(''));
|
|
45
67
|
|
|
46
|
-
|
|
47
|
-
})
|
|
68
|
+
const code = computed(() => characters.value.join(''));
|
|
48
69
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
70
|
+
const characterPattern = computed(() =>
|
|
71
|
+
props.type === 'alphanumeric' ? /^[A-Za-z0-9]$/ : /^[0-9]$/
|
|
72
|
+
);
|
|
52
73
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
const pattern = computed(() =>
|
|
75
|
+
props.type === 'alphanumeric' ? '[A-Za-z0-9]+' : '[0-9]*'
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const sizeClasses: Record<Size, string> = {
|
|
79
|
+
xs: 'h-8 w-7 rounded-md text-sm',
|
|
80
|
+
sm: 'h-10 w-8 rounded-md text-base',
|
|
81
|
+
md: 'h-12 w-10 rounded-lg text-xl',
|
|
82
|
+
lg: 'h-14 w-12 rounded-xl text-2xl',
|
|
83
|
+
xl: 'h-16 w-14 rounded-xl text-3xl',
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const classes = computed(() =>
|
|
87
|
+
twMerge(['flex items-center gap-2', props.class])
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const cellClasses = computed(() =>
|
|
91
|
+
twMerge([
|
|
92
|
+
'border bg-slate-50 p-0 text-center font-semibold text-slate-900 shadow-sm outline-none transition-all',
|
|
93
|
+
'focus:bg-white focus:outline-none focus:ring-4',
|
|
94
|
+
sizeClasses[props.size],
|
|
95
|
+
props.hasError
|
|
96
|
+
? 'border-red-300 focus:border-red-500 focus:ring-red-100'
|
|
97
|
+
: 'border-slate-200 focus:border-primary-500 focus:ring-primary-100',
|
|
98
|
+
props.disabled ? 'cursor-not-allowed opacity-50' : '',
|
|
99
|
+
])
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
watch(code, (value) => {
|
|
103
|
+
if (value !== normalizedModelValue()) {
|
|
104
|
+
emit('update:modelValue', value);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
56
107
|
|
|
57
108
|
watch(
|
|
58
|
-
() =>
|
|
109
|
+
() => props.modelValue,
|
|
59
110
|
() => {
|
|
60
|
-
|
|
111
|
+
const value = normalizedModelValue();
|
|
112
|
+
|
|
113
|
+
if (value !== code.value) {
|
|
114
|
+
setCharacters(value);
|
|
115
|
+
}
|
|
61
116
|
},
|
|
62
117
|
{ immediate: true }
|
|
63
118
|
);
|
|
64
119
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
120
|
+
function normalizedModelValue(): string {
|
|
121
|
+
return String(props.modelValue ?? '');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function setCharacters(value: string) {
|
|
125
|
+
const valid = filterValidCharacters(value);
|
|
71
126
|
|
|
72
|
-
|
|
73
|
-
|
|
127
|
+
characters.value = Array.from(
|
|
128
|
+
{ length: props.numberOfCharacters },
|
|
129
|
+
(_, index) => valid[index] || ''
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function filterValidCharacters(value: string): string[] {
|
|
134
|
+
return value.split('').filter((char) => characterPattern.value.test(char));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function setInputRef(el: unknown, index: number) {
|
|
138
|
+
codeInputs.value[index] = el as HTMLInputElement | null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function onInput(index: number, event: Event) {
|
|
74
142
|
const input = event.target as HTMLInputElement;
|
|
75
|
-
|
|
143
|
+
const value = input.value;
|
|
76
144
|
|
|
77
|
-
|
|
145
|
+
// Autofill (e.g. iOS one-time-code) can inject the full code into one input
|
|
146
|
+
if (value.length > 1) {
|
|
147
|
+
fillFrom(index, value);
|
|
148
|
+
input.value = characters.value[index] || '';
|
|
78
149
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const inputValue = parseInt(input.value);
|
|
82
|
-
if (isNaN(inputValue) || inputValue < 0 || inputValue > 9) {
|
|
83
|
-
input.value = '';
|
|
84
|
-
uniqueCode.value[index] = '';
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
85
152
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
153
|
+
if (value && !characterPattern.value.test(value)) {
|
|
154
|
+
input.value = characters.value[index] || '';
|
|
89
155
|
|
|
90
|
-
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
91
158
|
|
|
92
|
-
|
|
93
|
-
codeInputs.value[nextIndex - 1]?.focus();
|
|
94
|
-
}
|
|
159
|
+
characters.value[index] = value;
|
|
95
160
|
|
|
96
|
-
|
|
161
|
+
if (value) {
|
|
162
|
+
focusIndex(index + 1);
|
|
97
163
|
}
|
|
98
|
-
}
|
|
164
|
+
}
|
|
99
165
|
|
|
100
|
-
|
|
101
|
-
function handleCodeKeyDown(index: number, event: KeyboardEvent) {
|
|
166
|
+
function onKeydown(index: number, event: KeyboardEvent) {
|
|
102
167
|
const input = event.target as HTMLInputElement;
|
|
103
|
-
const allowedKeys = props.type === 'alphanumeric' ? /^[A-Za-z0-9]$/ : /^[0-9]$/;
|
|
104
168
|
|
|
105
|
-
if (
|
|
169
|
+
if (event.key === 'Backspace') {
|
|
170
|
+
event.preventDefault();
|
|
171
|
+
|
|
172
|
+
if (characters.value[index]) {
|
|
173
|
+
characters.value[index] = '';
|
|
174
|
+
} else if (index > 0) {
|
|
175
|
+
characters.value[index - 1] = '';
|
|
176
|
+
focusIndex(index - 1);
|
|
177
|
+
}
|
|
178
|
+
|
|
106
179
|
return;
|
|
107
180
|
}
|
|
108
181
|
|
|
109
|
-
if (
|
|
182
|
+
if (event.key === 'ArrowLeft') {
|
|
183
|
+
event.preventDefault();
|
|
184
|
+
focusIndex(index - 1);
|
|
185
|
+
|
|
110
186
|
return;
|
|
111
187
|
}
|
|
112
188
|
|
|
113
|
-
|
|
189
|
+
if (event.key === 'ArrowRight') {
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
focusIndex(index + 1);
|
|
114
192
|
|
|
115
|
-
|
|
116
|
-
if (index > 0 && index <= props.numberOfCharacters) {
|
|
117
|
-
|
|
118
|
-
if (input.value) {
|
|
119
|
-
input.value = '';
|
|
120
|
-
uniqueCode.value[index] = '';
|
|
121
|
-
updateFormCode();
|
|
122
|
-
} else {
|
|
123
|
-
setTimeout(() => {
|
|
124
|
-
codeInputs.value[prvIndex.value - 1]?.focus();
|
|
125
|
-
uniqueCode.value[prvIndex.value] = '';
|
|
126
|
-
updateFormCode();
|
|
127
|
-
}, 10);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
} else if (event.key === 'ArrowRight') {
|
|
131
|
-
codeInputs.value[index]?.focus();
|
|
132
|
-
} else if (event.key === 'ArrowLeft') {
|
|
133
|
-
codeInputs.value[prvIndex.value - 1]?.focus();
|
|
134
|
-
} else if (allowedKeys.test(event.key)) {
|
|
135
|
-
uniqueCode.value[index] = '';
|
|
193
|
+
return;
|
|
136
194
|
}
|
|
137
|
-
}
|
|
138
195
|
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
196
|
+
// Typing over a filled cell replaces its character
|
|
197
|
+
if (
|
|
198
|
+
characterPattern.value.test(event.key) &&
|
|
199
|
+
!event.metaKey &&
|
|
200
|
+
!event.ctrlKey &&
|
|
201
|
+
!event.altKey
|
|
202
|
+
) {
|
|
203
|
+
input.value = '';
|
|
204
|
+
}
|
|
142
205
|
}
|
|
143
206
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
207
|
+
function onPaste(index: number, event: ClipboardEvent) {
|
|
208
|
+
event.preventDefault();
|
|
209
|
+
|
|
210
|
+
const pasted = event.clipboardData?.getData('text/plain') || '';
|
|
211
|
+
const startIndex = filterValidCharacters(pasted).length >= props.numberOfCharacters ? 0 : index;
|
|
212
|
+
|
|
213
|
+
fillFrom(startIndex, pasted);
|
|
214
|
+
}
|
|
147
215
|
|
|
148
|
-
|
|
216
|
+
function fillFrom(startIndex: number, value: string) {
|
|
217
|
+
const valid = filterValidCharacters(value);
|
|
149
218
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
} else {
|
|
153
|
-
data = pastedData.split('').filter((char) => !isNaN(Number(char)));
|
|
219
|
+
for (let i = 0; i < valid.length && startIndex + i < props.numberOfCharacters; i++) {
|
|
220
|
+
characters.value[startIndex + i] = valid[i];
|
|
154
221
|
}
|
|
155
222
|
|
|
156
|
-
|
|
157
|
-
|
|
223
|
+
focusIndex(startIndex + valid.length);
|
|
224
|
+
}
|
|
158
225
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
226
|
+
function onFocus(event: FocusEvent) {
|
|
227
|
+
(event.target as HTMLInputElement).select();
|
|
228
|
+
}
|
|
163
229
|
|
|
164
|
-
|
|
165
|
-
|
|
230
|
+
function focusIndex(index: number) {
|
|
231
|
+
const clamped = Math.min(Math.max(index, 0), props.numberOfCharacters - 1);
|
|
166
232
|
|
|
167
|
-
|
|
168
|
-
}
|
|
233
|
+
codeInputs.value[clamped]?.focus();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function focusAction() {
|
|
237
|
+
const firstEmpty = characters.value.findIndex((char) => !char);
|
|
238
|
+
|
|
239
|
+
focusIndex(firstEmpty === -1 ? props.numberOfCharacters - 1 : firstEmpty);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function clearAction() {
|
|
243
|
+
characters.value = Array(props.numberOfCharacters).fill('');
|
|
244
|
+
}
|
|
169
245
|
|
|
170
|
-
// Focus the first input on component mount
|
|
171
246
|
onMounted(async () => {
|
|
172
247
|
await nextTick();
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
(
|
|
176
|
-
);
|
|
177
|
-
const firstInput = codeInputs.value[0];
|
|
178
|
-
if (firstInput !== null) {
|
|
179
|
-
firstInput.focus();
|
|
248
|
+
|
|
249
|
+
if (props.autofocus && !props.disabled) {
|
|
250
|
+
focusAction();
|
|
180
251
|
}
|
|
181
252
|
});
|
|
182
253
|
|
|
254
|
+
defineExpose({
|
|
255
|
+
focus: focusAction,
|
|
256
|
+
clear: clearAction,
|
|
257
|
+
});
|
|
183
258
|
</script>
|