@volverjs/ui-vue 0.0.6-beta.5 → 0.0.6-beta.7

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 (70) hide show
  1. package/auto-imports.d.ts +9 -0
  2. package/dist/Volver.d.ts +1 -1
  3. package/dist/components/VvAccordion/index.d.ts +1 -1
  4. package/dist/components/VvButton/VvButton.es.js +25 -19
  5. package/dist/components/VvButton/VvButton.umd.js +1 -1
  6. package/dist/components/VvCheckbox/VvCheckbox.es.js +151 -98
  7. package/dist/components/VvCheckbox/VvCheckbox.umd.js +1 -1
  8. package/dist/components/VvCheckbox/VvCheckbox.vue.d.ts +37 -1
  9. package/dist/components/VvCheckbox/index.d.ts +6 -1
  10. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.es.js +187 -101
  11. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.umd.js +1 -1
  12. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.vue.d.ts +36 -0
  13. package/dist/components/VvCheckboxGroup/index.d.ts +5 -0
  14. package/dist/components/VvCombobox/VvCombobox.es.js +236 -140
  15. package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
  16. package/dist/components/VvCombobox/VvCombobox.vue.d.ts +25 -1
  17. package/dist/components/VvDialog/VvDialog.es.js +25 -19
  18. package/dist/components/VvDialog/VvDialog.umd.js +1 -1
  19. package/dist/components/VvDropdown/VvDropdown.es.js +19 -4
  20. package/dist/components/VvDropdown/VvDropdown.umd.js +1 -1
  21. package/dist/components/VvDropdown/VvDropdown.vue.d.ts +8 -4
  22. package/dist/components/VvDropdown/index.d.ts +1 -1
  23. package/dist/components/VvIcon/VvIcon.es.js +25 -19
  24. package/dist/components/VvIcon/VvIcon.umd.js +1 -1
  25. package/dist/components/VvIcon/VvIcon.vue.d.ts +2 -2
  26. package/dist/components/VvIcon/index.d.ts +2 -2
  27. package/dist/components/VvInputText/VvInputText.es.js +160 -136
  28. package/dist/components/VvInputText/VvInputText.umd.js +1 -1
  29. package/dist/components/VvInputText/VvInputText.vue.d.ts +24 -0
  30. package/dist/components/VvRadio/VvRadio.es.js +151 -98
  31. package/dist/components/VvRadio/VvRadio.umd.js +1 -1
  32. package/dist/components/VvRadio/VvRadio.vue.d.ts +37 -1
  33. package/dist/components/VvRadio/index.d.ts +6 -1
  34. package/dist/components/VvRadioGroup/VvRadioGroup.es.js +187 -101
  35. package/dist/components/VvRadioGroup/VvRadioGroup.umd.js +1 -1
  36. package/dist/components/VvRadioGroup/VvRadioGroup.vue.d.ts +36 -0
  37. package/dist/components/VvRadioGroup/index.d.ts +5 -0
  38. package/dist/components/VvSelect/VvSelect.es.js +163 -137
  39. package/dist/components/VvSelect/VvSelect.umd.js +1 -1
  40. package/dist/components/VvSelect/VvSelect.vue.d.ts +24 -0
  41. package/dist/components/VvTextarea/VvTextarea.es.js +160 -136
  42. package/dist/components/VvTextarea/VvTextarea.umd.js +1 -1
  43. package/dist/components/VvTextarea/VvTextarea.vue.d.ts +24 -0
  44. package/dist/components/common/HintSlot.d.ts +38 -12
  45. package/dist/components/index.es.js +466 -168
  46. package/dist/components/index.umd.js +1 -1
  47. package/dist/composables/group/useInjectedGroupState.d.ts +1 -1
  48. package/dist/composables/useOptions.d.ts +2 -2
  49. package/dist/directives/index.d.ts +2 -2
  50. package/dist/icons.es.js +3 -3
  51. package/dist/icons.umd.js +1 -1
  52. package/dist/props/index.d.ts +22 -0
  53. package/package.json +33 -33
  54. package/src/assets/icons/detailed.json +1 -1
  55. package/src/assets/icons/normal.json +1 -1
  56. package/src/assets/icons/simple.json +1 -1
  57. package/src/components/VvCheckbox/VvCheckbox.vue +23 -2
  58. package/src/components/VvCheckboxGroup/VvCheckboxGroup.vue +15 -2
  59. package/src/components/VvCombobox/VvCombobox.vue +40 -16
  60. package/src/components/VvDropdown/VvDropdown.vue +20 -2
  61. package/src/components/VvIcon/VvIcon.vue +37 -34
  62. package/src/components/VvIcon/index.ts +2 -2
  63. package/src/components/VvInputText/VvInputText.vue +26 -9
  64. package/src/components/VvRadio/VvRadio.vue +23 -2
  65. package/src/components/VvRadioGroup/VvRadioGroup.vue +15 -2
  66. package/src/components/VvSelect/VvSelect.vue +26 -9
  67. package/src/components/VvTextarea/VvTextarea.vue +26 -9
  68. package/src/components/common/HintSlot.ts +129 -170
  69. package/src/composables/useOptions.ts +9 -7
  70. package/src/props/index.ts +2 -0
