vectis-ui 0.1.0 → 0.8.0

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 (475) hide show
  1. package/README.md +40 -6
  2. package/dist/components/VAccordion/VAccordion.css +1 -1
  3. package/dist/components/VAccordion/VAccordion.d.ts +9 -16
  4. package/dist/components/VAccordion/VAccordion.js.map +1 -1
  5. package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js +3 -3
  6. package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/components/VAccordion/VAccordionItem.css +1 -1
  8. package/dist/components/VAccordion/VAccordionItem.d.ts +33 -19
  9. package/dist/components/VAccordion/VAccordionItem.js.map +1 -1
  10. package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js +50 -38
  11. package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  12. package/dist/components/VAccordion/context.d.ts +1 -8
  13. package/dist/components/VAccordion/context.js.map +1 -1
  14. package/dist/components/VAvatar/VAvatar.css +1 -1
  15. package/dist/components/VAvatar/VAvatar.d.ts +44 -29
  16. package/dist/components/VAvatar/VAvatar.js.map +1 -1
  17. package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js +38 -35
  18. package/dist/components/VAvatar/VAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  19. package/dist/components/VAvatar/VAvatarGroup.d.ts +5 -16
  20. package/dist/components/VAvatar/VAvatarGroup.js.map +1 -1
  21. package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +7 -7
  22. package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  23. package/dist/components/VAvatar/context.d.ts +6 -10
  24. package/dist/components/VAvatar/context.js.map +1 -1
  25. package/dist/components/VBadge/VBadge.css +1 -1
  26. package/dist/components/VBadge/VBadge.d.ts +31 -10
  27. package/dist/components/VBadge/VBadge.js.map +1 -1
  28. package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js +39 -24
  29. package/dist/components/VBadge/VBadge.vue_vue_type_script_setup_true_lang.js.map +1 -1
  30. package/dist/components/VBreadcrumb/VBreadcrumb.css +1 -1
  31. package/dist/components/VBreadcrumb/VBreadcrumb.d.ts +4 -17
  32. package/dist/components/VBreadcrumb/VBreadcrumb.js.map +1 -1
  33. package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js +23 -25
  34. package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js.map +1 -1
  35. package/dist/components/VButton/VButton.css +1 -1
  36. package/dist/components/VButton/VButton.d.ts +30 -10
  37. package/dist/components/VButton/VButton.js.map +1 -1
  38. package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js +39 -30
  39. package/dist/components/VButton/VButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  40. package/dist/components/VButton/VButtonGroup.css +1 -1
  41. package/dist/components/VButton/VButtonGroup.d.ts +76 -13
  42. package/dist/components/VButton/VButtonGroup.js.map +1 -1
  43. package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js +74 -8
  44. package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  45. package/dist/components/VButton/context.d.ts +30 -0
  46. package/dist/components/VButton/context.js +6 -0
  47. package/dist/components/VButton/context.js.map +1 -0
  48. package/dist/components/VCalendar/VCalendar.css +1 -1
  49. package/dist/components/VCalendar/VCalendar.d.ts +50 -36
  50. package/dist/components/VCalendar/VCalendar.js.map +1 -1
  51. package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js +99 -85
  52. package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  53. package/dist/components/VCalendar/VCalendarEvent.css +1 -1
  54. package/dist/components/VCalendar/VCalendarEvent.d.ts +5 -11
  55. package/dist/components/VCalendar/VCalendarEvent.js.map +1 -1
  56. package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js +7 -1
  57. package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  58. package/dist/components/VCalendar/VCalendarMonth.css +1 -1
  59. package/dist/components/VCalendar/VCalendarMonth.d.ts +10 -13
  60. package/dist/components/VCalendar/VCalendarMonth.js.map +1 -1
  61. package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js +183 -244
  62. package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js.map +1 -1
  63. package/dist/components/VCalendar/VCalendarTimeGrid.css +1 -1
  64. package/dist/components/VCalendar/VCalendarTimeGrid.d.ts +15 -20
  65. package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -1
  66. package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js +385 -448
  67. package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
  68. package/dist/components/VCalendar/VCalendarYear.css +1 -1
  69. package/dist/components/VCalendar/VCalendarYear.js.map +1 -1
  70. package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js +53 -49
  71. package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -1
  72. package/dist/components/VCalendar/gesture.d.ts +158 -0
  73. package/dist/components/VCalendar/gesture.js +170 -0
  74. package/dist/components/VCalendar/gesture.js.map +1 -0
  75. package/dist/components/VCalendar/keyboard.d.ts +9 -3
  76. package/dist/components/VCalendar/keyboard.js +2 -6
  77. package/dist/components/VCalendar/keyboard.js.map +1 -1
  78. package/dist/components/VCalendar/layout.d.ts +67 -54
  79. package/dist/components/VCalendar/layout.js +77 -69
  80. package/dist/components/VCalendar/layout.js.map +1 -1
  81. package/dist/components/VCalendar/timeGrid.d.ts +55 -0
  82. package/dist/components/VCalendar/timeGrid.js +71 -0
  83. package/dist/components/VCalendar/timeGrid.js.map +1 -0
  84. package/dist/components/VCalendar/types.d.ts +41 -16
  85. package/dist/components/VCarousel/VCarousel.css +1 -1
  86. package/dist/components/VCarousel/VCarousel.d.ts +21 -41
  87. package/dist/components/VCarousel/VCarousel.js.map +1 -1
  88. package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js +157 -129
  89. package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  90. package/dist/components/VCarousel/VCarouselItem.d.ts +0 -17
  91. package/dist/components/VCarousel/VCarouselItem.js.map +1 -1
  92. package/dist/components/VCarousel/VCarouselItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  93. package/dist/components/VCarousel/context.d.ts +0 -12
  94. package/dist/components/VCarousel/context.js.map +1 -1
  95. package/dist/components/VCheckbox/VCheckbox.css +1 -1
  96. package/dist/components/VCheckbox/VCheckbox.d.ts +31 -16
  97. package/dist/components/VCheckbox/VCheckbox.js.map +1 -1
  98. package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js +62 -29
  99. package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  100. package/dist/components/VChip/VChip.css +1 -1
  101. package/dist/components/VChip/VChip.d.ts +36 -26
  102. package/dist/components/VChip/VChip.js.map +1 -1
  103. package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js +57 -48
  104. package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  105. package/dist/components/VCombobox/VCombobox.css +1 -1
  106. package/dist/components/VCombobox/VCombobox.d.ts +127 -31
  107. package/dist/components/VCombobox/VCombobox.js.map +1 -1
  108. package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +336 -247
  109. package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  110. package/dist/components/VCombobox/VComboboxGroup.css +1 -1
  111. package/dist/components/VCombobox/VComboboxGroup.d.ts +0 -9
  112. package/dist/components/VCombobox/VComboboxGroup.js.map +1 -1
  113. package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js +1 -1
  114. package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  115. package/dist/components/VCombobox/VComboboxOption.css +1 -1
  116. package/dist/components/VCombobox/VComboboxOption.d.ts +0 -15
  117. package/dist/components/VCombobox/VComboboxOption.js.map +1 -1
  118. package/dist/components/VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js +4 -4
  119. package/dist/components/VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js.map +1 -1
  120. package/dist/components/VCombobox/VComboboxSeparator.js.map +1 -1
  121. package/dist/components/VCombobox/VComboboxSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
  122. package/dist/components/VCombobox/infiniteScroll.js.map +1 -1
  123. package/dist/components/VDataTable/VDataTable.css +1 -1
  124. package/dist/components/VDataTable/VDataTable.d.ts +50 -28
  125. package/dist/components/VDataTable/VDataTable.js.map +1 -1
  126. package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +183 -194
  127. package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  128. package/dist/components/VDateInput/VDateInput.css +1 -1
  129. package/dist/components/VDateInput/VDateInput.d.ts +90 -42
  130. package/dist/components/VDateInput/VDateInput.js.map +1 -1
  131. package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +159 -191
  132. package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  133. package/dist/components/VDatePicker/VDatePicker.css +1 -1
  134. package/dist/components/VDatePicker/VDatePicker.d.ts +61 -30
  135. package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
  136. package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js +243 -221
  137. package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  138. package/dist/components/VDialog/VDialog.css +1 -1
  139. package/dist/components/VDialog/VDialog.d.ts +45 -33
  140. package/dist/components/VDialog/VDialog.js.map +1 -1
  141. package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js +65 -64
  142. package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  143. package/dist/components/VDialog/VDialogAlert.d.ts +24 -20
  144. package/dist/components/VDialog/VDialogAlert.js.map +1 -1
  145. package/dist/components/VDialog/VDialogAlert.vue_vue_type_script_setup_true_lang.js +36 -25
  146. package/dist/components/VDialog/VDialogAlert.vue_vue_type_script_setup_true_lang.js.map +1 -1
  147. package/dist/components/VFileInput/VFileInput.css +1 -1
  148. package/dist/components/VFileInput/VFileInput.d.ts +78 -26
  149. package/dist/components/VFileInput/VFileInput.js.map +1 -1
  150. package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +144 -132
  151. package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  152. package/dist/components/VFilePicker/VFilePicker.css +1 -1
  153. package/dist/components/VFilePicker/VFilePicker.d.ts +47 -30
  154. package/dist/components/VFilePicker/VFilePicker.js.map +1 -1
  155. package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js +166 -163
  156. package/dist/components/VFilePicker/VFilePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  157. package/dist/components/VFilePicker/fileKind.d.ts +2 -27
  158. package/dist/components/VFilePicker/fileKind.js +9 -8
  159. package/dist/components/VFilePicker/fileKind.js.map +1 -1
  160. package/dist/components/VHotkeys/VHotkeys.css +1 -1
  161. package/dist/components/VHotkeys/VHotkeys.d.ts +8 -30
  162. package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
  163. package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js +4 -4
  164. package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
  165. package/dist/components/VHotkeys/platform.js.map +1 -1
  166. package/dist/components/VIcon/VIcon.css +1 -1
  167. package/dist/components/VIcon/VIcon.d.ts +15 -6
  168. package/dist/components/VIcon/VIcon.js.map +1 -1
  169. package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js +45 -37
  170. package/dist/components/VIcon/VIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
  171. package/dist/components/VIcon/iconProps.js.map +1 -1
  172. package/dist/components/VIcon/icons/index.d.ts +1 -1
  173. package/dist/components/VIcon/icons/index.js.map +1 -1
  174. package/dist/components/VIcon/icons/names.d.ts +1 -1
  175. package/dist/components/VIcon/icons/names.js.map +1 -1
  176. package/dist/components/VIcon/resolver.d.ts +3 -3
  177. package/dist/components/VIcon/resolver.js.map +1 -1
  178. package/dist/components/VIcon/types.d.ts +12 -12
  179. package/dist/components/VIconButton/VIconButton.css +1 -1
  180. package/dist/components/VIconButton/VIconButton.d.ts +28 -11
  181. package/dist/components/VIconButton/VIconButton.js.map +1 -1
  182. package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js +26 -20
  183. package/dist/components/VIconButton/VIconButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  184. package/dist/components/VInput/VInput.css +1 -1
  185. package/dist/components/VInput/VInput.d.ts +26 -7
  186. package/dist/components/VInput/VInput.js.map +1 -1
  187. package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +86 -75
  188. package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  189. package/dist/components/VInput/VInputGroup.css +2 -0
  190. package/dist/components/VInput/VInputGroup.d.ts +47 -0
  191. package/dist/components/VInput/VInputGroup.js +9 -0
  192. package/dist/components/VInput/VInputGroup.js.map +1 -0
  193. package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +80 -0
  194. package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
  195. package/dist/components/VInput/context.d.ts +11 -0
  196. package/dist/components/VInput/context.js +6 -0
  197. package/dist/components/VInput/context.js.map +1 -0
  198. package/dist/components/VInputOTP/VInputOTP.css +1 -1
  199. package/dist/components/VInputOTP/VInputOTP.d.ts +37 -22
  200. package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
  201. package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +98 -61
  202. package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
  203. package/dist/components/VMenu/VMenu.d.ts +23 -30
  204. package/dist/components/VMenu/VMenu.js.map +1 -1
  205. package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js +31 -27
  206. package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  207. package/dist/components/VMenu/VMenuGroup.css +1 -1
  208. package/dist/components/VMenu/VMenuGroup.d.ts +12 -8
  209. package/dist/components/VMenu/VMenuGroup.js.map +1 -1
  210. package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js +11 -11
  211. package/dist/components/VMenu/VMenuGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  212. package/dist/components/VMenu/VMenuItem.css +1 -1
  213. package/dist/components/VMenu/VMenuItem.d.ts +11 -19
  214. package/dist/components/VMenu/VMenuItem.js.map +1 -1
  215. package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js +65 -57
  216. package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  217. package/dist/components/VMenu/VMenuPanel.d.ts +14 -30
  218. package/dist/components/VMenu/VMenuPanel.js.map +1 -1
  219. package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +43 -44
  220. package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  221. package/dist/components/VMenu/context.d.ts +2 -6
  222. package/dist/components/VMenu/context.js.map +1 -1
  223. package/dist/components/VPagination/VPagination.css +1 -1
  224. package/dist/components/VPagination/VPagination.d.ts +60 -22
  225. package/dist/components/VPagination/VPagination.js.map +1 -1
  226. package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +113 -161
  227. package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  228. package/dist/components/VPopover/VPopover.css +1 -1
  229. package/dist/components/VPopover/VPopover.d.ts +26 -7
  230. package/dist/components/VPopover/VPopover.js.map +1 -1
  231. package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js +43 -37
  232. package/dist/components/VPopover/VPopover.vue_vue_type_script_setup_true_lang.js.map +1 -1
  233. package/dist/components/VProgressCircular/VProgressCircular.css +1 -1
  234. package/dist/components/VProgressCircular/VProgressCircular.d.ts +15 -4
  235. package/dist/components/VProgressCircular/VProgressCircular.js.map +1 -1
  236. package/dist/components/VProgressCircular/VProgressCircular.vue_vue_type_script_setup_true_lang.js +32 -30
  237. package/dist/components/VProgressCircular/VProgressCircular.vue_vue_type_script_setup_true_lang.js.map +1 -1
  238. package/dist/components/VProgressLinear/VProgressLinear.css +1 -1
  239. package/dist/components/VProgressLinear/VProgressLinear.d.ts +23 -8
  240. package/dist/components/VProgressLinear/VProgressLinear.js.map +1 -1
  241. package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js +34 -32
  242. package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js.map +1 -1
  243. package/dist/components/VRadio/VRadio.css +1 -1
  244. package/dist/components/VRadio/VRadio.d.ts +36 -18
  245. package/dist/components/VRadio/VRadio.js.map +1 -1
  246. package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js +55 -26
  247. package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
  248. package/dist/components/VSeparator/VSeparator.d.ts +4 -2
  249. package/dist/components/VSeparator/VSeparator.js.map +1 -1
  250. package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
  251. package/dist/components/VSideNavigation/VSideNavigation.css +1 -1
  252. package/dist/components/VSideNavigation/VSideNavigation.d.ts +5 -19
  253. package/dist/components/VSideNavigation/VSideNavigation.js.map +1 -1
  254. package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +5 -5
  255. package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js.map +1 -1
  256. package/dist/components/VSideNavigation/VSideNavigationGroup.css +1 -1
  257. package/dist/components/VSideNavigation/VSideNavigationGroup.d.ts +9 -17
  258. package/dist/components/VSideNavigation/VSideNavigationGroup.js.map +1 -1
  259. package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js +2 -2
  260. package/dist/components/VSideNavigation/VSideNavigationGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  261. package/dist/components/VSideNavigation/VSideNavigationItem.css +1 -1
  262. package/dist/components/VSideNavigation/VSideNavigationItem.d.ts +22 -30
  263. package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -1
  264. package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +77 -87
  265. package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  266. package/dist/components/VSideNavigation/context.d.ts +0 -14
  267. package/dist/components/VSideNavigation/context.js.map +1 -1
  268. package/dist/components/VSkeletonLoader/VSkeletonLoader.css +1 -1
  269. package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +9 -9
  270. package/dist/components/VSkeletonLoader/VSkeletonLoader.js.map +1 -1
  271. package/dist/components/VSkeletonLoader/VSkeletonLoader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  272. package/dist/components/VSlider/VSlider.css +1 -1
  273. package/dist/components/VSlider/VSlider.d.ts +52 -27
  274. package/dist/components/VSlider/VSlider.js.map +1 -1
  275. package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js +202 -118
  276. package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
  277. package/dist/components/VSnackbar/VSnackbar.css +1 -1
  278. package/dist/components/VSnackbar/VSnackbar.d.ts +0 -23
  279. package/dist/components/VSnackbar/VSnackbar.js.map +1 -1
  280. package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js +38 -38
  281. package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  282. package/dist/components/VSnackbar/state.d.ts +0 -27
  283. package/dist/components/VSnackbar/state.js.map +1 -1
  284. package/dist/components/VSpinner/VSpinner.css +1 -1
  285. package/dist/components/VSpinner/VSpinner.d.ts +6 -6
  286. package/dist/components/VSpinner/VSpinner.js.map +1 -1
  287. package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js +10 -9
  288. package/dist/components/VSpinner/VSpinner.vue_vue_type_script_setup_true_lang.js.map +1 -1
  289. package/dist/components/VSwitch/VSwitch.css +1 -1
  290. package/dist/components/VSwitch/VSwitch.d.ts +35 -13
  291. package/dist/components/VSwitch/VSwitch.js.map +1 -1
  292. package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js +62 -21
  293. package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  294. package/dist/components/VTabs/VTab.css +1 -1
  295. package/dist/components/VTabs/VTab.d.ts +12 -12
  296. package/dist/components/VTabs/VTab.js.map +1 -1
  297. package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js +36 -24
  298. package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
  299. package/dist/components/VTabs/VTabPanel.d.ts +2 -10
  300. package/dist/components/VTabs/VTabPanel.js.map +1 -1
  301. package/dist/components/VTabs/VTabPanel.vue_vue_type_script_setup_true_lang.js +4 -4
  302. package/dist/components/VTabs/VTabPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  303. package/dist/components/VTabs/VTabs.css +1 -1
  304. package/dist/components/VTabs/VTabs.d.ts +27 -18
  305. package/dist/components/VTabs/VTabs.js.map +1 -1
  306. package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js +92 -81
  307. package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  308. package/dist/components/VTabs/context.d.ts +9 -19
  309. package/dist/components/VTabs/context.js +1 -1
  310. package/dist/components/VTabs/context.js.map +1 -1
  311. package/dist/components/VTextarea/VTextarea.css +1 -1
  312. package/dist/components/VTextarea/VTextarea.d.ts +34 -6
  313. package/dist/components/VTextarea/VTextarea.js.map +1 -1
  314. package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js +91 -74
  315. package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  316. package/dist/components/VTimeInput/VTimeInput.css +1 -1
  317. package/dist/components/VTimeInput/VTimeInput.d.ts +123 -33
  318. package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
  319. package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +294 -291
  320. package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  321. package/dist/components/VTimeInput/search.d.ts +24 -0
  322. package/dist/components/VTimeInput/search.js +22 -0
  323. package/dist/components/VTimeInput/search.js.map +1 -0
  324. package/dist/components/VTimePicker/VTimePicker.css +1 -1
  325. package/dist/components/VTimePicker/VTimePicker.d.ts +51 -30
  326. package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
  327. package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js +216 -151
  328. package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  329. package/dist/components/VTimePicker/limits.d.ts +88 -0
  330. package/dist/components/VTimePicker/limits.js +70 -0
  331. package/dist/components/VTimePicker/limits.js.map +1 -0
  332. package/dist/components/VToast/VToast.css +1 -1
  333. package/dist/components/VToast/VToast.d.ts +0 -10
  334. package/dist/components/VToast/VToast.js.map +1 -1
  335. package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js +10 -10
  336. package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js.map +1 -1
  337. package/dist/components/VToast/VToaster.css +1 -1
  338. package/dist/components/VToast/VToaster.d.ts +0 -17
  339. package/dist/components/VToast/VToaster.js.map +1 -1
  340. package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js +29 -28
  341. package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js.map +1 -1
  342. package/dist/components/VToast/state.d.ts +10 -19
  343. package/dist/components/VToast/state.js +1 -1
  344. package/dist/components/VToast/state.js.map +1 -1
  345. package/dist/components/VToggle/VToggle.css +1 -1
  346. package/dist/components/VToggle/VToggle.d.ts +56 -11
  347. package/dist/components/VToggle/VToggle.js.map +1 -1
  348. package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +80 -46
  349. package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
  350. package/dist/components/VToggle/VToggleItem.d.ts +16 -2
  351. package/dist/components/VToggle/VToggleItem.js +0 -2
  352. package/dist/components/VToggle/VToggleItem.js.map +1 -1
  353. package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js +23 -15
  354. package/dist/components/VToggle/VToggleItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  355. package/dist/components/VToggle/context.d.ts +4 -24
  356. package/dist/components/VToggle/context.js.map +1 -1
  357. package/dist/components/VTooltip/VTooltip.css +1 -1
  358. package/dist/components/VTooltip/VTooltip.d.ts +9 -33
  359. package/dist/components/VTooltip/VTooltip.js.map +1 -1
  360. package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js +28 -24
  361. package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  362. package/dist/components/VTypography/VTypography.js.map +1 -1
  363. package/dist/components/VTypography/VTypography.vue_vue_type_script_setup_true_lang.js.map +1 -1
  364. package/dist/composables/useAriaLabel.d.ts +0 -17
  365. package/dist/composables/useAriaLabel.js.map +1 -1
  366. package/dist/composables/useClearable.d.ts +42 -0
  367. package/dist/composables/useClearable.js +19 -0
  368. package/dist/composables/useClearable.js.map +1 -0
  369. package/dist/composables/useControlShape.d.ts +22 -0
  370. package/dist/composables/useControlShape.js +13 -0
  371. package/dist/composables/useControlShape.js.map +1 -0
  372. package/dist/composables/useDetailsOpen.d.ts +22 -0
  373. package/dist/composables/useDetailsOpen.js +21 -0
  374. package/dist/composables/useDetailsOpen.js.map +1 -0
  375. package/dist/composables/useFieldIds.d.ts +0 -15
  376. package/dist/composables/useFieldIds.js +8 -7
  377. package/dist/composables/useFieldIds.js.map +1 -1
  378. package/dist/composables/useFieldPanel.d.ts +21 -18
  379. package/dist/composables/useFieldPanel.js +43 -23
  380. package/dist/composables/useFieldPanel.js.map +1 -1
  381. package/dist/composables/useFileDrop.d.ts +0 -22
  382. package/dist/composables/useFileDrop.js.map +1 -1
  383. package/dist/composables/useFileField.d.ts +45 -17
  384. package/dist/composables/useFileField.js +40 -20
  385. package/dist/composables/useFileField.js.map +1 -1
  386. package/dist/composables/useFocusoutDismiss.d.ts +0 -15
  387. package/dist/composables/useFocusoutDismiss.js.map +1 -1
  388. package/dist/composables/useIconClickHandlers.d.ts +29 -14
  389. package/dist/composables/useIconClickHandlers.js +15 -5
  390. package/dist/composables/useIconClickHandlers.js.map +1 -1
  391. package/dist/composables/useInertLink.d.ts +20 -0
  392. package/dist/composables/useInertLink.js +23 -0
  393. package/dist/composables/useInertLink.js.map +1 -0
  394. package/dist/composables/useMaskedField.d.ts +33 -10
  395. package/dist/composables/useMaskedField.js +45 -1
  396. package/dist/composables/useMaskedField.js.map +1 -1
  397. package/dist/composables/usePopover.d.ts +15 -1
  398. package/dist/composables/usePopover.js +23 -8
  399. package/dist/composables/usePopover.js.map +1 -1
  400. package/dist/composables/useProgressValue.d.ts +5 -8
  401. package/dist/composables/useProgressValue.js +6 -3
  402. package/dist/composables/useProgressValue.js.map +1 -1
  403. package/dist/composables/useRootAttrs.d.ts +12 -19
  404. package/dist/composables/useRootAttrs.js.map +1 -1
  405. package/dist/composables/useTimer.d.ts +8 -10
  406. package/dist/composables/useTimer.js.map +1 -1
  407. package/dist/i18n/en.d.ts +2 -10
  408. package/dist/i18n/en.js +18 -19
  409. package/dist/i18n/en.js.map +1 -1
  410. package/dist/i18n/fr.d.ts +2 -18
  411. package/dist/i18n/fr.js +18 -19
  412. package/dist/i18n/fr.js.map +1 -1
  413. package/dist/i18n/state.d.ts +44 -47
  414. package/dist/i18n/state.js +20 -17
  415. package/dist/i18n/state.js.map +1 -1
  416. package/dist/i18n/types.d.ts +53 -44
  417. package/dist/icons.d.ts +3 -3
  418. package/dist/index.d.ts +43 -17
  419. package/dist/index.js +45 -44
  420. package/dist/styles.css +1 -1
  421. package/dist/tokens/css.js.map +1 -1
  422. package/dist/tokens/index.d.ts +5 -1
  423. package/dist/tokens/primitives.js.map +1 -1
  424. package/dist/tokens/semantic.d.ts +5 -1
  425. package/dist/tokens/semantic.js +6 -2
  426. package/dist/tokens/semantic.js.map +1 -1
  427. package/dist/tokens/themes/dark.js.map +1 -1
  428. package/dist/tokens/types.d.ts +7 -15
  429. package/dist/tokens/types.js.map +1 -1
  430. package/dist/tokens.json +25 -5
  431. package/dist/types.d.ts +24 -0
  432. package/dist/utils/array.d.ts +3 -6
  433. package/dist/utils/array.js.map +1 -1
  434. package/dist/utils/arrowNav.d.ts +17 -17
  435. package/dist/utils/arrowNav.js +5 -3
  436. package/dist/utils/arrowNav.js.map +1 -1
  437. package/dist/utils/chip.d.ts +11 -15
  438. package/dist/utils/chip.js.map +1 -1
  439. package/dist/utils/css.d.ts +22 -11
  440. package/dist/utils/css.js +5 -2
  441. package/dist/utils/css.js.map +1 -1
  442. package/dist/utils/date.d.ts +42 -19
  443. package/dist/utils/date.js +97 -98
  444. package/dist/utils/date.js.map +1 -1
  445. package/dist/utils/direction.d.ts +6 -12
  446. package/dist/utils/direction.js.map +1 -1
  447. package/dist/utils/env.d.ts +5 -6
  448. package/dist/utils/file.d.ts +46 -58
  449. package/dist/utils/file.js +43 -36
  450. package/dist/utils/file.js.map +1 -1
  451. package/dist/utils/focus.d.ts +8 -17
  452. package/dist/utils/focus.js.map +1 -1
  453. package/dist/utils/hostWarns.d.ts +12 -0
  454. package/dist/utils/hostWarns.js +6 -0
  455. package/dist/utils/hostWarns.js.map +1 -0
  456. package/dist/utils/ids.d.ts +10 -0
  457. package/dist/utils/ids.js +8 -0
  458. package/dist/utils/ids.js.map +1 -0
  459. package/dist/utils/matcher.d.ts +5 -9
  460. package/dist/utils/matcher.js.map +1 -1
  461. package/dist/utils/memo.d.ts +12 -0
  462. package/dist/utils/memo.js +9 -0
  463. package/dist/utils/memo.js.map +1 -0
  464. package/dist/utils/number.d.ts +3 -4
  465. package/dist/utils/number.js.map +1 -1
  466. package/dist/utils/text.d.ts +20 -9
  467. package/dist/utils/text.js +17 -3
  468. package/dist/utils/text.js.map +1 -1
  469. package/dist/utils/time.d.ts +53 -61
  470. package/dist/utils/time.js +49 -45
  471. package/dist/utils/time.js.map +1 -1
  472. package/dist/utils/vnode.d.ts +8 -15
  473. package/dist/utils/vnode.js.map +1 -1
  474. package/package.json +6 -6
  475. package/dist/components/VToggle/VToggleItem.css +0 -2
