@volverjs/ui-vue 0.0.10-beta.35 → 0.0.10-beta.36

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 (348) hide show
  1. package/README.md +78 -77
  2. package/bin/icons.cjs +1 -1
  3. package/bin/icons.js +5 -5
  4. package/dist/Volver.d.ts +10 -10
  5. package/dist/components/VvAccordion/VvAccordion.es.js +11 -11
  6. package/dist/components/VvAccordion/VvAccordion.umd.js +1 -1
  7. package/dist/components/VvAccordionGroup/VvAccordionGroup.es.js +17 -17
  8. package/dist/components/VvAccordionGroup/VvAccordionGroup.umd.js +1 -1
  9. package/dist/components/VvAction/VvAction.es.js +6 -6
  10. package/dist/components/VvAction/VvAction.umd.js +1 -1
  11. package/dist/components/VvAlert/VvAlert.es.js +23 -21
  12. package/dist/components/VvAlert/VvAlert.umd.js +1 -1
  13. package/dist/components/VvAlert/index.d.ts +2 -2
  14. package/dist/components/VvAlertGroup/VvAlertGroup.es.js +351 -349
  15. package/dist/components/VvAlertGroup/VvAlertGroup.umd.js +1 -1
  16. package/dist/components/VvAlertGroup/VvAlertGroup.vue.d.ts +3 -3
  17. package/dist/components/VvAlertGroup/index.d.ts +1 -1
  18. package/dist/components/VvAvatar/VvAvatar.es.js +4 -1
  19. package/dist/components/VvAvatar/VvAvatar.umd.js +1 -1
  20. package/dist/components/VvAvatarGroup/VvAvatarGroup.es.js +11 -3
  21. package/dist/components/VvAvatarGroup/VvAvatarGroup.umd.js +1 -1
  22. package/dist/components/VvBreadcrumb/VvBreadcrumb.es.js +10 -10
  23. package/dist/components/VvBreadcrumb/VvBreadcrumb.umd.js +1 -1
  24. package/dist/components/VvButton/VvButton.es.js +31 -25
  25. package/dist/components/VvButton/VvButton.umd.js +1 -1
  26. package/dist/components/VvButtonGroup/VvButtonGroup.es.js +1 -1
  27. package/dist/components/VvButtonGroup/VvButtonGroup.umd.js +1 -1
  28. package/dist/components/VvCheckbox/VvCheckbox.es.js +208 -202
  29. package/dist/components/VvCheckbox/VvCheckbox.umd.js +1 -1
  30. package/dist/components/VvCheckbox/VvCheckbox.vue.d.ts +3 -3
  31. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.es.js +21 -15
  32. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.umd.js +1 -1
  33. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.vue.d.ts +2 -2
  34. package/dist/components/VvCombobox/VvCombobox.es.js +454 -446
  35. package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
  36. package/dist/components/VvCombobox/VvCombobox.vue.d.ts +5 -5
  37. package/dist/components/VvCombobox/index.d.ts +5 -10
  38. package/dist/components/VvDialog/VvDialog.es.js +11 -11
  39. package/dist/components/VvDialog/VvDialog.umd.js +1 -1
  40. package/dist/components/VvDropdown/VvDropdown.es.js +29 -25
  41. package/dist/components/VvDropdown/VvDropdown.umd.js +1 -1
  42. package/dist/components/VvDropdown/VvDropdown.vue.d.ts +12 -8
  43. package/dist/components/VvDropdownAction/VvDropdownAction.es.js +11 -14
  44. package/dist/components/VvDropdownAction/VvDropdownAction.umd.js +1 -1
  45. package/dist/components/VvIcon/VvIcon.es.js +1 -1
  46. package/dist/components/VvIcon/VvIcon.umd.js +1 -1
  47. package/dist/components/VvInputFile/VvInputFile.es.js +61 -55
  48. package/dist/components/VvInputFile/VvInputFile.umd.js +1 -1
  49. package/dist/components/VvInputFile/VvInputFile.vue.d.ts +2 -2
  50. package/dist/components/VvInputFile/index.d.ts +6 -6
  51. package/dist/components/VvInputText/VvInputText.es.js +287 -286
  52. package/dist/components/VvInputText/VvInputText.umd.js +1 -1
  53. package/dist/components/VvInputText/VvInputText.vue.d.ts +2 -2
  54. package/dist/components/VvInputText/index.d.ts +7 -2
  55. package/dist/components/VvNav/VvNav.es.js +23 -20
  56. package/dist/components/VvNav/VvNav.umd.js +1 -1
  57. package/dist/components/VvNavItem/VvNavItem.es.js +6 -6
  58. package/dist/components/VvNavItem/VvNavItem.umd.js +1 -1
  59. package/dist/components/VvRadio/VvRadio.es.js +208 -202
  60. package/dist/components/VvRadio/VvRadio.umd.js +1 -1
  61. package/dist/components/VvRadio/VvRadio.vue.d.ts +2 -2
  62. package/dist/components/VvRadioGroup/VvRadioGroup.es.js +21 -15
  63. package/dist/components/VvRadioGroup/VvRadioGroup.umd.js +1 -1
  64. package/dist/components/VvRadioGroup/VvRadioGroup.vue.d.ts +2 -2
  65. package/dist/components/VvSelect/VvSelect.es.js +22 -20
  66. package/dist/components/VvSelect/VvSelect.umd.js +1 -1
  67. package/dist/components/VvSelect/VvSelect.vue.d.ts +2 -2
  68. package/dist/components/VvTab/VvTab.es.js +29 -23
  69. package/dist/components/VvTab/VvTab.umd.js +1 -1
  70. package/dist/components/VvTextarea/VvTextarea.es.js +29 -27
  71. package/dist/components/VvTextarea/VvTextarea.umd.js +1 -1
  72. package/dist/components/VvTextarea/VvTextarea.vue.d.ts +2 -2
  73. package/dist/components/VvTooltip/VvTooltip.es.js +4 -1
  74. package/dist/components/VvTooltip/VvTooltip.umd.js +1 -1
  75. package/dist/components/common/HintSlot.d.ts +3 -4
  76. package/dist/components/index.es.js +893 -876
  77. package/dist/components/index.umd.js +1 -1
  78. package/dist/composables/alert/useAlert.d.ts +2 -2
  79. package/dist/composables/index.es.js +10 -10
  80. package/dist/composables/index.umd.js +1 -1
  81. package/dist/composables/useBlurhash.d.ts +1 -1
  82. package/dist/composables/usePersistence.d.ts +2 -1
  83. package/dist/composables/useUniqueId.d.ts +1 -1
  84. package/dist/directives/index.es.js +5 -2
  85. package/dist/directives/index.umd.js +1 -1
  86. package/dist/directives/v-contextmenu.es.js +1 -1
  87. package/dist/directives/v-contextmenu.umd.js +1 -1
  88. package/dist/directives/v-tooltip.es.js +4 -1
  89. package/dist/directives/v-tooltip.umd.js +1 -1
  90. package/dist/icons.es.js +3 -3
  91. package/dist/icons.umd.js +1 -1
  92. package/dist/index.es.js +2 -2
  93. package/dist/stories/Alert/AlertModifiers.stories.d.ts +1 -1
  94. package/dist/stories/Alert/AlertSlots.stories.d.ts +1 -1
  95. package/dist/stories/AlertGroup/AlertGroupPosition.stories.d.ts +1 -1
  96. package/dist/stories/AlertGroup/AlertGroupSlots.stories.d.ts +1 -1
  97. package/dist/stories/AlertGroup/AlertGroupWithComposable.stories.d.ts +1 -1
  98. package/dist/stories/Badge/Badge.test.d.ts +1 -1
  99. package/dist/stories/Combobox/Combobox.settings.d.ts +1 -1
  100. package/dist/test/options.d.ts +1 -1
  101. package/dist/test/sleep.d.ts +1 -1
  102. package/dist/types/alert.d.ts +1 -1
  103. package/dist/utils/ObjectUtilities.d.ts +7 -7
  104. package/package.json +232 -239
  105. package/src/Volver.ts +243 -243
  106. package/src/assets/icons/detailed.json +1 -1
  107. package/src/assets/icons/normal.json +1 -1
  108. package/src/assets/icons/simple.json +1 -1
  109. package/src/components/VvAccordion/VvAccordion.vue +155 -155
  110. package/src/components/VvAccordion/index.ts +62 -62
  111. package/src/components/VvAccordionGroup/VvAccordionGroup.vue +220 -219
  112. package/src/components/VvAccordionGroup/index.ts +41 -41
  113. package/src/components/VvAction/VvAction.vue +144 -142
  114. package/src/components/VvAlert/VvAlert.vue +72 -70
  115. package/src/components/VvAlert/index.ts +147 -150
  116. package/src/components/VvAlertGroup/VvAlertGroup.vue +56 -55
  117. package/src/components/VvAlertGroup/index.ts +99 -103
  118. package/src/components/VvAvatar/VvAvatar.vue +20 -14
  119. package/src/components/VvAvatar/index.ts +5 -5
  120. package/src/components/VvAvatarGroup/VvAvatarGroup.vue +58 -53
  121. package/src/components/VvAvatarGroup/index.ts +21 -21
  122. package/src/components/VvBadge/VvBadge.vue +15 -14
  123. package/src/components/VvBadge/index.ts +2 -2
  124. package/src/components/VvBreadcrumb/VvBreadcrumb.vue +49 -48
  125. package/src/components/VvBreadcrumb/index.ts +2 -2
  126. package/src/components/VvButton/VvButton.vue +163 -162
  127. package/src/components/VvButton/index.ts +102 -102
  128. package/src/components/VvButtonGroup/VvButtonGroup.vue +72 -72
  129. package/src/components/VvButtonGroup/index.ts +22 -22
  130. package/src/components/VvCard/VvCard.vue +30 -30
  131. package/src/components/VvCard/index.ts +2 -2
  132. package/src/components/VvCheckbox/VvCheckbox.vue +185 -180
  133. package/src/components/VvCheckbox/index.ts +44 -44
  134. package/src/components/VvCheckboxGroup/VvCheckboxGroup.vue +88 -86
  135. package/src/components/VvCombobox/VvCombobox.vue +633 -623
  136. package/src/components/VvCombobox/index.ts +166 -166
  137. package/src/components/VvDialog/VvDialog.vue +131 -129
  138. package/src/components/VvDialog/index.ts +35 -35
  139. package/src/components/VvDropdown/VvDropdown.vue +464 -452
  140. package/src/components/VvDropdown/VvDropdownAction.vue +37 -39
  141. package/src/components/VvDropdown/VvDropdownItem.vue +29 -28
  142. package/src/components/VvDropdown/VvDropdownOptgroup.vue +13 -12
  143. package/src/components/VvDropdown/VvDropdownOption.vue +47 -47
  144. package/src/components/VvDropdown/index.ts +53 -53
  145. package/src/components/VvIcon/README.md +1 -1
  146. package/src/components/VvIcon/VvIcon.vue +133 -133
  147. package/src/components/VvIcon/index.ts +77 -77
  148. package/src/components/VvInputFile/VvInputFile.vue +367 -363
  149. package/src/components/VvInputFile/index.ts +125 -125
  150. package/src/components/VvInputText/VvInputClearAction.ts +50 -50
  151. package/src/components/VvInputText/VvInputPasswordAction.ts +65 -65
  152. package/src/components/VvInputText/VvInputStepAction.ts +43 -43
  153. package/src/components/VvInputText/VvInputText.vue +636 -637
  154. package/src/components/VvInputText/VvInputTextActions.ts +86 -86
  155. package/src/components/VvInputText/index.ts +198 -198
  156. package/src/components/VvNav/VvNav.vue +40 -33
  157. package/src/components/VvNav/VvNavItem.vue +12 -12
  158. package/src/components/VvNav/VvNavSeparator.vue +6 -6
  159. package/src/components/VvNav/index.ts +2 -2
  160. package/src/components/VvProgress/VvProgress.vue +27 -26
  161. package/src/components/VvProgress/index.ts +28 -28
  162. package/src/components/VvRadio/VvRadio.vue +115 -112
  163. package/src/components/VvRadio/index.ts +27 -27
  164. package/src/components/VvRadioGroup/VvRadioGroup.vue +91 -89
  165. package/src/components/VvSelect/VvSelect.vue +241 -238
  166. package/src/components/VvSelect/index.ts +62 -62
  167. package/src/components/VvTab/VvTab.vue +79 -73
  168. package/src/components/VvTab/index.ts +12 -12
  169. package/src/components/VvTextarea/VvTextarea.vue +218 -216
  170. package/src/components/VvTextarea/index.ts +35 -35
  171. package/src/components/VvTooltip/VvTooltip.vue +22 -16
  172. package/src/components/VvTooltip/index.ts +12 -12
  173. package/src/components/common/HintSlot.ts +149 -150
  174. package/src/composables/alert/useAlert.ts +74 -74
  175. package/src/composables/alert/useInjectAlert.ts +1 -1
  176. package/src/composables/alert/useProvideAlert.ts +10 -10
  177. package/src/composables/dropdown/useInjectDropdown.ts +6 -6
  178. package/src/composables/dropdown/useProvideDropdown.ts +62 -62
  179. package/src/composables/group/useInjectedGroupState.ts +41 -41
  180. package/src/composables/group/useProvideGroupState.ts +1 -2
  181. package/src/composables/useBlurhash.ts +52 -60
  182. package/src/composables/useComponentFocus.ts +9 -9
  183. package/src/composables/useComponentIcon.ts +35 -35
  184. package/src/composables/useDebouncedInput.ts +25 -25
  185. package/src/composables/useDefaults.ts +77 -76
  186. package/src/composables/useModifiers.ts +29 -29
  187. package/src/composables/useOptions.ts +45 -43
  188. package/src/composables/usePersistence.ts +70 -72
  189. package/src/composables/useTextCount.ts +44 -44
  190. package/src/composables/useUniqueId.ts +3 -2
  191. package/src/composables/useVolver.ts +1 -1
  192. package/src/constants.ts +70 -70
  193. package/src/directives/v-contextmenu.ts +34 -34
  194. package/src/directives/v-tooltip.ts +17 -17
  195. package/src/index.ts +3 -3
  196. package/src/props/index.ts +453 -453
  197. package/src/resolvers/unplugin.ts +138 -138
  198. package/src/shims.d.ts +4 -5
  199. package/src/stories/Accordion/Accordion.settings.ts +49 -49
  200. package/src/stories/Accordion/Accordion.stories.ts +21 -21
  201. package/src/stories/Accordion/Accordion.test.ts +56 -54
  202. package/src/stories/Accordion/AccordionSlots.stories.ts +13 -13
  203. package/src/stories/AccordionGroup/AccordionGroup.settings.ts +69 -67
  204. package/src/stories/AccordionGroup/AccordionGroup.stories.ts +37 -37
  205. package/src/stories/AccordionGroup/AccordionGroup.test.ts +49 -47
  206. package/src/stories/AccordionGroup/AccordionGroupSlots.stories.ts +34 -34
  207. package/src/stories/Alert/Alert.settings.ts +115 -115
  208. package/src/stories/Alert/Alert.stories.ts +30 -30
  209. package/src/stories/Alert/Alert.test.ts +78 -78
  210. package/src/stories/Alert/AlertModifiers.stories.ts +45 -45
  211. package/src/stories/Alert/AlertSlots.stories.ts +35 -35
  212. package/src/stories/AlertGroup/AlertGroup.settings.ts +104 -104
  213. package/src/stories/AlertGroup/AlertGroup.stories.ts +25 -25
  214. package/src/stories/AlertGroup/AlertGroup.test.ts +67 -67
  215. package/src/stories/AlertGroup/AlertGroupPosition.stories.ts +68 -68
  216. package/src/stories/AlertGroup/AlertGroupSlots.stories.ts +23 -23
  217. package/src/stories/AlertGroup/AlertGroupWithComposable.stories.ts +57 -57
  218. package/src/stories/Avatar/Avatar.settings.ts +29 -29
  219. package/src/stories/Avatar/Avatar.stories.ts +23 -23
  220. package/src/stories/Avatar/Avatar.test.ts +22 -22
  221. package/src/stories/Avatar/AvatarBadge.stories.ts +15 -15
  222. package/src/stories/Avatar/AvatarModifiers.stories.ts +61 -61
  223. package/src/stories/Avatar/AvatarSlots.stories.ts +18 -18
  224. package/src/stories/AvatarGroup/AvatarGroup.settings.ts +53 -53
  225. package/src/stories/AvatarGroup/AvatarGroup.stories.ts +17 -17
  226. package/src/stories/AvatarGroup/AvatarGroup.test.ts +24 -24
  227. package/src/stories/AvatarGroup/AvatarGroupModifiers.stories.ts +15 -15
  228. package/src/stories/AvatarGroup/AvatarGroupSlotDefault.stories.ts +17 -17
  229. package/src/stories/Badge/Badge.settings.ts +20 -20
  230. package/src/stories/Badge/Badge.stories.ts +23 -23
  231. package/src/stories/Badge/Badge.test.ts +8 -8
  232. package/src/stories/Badge/BadgeSlots.stories.ts +10 -10
  233. package/src/stories/Blurhash/BlurhashComposable.stories.ts +77 -76
  234. package/src/stories/Breadcrumb/Breadcrumb.settings.ts +34 -34
  235. package/src/stories/Breadcrumb/Breadcrumb.stories.ts +22 -22
  236. package/src/stories/Breadcrumb/Breadcrumb.test.ts +44 -43
  237. package/src/stories/Breadcrumb/BreadcrumbSlots.stories.ts +17 -17
  238. package/src/stories/Button/Button.settings.ts +144 -144
  239. package/src/stories/Button/Button.stories.ts +18 -18
  240. package/src/stories/Button/Button.test.ts +41 -40
  241. package/src/stories/Button/ButtonIcon.stories.ts +42 -42
  242. package/src/stories/Button/ButtonLink.stories.ts +24 -24
  243. package/src/stories/Button/ButtonLoading.stories.ts +22 -22
  244. package/src/stories/Button/ButtonModifiers.stories.ts +91 -91
  245. package/src/stories/Button/ButtonSlots.stories.ts +47 -47
  246. package/src/stories/Button/ButtonState.stories.ts +23 -23
  247. package/src/stories/Button/ButtonToggle.stories.ts +30 -30
  248. package/src/stories/ButtonGroup/ButtonGroup.settings.ts +32 -32
  249. package/src/stories/ButtonGroup/ButtonGroup.stories.ts +19 -19
  250. package/src/stories/ButtonGroup/ButtonGroup.test.ts +23 -22
  251. package/src/stories/ButtonGroup/ButtonGroupModifiers.stories.ts +20 -20
  252. package/src/stories/ButtonGroup/ButtonGroupSlots.stories.ts +18 -18
  253. package/src/stories/ButtonGroup/ButtonGroupToggle.stories.ts +22 -22
  254. package/src/stories/Card/Card.settings.ts +48 -48
  255. package/src/stories/Card/Card.stories.ts +22 -22
  256. package/src/stories/Card/Card.test.ts +14 -14
  257. package/src/stories/Card/CardSlots.stories.ts +42 -42
  258. package/src/stories/Checkbox/Checkbox.settings.ts +35 -35
  259. package/src/stories/Checkbox/Checkbox.stories.ts +57 -57
  260. package/src/stories/Checkbox/Checkbox.test.ts +63 -62
  261. package/src/stories/Checkbox/CheckboxBinary.stories.ts +17 -17
  262. package/src/stories/Checkbox/CheckboxSlots.stories.ts +15 -15
  263. package/src/stories/CheckboxGroup/CheckboxGroup.settings.ts +9 -9
  264. package/src/stories/CheckboxGroup/CheckboxGroup.stories.ts +50 -50
  265. package/src/stories/CheckboxGroup/CheckboxGroup.test.ts +63 -63
  266. package/src/stories/CheckboxGroup/CheckboxGroupOptions.stories.ts +34 -34
  267. package/src/stories/CheckboxGroup/CheckboxGroupSlots.stories.ts +23 -23
  268. package/src/stories/Combobox/Combobox.settings.ts +390 -390
  269. package/src/stories/Combobox/Combobox.stories.ts +107 -107
  270. package/src/stories/Combobox/Combobox.test.ts +89 -87
  271. package/src/stories/Combobox/ComboboxIconPosition.stories.ts +24 -24
  272. package/src/stories/Combobox/ComboboxMultiple.stories.ts +22 -22
  273. package/src/stories/Combobox/ComboboxOptions.stories.ts +84 -84
  274. package/src/stories/Combobox/ComboboxSlots.stories.ts +55 -55
  275. package/src/stories/Dialog/Dialog.settings.ts +39 -39
  276. package/src/stories/Dialog/Dialog.stories.ts +28 -28
  277. package/src/stories/Dialog/Dialog.test.ts +49 -49
  278. package/src/stories/Dialog/DialogSlots.stories.ts +20 -20
  279. package/src/stories/Dropdown/Dropdown.settings.ts +62 -62
  280. package/src/stories/Dropdown/Dropdown.stories.ts +59 -59
  281. package/src/stories/Dropdown/Dropdown.test.ts +9 -9
  282. package/src/stories/Dropdown/DropdownContextmenuDirective.stories.ts +16 -16
  283. package/src/stories/Dropdown/DropdownMultilevel.stories.ts +18 -18
  284. package/src/stories/Dropdown/DropdownSlots.stories.ts +49 -49
  285. package/src/stories/Icon/Icon.settings.ts +64 -64
  286. package/src/stories/Icon/Icon.stories.ts +28 -28
  287. package/src/stories/Icon/IconsCollection.stories.ts +22 -22
  288. package/src/stories/InputFile/InputFile.settings.ts +29 -29
  289. package/src/stories/InputFile/InputFile.stories.ts +54 -54
  290. package/src/stories/InputFile/InputFileDropArea.stories.ts +34 -34
  291. package/src/stories/InputFile/InputFileIconPosition.stories.ts +24 -24
  292. package/src/stories/InputFile/InputFileSlots.stories.ts +17 -17
  293. package/src/stories/InputText/InputText.settings.ts +245 -246
  294. package/src/stories/InputText/InputText.stories.ts +67 -67
  295. package/src/stories/InputText/InputText.test.ts +118 -117
  296. package/src/stories/InputText/InputTextIconPosition.stories.ts +24 -24
  297. package/src/stories/InputText/InputTextLength.stories.ts +33 -33
  298. package/src/stories/InputText/InputTextMask.stories.ts +91 -91
  299. package/src/stories/InputText/InputTextMinMax.stories.ts +29 -29
  300. package/src/stories/InputText/InputTextSlots.stories.ts +20 -20
  301. package/src/stories/InputText/InputTextType.stories.ts +70 -70
  302. package/src/stories/Nav/Nav.settings.ts +25 -25
  303. package/src/stories/Nav/Nav.stories.ts +17 -17
  304. package/src/stories/Nav/Nav.test.ts +10 -10
  305. package/src/stories/Nav/NavModifiers.stories.ts +25 -25
  306. package/src/stories/Progress/Progress.settings.ts +23 -23
  307. package/src/stories/Progress/Progress.stories.ts +23 -23
  308. package/src/stories/Progress/Progress.test.ts +4 -4
  309. package/src/stories/Radio/Radio.settings.ts +9 -9
  310. package/src/stories/Radio/Radio.stories.ts +47 -47
  311. package/src/stories/Radio/Radio.test.ts +54 -53
  312. package/src/stories/Radio/RadioSlots.stories.ts +15 -15
  313. package/src/stories/RadioGroup/RadioGroup.settings.ts +9 -9
  314. package/src/stories/RadioGroup/RadioGroup.stories.ts +50 -50
  315. package/src/stories/RadioGroup/RadioGroup.test.ts +63 -63
  316. package/src/stories/RadioGroup/RadioGroupOptions.stories.ts +34 -34
  317. package/src/stories/RadioGroup/RadioGroupSlots.stories.ts +23 -23
  318. package/src/stories/Select/Select.settings.ts +70 -70
  319. package/src/stories/Select/Select.stories.ts +66 -66
  320. package/src/stories/Select/Select.test.ts +65 -64
  321. package/src/stories/Select/SelectIconPosition.stories.ts +24 -24
  322. package/src/stories/Select/SelectOptions.stories.ts +54 -54
  323. package/src/stories/Select/SelectSlots.stories.ts +20 -20
  324. package/src/stories/Tab/Tab.settings.ts +32 -32
  325. package/src/stories/Tab/Tab.stories.ts +17 -17
  326. package/src/stories/Tab/Tab.test.ts +17 -17
  327. package/src/stories/Textarea/Textarea.settings.ts +78 -79
  328. package/src/stories/Textarea/Textarea.stories.ts +63 -63
  329. package/src/stories/Textarea/Textarea.test.ts +70 -69
  330. package/src/stories/Textarea/TextareaLength.stories.ts +33 -33
  331. package/src/stories/Textarea/TextareaSlots.stories.ts +20 -20
  332. package/src/stories/Textarea/TextareatIconPosition.stories.ts +24 -24
  333. package/src/stories/Tooltip/Tooltip.settings.ts +16 -16
  334. package/src/stories/Tooltip/Tooltip.stories.ts +18 -18
  335. package/src/stories/Tooltip/Tooltip.test.ts +53 -52
  336. package/src/stories/Tooltip/TooltipDirective.stories.ts +37 -37
  337. package/src/stories/argTypes.ts +484 -485
  338. package/src/test/expect.ts +71 -74
  339. package/src/test/options.ts +17 -16
  340. package/src/test/sleep.ts +3 -2
  341. package/src/test/types.d.ts +11 -11
  342. package/src/types/alert.ts +18 -18
  343. package/src/types/blurhash.ts +18 -18
  344. package/src/types/generic.ts +1 -2
  345. package/src/types/group.ts +21 -21
  346. package/src/types/input-file.ts +17 -17
  347. package/src/types/nav.ts +13 -13
  348. package/src/utils/ObjectUtilities.ts +192 -177
