@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mythpe/quasar-ui-qui",
3
- "version": "0.0.97",
3
+ "version": "0.0.98",
4
4
  "description": "MyTh Quasar UI Kit App Extension",
5
5
  "author": {
6
6
  "name": "MyTh Ahmed Faiz",
@@ -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
- export interface P {
21
- // modelValue?: Props['modelValue'];
20
+ type P = {
22
21
  inputLength?: Props['inputLength'];
23
- numeric?: Props['numeric'];
22
+ string?: Props['string'];
24
23
  time?: Props['time'];
25
- hideTime?: Props['hideTime'];
26
- hideSendAgain?: Props['hideSendAgain'];
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
- numeric: !0,
35
+ string: !1,
44
36
  time: 120,
45
- hideTime: !1,
46
- hideSendAgain: !1,
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 composite = computed(() => {
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(composite, () => {
71
- if (composite.value) {
72
- if (props.numeric !== !1) {
73
- if (!isNaN(composite.value) && composite.value?.toString()?.length?.toString() === props.inputLength.toString()) {
74
- modelValue.value = composite.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 = composite.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 (composite.value) {
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.numeric !== !1 && isNaN(value)) {
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.numeric !== !1 && evt.key && evt.key.toString() !== '0' && !parseInt(evt.key) && evt.key?.length === 1) {
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 (['Delete'].includes(key)) {
137
+ if (['delete', 'backspace'].includes(key?.toLowerCase())) {
138
138
  focus(index - 1)
139
139
  return
140
140
  }
141
141
 
142
- if (key === 'ArrowLeft' || key === 'Backspace') {
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.numeric !== !1 && isNaN(value)) {
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.hideTime) {
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('end')
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.hideTime) {
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.hideTime) {
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 onSend = () => {
214
+ const onResend = () => {
213
215
  if (disabled.value) {
214
216
  return
215
217
  }
216
- emit('send')
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
- <div>
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="!hideTime"
273
+ v-if="!noTiming"
273
274
  class="q-mt-sm"
274
275
  >
275
276
  <span>{{ __('myth.otp.expire_line') }}:&nbsp;</span>
@@ -278,13 +279,13 @@ defineOptions({
278
279
  </MFadeTransition>
279
280
  <MFadeTransition>
280
281
  <div
281
- v-if="!hideSendAgain"
282
+ v-if="!noSendAgain"
282
283
  class="q-mt-sm"
283
284
  >
284
285
  <span>{{ __('myth.otp.send_again_title') }}&nbsp;</span>
285
286
  <span
286
287
  :class="{'text-decoration-underline':!0, disabled,'cursor-pointer': !disabled}"
287
- @click="onSend()"
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
- modelValue?: string | number;
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
- numeric?: boolean;
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
- hideTime?: boolean;
570
- hideSendAgain?: boolean;
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
  }