@mythpe/quasar-ui-qui 0.0.96 → 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.96",
3
+ "version": "0.0.98",
4
4
  "description": "MyTh Quasar UI Kit App Extension",
5
5
  "author": {
6
6
  "name": "MyTh Ahmed Faiz",
@@ -17,37 +17,39 @@ 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'];
30
29
  errors?: Props['errors'];
30
+ type?: Props['type'];
31
31
  }
32
32
 
33
- type Emits = {
34
- (e: 'end'): void;
35
- (e: 'send'): void;
36
- }
37
- const emit = defineEmits<Emits>()
38
- const { __, props: pluginOptions } = useMyth()
39
33
  const props = withDefaults(defineProps<P>(), {
40
- // modelValue: undefined,
41
- inputLength: () => 6,
42
- numeric: () => !0,
43
- time: () => 120,
44
- hideTime: () => !1,
45
- hideSendAgain: () => !1,
34
+ inputLength: 4,
35
+ string: !1,
36
+ time: 120,
37
+ noTiming: !1,
38
+ noSendAgain: !1,
46
39
  topLabel: undefined,
47
40
  topLabelProps: undefined,
48
- autofocus: () => !1,
49
- errors: () => ([])
41
+ autofocus: !1,
42
+ errors: () => ([]),
43
+ type: 'tel'
50
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()
51
53
  const modelValue = defineModel<Props['modelValue']>({ required: !1, default: undefined })
52
54
  const otpErrors = computed(() => props.errors ? props.errors : [])
53
55
  const length = computed<number>(() => parseInt(props.inputLength?.toString() || '0'))
@@ -57,22 +59,23 @@ watchEffect(() => {
57
59
  fieldValues.value = (modelValue.value || '').toString().split('').slice(0, length.value)
58
60
  })
59
61
 
60
- const composite = computed(() => {
61
- 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))
62
65
  if (length.value !== nonNullFields.length) {
63
66
  return ''
64
67
  }
65
68
  return nonNullFields.join('')
66
69
  })
67
70
 
68
- watch(composite, () => {
69
- if (composite.value) {
70
- if (props.numeric !== !1) {
71
- if (!isNaN(composite.value) && composite.value?.toString()?.length?.toString() === props.inputLength.toString()) {
72
- 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
73
76
  }
74
77
  } else {
75
- modelValue.value = composite.value
78
+ modelValue.value = v
76
79
  }
77
80
  }
78
81
  })
@@ -93,12 +96,15 @@ const focus = (index: number) => {
93
96
  if (index < length.value) {
94
97
  fields.value[index]?.select()
95
98
  } else {
96
- if (composite.value) {
99
+ if (inputValue.value) {
97
100
  fields.value[index - 1]?.blur()
98
101
  }
99
102
  }
100
103
  }
101
104
  }
105
+ const select = (index: number) => {
106
+ fields.value[index]?.select()
107
+ }
102
108
 