@@ -1,670 +1,669 @@
1
- <script lang="ts">
2
- export default {
3
- name: 'VvInputText',
4
- }
5
- </script>
6
-
7
1
  <script setup lang="ts">
8
- import type { InputHTMLAttributes } from 'vue'
9
- import { useIMask } from 'vue-imask'
10
- import HintSlotFactory from '../common/HintSlot'
11
- import VvIcon from '../VvIcon/VvIcon.vue'
12
- import { ACTION_ICONS } from '../VvIcon'
13
- import VvInputTextActionsFactory from '../VvInputText/VvInputTextActions'
14
- import VvDropdown from '../VvDropdown/VvDropdown.vue'
15
- import VvDropdownOption from '../VvDropdown/VvDropdownOption.vue'
16
- import {
17
- VvInputTextEvents,
18
- VvInputTextProps,
19
- INPUT_TYPES,
20
- } from '../VvInputText'
2
+ import type { InputHTMLAttributes } from 'vue'
3
+ import { useIMask } from 'vue-imask'
4
+ import HintSlotFactory from '../common/HintSlot'
5
+ import VvIcon from '../VvIcon/VvIcon.vue'
6
+ import { ACTION_ICONS } from '../VvIcon'
7
+ import VvInputTextActionsFactory from '../VvInputText/VvInputTextActions'
8
+ import VvDropdown from '../VvDropdown/VvDropdown.vue'
9
+ import VvDropdownOption from '../VvDropdown/VvDropdownOption.vue'
10
+ import {
11
+ VvInputTextEvents,
12
+ VvInputTextProps,
13
+ INPUT_TYPES,
14
+ } from '../VvInputText'
15
+
16
+ // props, emit, slots and attrs
17
+ const props = defineProps(VvInputTextProps)
21
18
 
