@volverjs/ui-vue 0.0.10-beta.2 → 0.0.10-beta.20

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 (251) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +98 -3
  3. package/auto-imports.d.ts +6 -2
  4. package/bin/icons.cjs +1 -1
  5. package/bin/icons.js +23 -16
  6. package/dist/Volver.d.ts +1 -1
  7. package/dist/components/VvAccordion/VvAccordion.es.js +67 -13
  8. package/dist/components/VvAccordion/VvAccordion.umd.js +1 -1
  9. package/dist/components/VvAccordion/VvAccordion.vue.d.ts +13 -6
  10. package/dist/components/VvAccordion/index.d.ts +4 -1
  11. package/dist/components/VvAccordionGroup/VvAccordionGroup.es.js +111 -37
  12. package/dist/components/VvAccordionGroup/VvAccordionGroup.umd.js +1 -1
  13. package/dist/components/VvAccordionGroup/VvAccordionGroup.vue.d.ts +15 -8
  14. package/dist/components/VvAccordionGroup/index.d.ts +4 -1
  15. package/dist/components/VvAction/VvAction.es.js +56 -12
  16. package/dist/components/VvAction/VvAction.umd.js +1 -1
  17. package/dist/components/VvAction/VvAction.vue.d.ts +59 -12
  18. package/dist/components/VvAction/index.d.ts +25 -4
  19. package/dist/components/VvAlert/VvAlert.es.js +188 -152
  20. package/dist/components/VvAlert/VvAlert.umd.js +1 -1
  21. package/dist/components/VvAlert/VvAlert.vue.d.ts +18 -8
  22. package/dist/components/VvAlert/index.d.ts +9 -5
  23. package/dist/components/VvAlertGroup/VvAlertGroup.es.js +230 -174
  24. package/dist/components/VvAlertGroup/VvAlertGroup.umd.js +1 -1
  25. package/dist/components/VvAlertGroup/VvAlertGroup.vue.d.ts +13 -6
  26. package/dist/components/VvAlertGroup/index.d.ts +6 -2
  27. package/dist/components/VvAvatar/VvAvatar.es.js +54 -9
  28. package/dist/components/VvAvatar/VvAvatar.umd.js +1 -1
  29. package/dist/components/VvAvatar/VvAvatar.vue.d.ts +12 -4
  30. package/dist/components/VvAvatar/index.d.ts +4 -1
  31. package/dist/components/VvAvatarGroup/VvAvatarGroup.es.js +111 -36
  32. package/dist/components/VvAvatarGroup/VvAvatarGroup.umd.js +1 -1
  33. package/dist/components/VvAvatarGroup/VvAvatarGroup.vue.d.ts +10 -3
  34. package/dist/components/VvAvatarGroup/index.d.ts +4 -1
  35. package/dist/components/VvBadge/VvBadge.es.js +71 -16
  36. package/dist/components/VvBadge/VvBadge.umd.js +1 -1
  37. package/dist/components/VvBadge/VvBadge.vue.d.ts +12 -4
  38. package/dist/components/VvBadge/index.d.ts +4 -1
  39. package/dist/components/VvBreadcrumb/VvBreadcrumb.es.js +257 -49
  40. package/dist/components/VvBreadcrumb/VvBreadcrumb.umd.js +1 -1
  41. package/dist/components/VvBreadcrumb/VvBreadcrumb.vue.d.ts +27 -7
  42. package/dist/components/VvBreadcrumb/index.d.ts +6 -10
  43. package/dist/components/VvButton/VvButton.es.js +165 -137
  44. package/dist/components/VvButton/VvButton.umd.js +1 -1
  45. package/dist/components/VvButton/VvButton.vue.d.ts +101 -27
  46. package/dist/components/VvButton/index.d.ts +41 -14
  47. package/dist/components/VvButtonGroup/VvButtonGroup.es.js +67 -15
  48. package/dist/components/VvButtonGroup/VvButtonGroup.umd.js +1 -1
  49. package/dist/components/VvButtonGroup/VvButtonGroup.vue.d.ts +23 -10
  50. package/dist/components/VvButtonGroup/index.d.ts +8 -2
  51. package/dist/components/VvCard/VvCard.es.js +79 -24
  52. package/dist/components/VvCard/VvCard.umd.js +1 -1
  53. package/dist/components/VvCard/VvCard.vue.d.ts +12 -4
  54. package/dist/components/VvCard/index.d.ts +4 -1
  55. package/dist/components/VvCheckbox/VvCheckbox.es.js +89 -21
  56. package/dist/components/VvCheckbox/VvCheckbox.umd.js +1 -1
  57. package/dist/components/VvCheckbox/VvCheckbox.vue.d.ts +104 -32
  58. package/dist/components/VvCheckbox/index.d.ts +45 -12
  59. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.es.js +168 -66
  60. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.umd.js +1 -1
  61. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.vue.d.ts +100 -29
  62. package/dist/components/VvCheckboxGroup/index.d.ts +45 -12
  63. package/dist/components/VvCombobox/VvCombobox.es.js +721 -527
  64. package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
  65. package/dist/components/VvCombobox/VvCombobox.vue.d.ts +145 -72
  66. package/dist/components/VvCombobox/index.d.ts +53 -22
  67. package/dist/components/VvDialog/VvDialog.es.js +133 -141
  68. package/dist/components/VvDialog/VvDialog.umd.js +1 -1
  69. package/dist/components/VvDialog/VvDialog.vue.d.ts +4 -4
  70. package/dist/components/VvDropdown/VvDropdown.es.js +121 -55
  71. package/dist/components/VvDropdown/VvDropdown.umd.js +1 -1
  72. package/dist/components/VvDropdown/VvDropdown.vue.d.ts +61 -35
  73. package/dist/components/VvDropdown/VvDropdownAction.vue.d.ts +72 -11
  74. package/dist/components/VvDropdown/VvDropdownItem.vue.d.ts +1 -1
  75. package/dist/components/VvDropdown/VvDropdownOptgroup.vue.d.ts +12 -4
  76. package/dist/components/VvDropdown/VvDropdownOption.vue.d.ts +26 -7
  77. package/dist/components/VvDropdown/index.d.ts +16 -11
  78. package/dist/components/VvDropdownAction/VvDropdownAction.es.js +80 -21
  79. package/dist/components/VvDropdownAction/VvDropdownAction.umd.js +1 -1
  80. package/dist/components/VvDropdownItem/VvDropdownItem.es.js +13 -7
  81. package/dist/components/VvDropdownOptgroup/VvDropdownOptgroup.es.js +56 -8
  82. package/dist/components/VvDropdownOptgroup/VvDropdownOptgroup.umd.js +1 -1
  83. package/dist/components/VvDropdownOption/VvDropdownOption.es.js +76 -17
  84. package/dist/components/VvDropdownOption/VvDropdownOption.umd.js +1 -1
  85. package/dist/components/VvIcon/VvIcon.es.js +23 -96
  86. package/dist/components/VvIcon/VvIcon.umd.js +1 -1
  87. package/dist/components/VvIcon/VvIcon.vue.d.ts +23 -66
  88. package/dist/components/VvIcon/index.d.ts +21 -48
  89. package/dist/components/VvInputFile/VvInputFile.es.js +1558 -0
  90. package/dist/components/VvInputFile/VvInputFile.umd.js +1 -0
  91. package/dist/components/VvInputFile/VvInputFile.vue.d.ts +190 -0
  92. package/dist/components/VvInputFile/index.d.ts +74 -0
  93. package/dist/components/VvInputText/VvInputClearAction.d.ts +2 -2
  94. package/dist/components/VvInputText/VvInputPasswordAction.d.ts +1 -1
  95. package/dist/components/VvInputText/VvInputStepAction.d.ts +1 -1
  96. package/dist/components/VvInputText/VvInputText.es.js +266 -242
  97. package/dist/components/VvInputText/VvInputText.umd.js +1 -1
  98. package/dist/components/VvInputText/VvInputText.vue.d.ts +153 -46
  99. package/dist/components/VvInputText/index.d.ts +69 -18
  100. package/dist/components/VvNav/VvNav.es.js +150 -73
  101. package/dist/components/VvNav/VvNav.umd.js +1 -1
  102. package/dist/components/VvNav/VvNav.vue.d.ts +41 -14
  103. package/dist/components/VvNav/VvNavItem.vue.d.ts +9 -0
  104. package/dist/components/VvNav/{VvNavSeparator.d.ts → VvNavSeparator.vue.d.ts} +1 -1
  105. package/dist/components/VvNav/index.d.ts +5 -13
  106. package/dist/components/VvNavItem/VvNavItem.es.js +435 -0
  107. package/dist/components/VvNavItem/VvNavItem.umd.js +1 -0
  108. package/dist/components/VvNavSeparator/VvNavSeparator.es.js +24 -0
  109. package/dist/components/VvNavSeparator/VvNavSeparator.umd.js +1 -0
  110. package/dist/components/VvProgress/VvProgress.es.js +65 -14
  111. package/dist/components/VvProgress/VvProgress.umd.js +1 -1
  112. package/dist/components/VvProgress/VvProgress.vue.d.ts +10 -3
  113. package/dist/components/VvProgress/index.d.ts +4 -1
  114. package/dist/components/VvRadio/VvRadio.es.js +89 -21
  115. package/dist/components/VvRadio/VvRadio.umd.js +1 -1
  116. package/dist/components/VvRadio/VvRadio.vue.d.ts +102 -30
  117. package/dist/components/VvRadio/index.d.ts +44 -11
  118. package/dist/components/VvRadioGroup/VvRadioGroup.es.js +168 -66
  119. package/dist/components/VvRadioGroup/VvRadioGroup.umd.js +1 -1
  120. package/dist/components/VvRadioGroup/VvRadioGroup.vue.d.ts +100 -29
  121. package/dist/components/VvRadioGroup/index.d.ts +45 -12
  122. package/dist/components/VvSelect/VvSelect.es.js +244 -226
  123. package/dist/components/VvSelect/VvSelect.umd.js +1 -1
  124. package/dist/components/VvSelect/VvSelect.vue.d.ts +112 -39
  125. package/dist/components/VvSelect/index.d.ts +48 -14
  126. package/dist/components/VvTab/VvTab.es.js +251 -110
  127. package/dist/components/VvTab/VvTab.umd.js +1 -1
  128. package/dist/components/VvTab/VvTab.vue.d.ts +50 -13
  129. package/dist/components/VvTab/index.d.ts +13 -4
  130. package/dist/components/VvTextarea/VvTextarea.es.js +225 -212
  131. package/dist/components/VvTextarea/VvTextarea.umd.js +1 -1
  132. package/dist/components/VvTextarea/VvTextarea.vue.d.ts +155 -48
  133. package/dist/components/VvTextarea/index.d.ts +68 -19
  134. package/dist/components/VvTooltip/VvTooltip.es.js +72 -17
  135. package/dist/components/VvTooltip/VvTooltip.umd.js +1 -1
  136. package/dist/components/VvTooltip/VvTooltip.vue.d.ts +10 -3
  137. package/dist/components/VvTooltip/index.d.ts +4 -1
  138. package/dist/components/index.d.ts +10 -0
  139. package/dist/components/index.es.js +2635 -1301
  140. package/dist/components/index.umd.js +1 -1
  141. package/dist/composables/alert/useAlert.d.ts +37 -4
  142. package/dist/composables/dropdown/useProvideDropdown.d.ts +1 -1
  143. package/dist/composables/index.d.ts +1 -0
  144. package/dist/composables/index.es.js +88 -1
  145. package/dist/composables/index.umd.js +1 -1
  146. package/dist/composables/useBlurhash.d.ts +7 -0
  147. package/dist/composables/useComponentIcon.d.ts +9 -8
  148. package/dist/composables/useVolver.d.ts +1 -1
  149. package/dist/directives/index.d.ts +3 -5
  150. package/dist/directives/index.es.js +92 -31
  151. package/dist/directives/index.umd.js +1 -1
  152. package/dist/directives/v-tooltip.es.js +90 -26
  153. package/dist/directives/v-tooltip.umd.js +1 -1
  154. package/dist/icons.es.js +6 -6
  155. package/dist/icons.umd.js +1 -1
  156. package/dist/index.d.ts +3 -1
  157. package/dist/index.es.js +81 -16
  158. package/dist/index.umd.js +1 -1
  159. package/dist/props/index.d.ts +287 -73
  160. package/dist/resolvers/unplugin.d.ts +6 -1
  161. package/dist/resolvers/unplugin.es.js +78 -10
  162. package/dist/resolvers/unplugin.umd.js +1 -1
  163. package/dist/stories/AccordionGroup/AccordionGroup.stories.d.ts +72 -84
  164. package/dist/stories/AccordionGroup/AccordionGroupSlots.stories.d.ts +623 -461
  165. package/dist/stories/AlertGroup/AlertGroupWithComposable.stories.d.ts +1 -1
  166. package/dist/stories/Blurhash/BlurhashComposable.stories.d.ts +4 -0
  167. package/dist/stories/Combobox/Combobox.settings.d.ts +8 -0
  168. package/dist/stories/Icon/Icon.settings.d.ts +1 -0
  169. package/dist/stories/InputFile/InputFile.settings.d.ts +56 -0
  170. package/dist/stories/InputFile/InputFile.stories.d.ts +13 -0
  171. package/dist/stories/InputFile/InputFileModifiers.stories.d.ts +9 -0
  172. package/dist/stories/InputFile/InputFileSlots.stories.d.ts +6 -0
  173. package/dist/stories/Tab/Tab.settings.d.ts +4 -37
  174. package/dist/types/alert.d.ts +13 -0
  175. package/dist/types/blurhash.d.ts +12 -0
  176. package/dist/types/floating-ui.d.ts +6 -0
  177. package/dist/types/generic.d.ts +4 -0
  178. package/dist/types/group.d.ts +37 -0
  179. package/dist/types/index.d.ts +7 -0
  180. package/dist/types/input-file.d.ts +14 -0
  181. package/dist/types/nav.d.ts +18 -0
  182. package/dist/utils/ObjectUtilities.d.ts +0 -1
  183. package/dist/workers/blurhash.d.ts +1 -0
  184. package/package.json +91 -74
  185. package/src/Volver.ts +31 -20
  186. package/src/assets/icons/detailed.json +1 -1
  187. package/src/assets/icons/normal.json +1 -1
  188. package/src/assets/icons/simple.json +1 -1
  189. package/src/components/VvAccordion/VvAccordion.vue +2 -2
  190. package/src/components/VvAction/VvAction.vue +5 -2
  191. package/src/components/VvAlert/index.ts +1 -3
  192. package/src/components/VvAlertGroup/index.ts +2 -1
  193. package/src/components/VvBreadcrumb/VvBreadcrumb.vue +20 -19
  194. package/src/components/VvBreadcrumb/index.ts +2 -8
  195. package/src/components/VvButton/VvButton.vue +6 -6
  196. package/src/components/VvButton/index.ts +2 -4
  197. package/src/components/VvCombobox/VvCombobox.vue +24 -16
  198. package/src/components/VvCombobox/index.ts +4 -0
  199. package/src/components/VvIcon/VvIcon.vue +2 -2
  200. package/src/components/VvIcon/index.ts +22 -48
  201. package/src/components/VvInputFile/VvInputFile.vue +302 -0
  202. package/src/components/VvInputFile/index.ts +38 -0
  203. package/src/components/VvInputText/VvInputText.vue +13 -14
  204. package/src/components/VvNav/VvNav.vue +30 -50
  205. package/src/components/VvNav/VvNavItem.vue +18 -0
  206. package/src/components/VvNav/VvNavSeparator.vue +11 -0
  207. package/src/components/VvNav/index.ts +2 -15
  208. package/src/components/VvSelect/VvSelect.vue +5 -8
  209. package/src/components/VvTab/VvTab.vue +63 -35
  210. package/src/components/VvTab/index.ts +10 -4
  211. package/src/components/VvTextarea/VvTextarea.vue +6 -9
  212. package/src/components/index.ts +10 -0
  213. package/src/composables/index.ts +1 -0
  214. package/src/composables/useBlurhash.ts +76 -0
  215. package/src/composables/useComponentIcon.ts +15 -14
  216. package/src/composables/useUniqueId.ts +2 -2
  217. package/src/directives/index.ts +3 -6
  218. package/src/directives/v-tooltip.ts +19 -10
  219. package/src/index.ts +3 -1
  220. package/src/props/index.ts +115 -27
  221. package/src/resolvers/unplugin.ts +24 -14
  222. package/src/stories/AlertGroup/AlertGroupWithComposable.stories.ts +2 -2
  223. package/src/stories/Blurhash/BlurhashComposable.stories.ts +195 -0
  224. package/src/stories/Combobox/Combobox.settings.ts +8 -0
  225. package/src/stories/Icon/Icon.settings.ts +3 -3
  226. package/src/stories/InputFile/InputFile.settings.ts +36 -0
  227. package/src/stories/InputFile/InputFile.stories.ts +98 -0
  228. package/src/stories/InputFile/InputFileModifiers.stories.ts +51 -0
  229. package/src/stories/InputFile/InputFileSlots.stories.ts +25 -0
  230. package/src/stories/Nav/Nav.settings.ts +3 -4
  231. package/src/stories/Nav/Nav.test.ts +4 -15
  232. package/src/stories/Tab/Tab.settings.ts +9 -9
  233. package/src/stories/Tab/Tab.stories.ts +2 -2
  234. package/src/stories/Tab/Tab.test.ts +6 -14
  235. package/src/stories/argTypes.ts +1 -1
  236. package/src/types/blurhash.ts +21 -0
  237. package/src/types/generic.ts +6 -0
  238. package/src/types/index.ts +7 -0
  239. package/src/types/input-file.ts +16 -0
  240. package/src/types/nav.ts +20 -0
  241. package/src/utils/ObjectUtilities.ts +0 -11
  242. package/src/workers/blurhash.ts +9 -0
  243. package/dist/components/VvNav/VvNavItemTitle.vue.d.ts +0 -6
  244. package/dist/components/VvNavItemTitle/VvNavItemTitle.es.js +0 -19
  245. package/dist/components/VvNavItemTitle/VvNavItemTitle.umd.js +0 -1
  246. package/src/components/VvNav/VvNavItemTitle.vue +0 -11
  247. package/src/components/VvNav/VvNavSeparator.ts +0 -8
  248. package/src/types/generic.d.ts +0 -6
  249. /package/src/types/{alert.d.ts → alert.ts} +0 -0
  250. /package/src/types/{floating-ui.d.ts → floating-ui.ts} +0 -0
  251. /package/src/types/{group.d.ts → group.ts} +0 -0
