@volverjs/ui-vue 0.0.10-beta.53 → 0.0.10-beta.55

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 (45) hide show
  1. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.es.js +13 -1
  2. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.umd.js +1 -1
  3. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.vue.d.ts +9 -0
  4. package/dist/components/VvCheckboxGroup/index.d.ts +4 -0
  5. package/dist/components/VvCombobox/VvCombobox.es.js +357 -357
  6. package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
  7. package/dist/components/VvInputFile/VvInputFile.es.js +17 -3
  8. package/dist/components/VvInputFile/VvInputFile.umd.js +1 -1
  9. package/dist/components/VvInputFile/VvInputFile.vue.d.ts +9 -0
  10. package/dist/components/VvInputFile/index.d.ts +4 -0
  11. package/dist/components/VvInputText/VvInputText.es.js +18 -20
  12. package/dist/components/VvInputText/VvInputText.umd.js +1 -1
  13. package/dist/components/VvRadioGroup/VvRadioGroup.es.js +13 -1
  14. package/dist/components/VvRadioGroup/VvRadioGroup.umd.js +1 -1
  15. package/dist/components/VvRadioGroup/VvRadioGroup.vue.d.ts +9 -0
  16. package/dist/components/VvRadioGroup/index.d.ts +4 -0
  17. package/dist/components/VvTextarea/VvTextarea.es.js +1296 -397
  18. package/dist/components/VvTextarea/VvTextarea.umd.js +1 -1
  19. package/dist/components/VvTextarea/VvTextarea.vue.d.ts +52 -0
  20. package/dist/components/VvTextarea/index.d.ts +37 -1
  21. package/dist/components/index.es.js +421 -261
  22. package/dist/components/index.umd.js +1 -1
  23. package/dist/icons.es.js +3 -3
  24. package/dist/icons.umd.js +1 -1
  25. package/dist/props/index.d.ts +8 -1
  26. package/dist/stories/InputText/InputText.stories.d.ts +2 -0
  27. package/dist/stories/InputText/InputText.test.d.ts +2 -0
  28. package/package.json +23 -23
  29. package/src/assets/icons/detailed.json +1 -1
  30. package/src/assets/icons/normal.json +1 -1
  31. package/src/assets/icons/simple.json +1 -1
  32. package/src/components/VvCheckbox/VvCheckbox.vue +2 -2
  33. package/src/components/VvCheckboxGroup/VvCheckboxGroup.vue +2 -0
  34. package/src/components/VvCombobox/VvCombobox.vue +3 -3
  35. package/src/components/VvInputFile/VvInputFile.vue +12 -8
  36. package/src/components/VvInputFile/index.ts +2 -0
  37. package/src/components/VvInputText/VvInputText.vue +20 -22
  38. package/src/components/VvRadio/VvRadio.vue +2 -2
  39. package/src/components/VvRadioGroup/VvRadioGroup.vue +2 -0
  40. package/src/components/VvTextarea/VvTextarea.vue +109 -6
  41. package/src/components/VvTextarea/index.ts +32 -1
  42. package/src/props/index.ts +2 -1
  43. package/src/stories/InputText/InputText.stories.ts +37 -1
  44. package/src/stories/InputText/InputText.test.ts +18 -0
  45. package/src/stories/Textarea/Textarea.stories.ts +1 -1