22
- // props, emit, slots and attrs
23
- const props = defineProps(VvInputTextProps)
24
- const emit = defineEmits(VvInputTextEvents)
25
- const slots = useSlots()
19
+ const emit = defineEmits(VvInputTextEvents)
26
20
 
27
- // props merged with volver defaults (now only for labels)
28
- const propsDefaults = useDefaults<typeof VvInputTextProps>(
29
- 'VvInputText',
30
- VvInputTextProps,
31
- props,
32
- )
21
+ const slots = useSlots()
33
22
 
34
- // data
35
- const {
36
- id,
37
- icon,
38
- iconPosition,
39
- iconRemoveSuggestion,
40
- label,
41
- modelValue,
42
- count,
43
- valid,
44
- invalid,
45
- loading,
46
- debounce,
47
- maxlength,
48
- minlength,
49
- type,
50
- iMask,
51
- step,
52
- storageKey,
53
- storageType,
54
- } = toRefs(props)
55
- const hasId = useUniqueId(id)
56
- const hasHintId = computed(() => `${hasId.value}-hint`)
57
- // BUG: https://www.samanthaming.com/tidbits/88-css-placeholder-shown/
58
- const inputTextPlaceholder = computed(() =>
59
- props.floating && isEmpty(props.placeholder) ? ' ' : props.placeholder,
60
- )
23
+ // props merged with volver defaults (now only for labels)
24
+ const propsDefaults = useDefaults<typeof VvInputTextProps>(
25
+ 'VvInputText',
26
+ VvInputTextProps,
27
+ props,
28
+ )
61
29
 
