@volverjs/ui-vue 0.0.9-beta.17 → 0.0.9-beta.18
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/dist/components/VvCombobox/VvCombobox.es.js +10 -7
- package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
- package/dist/components/VvInputText/VvInputText.es.js +141 -96
- package/dist/components/VvInputText/VvInputText.umd.js +1 -1
- package/dist/components/VvInputText/VvInputText.vue.d.ts +10 -37
- package/dist/components/VvInputText/index.d.ts +18 -35
- package/dist/components/VvTextarea/VvTextarea.es.js +8 -5
- package/dist/components/VvTextarea/VvTextarea.umd.js +1 -1
- package/dist/components/index.es.js +159 -108
- package/dist/components/index.umd.js +1 -1
- package/dist/icons.es.js +3 -3
- package/dist/icons.umd.js +1 -1
- package/dist/stories/InputText/InputText.settings.d.ts +4 -30
- package/dist/stories/InputText/InputText.stories.d.ts +0 -1
- package/dist/stories/InputText/InputTextMask.stories.d.ts +12 -0
- package/package.json +39 -38
- package/src/assets/icons/detailed.json +1 -1
- package/src/assets/icons/normal.json +1 -1
- package/src/assets/icons/simple.json +1 -1
- package/src/components/VvCombobox/VvCombobox.vue +11 -7
- package/src/components/VvInputText/VvInputText.vue +124 -55
- package/src/components/VvInputText/index.ts +25 -34
- package/src/components/VvTextarea/VvTextarea.vue +8 -5
- package/src/stories/InputText/InputText.settings.ts +7 -33
- package/src/stories/InputText/InputText.stories.ts +4 -12
- package/src/stories/InputText/InputText.test.ts +31 -15
- package/src/stories/InputText/InputTextMask.stories.ts +122 -0
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
<script setup lang="ts">
|
|
14
14
|
import type { Ref } from 'vue'
|
|
15
|
+
import { toRefs } from 'vue'
|
|
15
16
|
import { VvComboboxProps, VvComboboxEvents } from '.'
|
|
16
17
|
import VvIcon from '../VvIcon/VvIcon.vue'
|
|
17
18
|
import VvDropdown from '../VvDropdown/VvDropdown.vue'
|
|
@@ -84,7 +85,7 @@
|
|
|
84
85
|
const searchText = ref('')
|
|
85
86
|
const debouncedSearchText = refDebounced(
|
|
86
87
|
searchText,
|
|
87
|
-
Number(props.debounceSearch),
|
|
88
|
+
computed(() => Number(props.debounceSearch)),
|
|
88
89
|
)
|
|
89
90
|
watch(debouncedSearchText, () =>
|
|
90
91
|
emit('change:search', debouncedSearchText.value),
|
|
@@ -235,12 +236,15 @@
|
|
|
235
236
|
} else if (props.modelValue) {
|
|
236
237
|
selectedValues = [props.modelValue]
|
|
237
238
|
}
|
|
238
|
-
const options = props.options.reduce(
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
239
|
+
const options = props.options.reduce(
|
|
240
|
+
(acc, value) => {
|
|
241
|
+
if (isGroup(value)) {
|
|
242
|
+
return [...acc, ...getOptionGrouped(value)]
|
|
243
|
+
}
|
|
244
|
+
return [...acc, value]
|
|
245
|
+
},
|
|
246
|
+
[] as Array<Option | string>,
|
|
247
|
+
)
|
|
244
248
|
|
|
245
249
|
return options.filter((option) => {
|
|
246
250
|
if (isGroup(option)) {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<script setup lang="ts">
|
|
8
8
|
import type { InputHTMLAttributes } from 'vue'
|
|
9
|
-
import {
|
|
9
|
+
import { useIMask } from 'vue-imask'
|
|
10
10
|
import HintSlotFactory from '../common/HintSlot'
|
|
11
11
|
import VvIcon from '../VvIcon/VvIcon.vue'
|
|
12
12
|
import VvInputTextActionsFactory from '../VvInputText/VvInputTextActions'
|
|
@@ -29,12 +29,6 @@
|
|
|
29
29
|
props,
|
|
30
30
|
)
|
|
31
31
|
|
|
32
|
-
// template refs
|
|
33
|
-
const inputEl = ref()
|
|
34
|
-
const innerEl = ref()
|
|
35
|
-
|
|
36
|
-
defineExpose({ $inner: innerEl })
|
|
37
|
-
|
|
38
32
|
// data
|
|
39
33
|
const {
|
|
40
34
|
id,
|
|
@@ -46,6 +40,12 @@
|
|
|
46
40
|
valid,
|
|
47
41
|
invalid,
|
|
48
42
|
loading,
|
|
43
|
+
debounce,
|
|
44
|
+
maxlength,
|
|
45
|
+
minlength,
|
|
46
|
+
type,
|
|
47
|
+
iMask,
|
|
48
|
+
step,
|
|
49
49
|
} = toRefs(props)
|
|
50
50
|
const hasId = useUniqueId(id)
|
|
51
51
|
const hasHintId = computed(() => `${hasId.value}-hint`)
|
|
@@ -54,29 +54,92 @@
|
|
|
54
54
|
props.floating && isEmpty(props.placeholder) ? ' ' : props.placeholder,
|
|
55
55
|
)
|
|
56
56
|
|
|
57
|
-
//
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
// template refs
|
|
58
|
+
const maskReady = ref(false)
|
|
59
|
+
const { el, mask, typed, masked, unmasked } = useIMask(
|
|
60
|
+
computed(
|
|
61
|
+
() =>
|
|
62
|
+
iMask?.value ?? {
|
|
63
|
+
mask: /./,
|
|
64
|
+
},
|
|
65
|
+
),
|
|
62
66
|
{
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
emit,
|
|
68
|
+
onAccept: () => {
|
|
69
|
+
if (!maskReady.value) {
|
|
70
|
+
return
|
|
66
71
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
emit('update:masked', masked.value)
|
|
73
|
+
if (type.value === INPUT_TYPES.NUMBER) {
|
|
74
|
+
if (typeof typed.value !== 'number') {
|
|
75
|
+
localModelValue.value = Number(typed.value)
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
localModelValue.value = typed.value
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
if (type.value === INPUT_TYPES.DATE) {
|
|
82
|
+
let date = typed.value
|
|
83
|
+
if (!(date instanceof Date)) {
|
|
84
|
+
date = new Date(date)
|
|
85
|
+
}
|
|
86
|
+
localModelValue.value = `${date.getFullYear()}-${(
|
|
87
|
+
'0' +
|
|
88
|
+
(date.getMonth() + 1)
|
|
89
|
+
).slice(-2)}-${('0' + date.getDate()).slice(-2)}`
|
|
90
|
+
return
|
|
72
91
|
}
|
|
73
|
-
if (
|
|
74
|
-
|
|
92
|
+
if (type.value === INPUT_TYPES.DATETIME_LOCAL) {
|
|
93
|
+
let date = typed.value
|
|
94
|
+
if (!(typed.value instanceof Date)) {
|
|
95
|
+
date = new Date(date)
|
|
96
|
+
}
|
|
97
|
+
localModelValue.value = `${date.getFullYear()}-${(
|
|
98
|
+
'0' +
|
|
99
|
+
(date.getMonth() + 1)
|
|
100
|
+
).slice(-2)}-${('0' + date.getDate()).slice(-2)}T${(
|
|
101
|
+
'0' + date.getHours()
|
|
102
|
+
).slice(-2)}:${('0' + date.getMinutes()).slice(-2)}`
|
|
103
|
+
return
|
|
75
104
|
}
|
|
76
|
-
|
|
105
|
+
localModelValue.value = unmasked.value
|
|
77
106
|
},
|
|
78
107
|
},
|
|
79
108
|
)
|
|
109
|
+
onMounted(() => {
|
|
110
|
+
if (mask.value) {
|
|
111
|
+
maskReady.value = true
|
|
112
|
+
typed.value = localModelValue.value ?? ''
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
watch(
|
|
116
|
+
() => props.modelValue,
|
|
117
|
+
(newValue) => {
|
|
118
|
+
if (mask.value) {
|
|
119
|
+
typed.value =
|
|
120
|
+
newValue && iMask?.value?.mask === Date
|
|
121
|
+
? new Date(newValue)
|
|
122
|
+
: newValue ?? null
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
)
|
|
126
|
+
watch(
|
|
127
|
+
() => props.masked,
|
|
128
|
+
(newValue) => {
|
|
129
|
+
masked.value = newValue ?? ''
|
|
130
|
+
},
|
|
131
|
+
)
|
|
132
|
+
const inputEl = el as Ref<HTMLInputElement>
|
|
133
|
+
const innerEl = ref()
|
|
134
|
+
|
|
135
|
+
defineExpose({ $inner: innerEl })
|
|
136
|
+
|
|
137
|
+
// debounce
|
|
138
|
+
const localModelValue = useDebouncedInput(
|
|
139
|
+
modelValue,
|
|
140
|
+
emit,
|
|
141
|
+
debounce?.value ?? 0,
|
|
142
|
+
)
|
|
80
143
|
|
|
81
144
|
// focus
|
|
82
145
|
const { focused } = useComponentFocus(inputEl, emit)
|
|
@@ -118,12 +181,21 @@
|
|
|
118
181
|
const isNumber = computed(() => props.type === INPUT_TYPES.NUMBER)
|
|
119
182
|
const onStepUp = () => {
|
|
120
183
|
if (isClickable.value) {
|
|
184
|
+
if (iMask?.value) {
|
|
185
|
+
typed.value = typed.value + Number(step?.value ?? 1)
|
|
186
|
+
return
|
|
187
|
+
}
|
|
121
188
|
inputEl.value.stepUp()
|
|
122
189
|
localModelValue.value = unref(inputEl).value
|
|
123
190
|
}
|
|
124
191
|
}
|
|
125
192
|
const onStepDown = () => {
|
|
126
193
|
if (isClickable.value) {
|
|
194
|
+
if (iMask?.value) {
|
|
195
|
+
typed.value = typed.value - Number(step?.value ?? 1)
|
|
196
|
+
|
|
197
|
+
return
|
|
198
|
+
}
|
|
127
199
|
inputEl.value.stepDown()
|
|
128
200
|
localModelValue.value = unref(inputEl).value
|
|
129
201
|
}
|
|
@@ -132,7 +204,7 @@
|
|
|
132
204
|
// search
|
|
133
205
|
const isSearch = computed(() => props.type === INPUT_TYPES.SEARCH)
|
|
134
206
|
const onClear = () => {
|
|
135
|
-
localModelValue.value =
|
|
207
|
+
localModelValue.value = ''
|
|
136
208
|
}
|
|
137
209
|
|
|
138
210
|
// icons
|
|
@@ -158,9 +230,9 @@
|
|
|
158
230
|
|
|
159
231
|
// count
|
|
160
232
|
const { formatted: countFormatted } = useTextCount(localModelValue, {
|
|
161
|
-
mode:
|
|
162
|
-
upperLimit: Number(
|
|
163
|
-
lowerLimit: Number(
|
|
233
|
+
mode: count.value,
|
|
234
|
+
upperLimit: Number(maxlength?.value),
|
|
235
|
+
lowerLimit: Number(minlength?.value),
|
|
164
236
|
})
|
|
165
237
|
|
|
166
238
|
// tabindex
|
|
@@ -212,6 +284,9 @@
|
|
|
212
284
|
if (isDateTime.value && !isDirty.value && !focused.value) {
|
|
213
285
|
return INPUT_TYPES.TEXT
|
|
214
286
|
}
|
|
287
|
+
if (iMask?.value) {
|
|
288
|
+
return INPUT_TYPES.TEXT
|
|
289
|
+
}
|
|
215
290
|
return props.type
|
|
216
291
|
})()
|
|
217
292
|
const toReturn: InputHTMLAttributes = {
|
|
@@ -304,33 +379,6 @@
|
|
|
304
379
|
props,
|
|
305
380
|
)
|
|
306
381
|
|
|
307
|
-
// mask
|
|
308
|
-
const mask = ref()
|
|
309
|
-
watch(
|
|
310
|
-
[
|
|
311
|
-
() => props.mask,
|
|
312
|
-
() => props.type,
|
|
313
|
-
() => props.maskEager,
|
|
314
|
-
() => props.maskReversed,
|
|
315
|
-
() => props.maskTokens,
|
|
316
|
-
() => props.maskTokensReplace,
|
|
317
|
-
],
|
|
318
|
-
([newMask, newType, eager, reversed, tokens, tokensReplace]) => {
|
|
319
|
-
if (newMask && newType === INPUT_TYPES.TEXT) {
|
|
320
|
-
mask.value = new Mask({
|
|
321
|
-
mask: newMask,
|
|
322
|
-
eager,
|
|
323
|
-
reversed,
|
|
324
|
-
tokens,
|
|
325
|
-
tokensReplace,
|
|
326
|
-
})
|
|
327
|
-
return
|
|
328
|
-
}
|
|
329
|
-
mask.value = undefined
|
|
330
|
-
},
|
|
331
|
-
{ immediate: true },
|
|
332
|
-
)
|
|
333
|
-
|
|
334
382
|
// auto-width
|
|
335
383
|
const onClickInner = () => {
|
|
336
384
|
if (isClickable.value) {
|
|
@@ -348,6 +396,26 @@
|
|
|
348
396
|
: undefined,
|
|
349
397
|
}
|
|
350
398
|
})
|
|
399
|
+
|
|
400
|
+
// keydown
|
|
401
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
402
|
+
switch (event.code) {
|
|
403
|
+
case 'ArrowUp':
|
|
404
|
+
if (isNumber.value) {
|
|
405
|
+
onStepUp()
|
|
406
|
+
event.preventDefault()
|
|
407
|
+
}
|
|
408
|
+
break
|
|
409
|
+
|
|
410
|
+
case 'ArrowDown':
|
|
411
|
+
if (isNumber.value) {
|
|
412
|
+
onStepDown()
|
|
413
|
+
event.preventDefault()
|
|
414
|
+
}
|
|
415
|
+
break
|
|
416
|
+
}
|
|
417
|
+
emit('keydown', event)
|
|
418
|
+
}
|
|
351
419
|
</script>
|
|
352
420
|
|
|
353
421
|
<template>
|
|
@@ -373,10 +441,11 @@
|
|
|
373
441
|
<input
|
|
374
442
|
:id="hasId"
|
|
375
443
|
ref="inputEl"
|
|
376
|
-
v-model="localModelValue"
|
|
377
444
|
v-bind="hasAttrs"
|
|
378
445
|
:style="hasStyle"
|
|
379
446
|
@keyup="emit('keyup', $event)"
|
|
447
|
+
@keydown="onKeyDown"
|
|
448
|
+
@keypress="emit('keypress', $event)"
|
|
380
449
|
/>
|
|
381
450
|
<div
|
|
382
451
|
v-if="(unit || $slots.unit) && isDirty"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtractPropTypes, PropType } from 'vue'
|
|
2
|
-
import type {
|
|
2
|
+
import type { FactoryOpts } from 'imask'
|
|
3
3
|
import { InputTextareaProps } from '../../props'
|
|
4
4
|
|
|
5
5
|
export const INPUT_TYPES = {
|
|
@@ -28,7 +28,23 @@ export const TYPES_ICON = {
|
|
|
28
28
|
SEARCH: 'close',
|
|
29
29
|
} as const
|
|
30
30
|
|
|
31
|
-
export const VvInputTextEvents = [
|
|
31
|
+
export const VvInputTextEvents = [
|
|
32
|
+
'update:modelValue',
|
|
33
|
+
'update:masked',
|
|
34
|
+
'accept',
|
|
35
|
+
'accept:typed',
|
|
36
|
+
'accept:masked',
|
|
37
|
+
'accept:unmasked',
|
|
38
|
+
'complete',
|
|
39
|
+
'complete:typed',
|
|
40
|
+
'complete:masked',
|
|
41
|
+
'complete:unmasked',
|
|
42
|
+
'focus',
|
|
43
|
+
'blur',
|
|
44
|
+
'keyup',
|
|
45
|
+
'keydown',
|
|
46
|
+
'keypress',
|
|
47
|
+
]
|
|
32
48
|
|
|
33
49
|
export const VvInputTextProps = {
|
|
34
50
|
...InputTextareaProps,
|
|
@@ -137,45 +153,20 @@ export const VvInputTextProps = {
|
|
|
137
153
|
default: 'Clear',
|
|
138
154
|
},
|
|
139
155
|
/**
|
|
140
|
-
*
|
|
141
|
-
* @see https://
|
|
156
|
+
* iMask options
|
|
157
|
+
* @see https://imask.js.org/guide.html
|
|
142
158
|
*/
|
|
143
|
-
|
|
144
|
-
type:
|
|
159
|
+
iMask: {
|
|
160
|
+
type: Object as PropType<FactoryOpts>,
|
|
145
161
|
default: undefined,
|
|
146
162
|
},
|
|
147
163
|
/**
|
|
148
|
-
*
|
|
149
|
-
* @see https://beholdr.github.io/maska/#/?id=maskinput-options
|
|
164
|
+
* Masked value
|
|
150
165
|
*/
|
|
151
|
-
|
|
152
|
-
type:
|
|
153
|
-
default: false,
|
|
154
|
-
},
|
|
155
|
-
/**
|
|
156
|
-
* Write values reverse (ex. for numbers)
|
|
157
|
-
* @see https://beholdr.github.io/maska/#/?id=maskinput-options
|
|
158
|
-
*/
|
|
159
|
-
maskReversed: {
|
|
160
|
-
type: Boolean,
|
|
161
|
-
default: false,
|
|
162
|
-
},
|
|
163
|
-
/**
|
|
164
|
-
* Add mask custom tokens
|
|
165
|
-
* @see https://beholdr.github.io/maska/#/?id=custom-tokens
|
|
166
|
-
*/
|
|
167
|
-
maskTokens: {
|
|
168
|
-
type: Object as PropType<MaskTokens>,
|
|
166
|
+
masked: {
|
|
167
|
+
type: String,
|
|
169
168
|
default: undefined,
|
|
170
169
|
},
|
|
171
|
-
/**
|
|
172
|
-
* Replace default tokens
|
|
173
|
-
* @see https://beholdr.github.io/maska/#/?id=custom-tokens
|
|
174
|
-
*/
|
|
175
|
-
maskTokensReplace: {
|
|
176
|
-
type: Boolean,
|
|
177
|
-
default: false,
|
|
178
|
-
},
|
|
179
170
|
/**
|
|
180
171
|
* Adjust input width to content
|
|
181
172
|
*/
|
|
@@ -37,6 +37,9 @@
|
|
|
37
37
|
invalid,
|
|
38
38
|
loading,
|
|
39
39
|
modifiers,
|
|
40
|
+
debounce,
|
|
41
|
+
minlength,
|
|
42
|
+
maxlength,
|
|
40
43
|
} = toRefs(props)
|
|
41
44
|
const hasId = useUniqueId(id)
|
|
42
45
|
const hasHintId = computed(() => `${hasId.value}-hint`)
|
|
@@ -46,7 +49,7 @@
|
|
|
46
49
|
)
|
|
47
50
|
|
|
48
51
|
// debounce
|
|
49
|
-
const localModelValue = useDebouncedInput(modelValue, emit,
|
|
52
|
+
const localModelValue = useDebouncedInput(modelValue, emit, debounce?.value)
|
|
50
53
|
|
|
51
54
|
// icons
|
|
52
55
|
const { hasIcon, hasIconBefore, hasIconAfter } = useComponentIcon(
|
|
@@ -67,9 +70,9 @@
|
|
|
67
70
|
|
|
68
71
|
// count
|
|
69
72
|
const { formatted: countFormatted } = useTextCount(localModelValue, {
|
|
70
|
-
mode:
|
|
71
|
-
upperLimit: Number(
|
|
72
|
-
lowerLimit: Number(
|
|
73
|
+
mode: count?.value,
|
|
74
|
+
upperLimit: Number(maxlength?.value),
|
|
75
|
+
lowerLimit: Number(minlength?.value),
|
|
73
76
|
})
|
|
74
77
|
|
|
75
78
|
// tabindex
|
|
@@ -143,7 +146,7 @@
|
|
|
143
146
|
'aria-errormessage': hasInvalidLabelOrSlot.value
|
|
144
147
|
? hasHintId.value
|
|
145
148
|
: undefined,
|
|
146
|
-
} as TextareaHTMLAttributes
|
|
149
|
+
}) as TextareaHTMLAttributes,
|
|
147
150
|
)
|
|
148
151
|
|
|
149
152
|
// slots props
|
|
@@ -174,42 +174,16 @@ export const argTypes = {
|
|
|
174
174
|
},
|
|
175
175
|
},
|
|
176
176
|
},
|
|
177
|
-
|
|
178
|
-
description: '
|
|
177
|
+
iMask: {
|
|
178
|
+
description: '[iMask](https://imask.js.org/guide.html) options',
|
|
179
179
|
control: {
|
|
180
|
-
type: '
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
maskEager: {
|
|
184
|
-
description: 'Show mask before typing',
|
|
185
|
-
table: {
|
|
186
|
-
defaultValue: {
|
|
187
|
-
summary: false,
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
|
-
maskReversed: {
|
|
192
|
-
description: 'Write typing reverse (ex. for numbers)',
|
|
193
|
-
table: {
|
|
194
|
-
defaultValue: {
|
|
195
|
-
summary: false,
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
maskTokens: {
|
|
200
|
-
description: 'Add mask custom tokens',
|
|
201
|
-
table: {
|
|
202
|
-
defaultValue: {
|
|
203
|
-
summary: 'undefined',
|
|
204
|
-
},
|
|
180
|
+
type: 'object',
|
|
205
181
|
},
|
|
206
182
|
},
|
|
207
|
-
|
|
208
|
-
description: '
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
summary: false,
|
|
212
|
-
},
|
|
183
|
+
masked: {
|
|
184
|
+
description: 'Masked input',
|
|
185
|
+
control: {
|
|
186
|
+
type: 'text',
|
|
213
187
|
},
|
|
214
188
|
},
|
|
215
189
|
autoWidth: {
|
|
@@ -25,14 +25,15 @@ export const Default: Story = {
|
|
|
25
25
|
setup() {
|
|
26
26
|
return { args }
|
|
27
27
|
},
|
|
28
|
-
data: () => ({ inputValue: undefined }),
|
|
28
|
+
data: () => ({ inputValue: undefined, maskedInputValue: undefined }),
|
|
29
29
|
template: /* html */ `
|
|
30
|
-
<vv-input-text v-bind="args" v-model="inputValue" :data-testData="inputValue" data-testId="element">
|
|
30
|
+
<vv-input-text v-bind="args" v-model="inputValue" v-model:masked="maskedInputValue" :data-testData="inputValue" data-testId="element">
|
|
31
31
|
<template #before v-if="args.before"><div class="flex" v-html="args.before"></div></template>
|
|
32
32
|
<template #after v-if="args.after"><div class="flex" v-html="args.after"></div></template>
|
|
33
33
|
<template #hint v-if="args.hint"><span v-html="args.hint"></span></template>
|
|
34
34
|
</vv-input-text>
|
|
35
|
-
<div>Value: <span data-testId="value">{{inputValue}}</span></div>
|
|
35
|
+
<div>Value: <span data-testId="value">{{ inputValue }}</span></div>
|
|
36
|
+
<div v-if="args.iMask" class="mt-sm">Masked Value: <span data-testId="masked-value">{{ maskedInputValue }}</span></div>
|
|
36
37
|
`,
|
|
37
38
|
}),
|
|
38
39
|
play: defaultTest,
|
|
@@ -82,7 +83,6 @@ export const Hint: Story = {
|
|
|
82
83
|
...defaultArgs,
|
|
83
84
|
hintLabel: 'Please enter your name.',
|
|
84
85
|
},
|
|
85
|
-
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
export const Loading: Story = {
|
|
@@ -102,14 +102,6 @@ export const Floating: Story = {
|
|
|
102
102
|
},
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
export const Mask: Story = {
|
|
106
|
-
...Default,
|
|
107
|
-
args: {
|
|
108
|
-
...defaultArgs,
|
|
109
|
-
mask: '##-###-##',
|
|
110
|
-
},
|
|
111
|
-
}
|
|
112
|
-
|
|
113
105
|
export const Unit: Story = {
|
|
114
106
|
...Default,
|
|
115
107
|
args: {
|
|
@@ -4,32 +4,48 @@ import { sleep } from '@/test/sleep'
|
|
|
4
4
|
import { within, userEvent } from '@storybook/testing-library'
|
|
5
5
|
import { INPUT_TYPES, type InputType } from '@/components/VvInputText'
|
|
6
6
|
|
|
7
|
-
const valueByType = (type: InputType, mask?: string) => {
|
|
7
|
+
const valueByType = (type: InputType, mask?: string, id?: string) => {
|
|
8
8
|
if (mask) {
|
|
9
|
-
|
|
9
|
+
switch (id) {
|
|
10
|
+
case 'phone-number':
|
|
11
|
+
return { toType: '393923847556' }
|
|
12
|
+
case 'date-placeholder':
|
|
13
|
+
return { toType: '01011970', toCheck: '1970-01-01' }
|
|
14
|
+
case 'phone-or-email':
|
|
15
|
+
return {
|
|
16
|
+
toType:
|
|
17
|
+
Math.random() < 0.5 ? '393923847556' : 'test@test.com',
|
|
18
|
+
}
|
|
19
|
+
case 'intl-number':
|
|
20
|
+
return { toType: '1234567890.22' }
|
|
21
|
+
case 'currency':
|
|
22
|
+
return { toType: '1234567890.22' }
|
|
23
|
+
default:
|
|
24
|
+
return { toType: '1234567890' }
|
|
25
|
+
}
|
|
10
26
|
}
|
|
11
27
|
switch (type) {
|
|
12
28
|
case INPUT_TYPES.TEXT:
|
|
13
29
|
case INPUT_TYPES.PASSWORD:
|
|
14
30
|
case INPUT_TYPES.SEARCH:
|
|
15
|
-
return 'Lorem ipsum'
|
|
31
|
+
return { toType: 'Lorem ipsum' }
|
|
16
32
|
case INPUT_TYPES.NUMBER:
|
|
17
|
-
return '1'
|
|
33
|
+
return { toType: '1' }
|
|
18
34
|
case INPUT_TYPES.EMAIL:
|
|
19
|
-
return 'test@test.com'
|
|
35
|
+
return { toType: 'test@test.com' }
|
|
20
36
|
case INPUT_TYPES.TEL:
|
|
21
|
-
return '+1234567890'
|
|
37
|
+
return { toType: '+1234567890' }
|
|
22
38
|
case INPUT_TYPES.URL:
|
|
23
|
-
return 'https://www.test.com'
|
|
39
|
+
return { toType: 'https://www.test.com' }
|
|
24
40
|
case INPUT_TYPES.DATE:
|
|
25
|
-
return new Date().toISOString().split('T')[0]
|
|
41
|
+
return { toType: new Date().toISOString().split('T')[0] }
|
|
26
42
|
case INPUT_TYPES.TIME:
|
|
27
|
-
return '12:00'
|
|
43
|
+
return { toType: '12:00' }
|
|
28
44
|
case INPUT_TYPES.COLOR:
|
|
29
45
|
case INPUT_TYPES.DATETIME_LOCAL:
|
|
30
46
|
case INPUT_TYPES.MONTH:
|
|
31
47
|
case INPUT_TYPES.WEEK:
|
|
32
|
-
return undefined
|
|
48
|
+
return { toType: undefined }
|
|
33
49
|
}
|
|
34
50
|
}
|
|
35
51
|
|
|
@@ -45,17 +61,17 @@ export async function defaultTest({ canvasElement, args }: PlayAttributes) {
|
|
|
45
61
|
|
|
46
62
|
// value
|
|
47
63
|
if (!args.invalid && !args.disabled && !args.readonly) {
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
64
|
+
const { toType, toCheck } = valueByType(args.type, args.iMask, args.id)
|
|
65
|
+
if (toType) {
|
|
50
66
|
await expect(input).toBeClicked()
|
|
51
|
-
await userEvent.keyboard(
|
|
67
|
+
await userEvent.keyboard(toType)
|
|
52
68
|
await sleep()
|
|
53
69
|
if (args.maxlength) {
|
|
54
70
|
await expect(value.innerHTML).toEqual(
|
|
55
|
-
|
|
71
|
+
toType.slice(0, args.maxlength),
|
|
56
72
|
)
|
|
57
73
|
} else {
|
|
58
|
-
await expect(value.innerHTML).toEqual(
|
|
74
|
+
await expect(value.innerHTML).toEqual(toCheck ?? toType)
|
|
59
75
|
}
|
|
60
76
|
}
|
|
61
77
|
}
|