@volverjs/ui-vue 0.0.10-beta.54 → 0.0.10-beta.56

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.
Files changed (30) hide show
  1. package/auto-imports.d.ts +3 -0
  2. package/dist/components/VvCombobox/VvCombobox.es.js +357 -357
  3. package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
  4. package/dist/components/VvInputText/VvInputText.es.js +150 -44
  5. package/dist/components/VvInputText/VvInputText.umd.js +1 -1
  6. package/dist/components/VvInputText/VvInputText.vue.d.ts +6 -6
  7. package/dist/components/VvInputText/index.d.ts +1 -1
  8. package/dist/components/VvTextarea/VvTextarea.es.js +966 -67
  9. package/dist/components/VvTextarea/VvTextarea.umd.js +1 -1
  10. package/dist/components/VvTextarea/VvTextarea.vue.d.ts +52 -0
  11. package/dist/components/VvTextarea/index.d.ts +37 -1
  12. package/dist/components/index.es.js +542 -284
  13. package/dist/components/index.umd.js +1 -1
  14. package/dist/icons.es.js +3 -3
  15. package/dist/icons.umd.js +1 -1
  16. package/dist/stories/InputText/InputText.test.d.ts +1 -0
  17. package/dist/stories/InputText/InputTextIso.stories.d.ts +10 -0
  18. package/dist/utils/DateUtilities.d.ts +22 -0
  19. package/package.json +22 -22
  20. package/src/assets/icons/detailed.json +1 -1
  21. package/src/assets/icons/normal.json +1 -1
  22. package/src/assets/icons/simple.json +1 -1
  23. package/src/components/VvCombobox/VvCombobox.vue +3 -3
  24. package/src/components/VvInputText/VvInputText.vue +103 -63
  25. package/src/components/VvInputText/index.ts +1 -1
  26. package/src/components/VvTextarea/VvTextarea.vue +108 -5
  27. package/src/components/VvTextarea/index.ts +32 -1
  28. package/src/stories/InputText/InputText.test.ts +25 -0
  29. package/src/stories/InputText/InputTextIso.stories.ts +69 -0
  30. package/src/utils/DateUtilities.ts +98 -0
@@ -1,7 +1,8 @@
1
1
  <script setup lang="ts" generic="T extends string | Option">
2
2
  import type { Ref } from 'vue'
3
- import { toRefs } from 'vue'
4
3
  import type { Option } from '../../types/generic'
4
+ import { toRefs } from 'vue'
5
+ import { useVvComboboxProps, type VvComboboxEvents } from '.'
5
6
  import { DropdownRole } from '../../constants'
6
7
  import HintSlotFactory from '../common/HintSlot'
7
8
  import VvBadge from '../VvBadge/VvBadge.vue'
@@ -11,7 +12,6 @@ import VvDropdownOptgroup from '../VvDropdown/VvDropdownOptgroup.vue'
11
12
  import VvDropdownOption from '../VvDropdown/VvDropdownOption.vue'
12
13
  import VvIcon from '../VvIcon/VvIcon.vue'
13
14
  import VvSelect from '../VvSelect/VvSelect.vue'
14
- import { type VvComboboxEvents, useVvComboboxProps } from '.'
15
15
 
16
16
  // props, emit and slots
17
17
  // WARNING: This is a provisiaonal implementation, it may change in the future