62
- // debounce
63
- const localModelValue = useDebouncedInput(
64
- modelValue,
65
- emit,
66
- debounce?.value ?? 0,
67
- )
30
+ // data
31
+ const {
32
+ count,
33
+ debounce,
34
+ icon,
35
+ iconPosition,
36
+ iconRemoveSuggestion,
37
+ id,
38
+ invalid,
39
+ label,
40
+ loading,
41
+ maxlength,
42
+ minlength,
43
+ modelValue,
44
+ step,
45
+ storageKey,
46
+ storageType,
47
+ type,
48
+ valid,
49
+ } = toRefs(props)
50
+ const hasId = useUniqueId(id)
51
+ const hasHintId = computed(() => `${hasId.value}-hint`)
52
+ // BUG: https://www.samanthaming.com/tidbits/88-css-placeholder-shown/
53
+ const inputTextPlaceholder = computed(() =>
54
+ props.floating && isEmpty(props.placeholder) ? ' ' : props.placeholder,
55
+ )
68
56
 
69
- // mask
70
- const NEGATIVE_ZERO_REGEX = /^-0?[.,]?[0*]?$/
71
- const maskReady = ref(false)
72
- const { el, mask, typed, masked, unmasked } = useIMask(
73
- computed(
74
- () =>
75
- iMask?.value ?? {
76
- mask: /./,
77
- },
78
- ),
79
- {
80
- emit,
81
- onAccept: () => {
82
- if (!maskReady.value) {
83
- return
84
- }
85
- emit('update:masked', masked.value)
86
- if (type.value === INPUT_TYPES.NUMBER) {
87
- if (/^-$|^$/.test(unmasked.value)) {
88
- if (
89
- localModelValue.value === null ||
90
- localModelValue.value === undefined
91
- ) {
92
- return
93
- }
94
- localModelValue.value = undefined
95
- return
96
- }
97
- if (NEGATIVE_ZERO_REGEX.test(unmasked.value)) {
98
- localModelValue.value = 0
99
- return
100
- }
101
- if (typeof typed.value !== 'number') {
102
- localModelValue.value = Number(typed.value)
103
- return
104
- }
105
- localModelValue.value = typed.value
106
- return
107
- }
108
- if (type.value === INPUT_TYPES.DATE) {
109
- if (
110
- el.value instanceof HTMLInputElement &&
111
- el.value.type === 'date'
112
- ) {
113
- localModelValue.value = el.value.value
114
- return
115
- }
116
- let date = typed.value
117
- if (date === null || date === '') {
118
- if (!localModelValue.value) {
119
- return
120
- }
121
- localModelValue.value = ''
122
- return
123
- }
124
- if (!(date instanceof Date)) {
125
- date = new Date(date)
126
- }
127
- localModelValue.value = `${date.getFullYear()}-${(
128
- '0' +
129
- (date.getMonth() + 1)
130
- ).slice(-2)}-${('0' + date.getDate()).slice(-2)}`
131
- return
132
- }
133
- if (type.value === INPUT_TYPES.DATETIME_LOCAL) {
134
- if (
135
- el.value instanceof HTMLInputElement &&
136
- el.value.type === 'datetime-local'
137
- ) {
138
- localModelValue.value = el.value.value
139
- return
140
- }
141
- let date = typed.value
142
- if (date === null || date === '') {
143
- if (!localModelValue.value) {
144
- return
145
- }
146
- localModelValue.value = ''
147
- return
148
- }
149
- if (!(typed.value instanceof Date)) {
150
- date = new Date(date)
151
- }
152
- localModelValue.value = `${date.getFullYear()}-${(
153
- '0' +
154
- (date.getMonth() + 1)
155
- ).slice(-2)}-${('0' + date.getDate()).slice(-2)}T${(
156
- '0' + date.getHours()
157
- ).slice(-2)}:${('0' + date.getMinutes()).slice(-2)}`
158
- return
159
- }
160
- if (!localModelValue.value && !unmasked.value) {
161
- return
162
- }
163
- localModelValue.value = unmasked.value
164
- },
165
- },
166
- )
167
- const updateMaskValue = (newValue: string | number | undefined) => {
168
- if (iMask?.value) {
169
- if (newValue === undefined) {
170
- typed.value = ''
171
- unmasked.value = ''
172
- return
173
- }
174
- if (iMask.value?.mask === Date) {
175
- typed.value = new Date(newValue)
176
- return
177
- }
178
- if (
179
- type.value === INPUT_TYPES.NUMBER &&
180
- NEGATIVE_ZERO_REGEX.test(unmasked.value) &&
181
- newValue === 0
182
- ) {
183
- return
184
- }
185
- typed.value = newValue
186
- unmasked.value = `${typed.value}`
187
- }
188
- }
189
- onMounted(() => {
190
- if (mask.value) {
191
- maskReady.value = true
192
- updateMaskValue(props.modelValue)
193
- }
194
- })
195
- watch(
196
- () => props.modelValue,
197
- (newValue) => {
198
- if (mask.value) {
199
- updateMaskValue(newValue)
200
- }
201
- },
202
- )
203
- watch(
204
- () => props.masked,
205
- (newValue) => {
206
- masked.value = newValue ?? ''
207
- },
208
- )
57
+ // debounce
58
+ const localModelValue = useDebouncedInput(
59
+ modelValue,
60
+ emit,
61
+ debounce?.value ?? 0,
62
+ )
209
63
 