@@ -1,45 +1,60 @@
1
1
  import { IconSource } from '../VIcon/types.js';
2
2
  export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
3
- /**
4
- * A round avatar standing for a person or an entity. It shows the best of what it
5
- * was given, in that order: the picture, failing that an icon, failing that the
6
- * initials taken from the name, and failing that whatever the default slot holds —
7
- * the escape hatch VAvatarGroup uses to render its "+X" overflow badge.
8
- *
9
- * Four things here genuinely need JavaScript. A picture that fails to download
10
- * reports it as a DOM event and nothing else, so the script listens for it and
11
- * hands over to the initials rather than leaving an empty circle. The initials and
12
- * the automatic colour are both computed from the name, which is arithmetic no
13
- * stylesheet can do. A disabled link has no native equivalent of a disabled
14
- * button, so it is turned inert by hand (its `href` is removed, `aria-disabled`
15
- * announces the state and the click handler is dropped). Finally the attributes
16
- * the consumer passes are split so that `style` never reaches the element
17
- * directly: the component has to merge its own `--avatar-hue`/`--custom-color`
18
- * into it first, and a plain fallthrough would overwrite them.
19
- */
20
3
  interface AvatarProps {
21
- /** Image URL (priority 1). */
4
+ /**
5
+ * The picture to show. It is what the avatar prefers above everything else, and an image
6
+ * that fails to load hands over to the icon or the initials rather than leaving a gap.
7
+ */
22
8
  src?: string;
23
- /** Icon shown in the absence of an image (priority 2): a name, or an explicit render. */
9
+ /**
10
+ * The icon to show when there is no picture. It comes before the initials, so an avatar
11
+ * given both an icon and a name shows the icon.
12
+ */
24
13
  icon?: IconSource;
25
- /** Full name — the default alt, the source of the initials and the seed of the auto hue. */
14
+ /**
15
+ * The person's full name. It does three things at once: it names the avatar for assistive
16
+ * technology, its initials are what shows when there is no picture and no icon, and it is
17
+ * the seed the automatic colour is derived from — so the same person keeps the same colour
18
+ * everywhere.
19
+ */
26
20
  name?: string;
27
- /** Explicit alt/label (wins over `name`). */
21
+ /**
22
+ * The accessible name, when it should not simply be `name` — an avatar standing for a team
23
+ * rather than a person, say. It wins over `name`.
24
+ */
28
25
  alt?: string;
29
26
  /**
30
- * Custom colour (hex, CSS name or oklch()) which REPLACES the auto hue: set inline
31
- * as `--custom-color`. Otherwise, in the absence of an image, a deterministic OKLCH
32
- * hue is derived from `name`.
27
+ * A colour of your own, as a hex value, a CSS colour name or an `oklch()`. It REPLACES the
28
+ * hue otherwise derived from `name`, and the text on it is always white, so a light colour
29
+ * is the consumer's own risk.
33
30
  */
34
31
  color?: string;
35
- /** Default `md`. `undefined` = inherited from an enclosing VAvatarGroup. */
32
+ /**
33
+ * The diameter of the disc, from the size scale shared by every control. Leaving it out
34
+ * inside a VAvatarGroup takes the group's size, which is the point of not defaulting it
35
+ * here; on its own it is `md`.
36
+ */
36
37
  size?: AvatarSize;
37
- /** Height reduced by 4px (like the other controls). */
38
+ /**
39
+ * Takes 4px off the diameter, as it does on every other control. Unlike `size` it is
40
+ * cumulative: inside a compact VAvatarGroup the avatar is compact whatever this says, and
41
+ * setting it on one avatar of a regular group makes that one compact alone.
42
+ */
38
43
  compact?: boolean;
39
- /** Rendered as `<a>`. disabled → an inert link (href removed + aria-disabled). */
44
+ /**
45
+ * Turns the avatar into an `<a>` pointing at this address. A disabled link becomes inert:
46
+ * the address is dropped, so it can be neither focused nor followed.
47
+ */
40
48
  href?: string;
41
- /** Rendered as `<button type="button">` (a VTooltip's #trigger slot plugs in through fallthrough). */
49
+ /**
50
+ * Turns the avatar into a `<button>`. It is ignored as soon as `href` makes it a link.
51
+ * A VTooltip wrapping the avatar reaches this button through fallthrough.
52
+ */
42
53
  clickable?: boolean;
54
+ /**
55
+ * Makes an interactive avatar unusable: it stops responding, leaves the tab order and greys
56
+ * out. It says nothing on a plain avatar, which was never interactive to begin with.
57
+ */
43
58
  disabled?: boolean;
44
59
  }