@@ -26,6 +26,7 @@
26
26
  isInGroup,
27
27
  } = useGroupProps(props, emit)
28
28
  const hasId = useUniqueId(id)
29
+ const hasHintId = computed(() => `${hasId.value}-hint`)
29
30
  const tabindex = computed(() => (isDisabled.value ? -1 : props.tabindex))
30
31
 
31
32
  // template ref
@@ -144,7 +145,12 @@
144
145
  })
145
146
 
146
147
  // hint
147
- const { HintSlot } = HintSlotFactory(props, slots)
148
+ const {
149
+ HintSlot,
150
+ hasHintLabelOrSlot,
151
+ hasInvalidLabelOrSlot,
152
+ hintSlotScope,
153
+ } = HintSlotFactory(props, slots)
148
154
  </script>
149
155
 
150
156
  <template>
@@ -160,11 +166,26 @@
160
166
  :value="hasValue"
161
167
  :tabindex="tabindex"
162
168
  :aria-invalid="isInvalid"
169
+ :aria-describedby="hasHintLabelOrSlot ? hasHintId : undefined"
170
+ :aria-errormessage="hasInvalidLabelOrSlot ? hasHintId : undefined"
163
171
  />
164
172
  <!-- @slot Use this slot for check label -->
165
173
  <slot :value="modelValue">
166
174
  {{ label }}
167
175
  </slot>
168
- <HintSlot class="vv-checkbox__hint" :params="{ value: modelValue }" />
176
+ <HintSlot :id="hasHintId" class="vv-checkbox__hint">
177
+ <template v-if="$slots.hint" #hint>
178
+ <slot name="hint" v-bind="hintSlotScope" />
179
+ </template>
180
+ <template v-if="$slots.loading" #loading>
181
+ <slot name="loading" v-bind="hintSlotScope" />
182
+ </template>
183
+ <template v-if="$slots.valid" #valid>
184
+ <slot name="valid" v-bind="hintSlotScope" />
185
+ </template>
186
+ <template v-if="$slots.invalid" #invalid>
187
+ <slot name="invalid" v-bind="hintSlotScope" />
188
+ </template>
189
+ </HintSlot>
169
190
  </label>
170
191
  </template>
@@ -56,7 +56,7 @@
56
56
  value: getOptionValue(option),
57
57
  }
58
58
  }
59
- const { HintSlot } = HintSlotFactory(props, slots)
59
+ const { HintSlot, hintSlotScope } = HintSlotFactory(props, slots)
60
60
  </script>
61
61
 
62
62
  <template>