210
- // template refs
211
- const inputEl = el as Ref<HTMLInputElement>
212
- const innerEl = ref<HTMLInputElement>()
213
- const wrapperEl = ref<HTMLDivElement>()
214
- const dropdownEl = ref<typeof VvDropdown>()
64
+ // mask
65
+ const NEGATIVE_ZERO_REGEX = /^-0?[.,]?[0*]?$/
66
+ const maskReady = ref(false)
67
+ const { el, mask, typed, masked, unmasked } = useIMask(
68
+ computed(
69
+ () =>
70
+ props.iMask ?? {
71
+ mask: /./,
72
+ },
73
+ ),
74
+ {
75
+ emit,
76
+ onAccept: () => {
77
+ if (!maskReady.value) {
78
+ return
79
+ }
80
+ emit('update:masked', masked.value)
81
+ if (type.value === INPUT_TYPES.NUMBER) {
82
+ if (/^-$|^$/.test(unmasked.value)) {
83
+ if (
84
+ localModelValue.value === null
85
+ || localModelValue.value === undefined
86
+ ) {
87
+ return
88
+ }
89
+ localModelValue.value = undefined
90
+ return
91
+ }
92
+ if (NEGATIVE_ZERO_REGEX.test(unmasked.value)) {
93
+ localModelValue.value = 0
94
+ return
95
+ }
96
+ if (typeof typed.value !== 'number') {
97
+ localModelValue.value = Number(typed.value)
98
+ return
99
+ }
100
+ localModelValue.value = typed.value
101
+ return
102
+ }
103
+ if (type.value === INPUT_TYPES.DATE) {
104
+ if (
105
+ el.value instanceof HTMLInputElement
106
+ && el.value.type === 'date'
107
+ ) {
108
+ localModelValue.value = el.value.value
109
+ return
110
+ }
111
+ let date = typed.value
112
+ if (date === null || date === '') {
113
+ if (!localModelValue.value) {
114
+ return
115
+ }
116
+ localModelValue.value = ''
117
+ return
118
+ }
119
+ if (!(date instanceof Date)) {
120
+ date = new Date(date)
121
+ }
122
+ localModelValue.value = `${date.getFullYear()}-${(
123
+ `0${
124
+ date.getMonth() + 1}`
125
+ ).slice(-2)}-${(`0${date.getDate()}`).slice(-2)}`
126
+ return
127
+ }
128
+ if (type.value === INPUT_TYPES.DATETIME_LOCAL) {
129
+ if (
130
+ el.value instanceof HTMLInputElement
131
+ && el.value.type === 'datetime-local'
132
+ ) {
133
+ localModelValue.value = el.value.value
134
+ return
135
+ }
136
+ let date = typed.value
137
+ if (date === null || date === '') {
138
+ if (!localModelValue.value) {
139
+ return
140
+ }
141
+ localModelValue.value = ''
142
+ return
143
+ }
144
+ if (!(typed.value instanceof Date)) {
145
+ date = new Date(date)
146
+ }
147
+ localModelValue.value = `${date.getFullYear()}-${(
148
+ `0${
149
+ date.getMonth() + 1}`
150
+ ).slice(-2)}-${(`0${date.getDate()}`).slice(-2)}T${(
151
+ `0${date.getHours()}`
152
+ ).slice(-2)}:${(`0${date.getMinutes()}`).slice(-2)}`
153
+ return
154
+ }
155
+ if (!localModelValue.value && !unmasked.value) {
156
+ return
157
+ }
158
+ localModelValue.value = unmasked.value
159
+ },
160
+ },
161
+ )
162
+ function updateMaskValue(newValue: string | number | undefined) {
163
+ if (newValue === undefined) {
164
+ typed.value = ''
165
+ unmasked.value = ''
166
+ return
167
+ }
168
+ if (props.iMask?.mask === Date) {
169
+ typed.value = new Date(newValue)
170
+ return
171
+ }
172
+ if (
173
+ type.value === INPUT_TYPES.NUMBER
174
+ && NEGATIVE_ZERO_REGEX.test(unmasked.value)
175
+ && newValue === 0
176
+ ) {
177
+ return
178
+ }
179
+ typed.value = newValue
180
+ unmasked.value = `${typed.value}`
181
+ }
182
+ onMounted(() => {
183
+ if (mask.value) {
184
+ maskReady.value = true
185
+ updateMaskValue(props.modelValue)
186
+ }
187
+ })
188
+ watch(
189
+ () => props.modelValue,
190
+ (newValue) => {
191
+ if (mask.value) {
192
+ updateMaskValue(newValue)
193
+ }
194
+ },
195
+ )
196
+ watch(
197
+ () => props.masked,
198
+ (newValue) => {
199
+ masked.value = newValue ?? ''
200
+ },
201
+ )
215
202
 
216
- defineExpose({ $inner: innerEl })
203
+ // template refs
204
+ const inputEl = el as Ref<HTMLInputElement>
205
+ const innerEl = ref<HTMLInputElement>()
206
+ const wrapperEl = ref<HTMLDivElement>()
207
+ const dropdownEl = ref<typeof VvDropdown>()
217
208
 
218
- // focus
219
- const { focused } = useComponentFocus(inputEl, emit)
220
- const isFocused = computed(
221
- () => focused.value && !props.disabled && !props.readonly,
222
- )
223
- watch(isFocused, (newValue) => {
224
- if (newValue && propsDefaults.value.selectOnFocus && inputEl.value) {
225
- inputEl.value.select()
226
- }
227
- if (newValue) {
228
- dropdownEl.value?.show()
229
- return
230
- }
231
- setTimeout(() => {
232
- if (isDirty.value && suggestions.value) {
233
- const suggestionsLimit = props.maxSuggestions - 1
234
- if (
235
- suggestions.value.size > suggestionsLimit &&
236
- !suggestions.value.has(localModelValue.value)
237
- ) {
238
- suggestions.value = new Set(
239
- [...suggestions.value].slice(
240
- suggestions.value.size - suggestionsLimit,
241
- ),
242
- )
243
- }
244
- suggestions.value.add(localModelValue.value)
245
- }
246
- }, 300)
247
- })
209
+ defineExpose({ $inner: innerEl })
248
210
 
249
- // visibility
250
- const isVisible = useElementVisibility(inputEl)
251
- watch(isVisible, (newValue) => {
252
- if (newValue && props.autofocus && !props.disabled && !props.readonly) {
253
- focused.value = true
254
- }
255
- })
211
+ // focus
212
+ const { focused } = useComponentFocus(inputEl, emit)
213
+ const isFocused = computed(
214
+ () => focused.value && !props.disabled && !props.readonly,
215
+ )
216
+ watch(isFocused, (newValue) => {
217
+ if (newValue && propsDefaults.value.selectOnFocus && inputEl.value) {
218
+ inputEl.value.select()
219
+ }
220
+ if (newValue) {
221
+ dropdownEl.value?.show()
222
+ return
223
+ }
224
+ setTimeout(() => {
225
+ if (isDirty.value && suggestions.value) {
226
+ const suggestionsLimit = props.maxSuggestions - 1
227
+ if (
228
+ suggestions.value.size > suggestionsLimit
229
+ && !suggestions.value.has(localModelValue.value)
230
+ ) {
231
+ suggestions.value = new Set(
232
+ [...suggestions.value].slice(
233
+ suggestions.value.size - suggestionsLimit,
234
+ ),
235
+ )
236
+ }
237
+ suggestions.value.add(localModelValue.value)
238
+ }
239
+ }, 300)
240
+ })
256
241
 
257
- // password
258
- const showPassword = ref(false)
259
- const isPassword = computed(() => props.type === INPUT_TYPES.PASSWORD)
260
- const onTogglePassword = () => {
261
- showPassword.value = !showPassword.value
262
- }
242
+ // visibility
243
+ const isVisible = useElementVisibility(inputEl)
244
+ watch(isVisible, (newValue) => {
245
+ if (newValue && props.autofocus && !props.disabled && !props.readonly) {
246
+ focused.value = true
247
+ }
248
+ })
263
249
 
264
- // time, datetime and date
265
- const isDateTime = computed(
266
- () =>
267
- props.type === INPUT_TYPES.TIME ||
268
- props.type === INPUT_TYPES.DATETIME_LOCAL ||
269
- props.type === INPUT_TYPES.DATE ||
270
- props.type === INPUT_TYPES.WEEK ||
271
- props.type === INPUT_TYPES.MONTH,
272
- )
250
+ // password
251
+ const showPassword = ref(false)
252
+ const isPassword = computed(() => props.type === INPUT_TYPES.PASSWORD)
253
+ function onTogglePassword() {
254
+ showPassword.value = !showPassword.value
255
+ }
273
256
 
274
- // number
275
- const isNumber = computed(() => props.type === INPUT_TYPES.NUMBER)
276
- const onStepUp = () => {
277
- if (isClickable.value) {
278
- if (iMask?.value) {
279
- typed.value = typed.value + Number(step?.value ?? 1)
280
- return
281
- }
282
- inputEl.value.stepUp()
283
- localModelValue.value = Number(unref(inputEl).value)
284
- }
285
- }
286
- const onStepDown = () => {
287
- if (isClickable.value) {
288
- if (iMask?.value) {
289
- typed.value = typed.value - Number(step?.value ?? 1)
257
+ // time, datetime and date
258
+ const isDateTime = computed(
259
+ () =>
260
+ props.type === INPUT_TYPES.TIME
261
+ || props.type === INPUT_TYPES.DATETIME_LOCAL
262
+ || props.type === INPUT_TYPES.DATE
263
+ || props.type === INPUT_TYPES.WEEK
264
+ || props.type === INPUT_TYPES.MONTH,
265
+ )
290
266
 
291
- return
292
- }
293
- inputEl.value.stepDown()
294
- localModelValue.value = Number(unref(inputEl).value)
295
- }
296
- }
267
+ // number
268
+ const isNumber = computed(() => props.type === INPUT_TYPES.NUMBER)
269
+ function onStepUp() {
270
+ if (isClickable.value) {
271
+ if (props.iMask) {
272
+ typed.value = typed.value + Number(step?.value ?? 1)
273
+ return
274
+ }
275
+ inputEl.value.stepUp()
276
+ localModelValue.value = Number(unref(inputEl).value)
277
+ }
278
+ }
279
+ function onStepDown() {
280
+ if (isClickable.value) {
281
+ if (props.iMask) {
282
+ typed.value = typed.value - Number(step?.value ?? 1)
297
283
 
298
- // search
299
- const isSearch = computed(() => props.type === INPUT_TYPES.SEARCH)
300
- const onClear = () => {
301
- localModelValue.value = ''
302
- }
284
+ return
285
+ }
286
+ inputEl.value.stepDown()
287
+ localModelValue.value = Number(unref(inputEl).value)
288
+ }
289
+ }
303
290
 
