@mythpe/quasar-ui-qui 0.0.97 → 0.0.98
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.
- package/package.json +1 -1
- package/src/components/form/MOtp.vue +50 -49
- package/src/types/components.d.ts +28 -4
package/package.json
CHANGED
|
@@ -17,13 +17,12 @@ import { date } from 'quasar'
|
|
|
17
17
|
import type { MOtpProps as Props } from '../../types'
|
|
18
18
|
import { useMyth } from '../../composable'
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
// modelValue?: Props['modelValue'];
|
|
20
|
+
type P = {
|
|
22
21
|
inputLength?: Props['inputLength'];
|
|
23
|
-
|
|
22
|
+
string?: Props['string'];
|
|
24
23
|
time?: Props['time'];
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
noTiming?: Props['noTiming'];
|
|
25
|
+
noSendAgain?: Props['noSendAgain'];
|
|
27
26
|
topLabel?: Props['topLabel'];
|
|
28
27
|
topLabelProps?: Props['topLabelProps'];
|
|
29
28
|
autofocus?: Props['autofocus'];
|
|
@@ -31,25 +30,26 @@ export interface P {
|
|
|
31
30
|
type?: Props['type'];
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
type Emits = {
|
|
35
|
-
(e: 'end'): void;
|
|
36
|
-
(e: 'send'): void;
|
|
37
|
-
}
|
|
38
|
-
const emit = defineEmits<Emits>()
|
|
39
|
-
const { __, props: pluginOptions } = useMyth()
|
|
40
33
|
const props = withDefaults(defineProps<P>(), {
|
|
41
|
-
// modelValue: undefined,
|
|
42
34
|
inputLength: 4,
|
|
43
|
-
|
|
35
|
+
string: !1,
|
|
44
36
|
time: 120,
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
noTiming: !1,
|
|
38
|
+
noSendAgain: !1,
|
|
47
39
|
topLabel: undefined,
|
|
48
40
|
topLabelProps: undefined,
|
|
49
41
|
autofocus: !1,
|
|
50
42
|
errors: () => ([]),
|
|
51
43
|
type: 'tel'
|
|
52
44
|
})
|
|
45
|
+
type Func = () => void;
|
|
46
|
+
type Emits = {
|
|
47
|
+
(e: 'countdown', options: { start: Func, clear: Func, startTiming: Func }): void;
|
|
48
|
+
(e: 'resend', options: { start: Func, clear: Func, startTiming: Func }): void;
|
|
49
|
+
}
|
|
50
|
+
const emit = defineEmits<Emits>()
|
|
51
|
+
|
|
52
|
+
const { __, props: pluginOptions } = useMyth()
|
|
53
53
|
const modelValue = defineModel<Props['modelValue']>({ required: !1, default: undefined })
|
|
54
54
|
const otpErrors = computed(() => props.errors ? props.errors : [])
|
|
55
55
|
const length = computed<number>(() => parseInt(props.inputLength?.toString() || '0'))
|
|
@@ -59,22 +59,23 @@ watchEffect(() => {
|
|
|
59
59
|
fieldValues.value = (modelValue.value || '').toString().split('').slice(0, length.value)
|
|
60
60
|
})
|
|
61
61
|
|
|
62
|
-
const
|
|
63
|
-
const nonNullFields = fieldValues.value.filter(v => (v || v?.toString() !== '0'))
|
|
62
|
+
const inputValue = computed(() => {
|
|
63
|
+
// const nonNullFields = fieldValues.value.filter(v => (v || v?.toString() !== '0'))
|
|
64
|
+
const nonNullFields = fieldValues.value.filter(v => (v === 0 || v === '0') || ((v?.toString?.()?.length || 0) > 0))
|
|
64
65
|
if (length.value !== nonNullFields.length) {
|
|
65
66
|
return ''
|
|
66
67
|
}
|
|
67
68
|
return nonNullFields.join('')
|
|
68
69
|
})
|
|
69
70
|
|
|
70
|
-
watch(
|
|
71
|
-
if (
|
|
72
|
-
if (props.
|
|
73
|
-
if (!isNaN(
|
|
74
|
-
modelValue.value =
|
|
71
|
+
watch(inputValue, (v) => {
|
|
72
|
+
if (v) {
|
|
73
|
+
if (props.string) {
|
|
74
|
+
if (!isNaN(v) && v?.toString?.()?.length?.toString?.() === props.inputLength.toString()) {
|
|
75
|
+
modelValue.value = v
|
|
75
76
|
}
|
|
76
77
|
} else {
|
|
77
|
-
modelValue.value =
|
|
78
|
+
modelValue.value = v
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
})
|
|
@@ -95,12 +96,15 @@ const focus = (index: number) => {
|
|
|
95
96
|
if (index < length.value) {
|
|
96
97
|
fields.value[index]?.select()
|
|
97
98
|
} else {
|
|
98
|
-
if (
|
|
99
|
+
if (inputValue.value) {
|
|
99
100
|
fields.value[index - 1]?.blur()
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
}
|
|
105
|
+
const select = (index: number) => {
|
|
106
|
+
fields.value[index]?.select()
|
|
107
|
+
}
|
|
104
108
|
|
|
105
109
|
const blur = (index: number) => {
|
|
106
110
|
fields.value[index]?.blur()
|
|
@@ -108,12 +112,8 @@ const blur = (index: number) => {
|
|
|
108
112
|
|
|
109
113
|
const onUpdate = (value: string | number | null, index: number) => {
|
|
110
114
|
if (value) {
|
|
111
|
-
if (props.
|
|
112
|
-
nextTick(() =>
|
|
113
|
-
setTimeout(() => {
|
|
114
|
-
focus(index)
|
|
115
|
-
}, 100)
|
|
116
|
-
})
|
|
115
|
+
if (props.string && isNaN(value)) {
|
|
116
|
+
nextTick(() => setTimeout(() => focus(index), 100))
|
|
117
117
|
return
|
|
118
118
|
}
|
|
119
119
|
focus(index + 1)
|
|
@@ -124,7 +124,7 @@ const onUpdate = (value: string | number | null, index: number) => {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
const onKeyDown = (evt: KeyboardEvent/*, index: number */) => {
|
|
127
|
-
if (props.
|
|
127
|
+
if (props.string && evt.key && evt.key.toString() !== '0' && !parseInt(evt.key) && evt.key?.length === 1) {
|
|
128
128
|
evt.preventDefault()
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -134,12 +134,12 @@ const onKeyUp = (evt: KeyboardEvent, index: number) => {
|
|
|
134
134
|
return
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
if (['
|
|
137
|
+
if (['delete', 'backspace'].includes(key?.toLowerCase())) {
|
|
138
138
|
focus(index - 1)
|
|
139
139
|
return
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
if (key === 'ArrowLeft'
|
|
142
|
+
if (key === 'ArrowLeft') {
|
|
143
143
|
focus(index - 1)
|
|
144
144
|
} else if (key === 'ArrowRight') {
|
|
145
145
|
focus(index + 1)
|
|
@@ -155,7 +155,7 @@ const onKeyUp = (evt: KeyboardEvent, index: number) => {
|
|
|
155
155
|
}
|
|
156
156
|
const onPaste = (evt: ClipboardEvent, index: number) => {
|
|
157
157
|
const value: any = evt.clipboardData?.getData('text')?.toString() || ''
|
|
158
|
-
if (props.
|
|
158
|
+
if (props.string && isNaN(value)) {
|
|
159
159
|
evt.preventDefault()
|
|
160
160
|
return
|
|
161
161
|
}
|
|
@@ -164,25 +164,28 @@ const onPaste = (evt: ClipboardEvent, index: number) => {
|
|
|
164
164
|
blur(index)
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
|
-
|
|
167
|
+
const onFocusIn = (evt: FocusEvent, index: number) => {
|
|
168
|
+
select(index)
|
|
169
|
+
}
|
|
168
170
|
const seconds = ref<number>(0)
|
|
169
171
|
const temp = ref<number>(0)
|
|
172
|
+
let interval: ReturnType<typeof setInterval> | null = null
|
|
170
173
|
watch(() => seconds.value, v => (temp.value = v))
|
|
171
174
|
const startTiming = () => {
|
|
172
|
-
if (props.
|
|
175
|
+
if (props.noTiming) {
|
|
173
176
|
return
|
|
174
177
|
}
|
|
175
178
|
|
|
176
179
|
if (seconds.value > 0) {
|
|
177
180
|
--seconds.value
|
|
178
181
|
if (!seconds.value) {
|
|
179
|
-
emit('
|
|
182
|
+
emit('countdown', { start, clear, startTiming })
|
|
180
183
|
}
|
|
181
184
|
}
|
|
182
185
|
}
|
|
183
186
|
const getTime = computed<string | null>(() => {
|
|
184
187
|
const nullValue = null
|
|
185
|
-
if (props.
|
|
188
|
+
if (props.noTiming) {
|
|
186
189
|
return nullValue
|
|
187
190
|
}
|
|
188
191
|
if (seconds.value < 1) {
|
|
@@ -195,12 +198,11 @@ const getTime = computed<string | null>(() => {
|
|
|
195
198
|
return `${(m < 9 ? '0' : '') + m}:${(s < 9 ? '0' : '') + s}`
|
|
196
199
|
})
|
|
197
200
|
const disabled = computed(() => seconds.value > 0)
|
|
198
|
-
let interval: any = null
|
|
199
201
|
const clear = () => {
|
|
200
202
|
interval && clearInterval(interval)
|
|
201
203
|
}
|
|
202
204
|
const start = () => {
|
|
203
|
-
if (props.
|
|
205
|
+
if (props.noTiming) {
|
|
204
206
|
return
|
|
205
207
|
}
|
|
206
208
|
clear()
|
|
@@ -209,13 +211,13 @@ const start = () => {
|
|
|
209
211
|
}
|
|
210
212
|
watch(() => props.time, () => start(), { immediate: !0, deep: !0 })
|
|
211
213
|
onBeforeUnmount(() => clear())
|
|
212
|
-
const
|
|
214
|
+
const onResend = () => {
|
|
213
215
|
if (disabled.value) {
|
|
214
216
|
return
|
|
215
217
|
}
|
|
216
|
-
emit('
|
|
218
|
+
emit('resend', { start, clear, startTiming })
|
|
217
219
|
}
|
|
218
|
-
defineExpose({ start })
|
|
220
|
+
defineExpose({ start, clear, startTiming, inputValue })
|
|
219
221
|
defineOptions({
|
|
220
222
|
name: 'MOtp',
|
|
221
223
|
inheritAttrs: !1
|
|
@@ -234,9 +236,7 @@ defineOptions({
|
|
|
234
236
|
class="justify-start q-mb-md text-body1"
|
|
235
237
|
v-bind="topLabelProps"
|
|
236
238
|
>
|
|
237
|
-
|
|
238
|
-
{{ __(topLabel) }}
|
|
239
|
-
</div>
|
|
239
|
+
{{ __(topLabel) }}
|
|
240
240
|
</MRow>
|
|
241
241
|
<div :class="`row ${$q.lang.rtl ? 'reverse' : ''} q-gutter-x-sm justify-center`">
|
|
242
242
|
<q-input
|
|
@@ -254,6 +254,7 @@ defineOptions({
|
|
|
254
254
|
outlined
|
|
255
255
|
style="width: 6ch"
|
|
256
256
|
v-bind="{...pluginOptions.otp as any,...$attrs}"
|
|
257
|
+
@focusin="onFocusIn($event, i - 1)"
|
|
257
258
|
@keydown="onKeyDown($event)"
|
|
258
259
|
@keyup="onKeyUp($event, i - 1)"
|
|
259
260
|
@paste.prevent="onPaste($event,i - 1)"
|
|
@@ -269,7 +270,7 @@ defineOptions({
|
|
|
269
270
|
<slot name="after-input" />
|
|
270
271
|
<MFadeTransition>
|
|
271
272
|
<div
|
|
272
|
-
v-if="!
|
|
273
|
+
v-if="!noTiming"
|
|
273
274
|
class="q-mt-sm"
|
|
274
275
|
>
|
|
275
276
|
<span>{{ __('myth.otp.expire_line') }}: </span>
|
|
@@ -278,13 +279,13 @@ defineOptions({
|
|
|
278
279
|
</MFadeTransition>
|
|
279
280
|
<MFadeTransition>
|
|
280
281
|
<div
|
|
281
|
-
v-if="!
|
|
282
|
+
v-if="!noSendAgain"
|
|
282
283
|
class="q-mt-sm"
|
|
283
284
|
>
|
|
284
285
|
<span>{{ __('myth.otp.send_again_title') }} </span>
|
|
285
286
|
<span
|
|
286
287
|
:class="{'text-decoration-underline':!0, disabled,'cursor-pointer': !disabled}"
|
|
287
|
-
@click="
|
|
288
|
+
@click="onResend()"
|
|
288
289
|
>{{ __('myth.otp.send_again_btn') }}</span>
|
|
289
290
|
</div>
|
|
290
291
|
</MFadeTransition>
|
|
@@ -562,13 +562,37 @@ export type MOptionsProps = Omit<QOptionGroupProps, 'name' | 'modelValue' | 'opt
|
|
|
562
562
|
}
|
|
563
563
|
|
|
564
564
|
export type MOtpProps = Omit<QInputProps, 'modelValue'> & {
|
|
565
|
-
|
|
565
|
+
/**
|
|
566
|
+
* Value of input after typing all inputs.
|
|
567
|
+
*/
|
|
568
|
+
modelValue?: any;
|
|
569
|
+
/**
|
|
570
|
+
* Length of inputs.
|
|
571
|
+
*/
|
|
566
572
|
inputLength?: string | number;
|
|
567
|
-
|
|
573
|
+
/**
|
|
574
|
+
* Values is string not number.
|
|
575
|
+
*/
|
|
576
|
+
string?: boolean;
|
|
577
|
+
/**
|
|
578
|
+
* Resend time countdown in seconds.
|
|
579
|
+
*/
|
|
568
580
|
time?: string | number;
|
|
569
|
-
|
|
570
|
-
|
|
581
|
+
/**
|
|
582
|
+
* Don't use timing to resend code.
|
|
583
|
+
*/
|
|
584
|
+
noTiming?: boolean;
|
|
585
|
+
/**
|
|
586
|
+
* Don't use send again button.
|
|
587
|
+
*/
|
|
588
|
+
noSendAgain?: boolean;
|
|
589
|
+
/**
|
|
590
|
+
* Top input label.
|
|
591
|
+
*/
|
|
571
592
|
topLabel?: string | undefined;
|
|
593
|
+
/**
|
|
594
|
+
* Top input props.
|
|
595
|
+
*/
|
|
572
596
|
topLabelProps?: any | undefined;
|
|
573
597
|
errors?: string[];
|
|
574
598
|
}
|