@@ -74,6 +74,19 @@
74
74
  <!-- #endregion -->
75
75
  <slot v-else />
76
76
  </div>
77
- <HintSlot class="vv-checkbox-group__hint" />
77
+ <HintSlot class="vv-checkbox-group__hint">
78
+ <template v-if="$slots.hint" #hint>
79
+ <slot name="hint" v-bind="hintSlotScope" />
80
+ </template>
81
+ <template v-if="$slots.loading" #loading>
82
+ <slot name="loading" v-bind="hintSlotScope" />
83
+ </template>
84
+ <template v-if="$slots.valid" #valid>
85
+ <slot name="valid" v-bind="hintSlotScope" />
86
+ </template>
87
+ <template v-if="$slots.invalid" #invalid>
88
+ <slot name="invalid" v-bind="hintSlotScope" />
89
+ </template>
90
+ </HintSlot>
78
91
  </fieldset>
79
92
  </template>
@@ -39,7 +39,12 @@
39
39
  }
40
40
 
41
41
  // hint slot
42
- const { HintSlot } = HintSlotFactory(props, slots)
42
+ const {
43
+ HintSlot,
44
+ hasHintLabelOrSlot,
45
+ hasInvalidLabelOrSlot,
46
+ hintSlotScope,
47
+ } = HintSlotFactory(props, slots)
43
48
 
44
49
  // template ref
45
50
  const inputEl: Ref<HTMLElement | null> = ref(null)
@@ -93,19 +98,18 @@
93
98
  if (props.disabled || props.readonly || !expanded.value) return
94
99
  expanded.value = false
95
100
  }
96
- watch(expanded, (newValue) => {
101
+ const onAfterExpand = () => {
97
102
  if (searchable.value) {
98
- nextTick(() => {
99
- if (newValue) {
100
- if (inputSearchEl.value) {
101
- inputSearchEl.value.focus()
102
- }
103
- return
104
- }
105
- searchText.value = ''
106
- })
103
+ if (inputSearchEl.value) {
104
+ inputSearchEl.value.focus()
105
+ }
107
106
  }
108
- })
107
+ }
108
+ const onAfterCollapse = () => {
109
+ if (searchable.value) {
110
+ searchText.value = ''
111
+ }
112
+ }
109
113
 
110
114
  // data
111
115
  const {
@@ -368,6 +372,8 @@
368
372
  v-model="expanded"
369
373
  v-bind="dropdownProps"
370
374
  :role="DropdownRole.listbox"
375
+ @after-expand="onAfterExpand"
376
+ @after-collapse="onAfterCollapse"
371
377
  >
372
378
  <template
373
379
  v-if="searchable || $slots['dropdown::before']"
@@ -383,8 +389,6 @@
383
389
  v-model="searchText"
384
390
  aria-autocomplete="list"
385
391
  :aria-controls="hasDropdownId"
386
- :aria-labelledby="hasLabelId"
387
- :aria-describedby="hasHintId"
388
392
  autocomplete="off"
389
393
  spellcheck="false"
390
394
  type="search"
@@ -406,9 +410,16 @@
406
410
  <div
407
411
  ref="inputEl"
408
412
  v-bind="aria"
409
- :aria-labelledby="hasLabelId"
410
413
  class="vv-select__input"
411
414
  role="combobox"
415
+ :aria-expanded="expanded"
416
+ :aria-labelledby="hasLabelId"
417
+ :aria-describedby="
418
+ hasHintLabelOrSlot ? hasHintId : undefined
419
+ "
420
+ :aria-errormessage="
421
+ hasInvalidLabelOrSlot ? hasHintId : undefined
422
+ "
412
423
  :tabindex="hasTabindex"
413
424
  @click.passive="onClickInput"
414
425
  >
@@ -558,7 +569,20 @@
558
569
  </template>
559
570
  </VvDropdown>
560
571
  </div>
561
- <HintSlot :id="hasHintId" class="vv-select__hint" />
572
+ <HintSlot :id="hasHintId" class="vv-select__hint">
573
+ <template v-if="$slots.hint" #hint>
574
+ <slot name="hint" v-bind="hintSlotScope" />
575
+ </template>
576
+ <template v-if="$slots.loading" #loading>
577
+ <slot name="loading" v-bind="hintSlotScope" />
578
+ </template>
579
+ <template v-if="$slots.valid" #valid>
580
+ <slot name="valid" v-bind="hintSlotScope" />
581
+ </template>
582
+ <template v-if="$slots.invalid" #invalid>
583
+ <slot name="invalid" v-bind="hintSlotScope" />
584
+ </template>
585
+ </HintSlot>
562
586
  </div>
563
587
  <VvSelect
564
588
  v-else
@@ -28,7 +28,13 @@
28
28
 
29
29
  // props, emit and attrs
30
30
  const props = defineProps(VvDropdownProps)
31
- const emit = defineEmits(['update:modelValue'])
31
+ const emit = defineEmits([
32
+ 'update:modelValue',
33
+ 'beforeExpand',
34
+ 'beforeCollapse',
35
+ 'afterExpand',
36
+ 'afterCollapse',
37
+ ])
32
38
  const { id } = toRefs(props)
33
39
  const hasId = useUniqueId(id)
34
40
  const attrs = useAttrs()
@@ -334,6 +340,12 @@
334
340
  activeElement.click()
335
341
  }