45
60
  type __VLS_Slots = {
@@ -48,8 +63,8 @@ type __VLS_Slots = {
48
63
  };
49
64
  declare const __VLS_base: import('vue').DefineComponent<AvatarProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<AvatarProps> & Readonly<{}>, {
50
65
  alt: string;
51
- size: AvatarSize;
52
66
  name: string;
67
+ size: AvatarSize;
53
68
  src: string;
54
69
  compact: boolean;
55
70
  href: string;
@@ -1 +1 @@
1
- {"version":3,"file":"VAvatar.js","names":[],"sources":["../../../src/components/VAvatar/VAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, inject, ref, useAttrs, watch } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\nimport { avatarGroupKey } from './context'\n\nexport type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/**\n * A round avatar standing for a person or an entity. It shows the best of what it\n * was given, in that order: the picture, failing that an icon, failing that the\n * initials taken from the name, and failing that whatever the default slot holds —\n * the escape hatch VAvatarGroup uses to render its \"+X\" overflow badge.\n *\n * Four things here genuinely need JavaScript. A picture that fails to download\n * reports it as a DOM event and nothing else, so the script listens for it and\n * hands over to the initials rather than leaving an empty circle. The initials and\n * the automatic colour are both computed from the name, which is arithmetic no\n * stylesheet can do. A disabled link has no native equivalent of a disabled\n * button, so it is turned inert by hand (its `href` is removed, `aria-disabled`\n * announces the state and the click handler is dropped). Finally the attributes\n * the consumer passes are split so that `style` never reaches the element\n * directly: the component has to merge its own `--avatar-hue`/`--custom-color`\n * into it first, and a plain fallthrough would overwrite them.\n */\ninterface AvatarProps {\n /** Image URL (priority 1). */\n src?: string\n /** Icon shown in the absence of an image (priority 2): a name, or an explicit render. */\n icon?: IconSource\n /** Full name — the default alt, the source of the initials and the seed of the auto hue. */\n name?: string\n /** Explicit alt/label (wins over `name`). */\n alt?: string\n /**\n * Custom colour (hex, CSS name or oklch()) which REPLACES the auto hue: set inline\n * as `--custom-color`. Otherwise, in the absence of an image, a deterministic OKLCH\n * hue is derived from `name`.\n */\n color?: string\n /** Default `md`. `undefined` = inherited from an enclosing VAvatarGroup. */\n size?: AvatarSize\n /** Height reduced by 4px (like the other controls). */\n compact?: boolean\n /** Rendered as `<a>`. disabled → an inert link (href removed + aria-disabled). */\n href?: string\n /** Rendered as `<button type=\"button\">` (a VTooltip's #trigger slot plugs in through fallthrough). */\n clickable?: boolean\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AvatarProps>(), {\n src: undefined,\n icon: undefined,\n name: undefined,\n alt: undefined,\n color: undefined,\n size: undefined,\n compact: false,\n href: undefined,\n clickable: false,\n disabled: false,\n})\n\ndefineSlots<{\n /** Fallback content (replaces the initials), e.g. VAvatarGroup's \"+X\". */\n default?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\nconst group = inject(avatarGroupKey, null)\n\n// Size/compact: the explicit prop, else the group's, else the default.\nconst resolvedSize = computed<AvatarSize>(() => props.size ?? group?.size ?? 'md')\nconst resolvedCompact = computed(() => props.compact || (group?.compact ?? false))\n\n/* Interactivity priority: href > clickable > static. */\nconst isLink = computed(() => props.href !== undefined)\nconst isInteractive = computed(() => isLink.value || props.clickable)\nconst tag = computed(() => (isLink.value ? 'a' : props.clickable ? 'button' : 'span'))\nconst isInertLink = computed(() => isLink.value && props.disabled)\n\n// @fallback — the image failed to load: the initials take over, so an avatar is\n// never an empty box.\nconst failed = ref(false)\nwatch(\n () => props.src,\n () => {\n failed.value = false\n },\n)\nconst showImage = computed(() => Boolean(props.src) && !failed.value)\n\nconst accessibleName = computed(() => props.alt ?? props.name)\n\nconst initials = computed(() => {\n if (!props.name) return ''\n return props.name\n .split(/\\s+/)\n .slice(0, 2)\n .map((part) => part[0]?.toLocaleUpperCase() ?? '')\n .join('')\n})\n\n/*\n * Auto hue: a pure JS hash of the name → an OKLCH hue (0–359). Only the hue is\n * inline (a unitless scalar); the CSS composes background/text with L/C fixed per\n * theme (light/dark adaptation without depending on contrast-color). A colour\n * computed outside the tokens, a deliberate exception. SSR-safe: no browser API.\n */\nconst hue = computed(() => {\n if (!props.name) return null\n let hash = 0\n for (let i = 0; i < props.name.length; i++) {\n hash = (hash * 31 + props.name.charCodeAt(i)) | 0\n }\n return Math.abs(hash) % 360\n})\nconst isAuto = computed(() => props.color === undefined && hue.value !== null)\n\nconst rootStyle = computed<StyleValue>(() => [\n props.color !== undefined\n ? { '--custom-color': props.color }\n : isAuto.value\n ? { '--avatar-hue': String(hue.value) }\n : undefined,\n attrs.style as StyleValue,\n])\n\n// Fallthrough without `style` (handled by rootStyle); onClick removed on an inert link.\nconst passedAttrs = computed(() => {\n const rest = { ...(attrs as Record<string, unknown>) }\n delete rest.style\n if (isInertLink.value) delete rest.onClick\n return rest\n})\n</script>\n\n<template>\n <component\n :is=\"tag\"\n v-bind=\"passedAttrs\"\n class=\"v-avatar v-control\"\n :style=\"rootStyle\"\n :data-size=\"resolvedSize\"\n :data-compact=\"resolvedCompact ? '' : undefined\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-auto=\"isAuto ? '' : undefined\"\n :href=\"isLink && !disabled ? href : undefined\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :aria-disabled=\"isInertLink ? 'true' : undefined\"\n :role=\"!isInteractive && !showImage && accessibleName ? 'img' : undefined\"\n :aria-label=\"!showImage ? accessibleName : undefined\"\n >\n <img\n v-if=\"showImage\"\n class=\"v-avatar-image\"\n :src=\"src\"\n :alt=\"alt ?? name ?? ''\"\n @error=\"failed = true\"\n />\n <VIcon v-else-if=\"icon\" v-bind=\"iconProps(icon)\" class=\"v-avatar-icon\" />\n <slot v-else>\n <span class=\"v-avatar-initials\" aria-hidden=\"true\">{{ initials }}</span>\n </slot>\n </component>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar {\n --avatar-bg: var(--vectis-color-surface-muted);\n --avatar-text: var(--vectis-color-text-muted);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--control-height);\n block-size: var(--control-height);\n flex: none;\n overflow: hidden;\n padding: 0;\n border: none;\n background: var(--avatar-bg);\n color: var(--avatar-text);\n border-radius: var(--vectis-radius-full);\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n font-weight: var(--vectis-font-weight-semibold);\n line-height: var(--vectis-text-control-leading);\n text-decoration: none;\n user-select: none;\n box-shadow: 0 0 0 var(--vectis-control-size-avatar-ring) var(--avatar-ring-color, transparent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n box-shadow var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /* Auto hue */\n .v-avatar[data-auto] {\n --avatar-bg: oklch(0.9 0.06 var(--avatar-hue));\n --avatar-text: oklch(0.42 0.13 var(--avatar-hue));\n }\n\n /* Custom colour (--custom-color inline): wins, with a fixed white text (contrast\n is the consumer's responsibility). */\n .v-avatar[data-custom] {\n --avatar-bg: var(--custom-color);\n --avatar-text: var(--vectis-color-text-on-accent);\n }\n\n [data-theme='dark'] .v-avatar[data-auto] {\n --avatar-bg: oklch(0.42 0.09 var(--avatar-hue));\n --avatar-text: oklch(0.92 0.05 var(--avatar-hue));\n }\n\n .v-avatar-image {\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n }\n\n /* The icon occupies ~55% of the disc (a unitless ratio, like the font-size). */\n .v-avatar-icon {\n --vectis-icon-size: calc(var(--control-height) * 0.55);\n }\n\n :is(a, button).v-avatar {\n cursor: pointer;\n }\n\n :is(a, button).v-avatar:hover:not([aria-disabled='true'], :disabled) {\n background: color-mix(in oklab, var(--avatar-bg), var(--vectis-color-text) 10%);\n }\n\n :is(a, button).v-avatar:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-avatar:is(:disabled, [aria-disabled='true']) {\n cursor: not-allowed;\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-avatar {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"VAvatar.js","names":[],"sources":["../../../src/components/VAvatar/VAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A round avatar standing for a person or an entity. It shows the best of what it\n * was given, in that order: the picture, failing that an icon, failing that the\n * initials taken from the name, and failing that whatever the default slot holds —\n * the escape hatch VAvatarGroup uses to render its \"+X\" overflow badge.\n *\n * Four things here genuinely need JavaScript. A picture that fails to download\n * reports it as a DOM event and nothing else, so the script listens for it and\n * hands over to the initials rather than leaving an empty circle. The initials and\n * the automatic colour are both computed from the name, which is arithmetic no\n * stylesheet can do. A disabled link has no native equivalent of a disabled\n * button, so it is turned inert by hand (composables/useInertLink). Finally the attributes\n * the consumer passes are split so that `style` never reaches the element\n * directly: the component has to merge its own `--avatar-hue`/`--custom-color`\n * into it first, and a plain fallthrough would overwrite them.\n */\n\nimport { computed, inject, ref, useAttrs, watch } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useInertLink } from '../../composables/useInertLink'\nimport { customColorStyle } from '../../utils/css'\n\nexport type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\ninterface AvatarProps {\n /**\n * The picture to show. It is what the avatar prefers above everything else, and an image\n * that fails to load hands over to the icon or the initials rather than leaving a gap.\n */\n src?: string\n /**\n * The icon to show when there is no picture. It comes before the initials, so an avatar\n * given both an icon and a name shows the icon.\n */\n icon?: IconSource\n /**\n * The person's full name. It does three things at once: it names the avatar for assistive\n * technology, its initials are what shows when there is no picture and no icon, and it is\n * the seed the automatic colour is derived from — so the same person keeps the same colour\n * everywhere.\n */\n name?: string\n /**\n * The accessible name, when it should not simply be `name` — an avatar standing for a team\n * rather than a person, say. It wins over `name`.\n */\n alt?: string\n /**\n * A colour of your own, as a hex value, a CSS colour name or an `oklch()`. It REPLACES the\n * hue otherwise derived from `name`, and the text on it is always white, so a light colour\n * is the consumer's own risk.\n */\n color?: string\n /**\n * The diameter of the disc, from the size scale shared by every control. Leaving it out\n * inside a VAvatarGroup takes the group's size, which is the point of not defaulting it\n * here; on its own it is `md`.\n */\n size?: AvatarSize\n /**\n * Takes 4px off the diameter, as it does on every other control. Unlike `size` it is\n * cumulative: inside a compact VAvatarGroup the avatar is compact whatever this says, and\n * setting it on one avatar of a regular group makes that one compact alone.\n */\n compact?: boolean\n /**\n * Turns the avatar into an `<a>` pointing at this address. A disabled link becomes inert:\n * the address is dropped, so it can be neither focused nor followed.\n */\n href?: string\n /**\n * Turns the avatar into a `<button>`. It is ignored as soon as `href` makes it a link.\n * A VTooltip wrapping the avatar reaches this button through fallthrough.\n */\n clickable?: boolean\n /**\n * Makes an interactive avatar unusable: it stops responding, leaves the tab order and greys\n * out. It says nothing on a plain avatar, which was never interactive to begin with.\n */\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AvatarProps>(), {\n src: undefined,\n icon: undefined,\n name: undefined,\n alt: undefined,\n color: undefined,\n size: undefined,\n compact: false,\n href: undefined,\n clickable: false,\n disabled: false,\n})\n\ndefineSlots<{\n /** Fallback content (replaces the initials), e.g. VAvatarGroup's \"+X\". */\n default?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\nconst group = inject(avatarGroupKey, null)\n\n// The size is the avatar's own answer first, then the group's; the density is cumulative,\n// the two terms written out in context.ts.\nconst resolvedSize = computed<AvatarSize>(() => props.size ?? group?.size ?? AVATAR_DEFAULT_SIZE)\nconst resolvedCompact = computed(() => props.compact || Boolean(group?.compact))\n\n// Fallthrough without `style`, which rootStyle merges with the component's own; the click\n// handler is also dropped on an inert link.\nconst {\n isLink,\n isInertLink,\n linkHref,\n attrs: passedAttrs,\n} = useInertLink({\n href: () => props.href,\n inert: () => props.disabled,\n attrs: () => Object.fromEntries(Object.entries(attrs).filter(([key]) => key !== 'style')),\n})\n\n/* Interactivity priority: href > clickable > static. */\nconst isInteractive = computed(() => isLink.value || props.clickable)\nconst tag = computed(() => (isLink.value ? 'a' : props.clickable ? 'button' : 'span'))\n\n// @fallback — the image failed to load: the initials take over, so an avatar is\n// never an empty box.\nconst failed = ref(false)\nwatch(\n () => props.src,\n () => {\n failed.value = false\n },\n)\nconst showImage = computed(() => Boolean(props.src) && !failed.value)\n\nconst accessibleName = computed(() => props.alt ?? props.name)\n\nconst initials = computed(() => {\n if (!props.name) return ''\n return props.name\n .split(/\\s+/)\n .slice(0, 2)\n .map((part) => part[0]?.toLocaleUpperCase() ?? '')\n .join('')\n})\n\n/*\n * Auto hue: a pure JS hash of the name → an OKLCH hue (0–359). Only the hue is\n * inline (a unitless scalar); the CSS composes background/text with L/C fixed per\n * theme (light/dark adaptation without depending on contrast-color). A colour\n * computed outside the tokens, a deliberate exception. SSR-safe: no browser API.\n *\n * VCalendar derives an event's hue the same way (`VCalendar/color.ts`, `hueOf`) with a hash\n * of its own, and the two stay apart ON PURPOSE: changing this one would give every person\n * already shown in an application a new colour. Nothing ties an avatar's hue to an event's,\n * so a person and an event sharing a string do not share a colour.\n */\nconst hue = computed(() => {\n if (!props.name) return null\n let hash = 0\n for (let i = 0; i < props.name.length; i++) {\n hash = (hash * 31 + props.name.charCodeAt(i)) | 0\n }\n return Math.abs(hash) % 360\n})\nconst isAuto = computed(() => props.color === undefined && hue.value !== null)\n\n// A static avatar with no picture is an image named by `alt`/`name`. Anything else keeps the\n// role that arrived in the attributes — `link` on an inert link, a consumer's own otherwise.\nconst role = computed(() =>\n !isInteractive.value && !showImage.value && accessibleName.value\n ? 'img'\n : (passedAttrs.value.role as string | undefined),\n)\n\nconst rootStyle = computed<StyleValue>(() => [\n customColorStyle(props.color) ??\n (isAuto.value ? { '--avatar-hue': String(hue.value) } : undefined),\n attrs.style as StyleValue,\n])\n</script>\n\n<template>\n <component\n :is=\"tag\"\n v-bind=\"passedAttrs\"\n class=\"v-avatar v-control\"\n :style=\"rootStyle\"\n :data-size=\"resolvedSize\"\n :data-compact=\"resolvedCompact ? '' : undefined\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-auto=\"isAuto ? '' : undefined\"\n :href=\"linkHref\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :aria-disabled=\"isInertLink ? 'true' : undefined\"\n :role=\"role\"\n :aria-label=\"!showImage ? accessibleName : undefined\"\n >\n <img\n v-if=\"showImage\"\n class=\"v-avatar-image\"\n :src=\"src\"\n :alt=\"alt ?? name ?? ''\"\n @error=\"failed = true\"\n />\n <VIcon v-else-if=\"icon\" v-bind=\"iconProps(icon)\" class=\"v-avatar-icon\" />\n <slot v-else>\n <span class=\"v-avatar-initials\" aria-hidden=\"true\">{{ initials }}</span>\n </slot>\n </component>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar {\n --avatar-bg: var(--vectis-color-surface-muted);\n --avatar-text: var(--vectis-color-text-muted);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--control-height);\n block-size: var(--control-height);\n flex: none;\n overflow: hidden;\n padding: 0;\n border: none;\n background: var(--avatar-bg);\n color: var(--avatar-text);\n border-radius: var(--vectis-radius-pill);\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n font-weight: var(--vectis-font-weight-semibold);\n line-height: var(--vectis-text-control-leading);\n text-decoration: none;\n user-select: none;\n /* `--avatar-ring-color` is a contract with VAvatarGroup, which is the only thing that\n ever sets it — a private name shared across two sheets, like the `anchor-name`\n idents. The `transparent` fallback is what lets a lone avatar render ringless, and\n it is also what makes a divergence silent: rename it on one side and the discs in a\n group simply stop being separated, with no error and nothing missing from the box. */\n box-shadow: 0 0 0 var(--vectis-control-size-avatar-ring) var(--avatar-ring-color, transparent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n box-shadow var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /* `--avatar-hue` is set inline by the script, which derives it from the name — so these\n pairs cannot be tokens: only the hue varies, and it is not known until render. The two\n themes are written out separately for the same reason relative colours are not used\n elsewhere in the library: OKLCH's lightness is perceptual, so the dark pair is a\n design decision rather than a delta off the light one.\n\n TRAP — the lightness/chroma pairs are set on the THEME scopes and INHERITED, rather\n than written in a `[data-theme='dark'] .v-avatar` rule: a descendant selector matches\n ANY dark ancestor, so a light subtree nested in a dark page kept the dark discs. An\n inherited value is resolved by the NEAREST scope, which is exactly how the semantic\n tokens behave. The selectors and their order are `tokens.css`'s own: all three are\n (0,1,0), so on a dark root the later block wins. */\n :root,\n [data-theme='light'] {\n --avatar-auto-bg-lc: 0.9 0.06;\n --avatar-auto-text-lc: 0.42 0.13;\n }\n\n [data-theme='dark'] {\n --avatar-auto-bg-lc: 0.42 0.09;\n --avatar-auto-text-lc: 0.92 0.05;\n }\n\n .v-avatar[data-auto] {\n --avatar-bg: oklch(var(--avatar-auto-bg-lc) var(--avatar-hue));\n --avatar-text: oklch(var(--avatar-auto-text-lc) var(--avatar-hue));\n }\n\n /* Custom colour (--custom-color inline): wins, with a fixed white text (contrast\n is the consumer's responsibility). */\n .v-avatar[data-custom] {\n --avatar-bg: var(--custom-color);\n --avatar-text: var(--vectis-color-text-on-accent);\n }\n\n .v-avatar-image {\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n }\n\n /* The icon occupies ~55% of the disc (a unitless ratio, like the font-size). */\n .v-avatar-icon {\n --vectis-icon-size: calc(var(--control-height) * 0.55);\n }\n\n :is(a, button).v-avatar {\n cursor: pointer;\n }\n\n :is(a, button).v-avatar:hover:not([aria-disabled='true'], :disabled) {\n background: color-mix(in oklab, var(--avatar-bg), var(--vectis-color-text) 10%);\n }\n\n :is(a, button).v-avatar:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-avatar:is(:disabled, [aria-disabled='true']) {\n cursor: not-allowed;\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-avatar {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}
@@ -1,12 +1,14 @@
1
- import e from "../VIcon/VIcon.js";
2
- import { iconProps as t } from "../VIcon/iconProps.js";
3
- import { avatarGroupKey as n } from "./context.js";
4
- import { computed as r, createBlock as i, createElementBlock as a, createElementVNode as o, defineComponent as s, inject as c, mergeProps as l, openBlock as u, ref as d, renderSlot as f, resolveDynamicComponent as p, toDisplayString as m, unref as h, useAttrs as g, watch as _, withCtx as v } from "vue";
1
+ import { iconProps as e } from "../VIcon/iconProps.js";
2
+ import { customColorStyle as t } from "../../utils/css.js";
3
+ import n from "../VIcon/VIcon.js";
4
+ import { useInertLink as r } from "../../composables/useInertLink.js";
5
+ import { avatarGroupKey as i } from "./context.js";
6
+ import { computed as a, createBlock as o, createElementBlock as s, createElementVNode as c, defineComponent as l, inject as u, mergeProps as d, openBlock as f, ref as p, renderSlot as m, resolveDynamicComponent as h, toDisplayString as g, unref as _, useAttrs as v, watch as y, withCtx as b } from "vue";
5
7
  //#region src/components/VAvatar/VAvatar.vue?vue&type=script&setup=true&lang.ts
6
- var y = ["src", "alt"], b = {
8
+ var x = ["src", "alt"], S = {
7
9
  class: "v-avatar-initials",
8
10
  "aria-hidden": "true"
9
- }, x = /*@__PURE__*/ s({
11
+ }, C = /*@__PURE__*/ l({
10
12
  inheritAttrs: !1,
11
13
  __name: "VAvatar",
12
14
  props: {
@@ -30,41 +32,42 @@ var y = ["src", "alt"], b = {
30
32
  default: !1
31
33
  }
32
34
  },
33
- setup(s) {
34
- let x = s, S = g(), C = c(n, null), w = r(() => x.size ?? C?.size ?? "md"), T = r(() => x.compact || (C?.compact ?? !1)), E = r(() => x.href !== void 0), D = r(() => E.value || x.clickable), O = r(() => E.value ? "a" : x.clickable ? "button" : "span"), k = r(() => E.value && x.disabled), A = d(!1);
35
- _(() => x.src, () => {
36
- A.value = !1;
35
+ setup(l) {
36
+ let C = l, w = v(), T = u(i, null), E = a(() => C.size ?? T?.size ?? "md"), D = a(() => C.compact || !!T?.compact), { isLink: O, isInertLink: k, linkHref: A, attrs: j } = r({
37
+ href: () => C.href,
38
+ inert: () => C.disabled,
39
+ attrs: () => Object.fromEntries(Object.entries(w).filter(([e]) => e !== "style"))
40
+ }), M = a(() => O.value || C.clickable), N = a(() => O.value ? "a" : C.clickable ? "button" : "span"), P = p(!1);
41
+ y(() => C.src, () => {
42
+ P.value = !1;
37
43
  });
38
- let j = r(() => !!x.src && !A.value), M = r(() => x.alt ?? x.name), N = r(() => x.name ? x.name.split(/\s+/).slice(0, 2).map((e) => e[0]?.toLocaleUpperCase() ?? "").join("") : ""), P = r(() => {
39
- if (!x.name) return null;
44
+ let F = a(() => !!C.src && !P.value), I = a(() => C.alt ?? C.name), L = a(() => C.name ? C.name.split(/\s+/).slice(0, 2).map((e) => e[0]?.toLocaleUpperCase() ?? "").join("") : ""), R = a(() => {
45
+ if (!C.name) return null;
40
46
  let e = 0;
41
- for (let t = 0; t < x.name.length; t++) e = e * 31 + x.name.charCodeAt(t) | 0;
47
+ for (let t = 0; t < C.name.length; t++) e = e * 31 + C.name.charCodeAt(t) | 0;
42
48
  return Math.abs(e) % 360;
43
- }), F = r(() => x.color === void 0 && P.value !== null), I = r(() => [x.color === void 0 ? F.value ? { "--avatar-hue": String(P.value) } : void 0 : { "--custom-color": x.color }, S.style]), L = r(() => {
44
- let e = { ...S };
45
- return delete e.style, k.value && delete e.onClick, e;
46
- });
47
- return (n, r) => (u(), i(p(O.value), l(L.value, {
49
+ }), z = a(() => C.color === void 0 && R.value !== null), B = a(() => !M.value && !F.value && I.value ? "img" : j.value.role), V = a(() => [t(C.color) ?? (z.value ? { "--avatar-hue": String(R.value) } : void 0), w.style]);
50
+ return (t, r) => (f(), o(h(N.value), d(_(j), {
48
51
  class: "v-avatar v-control",
49
- style: I.value,
50
- "data-size": w.value,
51
- "data-compact": T.value ? "" : void 0,
52
- "data-custom": s.color === void 0 ? void 0 : "",
53
- "data-auto": F.value ? "" : void 0,
54
- href: E.value && !s.disabled ? s.href : void 0,
55
- type: O.value === "button" ? "button" : void 0,
56
- disabled: O.value === "button" ? s.disabled : void 0,
57
- "aria-disabled": k.value ? "true" : void 0,
58
- role: !D.value && !j.value && M.value ? "img" : void 0,
59
- "aria-label": j.value ? void 0 : M.value
52
+ style: V.value,
53
+ "data-size": E.value,
54
+ "data-compact": D.value ? "" : void 0,
55
+ "data-custom": l.color === void 0 ? void 0 : "",
56
+ "data-auto": z.value ? "" : void 0,
57
+ href: _(A),
58
+ type: N.value === "button" ? "button" : void 0,
59
+ disabled: N.value === "button" ? l.disabled : void 0,
60
+ "aria-disabled": _(k) ? "true" : void 0,
61
+ role: B.value,
62
+ "aria-label": F.value ? void 0 : I.value
60
63
  }), {
61
- default: v(() => [j.value ? (u(), a("img", {
64
+ default: b(() => [F.value ? (f(), s("img", {
62
65
  key: 0,
63
66
  class: "v-avatar-image",
64
- src: s.src,
65
- alt: s.alt ?? s.name ?? "",
66
- onError: r[0] ||= (e) => A.value = !0
67
- }, null, 40, y)) : s.icon ? (u(), i(e, l({ key: 1 }, h(t)(s.icon), { class: "v-avatar-icon" }), null, 16)) : f(n.$slots, "default", {}, () => [o("span", b, m(N.value), 1)], void 0, 2)]),
67
+ src: l.src,
68
+ alt: l.alt ?? l.name ?? "",
69
+ onError: r[0] ||= (e) => P.value = !0
70
+ }, null, 40, x)) : l.icon ? (f(), o(n, d({ key: 1 }, _(e)(l.icon), { class: "v-avatar-icon" }), null, 16)) : m(t.$slots, "default", {}, () => [c("span", S, g(L.value), 1)], void 0, 2)]),
68
71
  _: 3
69
72
  }, 16, [
70
73
  "style",
@@ -82,6 +85,6 @@ var y = ["src", "alt"], b = {
82
85
  }
83
86
  });
84
87
  //#endregion
85
- export { x as default };
88
+ export { C as default };
86
89
 
87
90
  //# sourceMappingURL=VAvatar.vue_vue_type_script_setup_true_lang.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"VAvatar.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VAvatar/VAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, inject, ref, useAttrs, watch } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\nimport { avatarGroupKey } from './context'\n\nexport type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/**\n * A round avatar standing for a person or an entity. It shows the best of what it\n * was given, in that order: the picture, failing that an icon, failing that the\n * initials taken from the name, and failing that whatever the default slot holds —\n * the escape hatch VAvatarGroup uses to render its \"+X\" overflow badge.\n *\n * Four things here genuinely need JavaScript. A picture that fails to download\n * reports it as a DOM event and nothing else, so the script listens for it and\n * hands over to the initials rather than leaving an empty circle. The initials and\n * the automatic colour are both computed from the name, which is arithmetic no\n * stylesheet can do. A disabled link has no native equivalent of a disabled\n * button, so it is turned inert by hand (its `href` is removed, `aria-disabled`\n * announces the state and the click handler is dropped). Finally the attributes\n * the consumer passes are split so that `style` never reaches the element\n * directly: the component has to merge its own `--avatar-hue`/`--custom-color`\n * into it first, and a plain fallthrough would overwrite them.\n */\ninterface AvatarProps {\n /** Image URL (priority 1). */\n src?: string\n /** Icon shown in the absence of an image (priority 2): a name, or an explicit render. */\n icon?: IconSource\n /** Full name — the default alt, the source of the initials and the seed of the auto hue. */\n name?: string\n /** Explicit alt/label (wins over `name`). */\n alt?: string\n /**\n * Custom colour (hex, CSS name or oklch()) which REPLACES the auto hue: set inline\n * as `--custom-color`. Otherwise, in the absence of an image, a deterministic OKLCH\n * hue is derived from `name`.\n */\n color?: string\n /** Default `md`. `undefined` = inherited from an enclosing VAvatarGroup. */\n size?: AvatarSize\n /** Height reduced by 4px (like the other controls). */\n compact?: boolean\n /** Rendered as `<a>`. disabled → an inert link (href removed + aria-disabled). */\n href?: string\n /** Rendered as `<button type=\"button\">` (a VTooltip's #trigger slot plugs in through fallthrough). */\n clickable?: boolean\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AvatarProps>(), {\n src: undefined,\n icon: undefined,\n name: undefined,\n alt: undefined,\n color: undefined,\n size: undefined,\n compact: false,\n href: undefined,\n clickable: false,\n disabled: false,\n})\n\ndefineSlots<{\n /** Fallback content (replaces the initials), e.g. VAvatarGroup's \"+X\". */\n default?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\nconst group = inject(avatarGroupKey, null)\n\n// Size/compact: the explicit prop, else the group's, else the default.\nconst resolvedSize = computed<AvatarSize>(() => props.size ?? group?.size ?? 'md')\nconst resolvedCompact = computed(() => props.compact || (group?.compact ?? false))\n\n/* Interactivity priority: href > clickable > static. */\nconst isLink = computed(() => props.href !== undefined)\nconst isInteractive = computed(() => isLink.value || props.clickable)\nconst tag = computed(() => (isLink.value ? 'a' : props.clickable ? 'button' : 'span'))\nconst isInertLink = computed(() => isLink.value && props.disabled)\n\n// @fallback — the image failed to load: the initials take over, so an avatar is\n// never an empty box.\nconst failed = ref(false)\nwatch(\n () => props.src,\n () => {\n failed.value = false\n },\n)\nconst showImage = computed(() => Boolean(props.src) && !failed.value)\n\nconst accessibleName = computed(() => props.alt ?? props.name)\n\nconst initials = computed(() => {\n if (!props.name) return ''\n return props.name\n .split(/\\s+/)\n .slice(0, 2)\n .map((part) => part[0]?.toLocaleUpperCase() ?? '')\n .join('')\n})\n\n/*\n * Auto hue: a pure JS hash of the name → an OKLCH hue (0–359). Only the hue is\n * inline (a unitless scalar); the CSS composes background/text with L/C fixed per\n * theme (light/dark adaptation without depending on contrast-color). A colour\n * computed outside the tokens, a deliberate exception. SSR-safe: no browser API.\n */\nconst hue = computed(() => {\n if (!props.name) return null\n let hash = 0\n for (let i = 0; i < props.name.length; i++) {\n hash = (hash * 31 + props.name.charCodeAt(i)) | 0\n }\n return Math.abs(hash) % 360\n})\nconst isAuto = computed(() => props.color === undefined && hue.value !== null)\n\nconst rootStyle = computed<StyleValue>(() => [\n props.color !== undefined\n ? { '--custom-color': props.color }\n : isAuto.value\n ? { '--avatar-hue': String(hue.value) }\n : undefined,\n attrs.style as StyleValue,\n])\n\n// Fallthrough without `style` (handled by rootStyle); onClick removed on an inert link.\nconst passedAttrs = computed(() => {\n const rest = { ...(attrs as Record<string, unknown>) }\n delete rest.style\n if (isInertLink.value) delete rest.onClick\n return rest\n})\n</script>\n\n<template>\n <component\n :is=\"tag\"\n v-bind=\"passedAttrs\"\n class=\"v-avatar v-control\"\n :style=\"rootStyle\"\n :data-size=\"resolvedSize\"\n :data-compact=\"resolvedCompact ? '' : undefined\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-auto=\"isAuto ? '' : undefined\"\n :href=\"isLink && !disabled ? href : undefined\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :aria-disabled=\"isInertLink ? 'true' : undefined\"\n :role=\"!isInteractive && !showImage && accessibleName ? 'img' : undefined\"\n :aria-label=\"!showImage ? accessibleName : undefined\"\n >\n <img\n v-if=\"showImage\"\n class=\"v-avatar-image\"\n :src=\"src\"\n :alt=\"alt ?? name ?? ''\"\n @error=\"failed = true\"\n />\n <VIcon v-else-if=\"icon\" v-bind=\"iconProps(icon)\" class=\"v-avatar-icon\" />\n <slot v-else>\n <span class=\"v-avatar-initials\" aria-hidden=\"true\">{{ initials }}</span>\n </slot>\n </component>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar {\n --avatar-bg: var(--vectis-color-surface-muted);\n --avatar-text: var(--vectis-color-text-muted);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--control-height);\n block-size: var(--control-height);\n flex: none;\n overflow: hidden;\n padding: 0;\n border: none;\n background: var(--avatar-bg);\n color: var(--avatar-text);\n border-radius: var(--vectis-radius-full);\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n font-weight: var(--vectis-font-weight-semibold);\n line-height: var(--vectis-text-control-leading);\n text-decoration: none;\n user-select: none;\n box-shadow: 0 0 0 var(--vectis-control-size-avatar-ring) var(--avatar-ring-color, transparent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n box-shadow var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /* Auto hue */\n .v-avatar[data-auto] {\n --avatar-bg: oklch(0.9 0.06 var(--avatar-hue));\n --avatar-text: oklch(0.42 0.13 var(--avatar-hue));\n }\n\n /* Custom colour (--custom-color inline): wins, with a fixed white text (contrast\n is the consumer's responsibility). */\n .v-avatar[data-custom] {\n --avatar-bg: var(--custom-color);\n --avatar-text: var(--vectis-color-text-on-accent);\n }\n\n [data-theme='dark'] .v-avatar[data-auto] {\n --avatar-bg: oklch(0.42 0.09 var(--avatar-hue));\n --avatar-text: oklch(0.92 0.05 var(--avatar-hue));\n }\n\n .v-avatar-image {\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n }\n\n /* The icon occupies ~55% of the disc (a unitless ratio, like the font-size). */\n .v-avatar-icon {\n --vectis-icon-size: calc(var(--control-height) * 0.55);\n }\n\n :is(a, button).v-avatar {\n cursor: pointer;\n }\n\n :is(a, button).v-avatar:hover:not([aria-disabled='true'], :disabled) {\n background: color-mix(in oklab, var(--avatar-bg), var(--vectis-color-text) 10%);\n }\n\n :is(a, button).v-avatar:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-avatar:is(:disabled, [aria-disabled='true']) {\n cursor: not-allowed;\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-avatar {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsDA,IAAM,IAAQ,GAoBR,IAAQ,EAAS,GACjB,IAAQ,EAAO,GAAgB,IAAI,GAGnC,IAAe,QAA2B,EAAM,QAAQ,GAAO,QAAQ,IAAI,GAC3E,IAAkB,QAAe,EAAM,YAAY,GAAO,WAAW,GAAM,GAG3E,IAAS,QAAe,EAAM,SAAS,KAAA,CAAS,GAChD,IAAgB,QAAe,EAAO,SAAS,EAAM,SAAS,GAC9D,IAAM,QAAgB,EAAO,QAAQ,MAAM,EAAM,YAAY,WAAW,MAAO,GAC/E,IAAc,QAAe,EAAO,SAAS,EAAM,QAAQ,GAI3D,IAAS,EAAI,EAAK;EACxB,QACQ,EAAM,WACN;GACJ,EAAO,QAAQ;EACjB,CACF;EACA,IAAM,IAAY,QAAe,EAAQ,EAAM,OAAQ,CAAC,EAAO,KAAK,GAE9D,IAAiB,QAAe,EAAM,OAAO,EAAM,IAAI,GAEvD,IAAW,QACV,EAAM,OACJ,EAAM,KACV,MAAM,KAAK,CAAA,CACX,MAAM,GAAG,CAAC,CAAA,CACV,KAAK,MAAS,EAAK,EAAE,EAAE,kBAAkB,KAAK,EAAE,CAAA,CAChD,KAAK,EAAE,IALc,EAMzB,GAQK,IAAM,QAAe;GACzB,IAAI,CAAC,EAAM,MAAM,OAAO;GACxB,IAAI,IAAO;GACX,KAAK,IAAI,IAAI,GAAG,IAAI,EAAM,KAAK,QAAQ,KACrC,IAAQ,IAAO,KAAK,EAAM,KAAK,WAAW,CAAC,IAAK;GAElD,OAAO,KAAK,IAAI,CAAI,IAAI;EAC1B,CAAC,GACK,IAAS,QAAe,EAAM,UAAU,KAAA,KAAa,EAAI,UAAU,IAAI,GAEvE,IAAY,QAA2B,CAC3C,EAAM,UAAU,KAAA,IAEZ,EAAO,QACL,EAAE,gBAAgB,OAAO,EAAI,KAAK,EAAE,IACpC,KAAA,IAHF,EAAE,kBAAkB,EAAM,MAAM,GAIpC,EAAM,KACR,CAAC,GAGK,IAAc,QAAe;GACjC,IAAM,IAAO,EAAE,GAAI,EAAkC;GAGrD,OAFA,OAAO,EAAK,OACR,EAAY,SAAO,OAAO,EAAK,SAC5B;EACT,CAAC;yBAIC,EA2BY,EA1BL,EAAA,KAAG,GADV,EAEU,EAyBE,OAzBS;GACnB,OAAM;GACL,OAAO,EAAA;GACP,aAAW,EAAA;GACX,gBAAc,EAAA,QAAe,KAAQ,KAAA;GACrC,eAAa,EAAA,UAAU,KAAA,IAAiB,KAAA,IAAR;GAChC,aAAW,EAAA,QAAM,KAAQ,KAAA;GACzB,MAAM,EAAA,SAAM,CAAK,EAAA,WAAW,EAAA,OAAO,KAAA;GACnC,MAAM,EAAA,UAAG,WAAA,WAA2B,KAAA;GACpC,UAAU,EAAA,UAAG,WAAgB,EAAA,WAAW,KAAA;GACxC,iBAAe,EAAA,QAAW,SAAY,KAAA;GACtC,MAAI,CAAG,EAAA,SAAa,CAAK,EAAA,SAAa,EAAA,QAAc,QAAW,KAAA;GAC/D,cAAa,EAAA,QAA6B,KAAA,IAAjB,EAAA;;oBAQxB,CALM,EAAA,SAAA,EAAA,GADR,EAME,OAAA;;IAJA,OAAM;IACL,KAAK,EAAA;IACL,KAAK,EAAA,OAAO,EAAA,QAAI;IAChB,SAAK,AAAA,EAAA,QAAA,MAAE,EAAA,QAAM;sBAEE,EAAA,QAAA,EAAA,GAAlB,EAAyE,GAAzE,EAAyE,EAAA,KAAA,EAAA,GAAzC,EAAA,CAAA,CAAS,CAAC,EAAA,IAAI,GAAA,EAAG,OAAM,gBAAe,CAAA,GAAA,MAAA,EAAA,KACtE,EAEO,EAAA,QAAA,WAAA,CAAA,SAAA,CADL,EAAwE,QAAxE,GAAwE,EAAlB,EAAA,KAAQ,GAAA,CAAA,CAAA,GAAA,KAAA,GAAA,CAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"VAvatar.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VAvatar/VAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * A round avatar standing for a person or an entity. It shows the best of what it\n * was given, in that order: the picture, failing that an icon, failing that the\n * initials taken from the name, and failing that whatever the default slot holds —\n * the escape hatch VAvatarGroup uses to render its \"+X\" overflow badge.\n *\n * Four things here genuinely need JavaScript. A picture that fails to download\n * reports it as a DOM event and nothing else, so the script listens for it and\n * hands over to the initials rather than leaving an empty circle. The initials and\n * the automatic colour are both computed from the name, which is arithmetic no\n * stylesheet can do. A disabled link has no native equivalent of a disabled\n * button, so it is turned inert by hand (composables/useInertLink). Finally the attributes\n * the consumer passes are split so that `style` never reaches the element\n * directly: the component has to merge its own `--avatar-hue`/`--custom-color`\n * into it first, and a plain fallthrough would overwrite them.\n */\n\nimport { computed, inject, ref, useAttrs, watch } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { useInertLink } from '../../composables/useInertLink'\nimport { customColorStyle } from '../../utils/css'\n\nexport type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\ninterface AvatarProps {\n /**\n * The picture to show. It is what the avatar prefers above everything else, and an image\n * that fails to load hands over to the icon or the initials rather than leaving a gap.\n */\n src?: string\n /**\n * The icon to show when there is no picture. It comes before the initials, so an avatar\n * given both an icon and a name shows the icon.\n */\n icon?: IconSource\n /**\n * The person's full name. It does three things at once: it names the avatar for assistive\n * technology, its initials are what shows when there is no picture and no icon, and it is\n * the seed the automatic colour is derived from — so the same person keeps the same colour\n * everywhere.\n */\n name?: string\n /**\n * The accessible name, when it should not simply be `name` — an avatar standing for a team\n * rather than a person, say. It wins over `name`.\n */\n alt?: string\n /**\n * A colour of your own, as a hex value, a CSS colour name or an `oklch()`. It REPLACES the\n * hue otherwise derived from `name`, and the text on it is always white, so a light colour\n * is the consumer's own risk.\n */\n color?: string\n /**\n * The diameter of the disc, from the size scale shared by every control. Leaving it out\n * inside a VAvatarGroup takes the group's size, which is the point of not defaulting it\n * here; on its own it is `md`.\n */\n size?: AvatarSize\n /**\n * Takes 4px off the diameter, as it does on every other control. Unlike `size` it is\n * cumulative: inside a compact VAvatarGroup the avatar is compact whatever this says, and\n * setting it on one avatar of a regular group makes that one compact alone.\n */\n compact?: boolean\n /**\n * Turns the avatar into an `<a>` pointing at this address. A disabled link becomes inert:\n * the address is dropped, so it can be neither focused nor followed.\n */\n href?: string\n /**\n * Turns the avatar into a `<button>`. It is ignored as soon as `href` makes it a link.\n * A VTooltip wrapping the avatar reaches this button through fallthrough.\n */\n clickable?: boolean\n /**\n * Makes an interactive avatar unusable: it stops responding, leaves the tab order and greys\n * out. It says nothing on a plain avatar, which was never interactive to begin with.\n */\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<AvatarProps>(), {\n src: undefined,\n icon: undefined,\n name: undefined,\n alt: undefined,\n color: undefined,\n size: undefined,\n compact: false,\n href: undefined,\n clickable: false,\n disabled: false,\n})\n\ndefineSlots<{\n /** Fallback content (replaces the initials), e.g. VAvatarGroup's \"+X\". */\n default?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\n\nconst attrs = useAttrs()\nconst group = inject(avatarGroupKey, null)\n\n// The size is the avatar's own answer first, then the group's; the density is cumulative,\n// the two terms written out in context.ts.\nconst resolvedSize = computed<AvatarSize>(() => props.size ?? group?.size ?? AVATAR_DEFAULT_SIZE)\nconst resolvedCompact = computed(() => props.compact || Boolean(group?.compact))\n\n// Fallthrough without `style`, which rootStyle merges with the component's own; the click\n// handler is also dropped on an inert link.\nconst {\n isLink,\n isInertLink,\n linkHref,\n attrs: passedAttrs,\n} = useInertLink({\n href: () => props.href,\n inert: () => props.disabled,\n attrs: () => Object.fromEntries(Object.entries(attrs).filter(([key]) => key !== 'style')),\n})\n\n/* Interactivity priority: href > clickable > static. */\nconst isInteractive = computed(() => isLink.value || props.clickable)\nconst tag = computed(() => (isLink.value ? 'a' : props.clickable ? 'button' : 'span'))\n\n// @fallback — the image failed to load: the initials take over, so an avatar is\n// never an empty box.\nconst failed = ref(false)\nwatch(\n () => props.src,\n () => {\n failed.value = false\n },\n)\nconst showImage = computed(() => Boolean(props.src) && !failed.value)\n\nconst accessibleName = computed(() => props.alt ?? props.name)\n\nconst initials = computed(() => {\n if (!props.name) return ''\n return props.name\n .split(/\\s+/)\n .slice(0, 2)\n .map((part) => part[0]?.toLocaleUpperCase() ?? '')\n .join('')\n})\n\n/*\n * Auto hue: a pure JS hash of the name → an OKLCH hue (0–359). Only the hue is\n * inline (a unitless scalar); the CSS composes background/text with L/C fixed per\n * theme (light/dark adaptation without depending on contrast-color). A colour\n * computed outside the tokens, a deliberate exception. SSR-safe: no browser API.\n *\n * VCalendar derives an event's hue the same way (`VCalendar/color.ts`, `hueOf`) with a hash\n * of its own, and the two stay apart ON PURPOSE: changing this one would give every person\n * already shown in an application a new colour. Nothing ties an avatar's hue to an event's,\n * so a person and an event sharing a string do not share a colour.\n */\nconst hue = computed(() => {\n if (!props.name) return null\n let hash = 0\n for (let i = 0; i < props.name.length; i++) {\n hash = (hash * 31 + props.name.charCodeAt(i)) | 0\n }\n return Math.abs(hash) % 360\n})\nconst isAuto = computed(() => props.color === undefined && hue.value !== null)\n\n// A static avatar with no picture is an image named by `alt`/`name`. Anything else keeps the\n// role that arrived in the attributes — `link` on an inert link, a consumer's own otherwise.\nconst role = computed(() =>\n !isInteractive.value && !showImage.value && accessibleName.value\n ? 'img'\n : (passedAttrs.value.role as string | undefined),\n)\n\nconst rootStyle = computed<StyleValue>(() => [\n customColorStyle(props.color) ??\n (isAuto.value ? { '--avatar-hue': String(hue.value) } : undefined),\n attrs.style as StyleValue,\n])\n</script>\n\n<template>\n <component\n :is=\"tag\"\n v-bind=\"passedAttrs\"\n class=\"v-avatar v-control\"\n :style=\"rootStyle\"\n :data-size=\"resolvedSize\"\n :data-compact=\"resolvedCompact ? '' : undefined\"\n :data-custom=\"color !== undefined ? '' : undefined\"\n :data-auto=\"isAuto ? '' : undefined\"\n :href=\"linkHref\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :aria-disabled=\"isInertLink ? 'true' : undefined\"\n :role=\"role\"\n :aria-label=\"!showImage ? accessibleName : undefined\"\n >\n <img\n v-if=\"showImage\"\n class=\"v-avatar-image\"\n :src=\"src\"\n :alt=\"alt ?? name ?? ''\"\n @error=\"failed = true\"\n />\n <VIcon v-else-if=\"icon\" v-bind=\"iconProps(icon)\" class=\"v-avatar-icon\" />\n <slot v-else>\n <span class=\"v-avatar-initials\" aria-hidden=\"true\">{{ initials }}</span>\n </slot>\n </component>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar {\n --avatar-bg: var(--vectis-color-surface-muted);\n --avatar-text: var(--vectis-color-text-muted);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--control-height);\n block-size: var(--control-height);\n flex: none;\n overflow: hidden;\n padding: 0;\n border: none;\n background: var(--avatar-bg);\n color: var(--avatar-text);\n border-radius: var(--vectis-radius-pill);\n font-family: var(--vectis-text-family);\n font-size: var(--control-font-size);\n font-weight: var(--vectis-font-weight-semibold);\n line-height: var(--vectis-text-control-leading);\n text-decoration: none;\n user-select: none;\n /* `--avatar-ring-color` is a contract with VAvatarGroup, which is the only thing that\n ever sets it — a private name shared across two sheets, like the `anchor-name`\n idents. The `transparent` fallback is what lets a lone avatar render ringless, and\n it is also what makes a divergence silent: rename it on one side and the discs in a\n group simply stop being separated, with no error and nothing missing from the box. */\n box-shadow: 0 0 0 var(--vectis-control-size-avatar-ring) var(--avatar-ring-color, transparent);\n transition:\n background-color var(--vectis-duration-fast) var(--vectis-ease-default),\n box-shadow var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n /* `--avatar-hue` is set inline by the script, which derives it from the name — so these\n pairs cannot be tokens: only the hue varies, and it is not known until render. The two\n themes are written out separately for the same reason relative colours are not used\n elsewhere in the library: OKLCH's lightness is perceptual, so the dark pair is a\n design decision rather than a delta off the light one.\n\n TRAP — the lightness/chroma pairs are set on the THEME scopes and INHERITED, rather\n than written in a `[data-theme='dark'] .v-avatar` rule: a descendant selector matches\n ANY dark ancestor, so a light subtree nested in a dark page kept the dark discs. An\n inherited value is resolved by the NEAREST scope, which is exactly how the semantic\n tokens behave. The selectors and their order are `tokens.css`'s own: all three are\n (0,1,0), so on a dark root the later block wins. */\n :root,\n [data-theme='light'] {\n --avatar-auto-bg-lc: 0.9 0.06;\n --avatar-auto-text-lc: 0.42 0.13;\n }\n\n [data-theme='dark'] {\n --avatar-auto-bg-lc: 0.42 0.09;\n --avatar-auto-text-lc: 0.92 0.05;\n }\n\n .v-avatar[data-auto] {\n --avatar-bg: oklch(var(--avatar-auto-bg-lc) var(--avatar-hue));\n --avatar-text: oklch(var(--avatar-auto-text-lc) var(--avatar-hue));\n }\n\n /* Custom colour (--custom-color inline): wins, with a fixed white text (contrast\n is the consumer's responsibility). */\n .v-avatar[data-custom] {\n --avatar-bg: var(--custom-color);\n --avatar-text: var(--vectis-color-text-on-accent);\n }\n\n .v-avatar-image {\n inline-size: 100%;\n block-size: 100%;\n object-fit: cover;\n }\n\n /* The icon occupies ~55% of the disc (a unitless ratio, like the font-size). */\n .v-avatar-icon {\n --vectis-icon-size: calc(var(--control-height) * 0.55);\n }\n\n :is(a, button).v-avatar {\n cursor: pointer;\n }\n\n :is(a, button).v-avatar:hover:not([aria-disabled='true'], :disabled) {\n background: color-mix(in oklab, var(--avatar-bg), var(--vectis-color-text) 10%);\n }\n\n :is(a, button).v-avatar:focus-visible {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: var(--vectis-focus-ring-offset);\n }\n\n .v-avatar:is(:disabled, [aria-disabled='true']) {\n cursor: not-allowed;\n background: var(--vectis-color-surface-muted);\n color: var(--vectis-color-text-subtle);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-avatar {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyFA,IAAM,IAAQ,GAoBR,IAAQ,EAAS,GACjB,IAAQ,EAAO,GAAgB,IAAI,GAInC,IAAe,QAA2B,EAAM,QAAQ,GAAO,QAAA,IAA2B,GAC1F,IAAkB,QAAe,EAAM,WAAW,EAAQ,GAAO,OAAQ,GAIzE,EACJ,WACA,gBACA,aACA,OAAO,MACL,EAAa;GACf,YAAY,EAAM;GAClB,aAAa,EAAM;GACnB,aAAa,OAAO,YAAY,OAAO,QAAQ,CAAK,CAAC,CAAC,QAAQ,CAAC,OAAS,MAAQ,OAAO,CAAC;EAC1F,CAAC,GAGK,IAAgB,QAAe,EAAO,SAAS,EAAM,SAAS,GAC9D,IAAM,QAAgB,EAAO,QAAQ,MAAM,EAAM,YAAY,WAAW,MAAO,GAI/E,IAAS,EAAI,EAAK;EACxB,QACQ,EAAM,WACN;GACJ,EAAO,QAAQ;EACjB,CACF;EACA,IAAM,IAAY,QAAe,EAAQ,EAAM,OAAQ,CAAC,EAAO,KAAK,GAE9D,IAAiB,QAAe,EAAM,OAAO,EAAM,IAAI,GAEvD,IAAW,QACV,EAAM,OACJ,EAAM,KACV,MAAM,KAAK,CAAA,CACX,MAAM,GAAG,CAAC,CAAA,CACV,KAAK,MAAS,EAAK,EAAE,EAAE,kBAAkB,KAAK,EAAE,CAAA,CAChD,KAAK,EAAE,IALc,EAMzB,GAaK,IAAM,QAAe;GACzB,IAAI,CAAC,EAAM,MAAM,OAAO;GACxB,IAAI,IAAO;GACX,KAAK,IAAI,IAAI,GAAG,IAAI,EAAM,KAAK,QAAQ,KACrC,IAAQ,IAAO,KAAK,EAAM,KAAK,WAAW,CAAC,IAAK;GAElD,OAAO,KAAK,IAAI,CAAI,IAAI;EAC1B,CAAC,GACK,IAAS,QAAe,EAAM,UAAU,KAAA,KAAa,EAAI,UAAU,IAAI,GAIvE,IAAO,QACX,CAAC,EAAc,SAAS,CAAC,EAAU,SAAS,EAAe,QACvD,QACC,EAAY,MAAM,IACzB,GAEM,IAAY,QAA2B,CAC3C,EAAiB,EAAM,KAAK,MACzB,EAAO,QAAQ,EAAE,gBAAgB,OAAO,EAAI,KAAK,EAAE,IAAI,KAAA,IAC1D,EAAM,KACR,CAAC;yBAIC,EA2BY,EA1BL,EAAA,KAAG,GADV,EAEU,EAyBE,CAAA,GAzBS;GACnB,OAAM;GACL,OAAO,EAAA;GACP,aAAW,EAAA;GACX,gBAAc,EAAA,QAAe,KAAQ,KAAA;GACrC,eAAa,EAAA,UAAU,KAAA,IAAiB,KAAA,IAAR;GAChC,aAAW,EAAA,QAAM,KAAQ,KAAA;GACzB,MAAM,EAAA,CAAA;GACN,MAAM,EAAA,UAAG,WAAA,WAA2B,KAAA;GACpC,UAAU,EAAA,UAAG,WAAgB,EAAA,WAAW,KAAA;GACxC,iBAAe,EAAA,CAAA,IAAW,SAAY,KAAA;GACtC,MAAM,EAAA;GACN,cAAa,EAAA,QAA6B,KAAA,IAAjB,EAAA;;oBAQxB,CALM,EAAA,SAAA,EAAA,GADR,EAME,OAAA;;IAJA,OAAM;IACL,KAAK,EAAA;IACL,KAAK,EAAA,OAAO,EAAA,QAAI;IAChB,SAAK,AAAA,EAAA,QAAA,MAAE,EAAA,QAAM;sBAEE,EAAA,QAAA,EAAA,GAAlB,EAAyE,GAAzE,EAAyE,EAAA,KAAA,EAAA,GAAzC,EAAA,CAAA,CAAS,CAAC,EAAA,IAAI,GAAA,EAAG,OAAM,gBAAe,CAAA,GAAA,MAAA,EAAA,KACtE,EAEO,EAAA,QAAA,WAAA,CAAA,SAAA,CADL,EAAwE,QAAxE,GAAwE,EAAlB,EAAA,KAAQ,GAAA,CAAA,CAAA,GAAA,KAAA,GAAA,CAAA,CAAA,CAAA"}
@@ -1,18 +1,4 @@
1
1
  import { AvatarSize } from './VAvatar.js';
2
- /**
3
- * Stacks several VAvatars into an overlapping row, the usual way of showing the
4
- * members of a team or the participants in a conversation. Each disc bites into the
5
- * one before it and, coming later in the document, is painted over it: the
6
- * browser's own paint order does the work, no positioning code is involved. A ring
7
- * in `--avatar-ring-color` surrounds every disc so the overlapping edges stay
8
- * distinct from one another.
9
- *
10
- * Two things here do need JavaScript. Counting the avatars the group was given and
11
- * keeping only the first few, so that the rest can be summed up as a single "+X"
12
- * disc, is something neither HTML nor CSS can express. And the size and the density
13
- * chosen on the group are handed down to the avatars inside through Vue's
14
- * provide/inject.
15
- */
16
2
  interface AvatarGroupProps {
17
3
  /**
18
4
  * How many avatars to show before the remaining ones are summed up as a single
@@ -24,7 +10,10 @@ interface AvatarGroupProps {
24
10
  * of its own keeps it.
25
11
  */
26
12
  size?: AvatarSize;
27
- /** Applies the reduced density to the avatars inside, on the same terms as `size`. */
13
+ /**
14
+ * Applies the reduced density to every avatar inside. Unlike `size` it is cumulative: an
15
+ * avatar cannot opt back out of a compact group.
16
+ */
28
17
  compact?: boolean;
29
18
  /**
30
19
  * The colour of the ring drawn around each disc. It defaults to the page
@@ -46,8 +35,8 @@ type __VLS_Slots = {
46
35
  declare const __VLS_base: import('vue').DefineComponent<AvatarGroupProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<AvatarGroupProps> & Readonly<{}>, {
47
36
  size: AvatarSize;
48
37
  compact: boolean;
49
- max: number;
50
38
  ringColor: string;
39
+ max: number;
51
40
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
52
41
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
53
42
  declare const _default: typeof __VLS_export;
@@ -1 +1 @@
1
- {"version":3,"file":"VAvatarGroup.js","names":[],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, provide, useSlots } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VAvatar from './VAvatar.vue'\nimport type { AvatarSize } from './VAvatar.vue'\nimport { avatarGroupKey } from './context'\n\nimport { flattenSlot } from '../../utils/vnode'\n\n// @ssr @core — the number of avatars is read from the slot's VNODES through\n// `flattenSlot`, never from a registry the children would fill at mount: such a\n// registry is empty during the server render and full on the client, which is a\n// hydration mismatch.\n/**\n * Stacks several VAvatars into an overlapping row, the usual way of showing the\n * members of a team or the participants in a conversation. Each disc bites into the\n * one before it and, coming later in the document, is painted over it: the\n * browser's own paint order does the work, no positioning code is involved. A ring\n * in `--avatar-ring-color` surrounds every disc so the overlapping edges stay\n * distinct from one another.\n *\n * Two things here do need JavaScript. Counting the avatars the group was given and\n * keeping only the first few, so that the rest can be summed up as a single \"+X\"\n * disc, is something neither HTML nor CSS can express. And the size and the density\n * chosen on the group are handed down to the avatars inside through Vue's\n * provide/inject.\n */\ninterface AvatarGroupProps {\n /**\n * How many avatars to show before the remaining ones are summed up as a single\n * \"+X\" disc. Left out, or set to 0, every avatar is shown.\n */\n max?: number\n /**\n * The size given to the avatars inside the group. An avatar that sets a `size`\n * of its own keeps it.\n */\n size?: AvatarSize\n /** Applies the reduced density to the avatars inside, on the same terms as `size`. */\n compact?: boolean\n /**\n * The colour of the ring drawn around each disc. It defaults to the page\n * background, which is what makes the ring read as a gap between two avatars.\n */\n ringColor?: string\n}\n\nconst props = withDefaults(defineProps<AvatarGroupProps>(), {\n max: undefined,\n size: undefined,\n compact: false,\n ringColor: undefined,\n})\n\ndefineSlots<{\n /** The VAvatars to stack. */\n default?(): unknown\n /**\n * Replaces the \"+X\" disc that stands for the avatars beyond `max`. It receives\n * `count`, the number of avatars being hidden.\n */\n overflow?(props: { count: number }): unknown\n}>()\n\nprovide(avatarGroupKey, {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n})\n\nconst slots = useSlots()\n\nconst items = computed(() => flattenSlot(slots.default?.()))\nconst visibleItems = computed(() =>\n props.max != null ? items.value.slice(0, props.max) : items.value,\n)\nconst overflowCount = computed(() => items.value.length - visibleItems.value.length)\n\n// A functional component is the only way to render VNodes that have already been\n// captured: <component :is> expects a component definition, not a vnode.\nconst VisibleAvatars = () => visibleItems.value\n\nconst rootStyle = computed<StyleValue>(() =>\n props.ringColor !== undefined ? { '--avatar-ring-color': props.ringColor } : undefined,\n)\n\n// The group carries v-control so that --control-height is defined at ITS level,\n// which keeps the overlap computable even when a child is wrapped — a VTooltip, for\n// instance, inserts a <span> between the group and the VAvatar. An avatar given a\n// size of its own redefines --control-height on itself, so its own overlap follows\n// that size rather than the group's.\nconst resolvedGroupSize = computed<AvatarSize>(() => props.size ?? 'md')\n</script>\n\n<template>\n <div\n class=\"v-avatar-group v-control\"\n role=\"group\"\n :style=\"rootStyle\"\n :data-size=\"resolvedGroupSize\"\n :data-compact=\"compact ? '' : undefined\"\n >\n <component :is=\"VisibleAvatars\" />\n <slot v-if=\"overflowCount > 0\" name=\"overflow\" :count=\"overflowCount\">\n <VAvatar>+{{ overflowCount }}</VAvatar>\n </slot>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar-group {\n /* The separation ring, declared here so that every child .v-avatar inherits it. */\n --avatar-ring-color: var(--vectis-color-surface);\n display: inline-flex;\n align-items: center;\n }\n\n /* The overlap itself: each disc bites into the previous one by a fraction of its\n own height, and the DOM order is what makes the following one paint over it.\n The selector deliberately targets the direct child whatever it is — a bare\n VAvatar as well as a VTooltip wrapper — which is why --control-height has to\n come from the group; an avatar carrying its own size overrides it on itself.\n The ratio is unitless so it scales with whichever height applies. */\n .v-avatar-group > * + * {\n margin-inline-start: calc(var(--control-height) * -0.3);\n }\n\n /* On hover, or as soon as something inside it takes focus, a disc rises above its\n neighbours so it is seen whole rather than clipped by the next one. */\n .v-avatar-group > *:hover,\n .v-avatar-group > *:focus-within {\n z-index: 1;\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"VAvatarGroup.js","names":[],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core — the number of avatars is read from the slot's VNODES through\n// `flattenSlot`, never from a registry the children would fill at mount: such a\n// registry is empty during the server render and full on the client, which is a\n// hydration mismatch.\n/**\n * Several VAvatars stacked into an overlapping row — a team, the participants in a\n * conversation. Each disc bites into the one before it and, coming later in the document, is\n * painted over it: the browser's paint order does the work, with no positioning code. A ring\n * in `--avatar-ring-color` keeps the overlapping edges distinct.\n *\n * Two things need JS. Counting the avatars given and keeping only the first few, so the rest\n * can be summed up as one \"+N\" disc, is expressible in neither HTML nor CSS — and the count\n * comes from the slot's VNODES, never a registry, which would render 0 on the server and N\n * in the browser. And the group's size and density reach the avatars through provide/inject.\n */\n\nimport { computed, provide, useSlots } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VAvatar from './VAvatar.vue'\nimport type { AvatarSize } from './VAvatar.vue'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { flattenSlot } from '../../utils/vnode'\n\ninterface AvatarGroupProps {\n /**\n * How many avatars to show before the remaining ones are summed up as a single\n * \"+X\" disc. Left out, or set to 0, every avatar is shown.\n */\n max?: number\n /**\n * The size given to the avatars inside the group. An avatar that sets a `size`\n * of its own keeps it.\n */\n size?: AvatarSize\n /**\n * Applies the reduced density to every avatar inside. Unlike `size` it is cumulative: an\n * avatar cannot opt back out of a compact group.\n */\n compact?: boolean\n /**\n * The colour of the ring drawn around each disc. It defaults to the page\n * background, which is what makes the ring read as a gap between two avatars.\n */\n ringColor?: string\n}\n\nconst props = withDefaults(defineProps<AvatarGroupProps>(), {\n max: undefined,\n size: undefined,\n compact: false,\n ringColor: undefined,\n})\n\ndefineSlots<{\n /** The VAvatars to stack. */\n default?(): unknown\n /**\n * Replaces the \"+X\" disc that stands for the avatars beyond `max`. It receives\n * `count`, the number of avatars being hidden.\n */\n overflow?(props: { count: number }): unknown\n}>()\n\nprovide(avatarGroupKey, {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n})\n\nconst slots = useSlots()\n\nconst items = computed(() => flattenSlot(slots.default?.()))\n// `max: 0` means \"no limit\", as documented: a truthiness test, never `!= null`, which would\n// slice everything away and sum the whole group into the \"+X\" disc.\nconst visibleItems = computed(() => (props.max ? items.value.slice(0, props.max) : items.value))\nconst overflowCount = computed(() => items.value.length - visibleItems.value.length)\n\n// A functional component is the only way to render VNodes that have already been\n// captured: <component :is> expects a component definition, not a vnode.\nconst VisibleAvatars = () => visibleItems.value\n\nconst rootStyle = computed<StyleValue>(() =>\n props.ringColor !== undefined ? { '--avatar-ring-color': props.ringColor } : undefined,\n)\n\n// The group carries v-control so that --control-height is defined at ITS level,\n// which keeps the overlap computable even when a child is wrapped — a VTooltip, for\n// instance, inserts a <span> between the group and the VAvatar. An avatar given a\n// size of its own redefines --control-height on itself, so its own overlap follows\n// that size rather than the group's.\nconst resolvedGroupSize = computed<AvatarSize>(() => props.size ?? AVATAR_DEFAULT_SIZE)\n</script>\n\n<template>\n <div\n class=\"v-avatar-group v-control\"\n role=\"group\"\n :style=\"rootStyle\"\n :data-size=\"resolvedGroupSize\"\n :data-compact=\"compact ? '' : undefined\"\n >\n <component :is=\"VisibleAvatars\" />\n <slot v-if=\"overflowCount > 0\" name=\"overflow\" :count=\"overflowCount\">\n <VAvatar>+{{ overflowCount }}</VAvatar>\n </slot>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar-group {\n /* The separation ring, declared here so that every child .v-avatar inherits it. */\n --avatar-ring-color: var(--vectis-color-surface);\n display: inline-flex;\n align-items: center;\n }\n\n /* The overlap itself: each disc bites into the previous one by a fraction of its\n own height, and the DOM order is what makes the following one paint over it.\n The selector deliberately targets the direct child whatever it is — a bare\n VAvatar as well as a VTooltip wrapper — which is why --control-height has to\n come from the group; an avatar carrying its own size overrides it on itself.\n The ratio is unitless so it scales with whichever height applies. */\n .v-avatar-group > * + * {\n margin-inline-start: calc(var(--control-height) * -0.3);\n }\n\n /* On hover, or as soon as something inside it takes focus, a disc rises above its\n neighbours so it is seen whole rather than clipped by the next one. */\n .v-avatar-group > *:hover,\n .v-avatar-group > *:focus-within {\n z-index: 1;\n }\n}\n</style>\n"],"mappings":""}
@@ -1,6 +1,6 @@
1
- import { avatarGroupKey as e } from "./context.js";
2
- import t from "./VAvatar.js";
3
- import { flattenSlot as n } from "../../utils/vnode.js";
1
+ import { flattenSlot as e } from "../../utils/vnode.js";
2
+ import { avatarGroupKey as t } from "./context.js";
3
+ import n from "./VAvatar.js";
4
4
  import { computed as r, createBlock as i, createCommentVNode as a, createElementBlock as o, createTextVNode as s, createVNode as c, defineComponent as l, normalizeStyle as u, openBlock as d, provide as f, renderSlot as p, resolveDynamicComponent as m, toDisplayString as h, useSlots as g, withCtx as _ } from "vue";
5
5
  //#region src/components/VAvatar/VAvatarGroup.vue?vue&type=script&setup=true&lang.ts
6
6
  var v = ["data-size", "data-compact"], y = /*@__PURE__*/ l({
@@ -16,7 +16,7 @@ var v = ["data-size", "data-compact"], y = /*@__PURE__*/ l({
16
16
  },
17
17
  setup(l) {
18
18
  let y = l;
19
- f(e, {
19
+ f(t, {
20
20
  get size() {
21
21
  return y.size;
22
22
  },
@@ -24,14 +24,14 @@ var v = ["data-size", "data-compact"], y = /*@__PURE__*/ l({
24
24
  return y.compact;
25
25
  }
26
26
  });
27
- let b = g(), x = r(() => n(b.default?.())), S = r(() => y.max == null ? x.value : x.value.slice(0, y.max)), C = r(() => x.value.length - S.value.length), w = () => S.value, T = r(() => y.ringColor === void 0 ? void 0 : { "--avatar-ring-color": y.ringColor }), E = r(() => y.size ?? "md");
28
- return (e, n) => (d(), o("div", {
27
+ let b = g(), x = r(() => e(b.default?.())), S = r(() => y.max ? x.value.slice(0, y.max) : x.value), C = r(() => x.value.length - S.value.length), w = () => S.value, T = r(() => y.ringColor === void 0 ? void 0 : { "--avatar-ring-color": y.ringColor }), E = r(() => y.size ?? "md");
28
+ return (e, t) => (d(), o("div", {
29
29
  class: "v-avatar-group v-control",
30
30
  role: "group",
31
31
  style: u(T.value),
32
32
  "data-size": E.value,
33
33
  "data-compact": l.compact ? "" : void 0
34
- }, [(d(), i(m(w))), C.value > 0 ? p(e.$slots, "overflow", { count: C.value }, () => [c(t, null, {
34
+ }, [(d(), i(m(w))), C.value > 0 ? p(e.$slots, "overflow", { count: C.value }, () => [c(n, null, {
35
35
  default: _(() => [s("+" + h(C.value), 1)]),
36
36
  _: 1
37
37
  })], void 0, 0) : a("", !0)], 12, v));
@@ -1 +1 @@
1
- {"version":3,"file":"VAvatarGroup.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, provide, useSlots } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VAvatar from './VAvatar.vue'\nimport type { AvatarSize } from './VAvatar.vue'\nimport { avatarGroupKey } from './context'\n\nimport { flattenSlot } from '../../utils/vnode'\n\n// @ssr @core — the number of avatars is read from the slot's VNODES through\n// `flattenSlot`, never from a registry the children would fill at mount: such a\n// registry is empty during the server render and full on the client, which is a\n// hydration mismatch.\n/**\n * Stacks several VAvatars into an overlapping row, the usual way of showing the\n * members of a team or the participants in a conversation. Each disc bites into the\n * one before it and, coming later in the document, is painted over it: the\n * browser's own paint order does the work, no positioning code is involved. A ring\n * in `--avatar-ring-color` surrounds every disc so the overlapping edges stay\n * distinct from one another.\n *\n * Two things here do need JavaScript. Counting the avatars the group was given and\n * keeping only the first few, so that the rest can be summed up as a single \"+X\"\n * disc, is something neither HTML nor CSS can express. And the size and the density\n * chosen on the group are handed down to the avatars inside through Vue's\n * provide/inject.\n */\ninterface AvatarGroupProps {\n /**\n * How many avatars to show before the remaining ones are summed up as a single\n * \"+X\" disc. Left out, or set to 0, every avatar is shown.\n */\n max?: number\n /**\n * The size given to the avatars inside the group. An avatar that sets a `size`\n * of its own keeps it.\n */\n size?: AvatarSize\n /** Applies the reduced density to the avatars inside, on the same terms as `size`. */\n compact?: boolean\n /**\n * The colour of the ring drawn around each disc. It defaults to the page\n * background, which is what makes the ring read as a gap between two avatars.\n */\n ringColor?: string\n}\n\nconst props = withDefaults(defineProps<AvatarGroupProps>(), {\n max: undefined,\n size: undefined,\n compact: false,\n ringColor: undefined,\n})\n\ndefineSlots<{\n /** The VAvatars to stack. */\n default?(): unknown\n /**\n * Replaces the \"+X\" disc that stands for the avatars beyond `max`. It receives\n * `count`, the number of avatars being hidden.\n */\n overflow?(props: { count: number }): unknown\n}>()\n\nprovide(avatarGroupKey, {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n})\n\nconst slots = useSlots()\n\nconst items = computed(() => flattenSlot(slots.default?.()))\nconst visibleItems = computed(() =>\n props.max != null ? items.value.slice(0, props.max) : items.value,\n)\nconst overflowCount = computed(() => items.value.length - visibleItems.value.length)\n\n// A functional component is the only way to render VNodes that have already been\n// captured: <component :is> expects a component definition, not a vnode.\nconst VisibleAvatars = () => visibleItems.value\n\nconst rootStyle = computed<StyleValue>(() =>\n props.ringColor !== undefined ? { '--avatar-ring-color': props.ringColor } : undefined,\n)\n\n// The group carries v-control so that --control-height is defined at ITS level,\n// which keeps the overlap computable even when a child is wrapped — a VTooltip, for\n// instance, inserts a <span> between the group and the VAvatar. An avatar given a\n// size of its own redefines --control-height on itself, so its own overlap follows\n// that size rather than the group's.\nconst resolvedGroupSize = computed<AvatarSize>(() => props.size ?? 'md')\n</script>\n\n<template>\n <div\n class=\"v-avatar-group v-control\"\n role=\"group\"\n :style=\"rootStyle\"\n :data-size=\"resolvedGroupSize\"\n :data-compact=\"compact ? '' : undefined\"\n >\n <component :is=\"VisibleAvatars\" />\n <slot v-if=\"overflowCount > 0\" name=\"overflow\" :count=\"overflowCount\">\n <VAvatar>+{{ overflowCount }}</VAvatar>\n </slot>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar-group {\n /* The separation ring, declared here so that every child .v-avatar inherits it. */\n --avatar-ring-color: var(--vectis-color-surface);\n display: inline-flex;\n align-items: center;\n }\n\n /* The overlap itself: each disc bites into the previous one by a fraction of its\n own height, and the DOM order is what makes the following one paint over it.\n The selector deliberately targets the direct child whatever it is — a bare\n VAvatar as well as a VTooltip wrapper — which is why --control-height has to\n come from the group; an avatar carrying its own size overrides it on itself.\n The ratio is unitless so it scales with whichever height applies. */\n .v-avatar-group > * + * {\n margin-inline-start: calc(var(--control-height) * -0.3);\n }\n\n /* On hover, or as soon as something inside it takes focus, a disc rises above its\n neighbours so it is seen whole rather than clipped by the next one. */\n .v-avatar-group > *:hover,\n .v-avatar-group > *:focus-within {\n z-index: 1;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;EAgDA,IAAM,IAAQ;EAiBd,EAAQ,GAAgB;GACtB,IAAI,OAAO;IACT,OAAO,EAAM;GACf;GACA,IAAI,UAAU;IACZ,OAAO,EAAM;GACf;EACF,CAAC;EAED,IAAM,IAAQ,EAAS,GAEjB,IAAQ,QAAe,EAAY,EAAM,UAAU,CAAC,CAAC,GACrD,IAAe,QACnB,EAAM,OAAO,OAAyC,EAAM,QAAxC,EAAM,MAAM,MAAM,GAAG,EAAM,GAAG,CACpD,GACM,IAAgB,QAAe,EAAM,MAAM,SAAS,EAAa,MAAM,MAAM,GAI7E,UAAuB,EAAa,OAEpC,IAAY,QAChB,EAAM,cAAc,KAAA,IAAyD,KAAA,IAA7C,EAAE,uBAAuB,EAAM,UAAU,CAC3E,GAOM,IAAoB,QAA2B,EAAM,QAAQ,IAAI;yBAIrE,EAWM,OAAA;GAVJ,OAAM;GACN,MAAK;GACJ,OAAK,EAAE,EAAA,KAAS;GAChB,aAAW,EAAA;GACX,gBAAc,EAAA,UAAO,KAAQ,KAAA;YAE9B,EAAkC,EAAlB,CAAc,CAAA,IAClB,EAAA,QAAa,IAAzB,EAEO,EAAA,QAAA,YAAA,EAFyC,OAAO,EAAA,MAAa,SAE7D,CADL,EAAuC,GAAA,MAAA;oBAA7B,CAAA,EAAD,MAAC,EAAG,EAAA,KAAa,GAAA,CAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"VAvatarGroup.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/VAvatar/VAvatarGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @ssr @core — the number of avatars is read from the slot's VNODES through\n// `flattenSlot`, never from a registry the children would fill at mount: such a\n// registry is empty during the server render and full on the client, which is a\n// hydration mismatch.\n/**\n * Several VAvatars stacked into an overlapping row — a team, the participants in a\n * conversation. Each disc bites into the one before it and, coming later in the document, is\n * painted over it: the browser's paint order does the work, with no positioning code. A ring\n * in `--avatar-ring-color` keeps the overlapping edges distinct.\n *\n * Two things need JS. Counting the avatars given and keeping only the first few, so the rest\n * can be summed up as one \"+N\" disc, is expressible in neither HTML nor CSS — and the count\n * comes from the slot's VNODES, never a registry, which would render 0 on the server and N\n * in the browser. And the group's size and density reach the avatars through provide/inject.\n */\n\nimport { computed, provide, useSlots } from 'vue'\nimport type { StyleValue } from 'vue'\n\nimport VAvatar from './VAvatar.vue'\nimport type { AvatarSize } from './VAvatar.vue'\nimport { AVATAR_DEFAULT_SIZE, avatarGroupKey } from './context'\n\nimport { flattenSlot } from '../../utils/vnode'\n\ninterface AvatarGroupProps {\n /**\n * How many avatars to show before the remaining ones are summed up as a single\n * \"+X\" disc. Left out, or set to 0, every avatar is shown.\n */\n max?: number\n /**\n * The size given to the avatars inside the group. An avatar that sets a `size`\n * of its own keeps it.\n */\n size?: AvatarSize\n /**\n * Applies the reduced density to every avatar inside. Unlike `size` it is cumulative: an\n * avatar cannot opt back out of a compact group.\n */\n compact?: boolean\n /**\n * The colour of the ring drawn around each disc. It defaults to the page\n * background, which is what makes the ring read as a gap between two avatars.\n */\n ringColor?: string\n}\n\nconst props = withDefaults(defineProps<AvatarGroupProps>(), {\n max: undefined,\n size: undefined,\n compact: false,\n ringColor: undefined,\n})\n\ndefineSlots<{\n /** The VAvatars to stack. */\n default?(): unknown\n /**\n * Replaces the \"+X\" disc that stands for the avatars beyond `max`. It receives\n * `count`, the number of avatars being hidden.\n */\n overflow?(props: { count: number }): unknown\n}>()\n\nprovide(avatarGroupKey, {\n get size() {\n return props.size\n },\n get compact() {\n return props.compact\n },\n})\n\nconst slots = useSlots()\n\nconst items = computed(() => flattenSlot(slots.default?.()))\n// `max: 0` means \"no limit\", as documented: a truthiness test, never `!= null`, which would\n// slice everything away and sum the whole group into the \"+X\" disc.\nconst visibleItems = computed(() => (props.max ? items.value.slice(0, props.max) : items.value))\nconst overflowCount = computed(() => items.value.length - visibleItems.value.length)\n\n// A functional component is the only way to render VNodes that have already been\n// captured: <component :is> expects a component definition, not a vnode.\nconst VisibleAvatars = () => visibleItems.value\n\nconst rootStyle = computed<StyleValue>(() =>\n props.ringColor !== undefined ? { '--avatar-ring-color': props.ringColor } : undefined,\n)\n\n// The group carries v-control so that --control-height is defined at ITS level,\n// which keeps the overlap computable even when a child is wrapped — a VTooltip, for\n// instance, inserts a <span> between the group and the VAvatar. An avatar given a\n// size of its own redefines --control-height on itself, so its own overlap follows\n// that size rather than the group's.\nconst resolvedGroupSize = computed<AvatarSize>(() => props.size ?? AVATAR_DEFAULT_SIZE)\n</script>\n\n<template>\n <div\n class=\"v-avatar-group v-control\"\n role=\"group\"\n :style=\"rootStyle\"\n :data-size=\"resolvedGroupSize\"\n :data-compact=\"compact ? '' : undefined\"\n >\n <component :is=\"VisibleAvatars\" />\n <slot v-if=\"overflowCount > 0\" name=\"overflow\" :count=\"overflowCount\">\n <VAvatar>+{{ overflowCount }}</VAvatar>\n </slot>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-avatar-group {\n /* The separation ring, declared here so that every child .v-avatar inherits it. */\n --avatar-ring-color: var(--vectis-color-surface);\n display: inline-flex;\n align-items: center;\n }\n\n /* The overlap itself: each disc bites into the previous one by a fraction of its\n own height, and the DOM order is what makes the following one paint over it.\n The selector deliberately targets the direct child whatever it is — a bare\n VAvatar as well as a VTooltip wrapper — which is why --control-height has to\n come from the group; an avatar carrying its own size overrides it on itself.\n The ratio is unitless so it scales with whichever height applies. */\n .v-avatar-group > * + * {\n margin-inline-start: calc(var(--control-height) * -0.3);\n }\n\n /* On hover, or as soon as something inside it takes focus, a disc rises above its\n neighbours so it is seen whole rather than clipped by the next one. */\n .v-avatar-group > *:hover,\n .v-avatar-group > *:focus-within {\n z-index: 1;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;EAiDA,IAAM,IAAQ;EAiBd,EAAQ,GAAgB;GACtB,IAAI,OAAO;IACT,OAAO,EAAM;GACf;GACA,IAAI,UAAU;IACZ,OAAO,EAAM;GACf;EACF,CAAC;EAED,IAAM,IAAQ,EAAS,GAEjB,IAAQ,QAAe,EAAY,EAAM,UAAU,CAAC,CAAC,GAGrD,IAAe,QAAgB,EAAM,MAAM,EAAM,MAAM,MAAM,GAAG,EAAM,GAAG,IAAI,EAAM,KAAM,GACzF,IAAgB,QAAe,EAAM,MAAM,SAAS,EAAa,MAAM,MAAM,GAI7E,UAAuB,EAAa,OAEpC,IAAY,QAChB,EAAM,cAAc,KAAA,IAAyD,KAAA,IAA7C,EAAE,uBAAuB,EAAM,UAAU,CAC3E,GAOM,IAAoB,QAA2B,EAAM,QAAA,IAA2B;yBAIpF,EAWM,OAAA;GAVJ,OAAM;GACN,MAAK;GACJ,OAAK,EAAE,EAAA,KAAS;GAChB,aAAW,EAAA;GACX,gBAAc,EAAA,UAAO,KAAQ,KAAA;YAE9B,EAAkC,EAAlB,CAAc,CAAA,IAClB,EAAA,QAAa,IAAzB,EAEO,EAAA,QAAA,YAAA,EAFyC,OAAO,EAAA,MAAa,SAE7D,CADL,EAAuC,GAAA,MAAA;oBAA7B,CAAA,EAAD,MAAC,EAAG,EAAA,KAAa,GAAA,CAAA,CAAA,CAAA"}
@@ -1,17 +1,13 @@
1
1
  import { InjectionKey } from 'vue';
2
2
  import { AvatarSize } from './VAvatar.js';
3
- /**
4
- * This is what a VAvatarGroup passes down to the VAvatars it contains. Sizing a
5
- * row of avatars is a decision that belongs to the row, so the group announces
6
- * its size and its compact density once and every avatar inside picks them up,
7
- * instead of the writer repeating the same two props on each one.
8
- *
9
- * The values are only a fallback: an avatar that was given an explicit prop keeps
10
- * it, an avatar that was not takes the group's, and one that has neither falls
11
- * back to the default size (`props.size ?? group.size ?? 'md'`).
12
- */
13
3
  export interface AvatarGroupContext {
14
4
  size?: AvatarSize;
15
5
  compact?: boolean;
16
6
  }
7
+ /**
8
+ * The size of an avatar that neither names one nor sits in a group that does. VAvatar and
9
+ * VAvatarGroup both read it — the group sets `--control-height` at its own level, for the
10
+ * overlap — so the two cannot disagree on what an unsized avatar measures.
11
+ */
12
+ export declare const AVATAR_DEFAULT_SIZE: AvatarSize;
17
13
  export declare const avatarGroupKey: InjectionKey<AvatarGroupContext>;
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../../../src/components/VAvatar/context.ts"],"sourcesContent":["import type { InjectionKey } from 'vue'\n\nimport type { AvatarSize } from './VAvatar.vue'\n\n/**\n * This is what a VAvatarGroup passes down to the VAvatars it contains. Sizing a\n * row of avatars is a decision that belongs to the row, so the group announces\n * its size and its compact density once and every avatar inside picks them up,\n * instead of the writer repeating the same two props on each one.\n *\n * The values are only a fallback: an avatar that was given an explicit prop keeps\n * it, an avatar that was not takes the group's, and one that has neither falls\n * back to the default size (`props.size ?? group.size ?? 'md'`).\n */\nexport interface AvatarGroupContext {\n size?: AvatarSize\n compact?: boolean\n}\n\nexport const avatarGroupKey: InjectionKey<AvatarGroupContext> = Symbol('v-avatar-group')\n"],"mappings":";AAmBA,IAAa,IAAmD,OAAO,gBAAgB"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../../../src/components/VAvatar/context.ts"],"sourcesContent":["/**\n * This is what a VAvatarGroup passes down to the VAvatars it contains. Sizing a\n * row of avatars is a decision that belongs to the row, so the group announces\n * its size and its compact density once and every avatar inside picks them up,\n * instead of the writer repeating the same two props on each one.\n *\n * The two members are arbitrated differently, and on purpose:\n *\n * - `size` is a fallback: an avatar that was given an explicit size keeps it, one that was\n * not takes the group's, and one that has neither falls back to\n * `AVATAR_DEFAULT_SIZE` (`props.size ?? group.size ?? AVATAR_DEFAULT_SIZE`).\n * - `compact` is CUMULATIVE, the VButtonGroup `disabled` model (`props.compact ||\n * group.compact`): a compact group has no avatar that can opt back out, and one avatar\n * set compact in a regular group is compact alone. A boolean prop defaulting to `false`\n * has no way to say \"no opinion\", so a fallback could never let the avatar refuse.\n */\n\nimport type { InjectionKey } from 'vue'\n\nimport type { AvatarSize } from './VAvatar.vue'\n\nexport interface AvatarGroupContext {\n size?: AvatarSize\n compact?: boolean\n}\n\n/**\n * The size of an avatar that neither names one nor sits in a group that does. VAvatar and\n * VAvatarGroup both read it — the group sets `--control-height` at its own level, for the\n * overlap — so the two cannot disagree on what an unsized avatar measures.\n */\nexport const AVATAR_DEFAULT_SIZE: AvatarSize = 'md'\n\nexport const avatarGroupKey: InjectionKey<AvatarGroupContext> = Symbol('v-avatar-group')\n"],"mappings":";AAiCA,IAAa,IAAmD,OAAO,gBAAgB"}
@@ -1,2 +1,2 @@
1
1
  @layer vectis.reset, vectis.tokens, vectis.components, vectis.utilities;
2
- @layer vectis.components{.v-badge-host{align-items:center;gap:var(--vectis-space-2);display:inline-flex;position:relative}.v-badge{--vectis-icon-size:var(--vectis-icon-size-sm);--vectis-icon-opsz:20;height:var(--vectis-control-size-badge-h);min-width:var(--vectis-control-size-badge-h);padding-inline:var(--vectis-space-1);border-radius:var(--vectis-radius-pill);background:var(--badge-bg);font-family:var(--vectis-text-family);font-size:var(--vectis-text-caption-size);font-weight:var(--vectis-text-control-weight);line-height:var(--vectis-text-control-leading);color:var(--tone-text-fallback);justify-content:center;align-items:center;display:inline-flex}@supports (color:contrast-color(red)){.v-badge{color:contrast-color(var(--badge-bg))}}.v-badge[data-tone=accent]{--badge-bg:var(--vectis-color-accent);--tone-text-fallback:var(--vectis-color-text-on-accent)}.v-badge[data-tone=danger]{--badge-bg:var(--vectis-color-danger);--tone-text-fallback:var(--vectis-color-text-on-accent)}.v-badge[data-tone=success]{--badge-bg:var(--vectis-color-success);--tone-text-fallback:var(--vectis-color-text-on-accent)}.v-badge[data-tone=warning]{--badge-bg:var(--vectis-color-warning);--tone-text-fallback:var(--vectis-color-text-on-warning)}.v-badge[data-tone=neutral]{--badge-bg:var(--vectis-color-text);--tone-text-fallback:var(--vectis-color-surface)}.v-badge[data-custom]{--badge-bg:var(--custom-color);--tone-text-fallback:var(--vectis-color-text-on-accent)}.v-badge[data-icon-only]{padding:0}.v-badge[data-dot]{width:var(--vectis-control-size-badge-dot);height:var(--vectis-control-size-badge-dot);min-width:0;padding:0}.v-badge[data-bordered]{box-shadow:0 0 0 2px var(--vectis-color-surface)}.v-badge-host[data-overlay]>.v-badge{--badge-overlay-x:25%;--badge-overlay-y:-25%;translate:var(--badge-overlay-x) var(--badge-overlay-y);position:absolute;inset-block:0 auto;inset-inline-end:0}.v-badge-host[data-overlay][data-overlay-position=bottom]>.v-badge{--badge-overlay-y:25%;inset-block:auto 0}.v-badge-host[data-overlay]:dir(rtl)>.v-badge{--badge-overlay-x:-25%}}
2
+ @layer vectis.components{.v-badge-host{align-items:center;gap:var(--vectis-space-2);display:inline-flex;position:relative}.v-badge{--vectis-icon-size:var(--vectis-icon-size-sm);--vectis-icon-opsz:20;--badge-ring-color:var(--vectis-color-surface);--badge-bg:var(--tone-bg-solid);--badge-text-fallback:var(--tone-text-solid);height:var(--vectis-control-size-badge-h);min-width:var(--vectis-control-size-badge-h);padding-inline:var(--vectis-space-1);border-radius:var(--vectis-radius-pill);background:var(--badge-bg);font-family:var(--vectis-text-family);font-size:var(--vectis-text-caption-size);font-weight:var(--vectis-text-control-weight);line-height:var(--vectis-text-control-leading);color:var(--badge-text-fallback);justify-content:center;align-items:center;display:inline-flex}@supports (color:contrast-color(red)){.v-badge{color:contrast-color(var(--badge-bg))}}.v-badge[data-custom]{--badge-bg:var(--custom-color);--badge-text-fallback:var(--vectis-color-text-on-accent)}.v-badge[data-variant=soft]:not([data-dot]){--badge-bg:var(--tone-bg-soft);color:var(--tone-text-tinted)}.v-badge[data-variant=soft][data-custom]:not([data-dot]){--badge-bg:color-mix(in oklab, var(--custom-color), var(--vectis-color-surface) 85%);color:color-mix(in oklab, var(--custom-color), var(--vectis-color-text) 30%)}.v-badge[data-icon-only]{padding:0}.v-badge[data-dot]{width:var(--vectis-control-size-badge-dot);height:var(--vectis-control-size-badge-dot);min-width:0;padding:0}.v-badge[data-bordered]{box-shadow:0 0 0 var(--vectis-control-size-badge-ring) var(--badge-ring-color)}.v-badge-host[data-overlay]>.v-badge{--badge-overlay-x:25%;--badge-overlay-y:-25%;translate:var(--badge-overlay-x) var(--badge-overlay-y);z-index:1;position:absolute;inset-block:0 auto;inset-inline-end:0}.v-badge-host[data-overlay][data-overlay-position=bottom]>.v-badge{--badge-overlay-y:25%;inset-block:auto 0}.v-badge-host[data-overlay]:dir(rtl)>.v-badge{--badge-overlay-x:-25%}}
@@ -1,18 +1,27 @@
1
1
  import { IconSource } from '../VIcon/types.js';
2
+ export type BadgeVariant = 'solid' | 'soft';
2
3
  export type BadgeTone = 'neutral' | 'accent' | 'danger' | 'success' | 'warning';
3
4
  export type BadgeOverlayPosition = 'top' | 'bottom';
4
5
  interface BadgeProps {
5
6
  /**
6
- * The meaning the badge carries, expressed as a colour. The pill is filled with
7
- * it and the text adapts to stay readable; there is a single, fully coloured
8
- * rendering, so no variant to choose alongside it.
7
+ * How strongly the badge is painted: filled with the full colour (`solid`, the
8
+ * default), or a tinted background with the text in the colour (`soft`), for a
9
+ * count that should not draw the eye. A `dot` is always solid: with no content to
10
+ * tint, a soft dot would be a pale disc barely distinguishable from the page.
11
+ */
12
+ variant?: BadgeVariant;
13
+ /**
14
+ * The meaning the badge carries, expressed as a colour. A solid badge is filled
15
+ * with it and its text adapts to stay readable; a soft one is tinted with it and
16
+ * writes its text in it.
9
17
  */
10
18
  tone?: BadgeTone;
11
19
  /**
12
- * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. On
13
- * browsers that support `contrast-color()` the text turns black or white by
14
- * itself; everywhere else it falls back to white, so with a light colour the
15
- * contrast is yours to check.
20
+ * A colour of your own (hex, CSS name or `oklch()`), which replaces the tone. On a
21
+ * solid badge, browsers that support `contrast-color()` turn the text black or
22
+ * white by themselves; everywhere else it falls back to white, so with a light
23
+ * colour the contrast is yours to check. A soft badge derives its background and
24
+ * text from that colour mixed with the theme's surface and text.
16
25
  */
17
26
  color?: string;
18
27
  /**
@@ -44,11 +53,18 @@ interface BadgeProps {
44
53
  */
45
54
  overlayPosition?: BadgeOverlayPosition;
46
55
  /**
47
- * Draws a 2px ring in the colour of the surface behind the badge
48
- * (`--vectis-color-surface`, overridable per subtree), which detaches it from a
49
- * busy target such as a picture.
56
+ * Draws a 2px ring around the badge, in the colour of the surface behind it,
57
+ * which detaches it from a busy target such as a picture. That colour defaults to
58
+ * the page background and is named through `ringColor` on any other surface.
50
59
  */
51
60
  bordered?: boolean;
61
+ /**
62
+ * The colour of the ring drawn by `bordered`. It defaults to the page background,
63
+ * which is what makes the ring read as a gap around the badge; on another surface
64
+ * (a card, a coloured banner), pass that surface's colour. It does nothing without
65
+ * `bordered`.
66
+ */
67
+ ringColor?: string;
52
68
  }
53
69
  type __VLS_Slots = {
54
70
  /**
@@ -58,11 +74,16 @@ type __VLS_Slots = {
58
74
  default?(): unknown;
59
75
  };
60
76
  declare const __VLS_base: import('vue').DefineComponent<BadgeProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<BadgeProps> & Readonly<{}>, {
77
+ variant: BadgeVariant;
61
78
  tone: BadgeTone;
62
79
  icon: IconSource;
63
80
  color: string;
64
81
  count: number;
82
+ dot: boolean;
83
+ overlay: boolean;
65
84
  overlayPosition: BadgeOverlayPosition;
85
+ bordered: boolean;
86
+ ringColor: string;
66
87
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
67
88
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
68
89
  declare const _default: typeof __VLS_export;