304
- // icons
305
- const { hasIconBefore, hasIconAfter } = useComponentIcon(icon, iconPosition)
306
- const iconAfter = computed(() => {
307
- if (hasIconAfter.value !== undefined) {
308
- return hasIconAfter.value
309
- }
310
- switch (props.type) {
311
- case INPUT_TYPES.COLOR:
312
- return { name: ACTION_ICONS.showColorPicker }
313
- case INPUT_TYPES.DATE:
314
- case INPUT_TYPES.DATETIME_LOCAL:
315
- case INPUT_TYPES.WEEK:
316
- case INPUT_TYPES.MONTH:
317
- return { name: ACTION_ICONS.showDatePicker }
318
- case INPUT_TYPES.TIME:
319
- return { name: ACTION_ICONS.showTimePicker }
320
- }
321
- return undefined
322
- })
323
- const { hasIcon: hasIconRemoveSuggestion } =
324
- useComponentIcon(iconRemoveSuggestion)
291
+ // search
292
+ const isSearch = computed(() => props.type === INPUT_TYPES.SEARCH)
293
+ function onClear() {
294
+ localModelValue.value = ''
295
+ }
325
296
 
326
- // count
327
- const { formatted: countFormatted } = useTextCount(localModelValue, {
328
- mode: count.value,
329
- upperLimit: Number(maxlength?.value),
330
- lowerLimit: Number(minlength?.value),
331
- })
297
+ // icons
298
+ const { hasIconBefore, hasIconAfter } = useComponentIcon(icon, iconPosition)
299
+ const iconAfter = computed(() => {
300
+ if (hasIconAfter.value !== undefined) {
301
+ return hasIconAfter.value
302
+ }
303
+ switch (props.type) {
304
+ case INPUT_TYPES.COLOR:
305
+ return { name: ACTION_ICONS.showColorPicker }
306
+ case INPUT_TYPES.DATE:
307
+ case INPUT_TYPES.DATETIME_LOCAL:
308
+ case INPUT_TYPES.WEEK:
309
+ case INPUT_TYPES.MONTH:
310
+ return { name: ACTION_ICONS.showDatePicker }
311
+ case INPUT_TYPES.TIME:
312
+ return { name: ACTION_ICONS.showTimePicker }
313
+ }
314
+ return undefined
315
+ })
316
+ const { hasIcon: hasIconRemoveSuggestion }
317
+ = useComponentIcon(iconRemoveSuggestion)
332
318
 
333
- // tabindex
334
- const isClickable = computed(() => !props.disabled && !props.readonly)
335
- const hasTabindex = computed(() =>
336
- isClickable.value ? props.tabindex : -1,
337
- )
319
+ // count
320
+ const { formatted: countFormatted } = useTextCount(localModelValue, {
321
+ mode: count.value,
322
+ upperLimit: Number(maxlength?.value),
323
+ lowerLimit: Number(minlength?.value),
324
+ })
338
325
 
339
- // dirty
340
- const isDirty = computed(() => !isEmpty(modelValue))
326
+ // tabindex
327
+ const isClickable = computed(() => !props.disabled && !props.readonly)
328
+ const hasTabindex = computed(() =>
329
+ isClickable.value ? props.tabindex : -1,
330
+ )
341
331
 
342
- // invalid
343
- const isInvalid = computed(() => {
344
- if (invalid.value === true) {
345
- return true
346
- }
347
- if (valid.value === true) {
348
- return false
349
- }
350
- return undefined
351
- })
332
+ // dirty
333
+ const isDirty = computed(() => !isEmpty(modelValue))
352
334
 
353
- // suggestions
354
- const suggestions = usePersistence<Set<string>>(
355
- storageKey,
356
- storageType,
357
- new Set(),
358
- )
359
- const filteredSuggestions = computed(() => {
360
- if (!suggestions.value) {
361
- return []
362
- }
363
- return [...suggestions.value]
364
- .filter(
365
- (suggestion) =>
366
- isEmpty(localModelValue.value) ||
367
- (`${suggestion}`
368
- .toLowerCase()
369
- .includes(`${localModelValue.value}`.toLowerCase()) &&
370
- suggestion !== localModelValue.value),
371
- )
372
- .reverse()
373
- })
374
- const hasSuggestions = computed(
375
- () =>
376
- storageKey?.value &&
377
- suggestions.value &&
378
- suggestions.value.size > 0,
379
- )
380
- const onSuggestionSelect = (suggestion: string) => {
381
- localModelValue.value = suggestion
382
- dropdownEl.value?.hide()
383
- }
384
- const onSuggestionRemove = (suggestion: string) => {
385
- suggestions.value?.delete(suggestion)
386
- }
335
+ // invalid
336
+ const isInvalid = computed(() => {
337
+ if (invalid.value === true) {
338
+ return true
339
+ }
340
+ if (valid.value === true) {
341
+ return false
342
+ }
343
+ return undefined
344
+ })
387
345
 
388
- // styles
389
- const { modifiers } = toRefs(props)
390
- const bemCssClasses = useModifiers(
391
- 'vv-input-text',
392
- modifiers,
393
- computed(() => ({
394
- valid: valid.value,
395
- invalid: invalid.value,
396
- loading: loading.value,
397
- disabled: props.disabled,
398
- readonly: props.readonly,
399
- 'icon-before': !!hasIconBefore.value,
400
- 'icon-after': !!iconAfter.value,
401
- floating: props.floating && !isEmpty(props.label),
402
- dirty: isDirty.value,
403
- focus: isFocused.value,
404
- 'auto-width': props.autoWidth,
405
- })),
406
- )
346
+ // suggestions
347
+ const suggestions = usePersistence<Set<string>>(
348
+ storageKey,
349
+ storageType,
350
+ new Set(),
351
+ )
352
+ const filteredSuggestions = computed(() => {
353
+ if (!suggestions.value) {
354
+ return []
355
+ }
356
+ return [...suggestions.value]
357
+ .filter(
358
+ suggestion =>
359
+ isEmpty(localModelValue.value)
360
+ || (`${suggestion}`
361
+ .toLowerCase()
362
+ .includes(`${localModelValue.value}`.toLowerCase())
363
+ && suggestion !== localModelValue.value),
364
+ )
365
+ .reverse()
366
+ })
367
+ const hasSuggestions = computed(
368
+ () =>
369
+ storageKey?.value
370
+ && suggestions.value
371
+ && suggestions.value.size > 0,
372
+ )
373
+ function onSuggestionSelect(suggestion: string) {
374
+ localModelValue.value = suggestion
375
+ dropdownEl.value?.hide()
376
+ }
377
+ function onSuggestionRemove(suggestion: string) {
378
+ suggestions.value?.delete(suggestion)
379
+ }
407
380
 