103
109
  const blur = (index: number) => {
104
110
  fields.value[index]?.blur()
@@ -106,12 +112,8 @@ const blur = (index: number) => {
106
112
 
107
113
  const onUpdate = (value: string | number | null, index: number) => {
108
114
  if (value) {
109
- if (props.numeric !== !1 && isNaN(value)) {
110
- nextTick(() => {
111
- setTimeout(() => {
112
- focus(index)
113
- }, 100)
114
- })
115
+ if (props.string && isNaN(value)) {
116
+ nextTick(() => setTimeout(() => focus(index), 100))
115
117
  return
116
118
  }
117
119
  focus(index + 1)
@@ -122,7 +124,7 @@ const onUpdate = (value: string | number | null, index: number) => {
122
124
  }
123
125
 
124
126
  const onKeyDown = (evt: KeyboardEvent/*, index: number */) => {
125
- 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) {
126
128
  evt.preventDefault()
127
129
  }
128
130
  }
@@ -132,12 +134,12 @@ const onKeyUp = (evt: KeyboardEvent, index: number) => {
132
134
  return
133
135
  }
134
136
 
135
- if (['Delete'].includes(key)) {
137
+ if (['delete', 'backspace'].includes(key?.toLowerCase())) {
136
138
  focus(index - 1)
137
139
  return
138
140
  }
139
141
 
140
- if (key === 'ArrowLeft' || key === 'Backspace') {
142
+ if (key === 'ArrowLeft') {
141
143
  focus(index - 1)
142
144
  } else if (key === 'ArrowRight') {
143
145
  focus(index + 1)
@@ -153,7 +155,7 @@ const onKeyUp = (evt: KeyboardEvent, index: number) => {
153
155
  }
154
156
  const onPaste = (evt: ClipboardEvent, index: number) => {
155
157
  const value: any = evt.clipboardData?.getData('text')?.toString() || ''
156
- if (props.numeric !== !1 && isNaN(value)) {
158
+ if (props.string && isNaN(value)) {
157
159
  evt.preventDefault()
158
160
  return
159
161
  }
@@ -162,25 +164,28 @@ const onPaste = (evt: ClipboardEvent, index: number) => {
162
164
  blur(index)
163
165
  }
164
166
  }
165
-
167
+ const onFocusIn = (evt: FocusEvent, index: number) => {
168
+ select(index)
169
+ }
166
170
  const seconds = ref<number>(0)
167
171
  const temp = ref<number>(0)
172
+ let interval: ReturnType<typeof setInterval> | null = null
168
173
  watch(() => seconds.value, v => (temp.value = v))
169
174
  const startTiming = () => {
170
- if (props.hideTime) {
175
+ if (props.noTiming) {
171
176
  return
172
177
  }
173
178
 
174
179
  if (seconds.value > 0) {
175
180
  --seconds.value
176
181
  if (!seconds.value) {
177
- emit('end')
182
+ emit('countdown', { start, clear, startTiming })
178
183
  }
179
184
  }
180
185
  }
181
186
  const getTime = computed<string | null>(() => {
182
187
  const nullValue = null
183
- if (props.hideTime) {
188
+ if (props.noTiming) {
184
189
  return nullValue
185
190
  }
186
191
  if (seconds.value < 1) {
@@ -193,12 +198,11 @@ const getTime = computed<string | null>(() => {
193
198
  return `${(m < 9 ? '0' : '') + m}:${(s < 9 ? '0' : '') + s}`
194
199
  })
195
200
  const disabled = computed(() => seconds.value > 0)
196
- let interval: any = null
197
201
  const clear = () => {
198
202
  interval && clearInterval(interval)
199
203
  }
200
204
  const start = () => {
201
- if (props.hideTime) {
205
+ if (props.noTiming) {
202
206
  return
203
207
  }
204
208
  clear()
@@ -207,13 +211,13 @@ const start = () => {
207
211
  }
208
212
  watch(() => props.time, () => start(), { immediate: !0, deep: !0 })
209
213
  onBeforeUnmount(() => clear())
210
- const onSend = () => {
214
+ const onResend = () => {
211
215
  if (disabled.value) {
212
216
  return
213
217
  }
214
- emit('send')
218
+ emit('resend', { start, clear, startTiming })
215
219
  }
216
- defineExpose({ start })
220
+ defineExpose({ start, clear, startTiming, inputValue })
217
221
  defineOptions({
218
222
  name: 'MOtp',
219
223
  inheritAttrs: !1
@@ -232,9 +236,7 @@ defineOptions({
232
236
  class="justify-start q-mb-md text-body1"
233
237
  v-bind="topLabelProps"
234
238
  >
235
- <div>
236
- {{ __(topLabel) }}
237
- </div>
239
+ {{ __(topLabel) }}
238
240
  </MRow>
239
241
  <div :class="`row ${$q.lang.rtl ? 'reverse' : ''} q-gutter-x-sm justify-center`">
240
242
  <q-input
@@ -244,6 +246,7 @@ defineOptions({
244
246
  v-model="fieldValues[i - 1]"
245
247
  :autofocus="autofocus && i === 1"
246
248
  :error="otpErrors.length > 0"
249
+ :type="type"
247
250
  hide-bottom-space
248
251
  input-class="text-center"
249
252
  maxlength="1"
@@ -251,6 +254,7 @@ defineOptions({
251
254
  outlined
252
255
  style="width: 6ch"
253
256
  v-bind="{...pluginOptions.otp as any,...$attrs}"
257
+ @focusin="onFocusIn($event, i - 1)"
254
258
  @keydown="onKeyDown($event)"
255
259
  @keyup="onKeyUp($event, i - 1)"
256
260
  @paste.prevent="onPaste($event,i - 1)"
@@ -266,7 +270,7 @@ defineOptions({
266
270
  <slot name="after-input" />
267
271
  <MFadeTransition>
268
272
  <div
269
- v-if="!hideTime"
273
+ v-if="!noTiming"
270
274
  class="q-mt-sm"
271
275
  >
272
276
  <span>{{ __('myth.otp.expire_line') }}:&nbsp;</span>
@@ -275,13 +279,13 @@ defineOptions({
275
279
  </MFadeTransition>
276
280
  <MFadeTransition>
277
281
  <div
278
- v-if="!hideSendAgain"
282
+ v-if="!noSendAgain"
279
283
  class="q-mt-sm"
280
284
  >
281
285
  <span>{{ __('myth.otp.send_again_title') }}&nbsp;</span>
282
286
  <span
283
287
  :class="{'text-decoration-underline':!0, disabled,'cursor-pointer': !disabled}"
284
- @click="onSend()"
288
+ @click="onResend()"
285
289
  >{{ __('myth.otp.send_again_btn') }}</span>
286
290
  </div>
287
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
  }