@@ -31,7 +31,7 @@ const propsDefaults = useDefaults<typeof VvComboboxProps>(
31
31
  const inputEl: Ref<HTMLElement | null> = ref(null)
32
32
  const inputSearchEl: Ref<HTMLElement | null> = ref(null)
33
33
  const wrapperEl: Ref<HTMLElement | null> = ref(null)
34
- const dropdownEl = ref<typeof VvDropdown>()
34
+ const dropdownEl = ref<InstanceType<typeof VvDropdown>>()
35
35
 
36
36
  // hint slot
37
37
  const {
@@ -2,6 +2,11 @@
2
2
  import type { MaskedNumberOptions } from 'imask'
3
3
  import type { InputHTMLAttributes } from 'vue'
4
4
  import { useIMask } from 'vue-imask'
5
+ import {
6
+ getDateFromInputValue,
7
+ getInputValueFromDate,
8
+ isDateIsoString,
9
+ } from '../../utils/DateUtilities'
5
10
  import HintSlotFactory from '../common/HintSlot'
6
11
  import VvDropdown from '../VvDropdown/VvDropdown.vue'
7
12
  import VvDropdownOption from '../VvDropdown/VvDropdownOption.vue'
@@ -62,9 +67,20 @@ const localModelValue = useDebouncedInput(
62
67
  debounce?.value ?? 0,
63
68
  )
64
69
 
70
+ // seconds
71
+ const hasSeconds = computed(() => {
72
+ const stepValue = typeof step.value === 'number' ? step.value : Number.parseInt(step.value)
73
+ if (Number.isNaN(stepValue)) {
74
+ return false
75
+ }
76
+ return stepValue % 60 !== 0
77
+ })
78
+
65
79
  // mask
66
80
  const NEGATIVE_ZERO_REGEX = /^-0?[.,]?[0*]?$/
67
81
  const maskReady = ref(false)
82
+ const modelValueDate = ref<Date>()
83
+ const modelValueDateIsoString = ref<string>()
68
84
  const { el, mask, typed, masked, unmasked } = useIMask(
69
85
  computed(
70
86
  () => {
@@ -115,56 +131,62 @@ const { el, mask, typed, masked, unmasked } = useIMask(
115
131
  localModelValue.value = typed.value
116
132
  return
117
133
  }
118
- if (type.value === INPUT_TYPES.DATE) {
119
- if (
120
- el.value instanceof HTMLInputElement
121
- && el.value.type === 'date'
122
- ) {
123
- localModelValue.value = el.value.value
124
- return
125
- }
126
- let date = typed.value
127
- if (date === null || date === '') {
134
+ if (type.value === INPUT_TYPES.DATETIME_LOCAL
135
+ || type.value === INPUT_TYPES.DATE
136
+ || type.value === INPUT_TYPES.TIME
137
+ || type.value === INPUT_TYPES.MONTH
138
+ ) {
139
+ if (!typed.value) {
128
140
  if (!localModelValue.value) {
129
141
  return
130
142
  }
143
+ if (modelValueDate.value) {
144
+ localModelValue.value = undefined
145
+ return
146
+ }
131
147
  localModelValue.value = ''
132
148
  return
133
149
  }
134
- if (!(date instanceof Date)) {
135
- date = new Date(date)
136
- }
137
- localModelValue.value = `${date.getFullYear()}-${(
138
- `0${
139
- date.getMonth() + 1}`
140
- ).slice(-2)}-${(`0${date.getDate()}`).slice(-2)}`
141
- return
142
- }
143
- if (type.value === INPUT_TYPES.DATETIME_LOCAL) {
144
- if (
145
- el.value instanceof HTMLInputElement
146
- && el.value.type === 'datetime-local'
147
- ) {
148
- localModelValue.value = el.value.value
150
+ if (!(typed.value instanceof Date) && !modelValueDate.value && !modelValueDateIsoString.value) {
151
+ localModelValue.value = typed.value
149
152
  return
150
153
  }
154
+
151
155
  let date = typed.value
152
- if (date === null || date === '') {
153
- if (!localModelValue.value) {
156
+ if (!(date instanceof Date)) {
157
+ date = getDateFromInputValue(typed.value, type.value)
158
+ }
159
+ if (modelValueDate.value || modelValueDateIsoString.value) {
160
+ const toReturn = new Date(modelValueDate.value || modelValueDateIsoString.value as string)
161
+ if (type.value === INPUT_TYPES.DATETIME_LOCAL
162
+ || type.value === INPUT_TYPES.DATE
163
+ || type.value === INPUT_TYPES.MONTH
164
+ ) {
165
+ toReturn.setFullYear(date.getFullYear())
166
+ toReturn.setMonth(date.getMonth())
167
+ }
168
+ if (type.value === INPUT_TYPES.DATETIME_LOCAL
169
+ || type.value === INPUT_TYPES.DATE
170
+ ) {
171
+ toReturn.setDate(date.getDate())
172
+ }
173
+ if (type.value === INPUT_TYPES.DATETIME_LOCAL
174
+ || type.value === INPUT_TYPES.TIME) {
175
+ toReturn.setHours(date.getHours())
176
+ toReturn.setMinutes(date.getMinutes())
177
+ toReturn.setSeconds(date.getSeconds())
178
+ }
179
+ if (modelValueDate.value instanceof Date) {
180
+ if (localModelValue.value?.getTime() === toReturn.getTime()) {
181
+ return
182
+ }
183
+ localModelValue.value = toReturn
154
184
  return
155
185
  }
156
- localModelValue.value = ''
186
+ localModelValue.value = toReturn.toISOString()
157
187
  return
158
188
  }
159
- if (!(typed.value instanceof Date)) {
160
- date = new Date(date)
161
- }
162
- localModelValue.value = `${date.getFullYear()}-${(
163
- `0${
164
- date.getMonth() + 1}`
165
- ).slice(-2)}-${(`0${date.getDate()}`).slice(-2)}T${(
166
- `0${date.getHours()}`
167
- ).slice(-2)}:${(`0${date.getMinutes()}`).slice(-2)}`
189
+ localModelValue.value = getInputValueFromDate(date, type.value, hasSeconds.value)
168
190
  return
169
191
  }
170
192
  if (!localModelValue.value && !unmasked.value) {
@@ -174,14 +196,14 @@ const { el, mask, typed, masked, unmasked } = useIMask(
174
196
  },
175
197
  },
176
198
  )
177
- function updateMaskValue(newValue: string | number | undefined | null) {
199
+ function updateMaskValue(newValue: string | number | Date | undefined | null) {
178
200
  if (newValue === undefined || newValue === null) {
179
201
  typed.value = ''
180
202
  unmasked.value = ''
181
203
  return
182
204
  }
183
205
  if (props.iMask?.mask === Date) {
184
- typed.value = new Date(newValue)
206
+ typed.value = newValue instanceof Date ? newValue : new Date(newValue)
185
207
  return
186
208
  }
187
209
  if (
@@ -191,6 +213,27 @@ function updateMaskValue(newValue: string | number | undefined | null) {
191
213
  ) {
192
214
  return
193
215
  }
216
+ if (type.value === INPUT_TYPES.DATE
217
+ || type.value === INPUT_TYPES.MONTH
218
+ || type.value === INPUT_TYPES.DATETIME_LOCAL
219
+ || type.value === INPUT_TYPES.TIME) {
220
+ if (newValue instanceof Date || isDateIsoString(newValue)) {
221
+ if (newValue instanceof Date) {
222
+ modelValueDate.value = newValue
223
+ modelValueDateIsoString.value = undefined
224
+ }
225
+ else {
226
+ modelValueDateIsoString.value = newValue as string
227
+ modelValueDate.value = undefined
228
+ }
229
+ const newDate = new Date(newValue)
230
+ typed.value = getInputValueFromDate(newDate, type.value, hasSeconds.value)
231
+ unmasked.value = typed.value
232
+ return
233
+ }
234
+ modelValueDate.value = undefined
235
+ modelValueDateIsoString.value = undefined
236
+ }
194
237
  typed.value = newValue
195
238
  unmasked.value = `${typed.value}`
196
239
  }
@@ -219,7 +262,7 @@ watch(
219
262
  const inputEl = el as Ref<HTMLInputElement>
220
263
  const innerEl = ref<HTMLInputElement>()
221
264
  const wrapperEl = ref<HTMLDivElement>()
222
- const dropdownEl = ref<typeof VvDropdown>()
265
+ const suggestionsDropdownEl = ref<InstanceType<typeof VvDropdown>>()
223
266
 
224
267
  defineExpose({ $inner: innerEl })
225
268
 
@@ -232,26 +275,24 @@ watch(isFocused, (newValue) => {
232
275
  if (newValue && propsDefaults.value.selectOnFocus && inputEl.value) {
233
276
  inputEl.value.select()
234
277
  }
235
- if (newValue) {
236
- dropdownEl.value?.show()
278
+ if (newValue && suggestions.value?.size) {
279
+ suggestionsDropdownEl.value?.show()
237
280
  return
238
281
  }
239
- setTimeout(() => {
240
- if (isDirty.value && suggestions.value) {
241
- const suggestionsLimit = props.maxSuggestions - 1
242
- if (
243
- suggestions.value.size > suggestionsLimit
244
- && !suggestions.value.has(localModelValue.value)
245
- ) {
246
- suggestions.value = new Set(
247
- [...suggestions.value].slice(
248
- suggestions.value.size - suggestionsLimit,
249
- ),
250
- )
251
- }
252
- suggestions.value.add(localModelValue.value)
282
+ if (isDirty.value && suggestions.value) {
283
+ const suggestionsLimit = props.maxSuggestions
284
+ if (
285
+ suggestions.value.size >= suggestionsLimit
286
+ && !suggestions.value.has(localModelValue.value)
287
+ ) {
288
+ suggestions.value = new Set(
289
+ [...suggestions.value].slice(
290
+ suggestions.value.size - suggestionsLimit + 1,
291
+ ),
292
+ )
253
293
  }
254
- }, 300)
294
+ suggestions.value.add(localModelValue.value)
295
+ }
255
296
  })
256
297
 
257
298
  // visibility
@@ -386,7 +427,7 @@ const hasSuggestions = computed(
386
427
  )
387
428
  function onSuggestionSelect(suggestion: string) {
388
429
  localModelValue.value = suggestion
389
- dropdownEl.value?.hide()
430
+ suggestionsDropdownEl.value?.hide()
390
431
  }
391
432
  function onSuggestionRemove(suggestion: string) {
392
433
  suggestions.value?.delete(suggestion)
@@ -531,10 +572,9 @@ const hasStyle = computed(() => {
531
572
  return undefined
532
573
  }
533
574
  return {
534
- width:
535
- localModelValue.value !== undefined
536
- ? `${String(localModelValue.value).length + 1}ch`
537
- : undefined,
575
+ width: localModelValue.value !== undefined
576
+ ? `${String(localModelValue.value).length + 1}ch`
577
+ : undefined,
538
578
  }
539
579
  })
540
580
 
@@ -651,7 +691,7 @@ export default {
651
691
  </HintSlot>
652
692
  <VvDropdown
653
693
  v-if="hasSuggestions"
654
- ref="dropdownEl"
694
+ ref="suggestionsDropdownEl"
655
695
  :reference="wrapperEl"
656
696
  :autofocus-first="false"
657
697
  :trigger-width="true"
@@ -45,7 +45,7 @@ export const VvInputTextProps = {
45
45
  * Input value
46
46
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#value
47
47
  */
48
- modelValue: [String, Number],
48
+ modelValue: [String, Number, Date],
49
49
  /**
50
50
  * Type of form control
51
51
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#type
@@ -2,6 +2,8 @@
2
2
  import type { TextareaHTMLAttributes } from 'vue'
3
3
  import { VvTextareaEvents, VvTextareaProps } from '.'
4
4
  import HintSlotFactory from '../common/HintSlot'
5
+ import VvDropdown from '../VvDropdown/VvDropdown.vue'
6
+ import VvDropdownOption from '../VvDropdown/VvDropdownOption.vue'
5
7
  import VvIcon from '../VvIcon/VvIcon.vue'
6
8
 
7
9
  // props, emit and slots
@@ -19,13 +21,17 @@ const propsDefaults = useDefaults<typeof VvTextareaProps>(
19
21
  )
20
22
 
21
23
  // template refs
22
- const textarea = ref()
24
+ const textareaEl = ref<HTMLTextAreaElement>()
25
+ const wrapperEl = ref<HTMLDivElement>()
26
+ const suggestionsDropdownEl = ref<InstanceType<typeof VvDropdown>>()
23
27
 
24
28
  // data
25
29
  const {
26
30
  id,
27
31
  icon,
28
32
  iconPosition,
33
+ iconRemoveSuggestion,
34
+ labelRemoveSuggestion,
29
35
  label,
30
36
  modelValue,
31
37
  count,
@@ -36,6 +42,8 @@ const {
36
42
  debounce,
37
43
  minlength,
38
44
  maxlength,
45
+ storageKey,
46
+ storageType,
39
47
  } = toRefs(props)
40
48
  const hasId = useUniqueId(id)
41
49
  const hasHintId = computed(() => `${hasId.value}-hint`)
@@ -49,12 +57,41 @@ const localModelValue = useDebouncedInput(modelValue, emit, debounce?.value)
49
57
 
50
58
  // icons
51
59
  const { hasIconBefore, hasIconAfter } = useComponentIcon(icon, iconPosition)
60
+ const { hasIcon: hasIconRemoveSuggestion }
61
+ = useComponentIcon(iconRemoveSuggestion)
52
62
 
53
63
  // focus
54
- const { focused } = useComponentFocus(textarea, emit)
64
+ const { focused } = useComponentFocus(textareaEl, emit)
65
+ const isFocused = computed(
66
+ () => focused.value && !props.disabled && !props.readonly,
67
+ )
68
+ watch(isFocused, (newValue) => {
69
+ if (newValue && propsDefaults.value.selectOnFocus && textareaEl.value) {
70
+ textareaEl.value.select()
71
+ }
72
+ if (newValue && suggestions.value?.size) {
73
+ suggestionsDropdownEl.value?.show()
74
+ return
75
+ }
76
+ if (isDirty.value && suggestions.value) {
77
+ const suggestionsLimit = props.maxSuggestions
78
+
79
+ if (
80
+ suggestions.value.size >= suggestionsLimit
81
+ && !suggestions.value.has(localModelValue.value)
82
+ ) {
83
+ suggestions.value = new Set(
84
+ [...suggestions.value].slice(
85
+ suggestions.value.size - suggestionsLimit + 1,
86
+ ),
87
+ )
88
+ }
89
+ suggestions.value.add(localModelValue.value)
90
+ }
91
+ })
55
92
 
56
93
  // visibility
57
- const isVisible = useElementVisibility(textarea)
94
+ const isVisible = useElementVisibility(textareaEl)
58
95
  watch(isVisible, (newValue) => {
59
96
  if (newValue && props.autofocus) {
60
97
  focused.value = true
@@ -88,6 +125,41 @@ const isInvalid = computed(() => {
88
125
  return undefined
89
126
  })
90
127
 
128
+ // suggestions
129
+ const suggestions = usePersistence<Set<string>>(
130
+ storageKey,
131
+ storageType,
132
+ new Set(),
133
+ )
134
+ const filteredSuggestions = computed(() => {
135
+ if (!suggestions.value) {
136
+ return []
137
+ }
138
+ return [...suggestions.value]
139
+ .filter(
140
+ suggestion =>
141
+ isEmpty(localModelValue.value)
142
+ || (`${suggestion}`
143
+ .toLowerCase()
144
+ .includes(`${localModelValue.value}`.toLowerCase())
145
+ && suggestion !== localModelValue.value),
146
+ )
147
+ .reverse()
148
+ })
149
+ const hasSuggestions = computed(
150
+ () =>
151
+ storageKey?.value
152
+ && suggestions.value
153
+ && suggestions.value.size > 0,
154
+ )
155
+ function onSuggestionSelect(suggestion: string) {
156
+ localModelValue.value = suggestion
157
+ suggestionsDropdownEl.value?.hide()
158
+ }
159
+ function onSuggestionRemove(suggestion: string) {
160
+ suggestions.value?.delete(suggestion)
161
+ }
162
+
91
163
  // hint
92
164
  const {
93
165
  HintSlot,
@@ -171,7 +243,7 @@ export default {
171
243
  <label v-if="label" :for="hasId" class="vv-textarea__label">
172
244
  {{ label }}
173
245
  </label>
174
- <div class="vv-textarea__wrapper">
246
+ <div ref="wrapperEl" class="vv-textarea__wrapper">
175
247
  <!-- @slot Slot to replace icon before textarea -->
176
248
  <div v-if="$slots.before" class="vv-textarea__input-before">
177
249
  <!-- @slot Slot before input -->
@@ -185,7 +257,7 @@ export default {
185
257
  />
186
258
  <textarea
187
259
  :id="hasId"
188
- ref="textarea"
260
+ ref="textareaEl"
189
261
  v-model="localModelValue"
190
262
  v-bind="hasAttrs"
191
263
  @keyup="emit('keyup', $event)"
@@ -221,5 +293,36 @@ export default {
221
293
  <slot name="invalid" v-bind="hintSlotScope" />
222
294
  </template>
223
295
  </HintSlot>
296
+ <VvDropdown
297
+ v-if="hasSuggestions"
298
+ ref="suggestionsDropdownEl"
299
+ :reference="wrapperEl"
300
+ :autofocus-first="false"
301
+ :trigger-width="true"
302
+ >
303
+ <template #items>
304
+ <VvDropdownOption
305
+ v-for="value in filteredSuggestions"
306
+ :key="value"
307
+ @click.stop="onSuggestionSelect(value)"
308
+ >
309
+ <div class="flex-1">
310
+ <slot name="suggestion" v-bind="{ value }">
311
+ {{ value }}
312
+ </slot>
313
+ </div>
314
+ <button
315
+ v-if="suggestions && hasIconRemoveSuggestion"
316
+ type="button"
317
+ tabindex="-1"
318
+ class="cursor-pointer"
319
+ :title="labelRemoveSuggestion"
320
+ @click.stop="onSuggestionRemove(value)"
321
+ >
322
+ <VvIcon v-bind="hasIconRemoveSuggestion" />
323
+ </button>
324
+ </VvDropdownOption>
325
+ </template>
326
+ </VvDropdown>
224
327
  </div>
225
328
  </template>
@@ -1,5 +1,6 @@
1
1
  import type { ExtractPropTypes } from 'vue'
2
- import { InputTextareaProps } from '../../props'
2
+ import { InputTextareaProps, StorageProps } from '../../props'
3
+ import { ACTION_ICONS, type VvIconProps } from '../VvIcon'
3
4
 
4
5
  export const WRAP = {
5
6
  hard: 'hard',
@@ -16,6 +17,7 @@ export const VvTextareaEvents = ['update:modelValue', 'focus', 'blur', 'keyup']
16
17
 
17
18
  export const VvTextareaProps = {
18
19
  ...InputTextareaProps,
20
+ ...StorageProps,
19
21
  /**
20
22
  * Textarea value
21
23
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#value
@@ -41,6 +43,35 @@ export const VvTextareaProps = {
41
43
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#wrap
42
44
  */
43
45
  spellcheck: { type: [Boolean, String], default: SPELLCHECK.default },
46
+ /**
47
+ * VvIcon name for remove suggestion button
48
+ * @see VVIcon
49
+ */
50
+ iconRemoveSuggestion: {
51
+ type: [String, Object] as PropType<string | VvIconProps>,
52
+ default: ACTION_ICONS.remove,
53
+ },
54
+ /**
55
+ * Label for remove suggestion button
56
+ */
57
+ labelRemoveSuggestion: {
58
+ type: String,
59
+ default: 'Remove suggestion',
60
+ },
61
+ /**
62
+ * Maximum number of suggestions
63
+ */
64
+ maxSuggestions: {
65
+ type: Number,
66
+ default: 5,
67
+ },
68
+ /**
69
+ * Select input text on focus
70
+ */
71
+ selectOnFocus: {
72
+ type: Boolean,
73
+ default: false,
74
+ },
44
75
  /**
45
76
  * If true, the textarea will be resizable
46
77
  */
@@ -157,3 +157,28 @@ export async function defaultTest({ canvasElement, args }: PlayAttributes) {
157
157
  // check accessibility
158
158
  await expect(element).toHaveNoViolations()
159
159
  }
160
+
161
+ export async function isoTest({ canvasElement, args }: PlayAttributes) {
162
+ const element = await within(canvasElement).findByTestId('element')
163
+ const input = element.getElementsByTagName('input')[0] as HTMLInputElement
164
+ const value = await within(canvasElement).findByTestId('value')
165
+
166
+ const inputDate = getDateFromInputValue(input.value, args.type)
167
+ if (!inputDate) {
168
+ await expect(value.innerHTML).toEqual('null')
169
+ return
170
+ }
171
+ const valueDate = new Date(value.innerHTML)
172
+
173
+ if (args.type === INPUT_TYPES.TIME || args.type === INPUT_TYPES.DATETIME_LOCAL) {
174
+ expect(inputDate.getHours()).toEqual(valueDate.getHours())
175
+ expect(inputDate.getMinutes()).toEqual(valueDate.getMinutes())
176
+ }
177
+ if (args.type === INPUT_TYPES.MONTH || args.type === INPUT_TYPES.DATE || args.type === INPUT_TYPES.DATETIME_LOCAL) {
178
+ expect(inputDate.getMonth()).toEqual(valueDate.getMonth())
179
+ expect(inputDate.getFullYear()).toEqual(valueDate.getFullYear())
180
+ }
181
+ if (args.type === INPUT_TYPES.DATE || args.type === INPUT_TYPES.DATETIME_LOCAL) {
182
+ expect(inputDate.getDate()).toEqual(valueDate.getDate())
183
+ }
184
+ }
@@ -0,0 +1,69 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3'
2
+ import VvInputText from '@/components/VvInputText/VvInputText.vue'
3
+ import { argTypes, defaultArgs } from './InputText.settings'
4
+ import { isoTest } from './InputText.test'
5
+
6
+ const meta: Meta<typeof VvInputText> = {
7
+ title: 'Components/InputText/Iso',
8
+ component: VvInputText,
9
+ args: defaultArgs,
10
+ argTypes,
11
+ }
12
+
13
+ export default meta
14
+
15
+ type Story = StoryObj<typeof VvInputText>
16
+
17
+ export const TypeDate: Story = {
18
+ args: {
19
+ ...defaultArgs,
20
+ type: 'date',
21
+ },
22
+ render: args => ({
23
+ components: { VvInputText },
24
+ setup() {
25
+ return { args }
26
+ },
27
+ data: () => ({
28
+ inputValue: `2024-12-31T23:00:00.000Z`,
29
+ }),
30
+ template: /* html */ `
31
+ <vv-input-text v-bind="args" v-model="inputValue" :data-testData="inputValue" data-testId="element" />
32
+ <div>Value: <span data-testId="value">{{ inputValue }}</span></div>
33
+ `,
34
+ }),
35
+ play: isoTest,
36
+ }
37
+
38
+ export const TypeTime: Story = {
39
+ ...TypeDate,
40
+ args: {
41
+ ...defaultArgs,
42
+ type: 'time',
43
+ },
44
+ }
45
+
46
+ export const TypeTimeMinute: Story = {
47
+ ...TypeDate,
48
+ args: {
49
+ ...defaultArgs,
50
+ type: 'time',
51
+ step: 60,
52
+ },
53
+ }
54
+
55
+ export const TypeMonth: Story = {
56
+ ...TypeDate,
57
+ args: {
58
+ ...defaultArgs,
59
+ type: 'month',
60
+ },
61
+ }
62
+
63
+ export const TypeDateTime: Story = {
64
+ ...TypeDate,
65
+ args: {
66
+ ...defaultArgs,
67
+ type: 'datetime-local',
68
+ },
69
+ }