@@ -170,10 +170,10 @@ export default {
170
170
  v-model="localModelValue"
171
171
  type="checkbox"
172
172
  class="vv-checkbox__input"
173
- :name="name"
173
+ :name
174
174
  :disabled="isDisabled"
175
175
  :value="hasValue"
176
- :tabindex="tabindex"
176
+ :tabindex
177
177
  :aria-invalid="isInvalid"
178
178
  :aria-describedby="hasHintLabelOrSlot ? hasHintId : undefined"
179
179
  :aria-errormessage="hasInvalidLabelOrSlot ? hasHintId : undefined"
@@ -43,6 +43,7 @@ const bemCssClasses = useModifiers(
43
43
  computed(() => ({
44
44
  disabled: disabled.value,
45
45
  readonly: readonly.value,
46
+ required: props.required,
46
47
  horizontal: !vertical.value,
47
48
  valid: valid.value,
48
49
  invalid: invalid.value,
@@ -56,6 +57,7 @@ function getOptionProps(option: string | Option, index: number) {
56
57
  name: props.name,
57
58
  label: getOptionLabel(option),
58
59
  value: getOptionValue(option),
60
+ required: props.required,
59
61
  }
60
62
  }
61
63
  const { HintSlot, hintSlotScope } = HintSlotFactory(propsDefaults, slots)
@@ -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 {
@@ -43,10 +43,13 @@ const bemCssClasses = useModifiers(
43
43
  'vv-input-file',
44
44
  modifiers,
45
45
  computed(() => ({
46
- 'dragging': isDragging.value,
47
- 'loading': props.loading && !hasProgress.value,
48
46
  'valid': props.valid === true,
49
47
  'invalid': props.invalid === true,
48
+ 'loading': props.loading && !hasProgress.value,
49
+ 'disabled': props.disabled,
50
+ 'required': props.required,
51
+ 'readonly': props.readonly,
52
+ 'dragging': isDragging.value,
50
53
  'icon-before': !!hasIconBefore.value,
51
54
  'icon-after': !!hasIconAfter.value,
52
55
  'drop-area': hasDropArea.value,
@@ -325,18 +328,19 @@ export default {
325
328
  :id="hasId"
326
329
  ref="inputEl"
327
330
  type="file"
328
- :readonly="readonly"
329
- :disabled="disabled"
330
- :placeholder="placeholder"
331
+ :readonly
332
+ :disabled
333
+ :required
334
+ :placeholder
331
335
  :aria-describedby="hasHintLabelOrSlot ? hasHintId : undefined"
332
336
  :aria-invalid="invalid"
333
337
  :aria-errormessage="
334
338
  hasInvalidLabelOrSlot ? hasHintId : undefined
335
339
  "
336
340
  :multiple="isMultiple"
337
- :accept="accept"
338
- :capture="capture"
339
- :name="name"
341
+ :accept
342
+ :capture
343
+ :name
340
344
  @change="onChange"
341
345
  >
342
346
  <progress
@@ -9,6 +9,7 @@ import {
9
9
  LoadingProps,
10
10
  ModifiersProps,
11
11
  ReadonlyProps,
12
+ RequiredProps,
12
13
  ValidProps,
13
14
  } from '../../props'
14
15
  import { ACTION_ICONS, type VvIconProps } from '../VvIcon'
@@ -35,6 +36,7 @@ export const VvInputFileProps = {
35
36
  ...LoadingProps,
36
37
  ...ReadonlyProps,
37
38
  ...DisabledProps,
39
+ ...RequiredProps,
38
40
  ...IconProps,
39
41
  /**
40
42
  * Input value
@@ -174,8 +174,8 @@ const { el, mask, typed, masked, unmasked } = useIMask(
174
174
  },
175
175
  },
176
176
  )
177
- function updateMaskValue(newValue: string | number | undefined) {
178
- if (newValue === undefined) {
177
+ function updateMaskValue(newValue: string | number | undefined | null) {
178
+ if (newValue === undefined || newValue === null) {
179
179
  typed.value = ''
180
180
  unmasked.value = ''
181
181
  return
@@ -219,7 +219,7 @@ watch(
219
219
  const inputEl = el as Ref<HTMLInputElement>
220
220
  const innerEl = ref<HTMLInputElement>()
221
221
  const wrapperEl = ref<HTMLDivElement>()
222
- const dropdownEl = ref<typeof VvDropdown>()
222
+ const suggestionsDropdownEl = ref<InstanceType<typeof VvDropdown>>()
223
223
 
224
224
  defineExpose({ $inner: innerEl })
225
225
 
@@ -232,26 +232,24 @@ watch(isFocused, (newValue) => {
232
232
  if (newValue && propsDefaults.value.selectOnFocus && inputEl.value) {
233
233
  inputEl.value.select()
234
234
  }
235
- if (newValue) {
236
- dropdownEl.value?.show()
235
+ if (newValue && suggestions.value?.size) {
236
+ suggestionsDropdownEl.value?.show()
237
237
  return
238
238
  }
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)
239
+ if (isDirty.value && suggestions.value) {
240
+ const suggestionsLimit = props.maxSuggestions
241
+ if (
242
+ suggestions.value.size >= suggestionsLimit
243
+ && !suggestions.value.has(localModelValue.value)
244
+ ) {
245
+ suggestions.value = new Set(
246
+ [...suggestions.value].slice(
247
+ suggestions.value.size - suggestionsLimit + 1,
248
+ ),
249
+ )
253
250
  }
254
- }, 300)
251
+ suggestions.value.add(localModelValue.value)
252
+ }
255
253
  })
256
254
 
257
255
  // visibility
@@ -386,7 +384,7 @@ const hasSuggestions = computed(
386
384
  )
387
385
  function onSuggestionSelect(suggestion: string) {
388
386
  localModelValue.value = suggestion
389
- dropdownEl.value?.hide()
387
+ suggestionsDropdownEl.value?.hide()
390
388
  }
391
389
  function onSuggestionRemove(suggestion: string) {
392
390
  suggestions.value?.delete(suggestion)
@@ -651,7 +649,7 @@ export default {
651
649
  </HintSlot>
652
650
  <VvDropdown
653
651
  v-if="hasSuggestions"
654
- ref="dropdownEl"
652
+ ref="suggestionsDropdownEl"
655
653
  :reference="wrapperEl"
656
654
  :autofocus-first="false"
657
655
  :trigger-width="true"
@@ -98,10 +98,10 @@ export default {
98
98
  v-model="localModelValue"
99
99
  type="radio"
100
100
  class="vv-radio__input"
101
- :name="name"
101
+ :name
102
102
  :disabled="isDisabled"
103
103
  :value="hasValue"
104
- :tabindex="tabindex"
104
+ :tabindex
105
105
  :aria-invalid="isInvalid"
106
106
  :aria-describedby="hasHintLabelOrSlot ? hasHintId : undefined"
107
107
  :aria-errormessage="hasInvalidLabelOrSlot ? hasHintId : undefined"
@@ -43,6 +43,7 @@ const bemCssClasses = useModifiers(
43
43
  computed(() => ({
44
44
  disabled: disabled.value,
45
45
  readonly: readonly.value,
46
+ required: props.required,
46
47
  horizontal: !vertical.value,
47
48
  valid: valid.value,
48
49
  invalid: invalid.value,
@@ -56,6 +57,7 @@ function getOptionProps(option: string | Option, index: number) {
56
57
  name: props.name,
57
58
  label: getOptionLabel(option),
58
59
  value: getOptionValue(option),
60
+ required: props.required,
59
61
  }
60
62
  }
61
63
 
@@ -1,8 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  import type { TextareaHTMLAttributes } from 'vue'
3
+ import { VvTextareaEvents, VvTextareaProps } from '.'
3
4
  import HintSlotFactory from '../common/HintSlot'
5
+ import VvDropdown from '../VvDropdown/VvDropdown.vue'
6
+ import VvDropdownOption from '../VvDropdown/VvDropdownOption.vue'
4
7
  import VvIcon from '../VvIcon/VvIcon.vue'
5
- import { VvTextareaEvents, VvTextareaProps } from '.'
6
8
 
7
9
  // props, emit and slots
8
10
  const props = defineProps(VvTextareaProps)
@@ -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
  */
@@ -1,4 +1,3 @@
1
- import type { PropType } from 'vue'
2
1
  import type { VvIconProps } from '@/components/VvIcon'
3
2
  import type {
4
3
  AutoPlacementOptions,
@@ -9,6 +8,7 @@ import type {
9
8
  } from '@/types/floating-ui'
10
9
  import type { Option } from '@/types/generic'
11
10
  import type { NavItem } from '@/types/nav'
11
+ import type { PropType } from 'vue'
12
12
  import {
13
13
  ActionTag,
14
14
  ButtonType,
@@ -493,6 +493,7 @@ export const CheckboxRadioGroupProps = {
493
493
  ...ModifiersProps,
494
494
  ...LabelProps,
495
495
  ...LoadingProps,
496
+ ...RequiredProps,
496
497
  /**
497
498
  * Input value
498
499
  */
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/vue3'
2
2
  import VvInputText from '@/components/VvInputText/VvInputText.vue'
3
3
  import { Position } from '@/constants'
4
4
  import { argTypes, defaultArgs } from './InputText.settings'
5
- import { defaultTest } from './InputText.test'
5
+ import { checkNullTest, checkUndefinedTest, defaultTest } from './InputText.test'
6
6
 
7
7
  const meta: Meta<typeof VvInputText> = {
8
8
  title: 'Components/InputText',
@@ -39,6 +39,42 @@ export const Default: Story = {
39
39
  play: defaultTest,
40
40
  }
41
41
 
42
+ export const Null: Story = {
43
+ args: {
44
+ ...defaultArgs,
45
+ },
46
+ render: args => ({
47
+ components: { VvInputText },
48
+ setup() {
49
+ return { args }
50
+ },
51
+ data: () => ({ inputValue: null, maskedInputValue: undefined }),
52
+ template: /* html */ `
53
+ <vv-input-text v-bind="args" v-model="inputValue" v-model:masked="maskedInputValue" :data-testData="inputValue" data-testId="element" />
54
+ <div>Value: <span data-testId="value">{{ JSON.stringify(inputValue) }}</span></div>
55
+ `,
56
+ }),
57
+ play: checkNullTest,
58
+ }
59
+
60
+ export const Undefined: Story = {
61
+ args: {
62
+ ...defaultArgs,
63
+ },
64
+ render: args => ({
65
+ components: { VvInputText },
66
+ setup() {
67
+ return { args }
68
+ },
69
+ data: () => ({ inputValue: undefined, maskedInputValue: undefined }),
70
+ template: /* html */ `
71
+ <vv-input-text v-bind="args" v-model="inputValue" v-model:masked="maskedInputValue" :data-testData="inputValue" data-testId="element" />
72
+ <div>Value: <span data-testId="value">{{ inputValue === undefined ? 'undefined' : inputValue }}</span></div>
73
+ `,
74
+ }),
75
+ play: checkUndefinedTest,
76
+ }
77
+
42
78
  export const Disabled: Story = {
43
79
  ...Default,
44
80
  args: {
@@ -49,6 +49,24 @@ function valueByType(type: InputType, mask?: string, id?: string) {
49
49
  }
50
50
  }
51
51
 
52
+ export async function checkNullTest({ canvasElement }: PlayAttributes) {
53
+ const element = await within(canvasElement).findByTestId('element')
54
+ const value = await within(canvasElement).findByTestId('value')
55
+ const input = element.getElementsByTagName('input')[0]
56
+
57
+ await expect(input).toHaveProperty('value', '')
58
+ await expect(value.innerHTML).toEqual('null')
59
+ }
60
+
61
+ export async function checkUndefinedTest({ canvasElement }: PlayAttributes) {
62
+ const element = await within(canvasElement).findByTestId('element')
63
+ const value = await within(canvasElement).findByTestId('value')
64
+ const input = element.getElementsByTagName('input')[0]
65
+
66
+ await expect(input).toHaveProperty('value', '')
67
+ await expect(value.innerHTML).toEqual('undefined')
68
+ }
69
+
52
70
  export async function defaultTest({ canvasElement, args }: PlayAttributes) {
53
71
  const element = await within(canvasElement).findByTestId('element')
54
72
  const value = await within(canvasElement).findByTestId('value')
@@ -31,7 +31,7 @@ export const Default: Story = {
31
31
  <template #after v-if="args.after"><div class="flex" v-html="args.after"></div></template>
32
32
  <template #hint v-if="args.hint"><span v-html="args.hint"></span></template>
33
33
  </vv-textarea>
34
- <div>Value: <span data-testId="value">{{inputValue}}</span></div>
34
+ <div>Value: <span data-testId="value">{{ inputValue }}</span></div>
35
35
  `,
36
36
  }),
37
37
  play: defaultTest,