408
- // attrs
409
- const hasAttrs = computed(() => {
410
- const type = (() => {
411
- if (isPassword.value && showPassword.value) {
412
- return INPUT_TYPES.TEXT
413
- }
414
- if (isDateTime.value && !isDirty.value && !focused.value) {
415
- return INPUT_TYPES.TEXT
416
- }
417
- if (iMask?.value) {
418
- return INPUT_TYPES.TEXT
419
- }
420
- return props.type
421
- })()
422
- const toReturn: InputHTMLAttributes = {
423
- type,
424
- name: props.name,
425
- tabindex: hasTabindex.value,
426
- disabled: props.disabled,
427
- readonly: props.readonly,
428
- required: props.required,
429
- autocomplete: props.autocomplete,
430
- 'aria-invalid': isInvalid.value,
431
- 'aria-describedby': hasHintLabelOrSlot.value
432
- ? hasHintId.value
433
- : undefined,
434
- 'aria-errormessage': hasInvalidLabelOrSlot.value
435
- ? hasHintId.value
436
- : undefined,
437
- }
438
- if (
439
- type === INPUT_TYPES.DATE ||
440
- type === INPUT_TYPES.MONTH ||
441
- type === INPUT_TYPES.WEEK ||
442
- type === INPUT_TYPES.TIME ||
443
- type === INPUT_TYPES.DATETIME_LOCAL ||
444
- type === INPUT_TYPES.NUMBER
445
- ) {
446
- let max = props.max
447
- if (type === INPUT_TYPES.DATE && !max) {
448
- max = '9999-12-31'
449
- }
450
- toReturn.step = props.step
451
- toReturn.max = max !== undefined ? String(max) : undefined
452
- toReturn.min =
453
- props.min !== undefined ? String(props.min) : undefined
454
- }
455
- if (
456
- type === INPUT_TYPES.TEXT ||
457
- type === INPUT_TYPES.SEARCH ||
458
- type === INPUT_TYPES.URL ||
459
- type === INPUT_TYPES.TEL ||
460
- type === INPUT_TYPES.EMAIL ||
461
- type === INPUT_TYPES.PASSWORD ||
462
- type === INPUT_TYPES.NUMBER
463
- ) {
464
- toReturn.placeholder = inputTextPlaceholder.value
465
- }
466
- if (
467
- type === INPUT_TYPES.TEXT ||
468
- type === INPUT_TYPES.SEARCH ||
469
- type === INPUT_TYPES.URL ||
470
- type === INPUT_TYPES.TEL ||
471
- type === INPUT_TYPES.EMAIL ||
472
- type === INPUT_TYPES.PASSWORD
473
- ) {
474
- toReturn.minlength = props.minlength
475
- toReturn.maxlength = props.maxlength
476
- toReturn.pattern = props.pattern
477
- }
478
- if (type === INPUT_TYPES.EMAIL) {
479
- toReturn.multiple = props.multiple
480
- }
481
- return toReturn
482
- })
381
+ // styles
382
+ const { modifiers } = toRefs(props)
383
+ const bemCssClasses = useModifiers(
384
+ 'vv-input-text',
385
+ modifiers,
386
+ computed(() => ({
387
+ 'valid': valid.value,
388
+ 'invalid': invalid.value,
389
+ 'loading': loading.value,
390
+ 'disabled': props.disabled,
391
+ 'readonly': props.readonly,
392
+ 'icon-before': !!hasIconBefore.value,
393
+ 'icon-after': !!iconAfter.value,
394
+ 'floating': props.floating && !isEmpty(props.label),
395
+ 'dirty': isDirty.value,
396
+ 'focus': isFocused.value,
397
+ 'auto-width': props.autoWidth,
398
+ })),
399
+ )
483
400
 
484
- // slots
485
- const slotProps = computed(() => ({
486
- valid: props.valid,
487
- invalid: props.invalid,
488
- modelValue: props.modelValue,
489
- togglePassword: onTogglePassword,
490
- stepUp: onStepUp,
491
- stepDown: onStepDown,
492
- clear: onClear,
493
- }))
401
+ // attrs
402
+ const hasAttrs = computed(() => {
403
+ const type = (() => {
404
+ if (isPassword.value && showPassword.value) {
405
+ return INPUT_TYPES.TEXT
406
+ }
407
+ if (isDateTime.value && !isDirty.value && !focused.value) {
408
+ return INPUT_TYPES.TEXT
409
+ }
410
+ if (props.iMask) {
411
+ return INPUT_TYPES.TEXT
412
+ }
413
+ return props.type
414
+ })()
415
+ const toReturn: InputHTMLAttributes = {
416
+ type,
417
+ 'name': props.name,
418
+ 'tabindex': hasTabindex.value,
419
+ 'disabled': props.disabled,
420
+ 'readonly': props.readonly,
421
+ 'required': props.required,
422
+ 'autocomplete': props.autocomplete,
423
+ 'aria-invalid': isInvalid.value,
424
+ 'aria-describedby': hasHintLabelOrSlot.value
425
+ ? hasHintId.value
426
+ : undefined,
427
+ 'aria-errormessage': hasInvalidLabelOrSlot.value
428
+ ? hasHintId.value
429
+ : undefined,
430
+ }
431
+ if (
432
+ type === INPUT_TYPES.DATE
433
+ || type === INPUT_TYPES.MONTH
434
+ || type === INPUT_TYPES.WEEK
435
+ || type === INPUT_TYPES.TIME
436
+ || type === INPUT_TYPES.DATETIME_LOCAL
437
+ || type === INPUT_TYPES.NUMBER
438
+ ) {
439
+ let max = props.max
440
+ if (type === INPUT_TYPES.DATE && !max) {
441
+ max = '9999-12-31'
442
+ }
443
+ toReturn.step = props.step
444
+ toReturn.max = max !== undefined ? String(max) : undefined
445
+ toReturn.min
446
+ = props.min !== undefined ? String(props.min) : undefined
447
+ }
448
+ if (
449
+ type === INPUT_TYPES.TEXT
450
+ || type === INPUT_TYPES.SEARCH
451
+ || type === INPUT_TYPES.URL
452
+ || type === INPUT_TYPES.TEL
453
+ || type === INPUT_TYPES.EMAIL
454
+ || type === INPUT_TYPES.PASSWORD
455
+ || type === INPUT_TYPES.NUMBER
456
+ ) {
457
+ toReturn.placeholder = inputTextPlaceholder.value
458
+ }
459
+ if (
460
+ type === INPUT_TYPES.TEXT
461
+ || type === INPUT_TYPES.SEARCH
462
+ || type === INPUT_TYPES.URL
463
+ || type === INPUT_TYPES.TEL
464
+ || type === INPUT_TYPES.EMAIL
465
+ || type === INPUT_TYPES.PASSWORD
466
+ ) {
467
+ toReturn.minlength = props.minlength
468
+ toReturn.maxlength = props.maxlength
469
+ toReturn.pattern = props.pattern
470
+ }
471
+ if (type === INPUT_TYPES.EMAIL) {
472
+ toReturn.multiple = props.multiple
473
+ }
474
+ return toReturn
475
+ })
494
476
 
495
- // components
496
- const {
497
- HintSlot,
498
- hasHintLabelOrSlot,
499
- hasInvalidLabelOrSlot,
500
- hintSlotScope,
501
- } = HintSlotFactory(propsDefaults, slots)
502
- const PasswordInputActions = VvInputTextActionsFactory(
503
- INPUT_TYPES.PASSWORD,
504
- props,
505
- )
506
- const NumberInputActions = VvInputTextActionsFactory(
507
- INPUT_TYPES.NUMBER,
508
- props,
509
- )
510
- const SearchInputActions = VvInputTextActionsFactory(
511
- INPUT_TYPES.SEARCH,
512
- props,
513
- )
477
+ // slots
478
+ const slotProps = computed(() => ({
479
+ valid: props.valid,
480
+ invalid: props.invalid,
481
+ modelValue: props.modelValue,
482
+ togglePassword: onTogglePassword,
483
+ stepUp: onStepUp,
484
+ stepDown: onStepDown,
485
+ clear: onClear,
486
+ }))
514
487
 
515
- // auto-width
516
- const onClickInner = () => {
517
- if (isClickable.value) {
518
- focused.value = true
519
- }
520
- }
521
- const hasStyle = computed(() => {
522
- if (!props.autoWidth) {
523
- return undefined
524
- }
525
- return {
526
- width:
488
+ // components
489
+ const {
490
+ HintSlot,
491
+ hasHintLabelOrSlot,
492
+ hasInvalidLabelOrSlot,
493
+ hintSlotScope,
494
+ } = HintSlotFactory(propsDefaults, slots)
495
+ const PasswordInputActions = VvInputTextActionsFactory(
496
+ INPUT_TYPES.PASSWORD,
497
+ props,
498
+ )
499
+ const NumberInputActions = VvInputTextActionsFactory(
500
+ INPUT_TYPES.NUMBER,
501
+ props,
502
+ )
503
+ const SearchInputActions = VvInputTextActionsFactory(
504
+ INPUT_TYPES.SEARCH,
505
+ props,
506
+ )
507
+
508
+ // auto-width
509
+ function onClickInner() {
510
+ if (isClickable.value) {
511
+ focused.value = true
512
+ }
513
+ }
514
+ const hasStyle = computed(() => {
515
+ if (!props.autoWidth) {
516
+ return undefined
517
+ }
518
+ return {
519
+ width:
527
520
  localModelValue.value !== undefined
528
- ? `${String(localModelValue.value).length + 1}ch`
529
- : undefined,
530
- }
531
- })
521
+ ? `${String(localModelValue.value).length + 1}ch`
522
+ : undefined,
523
+ }
524
+ })
525
+
526
+ // keydown
527
+ function onKeyDown(event: KeyboardEvent) {
528
+ switch (event.code) {
529
+ case 'ArrowUp':
530
+ if (isNumber.value) {
531
+ onStepUp()
532
+ event.preventDefault()
533
+ }
534
+ break
532
535
 
533
- // keydown
534
- const onKeyDown = (event: KeyboardEvent) => {
535
- switch (event.code) {
536
- case 'ArrowUp':
537
- if (isNumber.value) {
538
- onStepUp()
539
- event.preventDefault()
540
- }
541
- break
536
+ case 'ArrowDown':
537
+ if (isNumber.value) {
538
+ onStepDown()
539
+ event.preventDefault()
540
+ }
541
+ break
542
+ }
543
+ emit('keydown', event)
544
+ }
545
+ </script>
542
546
 
543
- case 'ArrowDown':
544
- if (isNumber.value) {
545
- onStepDown()
546
- event.preventDefault()
547
- }
548
- break
549
- }
550
- emit('keydown', event)
551
- }
547
+ <script lang="ts">
548
+ export default {
549
+ name: 'VvInputText',
550
+ }
552
551
  </script>