336
342
  })
343
+ const onTransitionBeforeEnter = () => {
344
+ emit(expanded.value ? 'beforeExpand' : 'beforeCollapse')
345
+ }
346
+ const onTransitionAfterLeave = () => {
347
+ emit(expanded.value ? 'afterExpand' : 'afterCollapse')
348
+ }
337
349
  </script>
338
350
 
339
351
  <template>
@@ -342,7 +354,13 @@
342
354
  v-bind="{ init, show, hide, toggle, expanded, aria: referenceAria }"
343
355
  />
344
356
  </VvDropdownTriggerProvider>
345
- <Transition :name="transitionName">
357
+ <Transition
358
+ :name="transitionName"
359
+ v-on="{
360
+ beforeEnter: onTransitionBeforeEnter,
361
+ onAfterLeave: onTransitionAfterLeave,
362
+ }"
363
+ >
346
364
  <div
347
365
  v-show="expanded"
348
366
  ref="floatingEl"
@@ -5,12 +5,19 @@
5
5
  </script>
6
6
 
7
7
  <script setup lang="ts">
8
- import { Icon, addIcon, iconExists, type IconifyJSON } from '@iconify/vue'
8
+ import { Icon, addIcon, iconExists } from '@iconify/vue'
9
9
  import { VvIconProps } from '.'
10
10
 
11
11
  // props
12
12
  const props = defineProps(VvIconProps)
13
13
 
14
+ const hasRotate = computed(() => {
15
+ if (typeof props.rotate === 'string') {
16
+ return parseFloat(props.rotate)
17
+ }
18
+ return props.rotate
19
+ })
20
+
14
21
  // data
15
22
  const show = ref(true)
16
23
 
@@ -21,49 +28,43 @@
21
28
  const { modifiers } = toRefs(props)
22
29
  const bemCssClasses = useModifiers('vv-icon', modifiers)
23
30
 
24
- /**
25
- * Provider name
26
- */
31
+ // provider name
27
32
  const provider = computed(() => {
28
33
  return props.provider || volver?.iconsProvider
29
34
  })
30
35
 