@@ -0,0 +1,302 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'VvInputFile',
4
+ }
5
+ </script>
6
+
7
+ <script setup lang="ts">
8
+ import { useVModel } from '@vueuse/core'
9
+ import type { UploadedFile } from '../../types'
10
+ import { computed, onBeforeUnmount, ref } from 'vue'
11
+ import VvButton from '../VvButton/VvButton.vue'
12
+ import VvIcon from '../VvIcon/VvIcon.vue'
13
+ import HintSlotFactory from '../common/HintSlot'
14
+ import { VvInputFileProps, type VvInputFileEvents } from '.'
15
+
16
+ // props, emit, slots and attrs
17
+ const props = defineProps(VvInputFileProps)
18
+ const emit = defineEmits<VvInputFileEvents>()
19
+ const slots = useSlots()
20
+
21
+ // props merged with volver defaults (now only for labels)
22
+ const propsDefaults = useDefaults<typeof VvInputFileProps>(
23
+ 'VvInputFile',
24
+ VvInputFileProps,
25
+ props,
26
+ )
27
+
28
+ const { modifiers, id, readonly } = toRefs(props)
29
+
30
+ const hasId = useUniqueId(id)
31
+ const hasHintId = computed(() => `${hasId.value}-hint`)
32
+
33
+ // styles
34
+ const bemCssClasses = useModifiers(
35
+ 'vv-input-file',
36
+ modifiers,
37
+ computed(() => ({
38
+ dragging: isDragging.value,
39
+ loading: props.loading,
40
+ valid: props.valid === true,
41
+ invalid: props.invalid === true,
42
+ 'icon-before': !!props.iconLeft,
43
+ 'icon-after': !!props.iconRight,
44
+ })),
45
+ )
46
+
47
+ const {
48
+ HintSlot,
49
+ hasHintLabelOrSlot,
50
+ hasInvalidLabelOrSlot,
51
+ hintSlotScope,
52
+ } = HintSlotFactory(propsDefaults, slots)
53
+
54
+ const localModelValue = useVModel(props, 'modelValue', emit)
55
+ const files = computed(() => {
56
+ if (
57
+ !localModelValue.value ||
58
+ (!Array.isArray(localModelValue.value) &&
59
+ !(localModelValue.value as File)?.name)
60
+ ) {
61
+ return []
62
+ }
63
+ return Array.isArray(localModelValue.value)
64
+ ? localModelValue.value
65
+ : [localModelValue.value]
66
+ })
67
+
68
+ const hasMax = computed(() => {
69
+ return typeof props.max === 'string' ? parseInt(props.max) : props.max
70
+ })
71
+
72
+ const hasDropArea = computed(() => {
73
+ return modifiers?.value?.includes('drop-area')
74
+ })
75
+
76
+ const isMultiple = computed(() => {
77
+ if (!props.multiple) {
78
+ return false
79
+ }
80
+ if (!hasMax.value) {
81
+ return true
82
+ }
83
+ return hasMax.value - files.value.length > 1
84
+ })
85
+
86
+ const isDragging = ref(false)
87
+
88
+ const inputEl = ref<HTMLInputElement>()
89
+ const onDragenter = () => {
90
+ isDragging.value = true
91
+ }
92
+
93
+ const onDragleave = () => {
94
+ isDragging.value = false
95
+ }
96
+
97
+ const onDrop = (event: DragEvent) => {
98
+ if (!event.dataTransfer?.files) {
99
+ return
100
+ }
101
+ isDragging.value = false
102
+ addFiles(event.dataTransfer?.files)
103
+ }
104
+
105
+ const onChange = () => {
106
+ if (!inputEl.value?.files) {
107
+ return
108
+ }
109
+ addFiles(inputEl.value.files)
110
+ inputEl.value.value = ''
111
+ }
112
+
113
+ const addFiles = (uploadedFiles: FileList) => {
114
+ if (!props.multiple) {
115
+ if (Array.isArray(localModelValue.value)) {
116
+ localModelValue.value = [...uploadedFiles]
117
+ return
118
+ }
119
+ localModelValue.value = uploadedFiles[0]
120
+ return
121
+ }
122
+ let toReturn: (File | UploadedFile)[] = []
123
+ if (!Array.isArray(localModelValue.value) && localModelValue.value) {
124
+ toReturn = [localModelValue.value]
125
+ } else {
126
+ toReturn =
127
+ localModelValue.value && Array.isArray(localModelValue.value)
128
+ ? [...localModelValue.value]
129
+ : toReturn
130
+ }
131
+ for (const file of uploadedFiles) {
132
+ if (hasMax.value && toReturn.length >= hasMax.value) {
133
+ break
134
+ }
135
+ toReturn.push(file)
136
+ }
137
+
138
+ localModelValue.value = toReturn
139
+ }
140
+
141
+ const onClick = () => {
142
+ if (!inputEl.value) {
143
+ return
144
+ }
145
+ if (!readonly.value) {
146
+ inputEl.value.click()
147
+ }
148
+ }
149
+
150
+ const onClickRemoveFile = (index: number) => {
151
+ if (!Array.isArray(localModelValue.value)) {
152
+ localModelValue.value = undefined
153
+ return
154
+ }
155
+ const toReturn = [...localModelValue.value]
156
+ toReturn.splice(index, 1)
157
+ localModelValue.value = toReturn
158
+ }
159
+
160
+ const currentFileIndex = ref(0)
161
+ const previewSrc = computed(() => {
162
+ if (files.value.length === 0) {
163
+ return
164
+ }
165
+ if (files.value[currentFileIndex.value] instanceof File) {
166
+ return URL.createObjectURL(
167
+ files.value[currentFileIndex.value] as File,
168
+ )
169
+ }
170
+ return (files.value[currentFileIndex.value] as UploadedFile).url
171
+ })
172
+
173
+ onBeforeUnmount(() => {
174
+ if (previewSrc.value) {
175
+ URL.revokeObjectURL(previewSrc.value)
176
+ }
177
+ })
178
+
179
+ const sizeInKiB = (size?: number) => {
180
+ if (!size) {
181
+ return
182
+ }
183
+ return Math.floor(size / 1024)
184
+ }
185
+
186
+ const onClickDownloadFile = (file: File | UploadedFile) => {
187
+ const link = document.createElement('a')
188
+ if (file instanceof File) {
189
+ link.href = URL.createObjectURL(file)
190
+ } else if (file.url) {
191
+ link.href = file.url
192
+ }
193
+ link.setAttribute('download', file.name)
194
+ document.body.appendChild(link)
195
+ link.click()
196
+ }
197
+ </script>
198
+
199
+ <template>
200
+ <div :class="bemCssClasses">
201
+ <label v-if="label" :for="hasId">
202
+ {{ label }}
203
+ </label>
204
+ <div
205
+ v-if="hasDropArea"
206
+ class="vv-input-file__drop-area"
207
+ @dragenter.prevent.stop="onDragenter"
208
+ @dragleave.prevent.stop="onDragleave"
209
+ @drop.prevent.stop="onDrop"
210
+ @dragover.prevent.stop
211
+ @click.stop="onClick"
212
+ >
213
+ <slot name="drop-area">
214
+ <VvButton
215
+ v-if="!readonly"
216
+ modifiers="action"
217
+ aria-label="upload"
218
+ :label="!previewSrc ? labelButton : undefined"
219
+ :class="{
220
+ 'absolute top-8 right-8': previewSrc,
221
+ }"
222
+ :icon="!previewSrc ? 'image' : isMultiple ? 'add' : 'edit'"
223
+ class="z-1"
224
+ @click.stop="onClick"
225
+ />
226
+ <picture class="vv-input-file__preview">
227
+ <img
228
+ v-if="previewSrc"
229
+ :src="previewSrc"
230
+ :alt="files[currentFileIndex].name"
231
+ />
232
+ </picture>
233
+ </slot>
234
+ </div>
235
+ <div class="vv-input-file__wrapper">
236
+ <VvIcon v-if="iconLeft" :name="iconLeft" />
237
+ <input
238
+ :id="hasId"
239
+ ref="inputEl"
240
+ :readonly="readonly"
241
+ :placeholder="placeholder"
242
+ :aria-describedby="hasHintLabelOrSlot ? hasHintId : undefined"
243
+ :aria-invalid="invalid"
244
+ :aria-errormessage="
245
+ hasInvalidLabelOrSlot ? hasHintId : undefined
246
+ "
247
+ :multiple="isMultiple"
248
+ :accept="accept"
249
+ type="file"
250
+ :name="name"
251
+ @change="onChange"
252
+ />
253
+ <VvIcon v-if="iconRight" :name="iconRight" />
254
+ </div>
255
+ <ul class="vv-input-file__list">
256
+ <li
257
+ v-for="(file, index) in files"
258
+ :key="index"
259
+ class="vv-input-file__item"
260
+ @click.stop="currentFileIndex = index"
261
+ >
262
+ <button
263
+ type="button"
264
+ class="vv-input-file__item-icon cursor-pointer"
265
+ title="Download"
266
+ aria-label="download-file"
267
+ @click.stop="onClickDownloadFile(file)"
268
+ >
269
+ <VvIcon name="download" />
270
+ </button>
271
+ <div class="vv-input-file__item-name cursor-pointer">
272
+ {{ file.name }}
273
+ </div>
274
+ <small class="vv-input-file__item-info">
275
+ {{ sizeInKiB(file.size) }} KB
276
+ </small>
277
+ <button
278
+ v-if="!readonly"
279
+ type="button"
280
+ class="vv-input-file__item-remove"
281
+ title="Remove"
282
+ aria-label="remove-file"
283
+ @click.stop="onClickRemoveFile(index)"
284
+ />
285
+ </li>
286
+ </ul>
287
+ <HintSlot :id="hasHintId" class="vv-input-file__hint">
288
+ <template v-if="$slots.hint" #hint>
289
+ <slot name="hint" v-bind="hintSlotScope" />
290
+ </template>
291
+ <template v-if="$slots.loading" #loading>
292
+ <slot name="loading" v-bind="hintSlotScope" />
293
+ </template>
294
+ <template v-if="$slots.valid" #valid>
295
+ <slot name="valid" v-bind="hintSlotScope" />
296
+ </template>
297
+ <template v-if="$slots.invalid" #invalid>
298
+ <slot name="invalid" v-bind="hintSlotScope" />
299
+ </template>
300
+ </HintSlot>
301
+ </div>
302
+ </template>
@@ -0,0 +1,38 @@
1
+ import type { UploadedFile } from '@/types'
2
+ import {
3
+ ModifiersProps,
4
+ ValidProps,
5
+ InvalidProps,
6
+ HintProps,
7
+ LabelProps,
8
+ LoadingProps,
9
+ ReadonlyProps,
10
+ } from '../../props'
11
+
12
+ export type VvInputFileEvents = {
13
+ 'update:modelValue': [File | undefined]
14
+ }
15
+
16
+ export const VvInputFileProps = {
17
+ ...ModifiersProps,
18
+ ...ValidProps,
19
+ ...InvalidProps,
20
+ ...HintProps,
21
+ ...LabelProps,
22
+ ...LoadingProps,
23
+ ...ReadonlyProps,
24
+ name: { type: String },
25
+ id: { type: String },
26
+ modelValue: {
27
+ type: Object as PropType<File | (File | UploadedFile)[] | UploadedFile>,
28
+ required: true,
29
+ },
30
+ max: [Number, String],
31
+ labelButton: { type: String, default: 'Image' },
32
+ loading: Boolean,
33
+ accept: String,
34
+ placeholder: String,
35
+ multiple: Boolean,
36
+ iconLeft: String,
37
+ iconRight: String,
38
+ }
@@ -227,7 +227,7 @@
227
227
  return
