@volverjs/ui-vue 0.0.9-beta.16 → 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 +153 -96
- package/dist/components/VvInputText/VvInputText.umd.js +1 -1
- package/dist/components/VvInputText/VvInputText.vue.d.ts +19 -37
- package/dist/components/VvInputText/index.d.ts +25 -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 +171 -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 +31 -9
- 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 +129 -55
- package/src/components/VvInputText/index.ts +32 -34
- package/src/components/VvTextarea/VvTextarea.vue +8 -5
- package/src/stories/InputText/InputText.settings.ts +36 -15
- 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,35 +54,103 @@
|
|
|
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)
|
|
83
146
|
const isFocused = computed(
|
|
84
147
|
() => focused.value && !props.disabled && !props.readonly,
|
|
85
148
|
)
|
|
149
|
+
watch(isFocused, (newValue) => {
|
|
150
|
+
if (newValue && propsDefaults.value.selectOnFocus && inputEl.value) {
|
|
151
|
+
inputEl.value.select()
|
|
152
|
+
}
|
|
153
|
+
})
|
|
86
154
|
|
|
87
155
|
// visibility
|
|
88
156
|
const isVisible = useElementVisibility(inputEl)
|
|
@@ -113,12 +181,21 @@
|
|
|
113
181
|
const isNumber = computed(() => props.type === INPUT_TYPES.NUMBER)
|
|
114
182
|
const onStepUp = () => {
|
|
115
183
|
if (isClickable.value) {
|
|
184
|
+
if (iMask?.value) {
|
|
185
|
+
typed.value = typed.value + Number(step?.value ?? 1)
|
|
186
|
+
return
|
|
187
|
+
}
|
|
116
188
|
inputEl.value.stepUp()
|
|
117
189
|
localModelValue.value = unref(inputEl).value
|
|
118
190
|
}
|
|
119
191
|
}
|
|
120
192
|
const onStepDown = () => {
|
|
121
193
|
if (isClickable.value) {
|
|
194
|
+
if (iMask?.value) {
|
|
195
|
+
typed.value = typed.value - Number(step?.value ?? 1)
|
|
196
|
+
|
|
197
|
+
return
|
|
198
|
+
}
|
|
122
199
|
inputEl.value.stepDown()
|
|
123
200
|
localModelValue.value = unref(inputEl).value
|
|
124
201
|
}
|
|
@@ -127,7 +204,7 @@
|
|
|
127
204
|
// search
|
|
128
205
|
const isSearch = computed(() => props.type === INPUT_TYPES.SEARCH)
|
|
129
206
|
const onClear = () => {
|
|
130
|
-
localModelValue.value =
|
|
207
|
+
localModelValue.value = ''
|
|
131
208
|
}
|
|
132
209
|
|
|
133
210
|
// icons
|
|
@@ -153,9 +230,9 @@
|
|
|
153
230
|
|
|
154
231
|
// count
|
|
155
232
|
const { formatted: countFormatted } = useTextCount(localModelValue, {
|
|
156
|
-
mode:
|
|
157
|
-
upperLimit: Number(
|
|
158
|
-
lowerLimit: Number(
|
|
233
|
+
mode: count.value,
|
|
234
|
+
upperLimit: Number(maxlength?.value),
|
|
235
|
+
lowerLimit: Number(minlength?.value),
|
|
159
236
|
})
|
|
160
237
|
|
|
161
238
|
// tabindex
|
|
@@ -207,6 +284,9 @@
|
|
|
207
284
|
if (isDateTime.value && !isDirty.value && !focused.value) {
|
|
208
285
|
return INPUT_TYPES.TEXT
|
|
209
286
|
}
|
|
287
|
+
if (iMask?.value) {
|
|
288
|
+
return INPUT_TYPES.TEXT
|
|
289
|
+
}
|
|
210
290
|
return props.type
|
|
211
291
|
})()
|
|
212
292
|
const toReturn: InputHTMLAttributes = {
|
|
@@ -299,33 +379,6 @@
|
|
|
299
379
|
props,
|
|
300
380
|
)
|
|
301
381
|
|
|
302
|
-
// mask
|
|
303
|
-
const mask = ref()
|
|
304
|
-
watch(
|
|
305
|
-
[
|
|
306
|
-
() => props.mask,
|
|
307
|
-
() => props.type,
|
|
308
|
-
() => props.maskEager,
|
|
309
|
-
() => props.maskReversed,
|
|
310
|
-
() => props.maskTokens,
|
|
311
|
-
() => props.maskTokensReplace,
|
|
312
|
-
],
|
|
313
|
-
([newMask, newType, eager, reversed, tokens, tokensReplace]) => {
|
|
314
|
-
if (newMask && newType === INPUT_TYPES.TEXT) {
|
|
315
|
-
mask.value = new Mask({
|
|
316
|
-
mask: newMask,
|
|
317
|
-
eager,
|
|
318
|
-
reversed,
|
|
319
|
-
tokens,
|
|
320
|
-
tokensReplace,
|
|
321
|
-
})
|
|
322
|
-
return
|
|
323
|
-
}
|
|
324
|
-
mask.value = undefined
|
|
325
|
-
},
|
|
326
|
-
{ immediate: true },
|
|
327
|
-
)
|
|
328
|
-
|
|
329
382
|
// auto-width
|
|
330
383
|
const onClickInner = () => {
|
|
331
384
|
if (isClickable.value) {
|
|
@@ -343,6 +396,26 @@
|
|
|
343
396
|
: undefined,
|
|
344
397
|
}
|
|
345
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
|
+
}
|
|
346
419
|
</script>
|
|
347
420
|
|
|
348
421
|
<template>
|
|
@@ -368,10 +441,11 @@
|
|
|
368
441
|
<input
|
|
369
442
|
:id="hasId"
|
|
370
443
|
ref="inputEl"
|
|
371
|
-
v-model="localModelValue"
|
|
372
444
|
v-bind="hasAttrs"
|
|
373
445
|
:style="hasStyle"
|
|
374
446
|
@keyup="emit('keyup', $event)"
|
|
447
|
+
@keydown="onKeyDown"
|
|
448
|
+
@keypress="emit('keypress', $event)"
|
|
375
449
|
/>
|
|
376
450
|
<div
|
|
377
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
|
|
150
|
-
*/
|
|
151
|
-
maskEager: {
|
|
152
|
-
type: Boolean,
|
|
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
|
|
164
|
+
* Masked value
|
|
166
165
|
*/
|
|
167
|
-
|
|
168
|
-
type:
|
|
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
|
*/
|
|
@@ -196,6 +187,13 @@ export const VvInputTextProps = {
|
|
|
196
187
|
unit: {
|
|
197
188
|
type: String,
|
|
198
189
|
},
|
|
190
|
+
/**
|
|
191
|
+
* Select input text on focus
|
|
192
|
+
*/
|
|
193
|
+
selectOnFocus: {
|
|
194
|
+
type: Boolean,
|
|
195
|
+
default: false,
|
|
196
|
+
},
|
|
199
197
|
}
|
|
200
198
|
|
|
201
199
|
export type VvInputTextPropsTypes = ExtractPropTypes<typeof VvInputTextProps>
|
|
@@ -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,43 +174,64 @@ export const argTypes = {
|
|
|
174
174
|
},
|
|
175
175
|
},
|
|
176
176
|
},
|
|
177
|
-
|
|
178
|
-
description: '
|
|
179
|
-
|
|
177
|
+
iMask: {
|
|
178
|
+
description: '[iMask](https://imask.js.org/guide.html) options',
|
|
179
|
+
control: {
|
|
180
|
+
type: 'object',
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
masked: {
|
|
184
|
+
description: 'Masked input',
|
|
180
185
|
control: {
|
|
181
186
|
type: 'text',
|
|
182
187
|
},
|
|
183
188
|
},
|
|
184
|
-
|
|
185
|
-
description: '
|
|
189
|
+
autoWidth: {
|
|
190
|
+
description: 'Adjust input width to content',
|
|
191
|
+
control: {
|
|
192
|
+
type: 'boolean',
|
|
193
|
+
},
|
|
186
194
|
table: {
|
|
187
195
|
defaultValue: {
|
|
188
196
|
summary: false,
|
|
189
197
|
},
|
|
198
|
+
type: {
|
|
199
|
+
summary: 'boolean',
|
|
200
|
+
},
|
|
190
201
|
},
|
|
191
202
|
},
|
|
192
|
-
|
|
193
|
-
description: '
|
|
203
|
+
hideActions: {
|
|
204
|
+
description: 'Hide type number, password and search actions',
|
|
205
|
+
control: {
|
|
206
|
+
type: 'boolean',
|
|
207
|
+
},
|
|
194
208
|
table: {
|
|
195
209
|
defaultValue: {
|
|
196
210
|
summary: false,
|
|
197
211
|
},
|
|
212
|
+
type: {
|
|
213
|
+
summary: 'boolean',
|
|
214
|
+
},
|
|
198
215
|
},
|
|
199
216
|
},
|
|
200
|
-
|
|
201
|
-
description: 'Add
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
summary: 'undefined',
|
|
205
|
-
},
|
|
217
|
+
unit: {
|
|
218
|
+
description: 'Add unit label to input',
|
|
219
|
+
control: {
|
|
220
|
+
type: 'text',
|
|
206
221
|
},
|
|
207
222
|
},
|
|
208
|
-
|
|
209
|
-
description: '
|
|
223
|
+
selectOnFocus: {
|
|
224
|
+
description: 'Select input text on focus',
|
|
225
|
+
control: {
|
|
226
|
+
type: 'boolean',
|
|
227
|
+
},
|
|
210
228
|
table: {
|
|
211
229
|
defaultValue: {
|
|
212
230
|
summary: false,
|
|
213
231
|
},
|
|
232
|
+
type: {
|
|
233
|
+
summary: 'boolean',
|
|
234
|
+
},
|
|
214
235
|
},
|
|
215
236
|
},
|
|
216
237
|
before: {
|
|
@@ -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
|
}
|