31
- /**
32
- * Icon name
33
- */
36
+ // icon name
34
37
  const icon = computed(() => {
35
- const _name = props.name ?? ''
38
+ const name = props.name ?? ''
36
39
  // compose Iconify icon name format
37
- const iconName = `@${provider.value}:${props.prefix}:${props.name}`
40
+ const iconName = `@${provider.value}:${props.prefix}:${name}`
38
41
 
39
- // Check first if icon with "name" exist
40
- if (iconExists(_name)) {
41
- return _name
42
- } else if (iconExists(iconName)) {
43
- // Check and return composed icon name if exist
42
+ // Check if icon with prefix and provider exist
43
+ if (iconExists(iconName)) {
44
44
  return iconName
45
- } else {
46
- // Check into all collections and set "iconName" data
47
- return (
48
- volver?.iconsCollections.find(
49
- (iconsCollection: IconifyJSON) => {
50
- const icon = `@${provider.value}:${iconsCollection.prefix}:${_name}`
51
- if (iconExists(icon)) {
52
- return icon
53
- }
54
- },
55
- ) || _name
56
- )
57
45
  }
46
+
47
+ // Check if icon exist into any collection
48
+ const iconsCollection = volver?.iconsCollections.find(
49
+ (iconsCollection) => {
50
+ const icon = `@${provider.value}:${iconsCollection.prefix}:${name}`
51
+ return iconExists(icon)
52
+ },
53
+ )
54
+ if (iconsCollection) {
55
+ return `@${provider.value}:${iconsCollection.prefix}:${name}`
56
+ }
57
+
58
+ return name
58
59
  })
59
60
 
60
61
  /**
61
62
  * Get SVG content from SVG string
62
63
  * @param {string} svg
63
- * @return {SVGSVGElement | null} https://developer.mozilla.org/en-US/docs/Web/API/SVGSVGElement
64
+ * @return {SVGSVGElement | undefined} https://developer.mozilla.org/en-US/docs/Web/API/SVGSVGElement
64
65
  */
65
- function getSvgContent(svg: string): SVGSVGElement | null {
66
- let dom = null
66
+ function getSvgContent(svg: string): SVGSVGElement | undefined {
67
+ let dom
67
68
  if (typeof window === 'undefined') {
68
69
  // SSR
69
70
  // eslint-disable-next-line @typescript-eslint/no-var-requires, no-undef
@@ -81,7 +82,7 @@
81
82
  * @param {string} svg
82
83
  */
83
84
  function addIconFromSvg(svg: string) {
84
- const svgContentEl: SVGSVGElement | null = getSvgContent(svg)
85
+ const svgContentEl = getSvgContent(svg)
85
86
  const svgContent = svgContentEl?.innerHTML.trim() || ''
86
87
  if (svgContentEl && svgContent) {
87
88
  addIcon(`@${provider.value}:${props.prefix}:${props.name}`, {
@@ -108,12 +109,14 @@
108
109
  }
109
110
  })
110
111
  .catch((e) => {
111
- throw new Error(`During fetch icon: ${e?.message}`)
112
+ throw new Error(`Error during fetch icon: ${e?.message}`)
112
113
  })
113
- } else if (props.svg) {
114
- addIconFromSvg(props.svg)
115
114
  }
116
115
  }
116
+
117
+ if (props.svg) {
118
+ addIconFromSvg(props.svg)
119
+ }
117
120
  </script>
118
121
 
119
122
  <template>
@@ -127,7 +130,7 @@
127
130
  horizontalFlip,
128
131
  verticalFlip,
129
132
  flip,
130
- rotate,
133
+ rotate: hasRotate,
131
134
  color,
132
135
  onLoad,
133
136
  icon,
@@ -1,5 +1,5 @@
1
1
  import type { PropType } from 'vue'
2
- import type { IconifyRenderMode } from '@iconify/vue'
2
+ import type { IconifyIconOnLoad, IconifyRenderMode } from '@iconify/vue'
3
3
 
4
4
  export enum IconPrefix {
5
5
  simple = 'simple',
@@ -88,7 +88,7 @@ export const VvIconProps = {
88
88
  /**
89
89
  * A callback that is called when icon data has been loaded
90
90
  */
91
- onLoad: Function,
91
+ onLoad: Function as PropType<IconifyIconOnLoad>,
92
92
  /**
93
93
  * SVG icon string
94
94
  */
@@ -41,7 +41,7 @@
41
41
  loading,
42
42
  } = toRefs(props)
43
43
  const hasId = useUniqueId(id)
44
- const hasDescribedBy = computed(() => `${hasId.value}-hint`)
44
+ const hasHintId = computed(() => `${hasId.value}-hint`)
45
45
  // BUG: https://www.samanthaming.com/tidbits/88-css-placeholder-shown/
46
46
  const inputTextPlaceholder = computed(() =>
47
47
  props.floating && isEmpty(props.placeholder) ? ' ' : props.placeholder,
@@ -211,12 +211,11 @@
211
211
  required: props.required,
212
212
  autocomplete: props.autocomplete,
213
213
  'aria-invalid': isInvalid.value,
214
- 'aria-describedby':
215
- !hasInvalid.value && hasHint.value
216
- ? hasDescribedBy.value
217
- : undefined,
218
- 'aria-errormessage': hasInvalid.value
219
- ? hasDescribedBy.value
214
+ 'aria-describedby': hasHintLabelOrSlot.value
215
+ ? hasHintId.value
216
+ : undefined,
217
+ 'aria-errormessage': hasInvalidLabelOrSlot.value
218
+ ? hasHintId.value
220
219
  : undefined,
221
220
  }
222
221
  if (
@@ -274,7 +273,12 @@
274
273
  }))
275
274
 
276
275
  // components
277
- const { HintSlot, hasHint, hasInvalid } = HintSlotFactory(props, slots)
276
+ const {
277
+ HintSlot,
278
+ hasHintLabelOrSlot,
279
+ hasInvalidLabelOrSlot,
280
+ hintSlotScope,
281
+ } = HintSlotFactory(props, slots)
278
282
  const PasswordInputActions = VvInputTextActionsFactory(
279
283
  INPUT_TYPES.PASSWORD,
280
284
  props,
@@ -403,6 +407,19 @@
403
407
  </slot>
404
408
  </span>
405
409
  </div>
406
- <HintSlot :id="hasDescribedBy" class="vv-input-text__hint" />
410
+ <HintSlot :id="hasHintId" class="vv-input-text__hint">
411
+ <template v-if="$slots.hint" #hint>
412
+ <slot name="hint" v-bind="hintSlotScope" />
413
+ </template>
414
+ <template v-if="$slots.loading" #loading>
415
+ <slot name="loading" v-bind="hintSlotScope" />
416
+ </template>
417
+ <template v-if="$slots.valid" #valid>
418
+ <slot name="valid" v-bind="hintSlotScope" />
419
+ </template>
420
+ <template v-if="$slots.invalid" #invalid>
421
+ <slot name="invalid" v-bind="hintSlotScope" />
422
+ </template>
423
+ </HintSlot>
407
424
  </div>
408
425
  </template>
@@ -17,6 +17,7 @@
17
17
  const { id, disabled, readonly, modelValue, valid, invalid } =
18
18
  useGroupProps(props, emit)
19
19
  const hasId = useUniqueId(id)
20
+ const hasHintId = computed(() => `${hasId.value}-hint`)
20
21
  const tabindex = computed(() => (isDisabled.value ? -1 : props.tabindex))
21
22
 
22
23
  // template refs
@@ -71,7 +72,12 @@
71
72
  )
72
73
 
73
74
  // hint
74
- const { HintSlot } = HintSlotFactory(props, slots)
75
+ const {
76
+ HintSlot,
77
+ hasHintLabelOrSlot,
78
+ hasInvalidLabelOrSlot,
79
+ hintSlotScope,
80
+ } = HintSlotFactory(props, slots)
75
81
  </script>
76
82
 
77
83
  <template>
@@ -87,10 +93,25 @@
87
93
  :value="hasValue"
88
94
  :tabindex="tabindex"
89
95
  :aria-invalid="isInvalid"
96
+ :aria-describedby="hasHintLabelOrSlot ? hasHintId : undefined"
97
+ :aria-errormessage="hasInvalidLabelOrSlot ? hasHintId : undefined"
90
98
  />
91
99
  <slot :value="modelValue">
92
100
  {{ label }}
93
101
  </slot>
94
- <HintSlot class="vv-radio__hint" :params="{ value: modelValue }" />
102
+ <HintSlot :id="hasHintId" class="vv-radio__hint">
103
+ <template v-if="$slots.hint" #hint>
104
+ <slot name="hint" v-bind="hintSlotScope" />
105
+ </template>
106
+ <template v-if="$slots.loading" #loading>
107
+ <slot name="loading" v-bind="hintSlotScope" />
108
+ </template>
109
+ <template v-if="$slots.valid" #valid>
110
+ <slot name="valid" v-bind="hintSlotScope" />
111
+ </template>
112
+ <template v-if="$slots.invalid" #invalid>
113
+ <slot name="invalid" v-bind="hintSlotScope" />
114
+ </template>
115
+ </HintSlot>
95
116
  </label>
96
117
  </template>
@@ -58,7 +58,7 @@
58
58
  }
59
59
 
60
60
  // hint
61
- const { HintSlot } = HintSlotFactory(props, slots)
61
+ const { HintSlot, hintSlotScope } = HintSlotFactory(props, slots)
62
62
  </script>
63
63
 
64
64
  <template>
@@ -78,6 +78,19 @@
78
78
  <slot v-else />
79
79
  <!-- #endregion -->
80
80
  </div>
81
- <HintSlot class="vv-radio-group__hint" />
81
+ <HintSlot class="vv-radio-group__hint">
82
+ <template v-if="$slots.hint" #hint>
83
+ <slot name="hint" v-bind="hintSlotScope" />
84
+ </template>
85
+ <template v-if="$slots.loading" #loading>
86
+ <slot name="loading" v-bind="hintSlotScope" />
87
+ </template>
88
+ <template v-if="$slots.valid" #valid>
89
+ <slot name="valid" v-bind="hintSlotScope" />
90
+ </template>
91
+ <template v-if="$slots.invalid" #invalid>
92
+ <slot name="invalid" v-bind="hintSlotScope" />
93
+ </template>
94
+ </HintSlot>
82
95
  </fieldset>
83
96
  </template>
@@ -20,7 +20,12 @@
20
20
  const select = ref()
21
21
 
22
22
  // hint
23
- const { HintSlot, hasHint, hasInvalid } = HintSlotFactory(props, slots)
23
+ const {
24
+ HintSlot,
25
+ hasHintLabelOrSlot,
26
+ hasInvalidLabelOrSlot,
27
+ hintSlotScope,
28
+ } = HintSlotFactory(props, slots)
24
29
 
25
30
  // data
26
31
  const {
@@ -39,7 +44,7 @@
39
44
 
40
45
  // computed
41
46
  const hasId = useUniqueId(id)
42
- const hasDescribedBy = computed(() => `${hasId.value}-hint`)
47
+ const hasHintId = computed(() => `${hasId.value}-hint`)
43
48
 
44
49
  // focus
45
50
  const { focused } = useComponentFocus(select, emit)
@@ -108,12 +113,11 @@
108
113
  autocomplete: props.autocomplete,
109
114
  multiple: props.multiple,
110
115
  'aria-invalid': isInvalid.value,
111
- 'aria-describedby':
112
- !hasInvalid.value && hasHint.value
113
- ? hasDescribedBy.value
114
- : undefined,
115
- 'aria-errormessage': hasInvalid.value
116
- ? hasDescribedBy.value
116
+ 'aria-describedby': hasHintLabelOrSlot.value
117
+ ? hasHintId.value
118
+ : undefined,
119
+ 'aria-errormessage': hasInvalidLabelOrSlot.value
120
+ ? hasHintId.value
117
121
  : undefined,
118
122
  }
119
123
  })