228
228
  }
229
229
  inputEl.value.stepUp()
230
- localModelValue.value = unref(inputEl).value
230
+ localModelValue.value = Number(unref(inputEl).value)
231
231
  }
232
232
  }
233
233
  const onStepDown = () => {
@@ -238,7 +238,7 @@
238
238
  return
239
239
  }
240
240
  inputEl.value.stepDown()
241
- localModelValue.value = unref(inputEl).value
241
+ localModelValue.value = Number(unref(inputEl).value)
242
242
  }
243
243
  }
244
244
 
@@ -249,11 +249,11 @@
249
249
  }
250
250
 
251
251
  // icons
252
- const { hasIcon, hasIconBefore, hasIconAfter } = useComponentIcon(
253
- icon,
254
- iconPosition,
255
- )
256
- const defaultAfterIcon = computed(() => {
252
+ const { hasIconBefore, hasIconAfter } = useComponentIcon(icon, iconPosition)
253
+ const iconAfter = computed(() => {
254
+ if (hasIconAfter.value !== undefined) {
255
+ return hasIconAfter.value
256
+ }
257
257
  switch (props.type) {
258
258
  case INPUT_TYPES.COLOR:
259
259
  return { name: TYPES_ICON.COLOR }
@@ -264,9 +264,8 @@
264
264
  return { name: TYPES_ICON.DATE }
265
265
  case INPUT_TYPES.TIME:
266
266
  return { name: TYPES_ICON.TIME }
267
- default:
268
- return ''
269
267
  }
268
+ return undefined
270
269
  })
271
270
 
272
271
  // count
@@ -307,8 +306,8 @@
307
306
  loading: loading.value,
308
307
  disabled: props.disabled,
309
308
  readonly: props.readonly,
310
- 'icon-before': hasIconBefore.value,
311
- 'icon-after': hasIconAfter.value || !isEmpty(defaultAfterIcon),
309
+ 'icon-before': hasIconBefore.value !== undefined,
310
+ 'icon-after': iconAfter.value !== undefined,
312
311
  floating: props.floating && !isEmpty(props.label),
313
312
  dirty: isDirty.value,
314
313
  focus: isFocused.value,
@@ -476,8 +475,8 @@
476
475
  >
477
476
  <VvIcon
478
477
  v-if="hasIconBefore"
478
+ v-bind="hasIconBefore"
479
479
  class="vv-input-text__icon"
480
- v-bind="hasIcon"
481
480
  />
482
481
  <input
483
482
  :id="hasId"
@@ -500,9 +499,9 @@
500
499
  </div>
501
500
  <!-- @slot Slot to replace right icon -->
502
501
  <VvIcon
503
- v-if="hasIconAfter || defaultAfterIcon"
502
+ v-if="iconAfter"
503
+ v-bind="iconAfter"
504
504
  class="vv-input-text__icon vv-input-text__icon-after"
505
- v-bind="hasIconAfter ? hasIcon : defaultAfterIcon"
506
505
  />
507
506
  <PasswordInputActions
508
507
  v-else-if="isPassword && !hideActions && isClickable"
@@ -1,66 +1,46 @@
1
1
  <script setup lang="ts">
2
- import { VvNavProps, VvNavEvents, type NavItem } from '@/components/VvNav'
3
- import VvAction from '@/components/VvAction/VvAction.vue'
2
+ import { VvNavProps, VvNavEvents } from '@/components/VvNav'
3
+ import VvNavItem from './VvNavItem.vue'
4
4
 
5
5
  const props = defineProps(VvNavProps)
6
- const emit = defineEmits(VvNavEvents)
7
- const { modifiers, items } = toRefs(props)
8
- const activeItem: Ref<string | null> = ref(null)
6
+ const { modifiers } = toRefs(props)
9
7
 
10
- // bem css classes
11
- const bemCssClasses = useModifiers('vv-nav', modifiers)
12
-
13
- const localItems = computed(() => {
14
- return items.value.map((item, index) => {
15
- return {
16
- ...item,
17
- id: item.id || `nav-item_${index}`,
8
+ const emit = defineEmits(VvNavEvents)
9
+ const onClick = (event: Event) => {
10
+ const target = event.target as HTMLElement
11
+ if (target?.dataset.index) {
12
+ const index = parseInt(target.dataset.index)
13
+ const item = props.items?.[index]
14
+ if (!item || item?.disabled) {
15
+ return
18
16
  }
19
- })
20
- })
21
-
22
- /**
23
- * Triggers when the item is clicked.
24
- * @private
25
- * @event click
26
- * @param [NavItem, string] item - the clicked item
27
- */
28
- function onClick(item: NavItem) {
29
- if (!item.disabled) {
30
17
  emit('click', item)
31
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
32
- activeItem.value = item.id!
33
18
  }
34
19
  }
20
+
21
+ // bem css classes
22
+ const bemCssClasses = useModifiers('vv-nav', modifiers)
35
23
  </script>
36
24
 
37
25
  <template>
38
26
  <nav :class="bemCssClasses">
39
- <ul class="vv-nav__menu" role="menu" aria-busy="true">
40
- <li
41
- v-for="navItem in localItems"
42
- :key="navItem.id"
43
- class="vv-nav__item"
44
- role="presentation"
45
- >
46
- <VvAction
47
- v-bind="{
48
- disabled: navItem.disabled,
49
- to: navItem.to,
50
- href: navItem.href,
51
- tabindex: 0,
52
- }"
53
- :class="{
54
- current: activeItem == navItem.id,
55
- disabled: navItem.disabled,
56
- }"
57
- class="vv-nav__item-label"
58
- v-on="navItem.on"
59
- @click="onClick(navItem)"
27
+ <ul
28
+ class="vv-nav__menu"
29
+ role="menu"
30
+ aria-busy="true"
31
+ @click.stop="onClick"
32
+ >
33
+ <slot>
34
+ <VvNavItem
35
+ v-for="({ on = {}, data, ...item }, index) in items"
36
+ :key="index"
37
+ :data-index="index"
38
+ v-bind="item"
39
+ v-on="on"
60
40
  >
61
- {{ navItem.title }}
62
- </VvAction>
63
- </li>
41
+ <slot name="item" v-bind="{ item, data, index }" />
42
+ </VvNavItem>
43
+ </slot>
64
44
  </ul>
65
45
  </nav>
66
46
  </template>
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'VvNavItem',
4
+ inheritAttrs: false,
5
+ }
6
+ </script>
7
+
8
+ <script setup lang="ts">
9
+ import VvAction from '@/components/VvAction/VvAction.vue'
10
+ </script>
11
+
12
+ <template>
13
+ <li class="vv-nav__item" role="presentation">
14
+ <VvAction v-bind="$attrs" class="vv-nav__item-label">
15
+ <slot />
16
+ </VvAction>
17
+ </li>
18
+ </template>
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'VvNavSeparator',
4
+ }
5
+ </script>
6
+
7
+ <template>
8
+ <li class="vv-nav__separator" role="separator">
9
+ <slot />
10
+ </li>
11
+ </template>
@@ -1,21 +1,8 @@
1
- import { ModifiersProps } from '@/props'
2
-
3
- export type NavItem = {
4
- id?: string
5
- title: string
6
- to?: string | { [key: string]: unknown }
7
- href?: string
8
- disabled?: boolean
9
- on?: Record<string, () => void>
10
- }
1
+ import { ModifiersProps, NavProps } from '@/props'
11
2
 
12
3
  export const VvNavProps = {
13
4
  ...ModifiersProps,
14
- items: {
15
- type: Array as PropType<NavItem[]>,
16
- required: true,
17
- default: () => [],
18
- },
5
+ ...NavProps,
19
6
  }
20
7
 
21
8
  export const VvNavEvents = ['click']
@@ -65,10 +65,7 @@
65
65
  })