553
552
 
554
553
  <template>
555
- <div :class="bemCssClasses">
556
- <label v-if="label" :for="hasId" class="vv-input-text__label">
557
- {{ label }}
558
- </label>
559
- <div ref="wrapperEl" class="vv-input-text__wrapper">
560
- <div v-if="$slots.before" class="vv-input-text__input-before">
561
- <!-- @slot Slot before input icon -->
562
- <slot name="before" v-bind="slotProps" />
563
- </div>
564
- <div
565
- ref="innerEl"
566
- class="vv-input-text__inner"
567
- @click.stop="onClickInner"
568
- >
569
- <VvIcon
570
- v-if="hasIconBefore"
571
- v-bind="hasIconBefore"
572
- class="vv-input-text__icon"
573
- />
574
- <input
575
- :id="hasId"
576
- ref="inputEl"
577
- v-bind="hasAttrs"
578
- :style="hasStyle"
579
- @keyup="emit('keyup', $event)"
580
- @keydown="onKeyDown"
581
- @keypress="emit('keypress', $event)"
582
- />
583
- <div
584
- v-if="(unit || $slots.unit) && isDirty"
585
- class="vv-input-text__unit"
586
- >
587
- <!-- @slot Slot to replace unit-->
588
- <slot name v-bind="slotProps">
589
- {{ unit }}
590
- </slot>
591
- </div>
592
- </div>
593
- <!-- @slot Slot to replace right icon -->
594
- <VvIcon
595
- v-if="iconAfter"
596
- v-bind="iconAfter"
597
- class="vv-input-text__icon vv-input-text__icon-after"
598
- />
599
- <PasswordInputActions
600
- v-else-if="isPassword && !hideActions && isClickable"
601
- @toggle-password="onTogglePassword"
602
- />
603
- <NumberInputActions
604
- v-else-if="isNumber && !hideActions && isClickable"
605
- @step-up="onStepUp"
606
- @step-down="onStepDown"
607
- />
608
- <SearchInputActions
609
- v-else-if="isSearch && !hideActions && isClickable"
610
- @clear="onClear"
611
- />
612
- <!-- @slot Slot after input -->
613
- <div v-if="$slots.after" class="vv-input-text__input-after">
614
- <!-- @slot Slot before input icon -->
615
- <slot name="after" v-bind="slotProps" />
616
- </div>
617
- <span v-if="count" class="vv-input-text__limit">
618
- <!-- @slot Slot to replace count -->
619
- <slot name="count" v-bind="slotProps">
620
- {{ countFormatted }}
621
- </slot>
622
- </span>
623
- </div>
624
- <HintSlot :id="hasHintId" class="vv-input-text__hint">
625
- <template v-if="$slots.hint" #hint>
626
- <slot name="hint" v-bind="hintSlotScope" />
627
- </template>
628
- <template v-if="$slots.loading" #loading>
629
- <slot name="loading" v-bind="hintSlotScope" />
630
- </template>
631
- <template v-if="$slots.valid" #valid>
632
- <slot name="valid" v-bind="hintSlotScope" />
633
- </template>
634
- <template v-if="$slots.invalid" #invalid>
635
- <slot name="invalid" v-bind="hintSlotScope" />
636
- </template>
637
- </HintSlot>
638
- <VvDropdown
639
- v-if="hasSuggestions"
640
- ref="dropdownEl"
641
- :reference="wrapperEl"
642
- :autofocus-first="false"
643
- :trigger-width="true"
644
- >
645
- <template #items>
646
- <VvDropdownOption
647
- v-for="value in filteredSuggestions"
648
- :key="value"
649
- @click.stop="onSuggestionSelect(value)"
650
- >
651
- <div class="flex-1">
652
- <slot name="suggestion" v-bind="{ value }">
653
- {{ value }}
654
- </slot>
655
- </div>
656
- <button
657
- v-if="suggestions && hasIconRemoveSuggestion"
658
- type="button"
659
- tabindex="-1"
660
- class="cursor-pointer"
661
- :title="labelRemoveSuggestion"
662
- @click.stop="onSuggestionRemove(value)"
663
- >
664
- <VvIcon v-bind="hasIconRemoveSuggestion" />
665
- </button>
666
- </VvDropdownOption>
667
- </template>
668
- </VvDropdown>
669
- </div>
554
+ <div :class="bemCssClasses">
555
+ <label v-if="label" :for="hasId" class="vv-input-text__label">
556
+ {{ label }}
557
+ </label>
558
+ <div ref="wrapperEl" class="vv-input-text__wrapper">
559
+ <div v-if="$slots.before" class="vv-input-text__input-before">
560
+ <!-- @slot Slot before input icon -->
561
+ <slot name="before" v-bind="slotProps" />
562
+ </div>
563
+ <div
564
+ ref="innerEl"
565
+ class="vv-input-text__inner"
566
+ @click.stop="onClickInner"
567
+ >
568
+ <VvIcon
569
+ v-if="hasIconBefore"
570
+ v-bind="hasIconBefore"
571
+ class="vv-input-text__icon"
572
+ />
573
+ <input
574
+ :id="hasId"
575
+ ref="inputEl"
576
+ v-bind="hasAttrs"
577
+ :style="hasStyle"
578
+ @keyup="emit('keyup', $event)"
579
+ @keydown="onKeyDown"
580
+ @keypress="emit('keypress', $event)"
581
+ >
582
+ <div
583
+ v-if="(unit || $slots.unit) && isDirty"
584
+ class="vv-input-text__unit"
585
+ >
586
+ <!-- @slot Slot to replace unit -->
587
+ <slot name v-bind="slotProps">
588
+ {{ unit }}
589
+ </slot>
590
+ </div>
591
+ </div>
592
+ <!-- @slot Slot to replace right icon -->
593
+ <VvIcon
594
+ v-if="iconAfter"
595
+ v-bind="iconAfter"
596
+ class="vv-input-text__icon vv-input-text__icon-after"
597
+ />
598
+ <PasswordInputActions
599
+ v-else-if="isPassword && !hideActions && isClickable"
600
+ @toggle-password="onTogglePassword"
601
+ />
602
+ <NumberInputActions
603
+ v-else-if="isNumber && !hideActions && isClickable"
604
+ @step-up="onStepUp"
605
+ @step-down="onStepDown"
606
+ />
607
+ <SearchInputActions
608
+ v-else-if="isSearch && !hideActions && isClickable"
609
+ @clear="onClear"
610
+ />
611
+ <!-- @slot Slot after input -->
612
+ <div v-if="$slots.after" class="vv-input-text__input-after">
613
+ <!-- @slot Slot before input icon -->
614
+ <slot name="after" v-bind="slotProps" />
615
+ </div>
616
+ <span v-if="count" class="vv-input-text__limit">
617
+ <!-- @slot Slot to replace count -->
618
+ <slot name="count" v-bind="slotProps">
619
+ {{ countFormatted }}
620
+ </slot>
621
+ </span>
622
+ </div>
623
+ <HintSlot :id="hasHintId" class="vv-input-text__hint">
624
+ <template v-if="$slots.hint" #hint>
625
+ <slot name="hint" v-bind="hintSlotScope" />
626
+ </template>
627
+ <template v-if="$slots.loading" #loading>
628
+ <slot name="loading" v-bind="hintSlotScope" />
629
+ </template>
630
+ <template v-if="$slots.valid" #valid>
631
+ <slot name="valid" v-bind="hintSlotScope" />
632
+ </template>
633
+ <template v-if="$slots.invalid" #invalid>
634
+ <slot name="invalid" v-bind="hintSlotScope" />
635
+ </template>
636
+ </HintSlot>
637
+ <VvDropdown
638
+ v-if="hasSuggestions"
639
+ ref="dropdownEl"
640
+ :reference="wrapperEl"
641
+ :autofocus-first="false"
642
+ :trigger-width="true"
643
+ >
644
+ <template #items>
645
+ <VvDropdownOption
646
+ v-for="value in filteredSuggestions"
647
+ :key="value"
648
+ @click.stop="onSuggestionSelect(value)"
649
+ >
650
+ <div class="flex-1">
651
+ <slot name="suggestion" v-bind="{ value }">
652
+ {{ value }}
653
+ </slot>
654
+ </div>
655
+ <button
656
+ v-if="suggestions && hasIconRemoveSuggestion"
657
+ type="button"
658
+ tabindex="-1"
659
+ class="cursor-pointer"
660
+ :title="labelRemoveSuggestion"
661
+ @click.stop="onSuggestionRemove(value)"
662
+ >
663
+ <VvIcon v-bind="hasIconRemoveSuggestion" />
664
+ </button>
665
+ </VvDropdownOption>
666
+ </template>
667
+ </VvDropdown>
668
+ </div>
670
669
  </template>