@@ -218,6 +222,19 @@
218
222
  </div>
219
223
  </div>
220
224
  <!-- #endregion native select -->
221
- <HintSlot :id="hasDescribedBy" class="vv-select__hint" />
225
+ <HintSlot :id="hasHintId" class="vv-select__hint">
226
+ <template v-if="$slots.hint" #hint>
227
+ <slot name="hint" v-bind="hintSlotScope" />
228
+ </template>
229
+ <template v-if="$slots.loading" #loading>
230
+ <slot name="loading" v-bind="hintSlotScope" />
231
+ </template>
232
+ <template v-if="$slots.valid" #valid>
233
+ <slot name="valid" v-bind="hintSlotScope" />
234
+ </template>
235
+ <template v-if="$slots.invalid" #invalid>
236
+ <slot name="invalid" v-bind="hintSlotScope" />
237
+ </template>
238
+ </HintSlot>
222
239
  </div>
223
240
  </template>
@@ -32,7 +32,7 @@
32
32
  modifiers,
33
33
  } = toRefs(props)
34
34
  const hasId = useUniqueId(id)
35
- const hasDescribedBy = computed(() => `${hasId.value}-hint`)
35
+ const hasHintId = computed(() => `${hasId.value}-hint`)
36
36
  // BUG - https://www.samanthaming.com/tidbits/88-css-placeholder-shown/