66
66
 
67
67
  // icons
68
- const { hasIcon, hasIconBefore, hasIconAfter } = useComponentIcon(
69
- icon,
70
- iconPosition,
71
- )
68
+ const { hasIconBefore, hasIconAfter } = useComponentIcon(icon, iconPosition)
72
69
 
73
70
  // dirty
74
71
  const isDirty = computed(() => !isEmpty(props.modelValue))
@@ -100,8 +97,8 @@
100
97
  loading: loading.value,
101
98
  disabled: disabled.value,
102
99
  readonly: readonly.value,
103
- 'icon-before': hasIconBefore.value,
104
- 'icon-after': hasIconAfter.value,
100
+ 'icon-before': hasIconBefore.value !== undefined,
101
+ 'icon-after': hasIconAfter.value !== undefined,
105
102
  dirty: isDirty.value,
106
103
  focus: focused.value,
107
104
  floating: floating.value,
@@ -174,8 +171,8 @@
174
171
  <div class="vv-select__inner">
175
172
  <VvIcon
176
173
  v-if="hasIconBefore"
174
+ v-bind="hasIconBefore"
177
175
  class="vv-select__icon"
178
- v-bind="hasIcon"
179
176
  />
180
177
  <select
181
178
  :id="hasId"
@@ -219,8 +216,8 @@
219
216
  </select>
220
217
  <VvIcon
221
218
  v-if="hasIconAfter"
219
+ v-bind="hasIconAfter"
222
220
  class="vv-select__icon vv-select__icon-after"
223
- v-bind="hasIcon"
224
221
  />
225
222
  </div>
226
223
  <div v-if="$slots.after" class="vv-select__input-after">