37
37
  const hasPlaceholder = computed(() =>
38
38
  props.floating && isEmpty(props.placeholder) ? ' ' : props.placeholder,
@@ -86,7 +86,12 @@
86
86
  })
87
87
 
88
88
  // hint
89
- const { HintSlot, hasHint, hasInvalid } = HintSlotFactory(props, slots)
89
+ const {
90
+ HintSlot,
91
+ hasHintLabelOrSlot,
92
+ hasInvalidLabelOrSlot,
93
+ hintSlotScope,
94
+ } = HintSlotFactory(props, slots)
90
95
 
91
96
  // styles
92
97
  const bemCssClasses = useModifiers(
@@ -125,12 +130,11 @@
125
130
  wrap: props.wrap,
126
131
  spellcheck: props.spellcheck,
127
132
  'aria-invalid': isInvalid.value,
128
- 'aria-describedby':
129
- !hasInvalid.value && hasHint.value
130
- ? hasDescribedBy.value
131
- : undefined,
132
- 'aria-errormessage': hasInvalid.value
133
- ? hasDescribedBy.value
133
+ 'aria-describedby': hasHintLabelOrSlot.value
134
+ ? hasHintId.value
135
+ : undefined,
136
+ 'aria-errormessage': hasInvalidLabelOrSlot.value
137
+ ? hasHintId.value
134
138
  : undefined,
135
139
  } as TextareaHTMLAttributes),
136
140
  )
@@ -193,6 +197,19 @@
193
197
  </slot>
194
198
  </span>
195
199
  </div>
196
- <HintSlot :id="hasDescribedBy" class="vv-textarea__hint" />
200
+ <HintSlot :id="hasHintId" class="vv-textarea__hint">
201
+ <template v-if="$slots.hint" #hint>
202
+ <slot name="hint" v-bind="hintSlotScope" />
203
+ </template>
204
+ <template v-if="$slots.loading" #loading>
205
+ <slot name="loading" v-bind="hintSlotScope" />
206
+ </template>
207
+ <template v-if="$slots.valid" #valid>
208
+ <slot name="valid" v-bind="hintSlotScope" />
209
+ </template>
210
+ <template v-if="$slots.invalid" #invalid>
211
+ <slot name="invalid" v-bind="hintSlotScope" />
212
+ </template>
213
+ </HintSlot>
197
214
  </div>
198
215
  </template>