vectis-ui 0.12.0 → 0.14.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 (519) hide show
  1. package/dist/components/VAccordion/VAccordion.css +1 -1
  2. package/dist/components/VAccordion/VAccordion.d.ts +6 -5
  3. package/dist/components/VAccordion/VAccordion.js.map +1 -1
  4. package/dist/components/VAccordion/VAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
  5. package/dist/components/VAccordion/VAccordionItem.css +1 -1
  6. package/dist/components/VAccordion/VAccordionItem.d.ts +1 -1
  7. package/dist/components/VAccordion/VAccordionItem.js.map +1 -1
  8. package/dist/components/VAccordion/VAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  9. package/dist/components/VAlert/VAlert.css +2 -0
  10. package/dist/components/VAlert/VAlert.d.ts +73 -0
  11. package/dist/components/VAlert/VAlert.js +9 -0
  12. package/dist/components/VAlert/VAlert.js.map +1 -0
  13. package/dist/components/VAlert/VAlert.vue_vue_type_script_setup_true_lang.js +96 -0
  14. package/dist/components/VAlert/VAlert.vue_vue_type_script_setup_true_lang.js.map +1 -0
  15. package/dist/components/VAvatar/VAvatar.d.ts +2 -2
  16. package/dist/components/VAvatar/VAvatarGroup.d.ts +1 -1
  17. package/dist/components/VAvatar/VAvatarGroup.vue_vue_type_script_setup_true_lang.js +8 -8
  18. package/dist/components/VBadge/VBadge.d.ts +3 -3
  19. package/dist/components/VBreadcrumb/VBreadcrumb.vue_vue_type_script_setup_true_lang.js +9 -9
  20. package/dist/components/VButton/VButton.d.ts +4 -4
  21. package/dist/components/VButton/VButtonGroup.css +1 -1
  22. package/dist/components/VButton/VButtonGroup.d.ts +2 -2
  23. package/dist/components/VButton/VButtonGroup.js.map +1 -1
  24. package/dist/components/VButton/VButtonGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  25. package/dist/components/VCalendar/VCalendar.css +1 -1
  26. package/dist/components/VCalendar/VCalendar.d.ts +7 -1
  27. package/dist/components/VCalendar/VCalendar.js.map +1 -1
  28. package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js +20 -18
  29. package/dist/components/VCalendar/VCalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  30. package/dist/components/VCalendar/VCalendarEvent.js.map +1 -1
  31. package/dist/components/VCalendar/VCalendarEvent.vue_vue_type_script_setup_true_lang.js.map +1 -1
  32. package/dist/components/VCalendar/VCalendarMonth.css +1 -1
  33. package/dist/components/VCalendar/VCalendarMonth.d.ts +2 -2
  34. package/dist/components/VCalendar/VCalendarMonth.js.map +1 -1
  35. package/dist/components/VCalendar/VCalendarMonth.vue_vue_type_script_setup_true_lang.js.map +1 -1
  36. package/dist/components/VCalendar/VCalendarTimeGrid.css +1 -1
  37. package/dist/components/VCalendar/VCalendarTimeGrid.d.ts +3 -3
  38. package/dist/components/VCalendar/VCalendarTimeGrid.js.map +1 -1
  39. package/dist/components/VCalendar/VCalendarTimeGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
  40. package/dist/components/VCalendar/VCalendarYear.css +1 -1
  41. package/dist/components/VCalendar/VCalendarYear.js.map +1 -1
  42. package/dist/components/VCalendar/VCalendarYear.vue_vue_type_script_setup_true_lang.js.map +1 -1
  43. package/dist/components/VCalendar/gesture.d.ts +1 -16
  44. package/dist/components/VCalendar/gesture.js +1 -1
  45. package/dist/components/VCalendar/gesture.js.map +1 -1
  46. package/dist/components/VCalendar/types.d.ts +2 -0
  47. package/dist/components/VCard/VCard.css +2 -0
  48. package/dist/components/VCard/VCard.d.ts +87 -0
  49. package/dist/components/VCard/VCard.js +9 -0
  50. package/dist/components/VCard/VCard.js.map +1 -0
  51. package/dist/components/VCard/VCard.vue_vue_type_script_setup_true_lang.js +103 -0
  52. package/dist/components/VCard/VCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  53. package/dist/components/VCarousel/VCarousel.d.ts +1 -1
  54. package/dist/components/VCarousel/VCarousel.js.map +1 -1
  55. package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js +18 -18
  56. package/dist/components/VCarousel/VCarousel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  57. package/dist/components/VCheckbox/VCheckMark.css +2 -0
  58. package/dist/components/VCheckbox/VCheckMark.js +9 -0
  59. package/dist/components/VCheckbox/VCheckMark.js.map +1 -0
  60. package/dist/components/VCheckbox/VCheckMark.vue_vue_type_script_setup_true_lang.js +33 -0
  61. package/dist/components/VCheckbox/VCheckMark.vue_vue_type_script_setup_true_lang.js.map +1 -0
  62. package/dist/components/VCheckbox/VCheckbox.css +1 -1
  63. package/dist/components/VCheckbox/VCheckbox.d.ts +8 -3
  64. package/dist/components/VCheckbox/VCheckbox.js.map +1 -1
  65. package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js +54 -69
  66. package/dist/components/VCheckbox/VCheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  67. package/dist/components/VChip/VChip.d.ts +6 -6
  68. package/dist/components/VChip/VChip.js.map +1 -1
  69. package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js +26 -26
  70. package/dist/components/VChip/VChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  71. package/dist/components/VColorInput/VColorInput.css +2 -0
  72. package/dist/components/VColorInput/VColorInput.d.ts +113 -0
  73. package/dist/components/VColorInput/VColorInput.js +9 -0
  74. package/dist/components/VColorInput/VColorInput.js.map +1 -0
  75. package/dist/components/VColorInput/VColorInput.vue_vue_type_script_setup_true_lang.js +230 -0
  76. package/dist/components/VColorInput/VColorInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
  77. package/dist/components/VColorPicker/VColorPicker.css +2 -0
  78. package/dist/components/VColorPicker/VColorPicker.d.ts +67 -0
  79. package/dist/components/VColorPicker/VColorPicker.js +9 -0
  80. package/dist/components/VColorPicker/VColorPicker.js.map +1 -0
  81. package/dist/components/VColorPicker/VColorPicker.vue_vue_type_script_setup_true_lang.js +390 -0
  82. package/dist/components/VColorPicker/VColorPicker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  83. package/dist/components/VColorPicker/color.d.ts +42 -0
  84. package/dist/components/VColorPicker/color.js +158 -0
  85. package/dist/components/VColorPicker/color.js.map +1 -0
  86. package/dist/components/VCombobox/VCombobox.css +1 -1
  87. package/dist/components/VCombobox/VCombobox.d.ts +46 -60
  88. package/dist/components/VCombobox/VCombobox.js.map +1 -1
  89. package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js +271 -372
  90. package/dist/components/VCombobox/VCombobox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  91. package/dist/components/VCommandPalette/VCommandPalette.css +2 -0
  92. package/dist/components/VCommandPalette/VCommandPalette.d.ts +163 -0
  93. package/dist/components/VCommandPalette/VCommandPalette.js +9 -0
  94. package/dist/components/VCommandPalette/VCommandPalette.js.map +1 -0
  95. package/dist/components/VCommandPalette/VCommandPalette.vue_vue_type_script_setup_true_lang.js +321 -0
  96. package/dist/components/VCommandPalette/VCommandPalette.vue_vue_type_script_setup_true_lang.js.map +1 -0
  97. package/dist/components/VCommandPalette/VCommandPaletteItem.css +2 -0
  98. package/dist/components/VCommandPalette/VCommandPaletteItem.d.ts +38 -0
  99. package/dist/components/VCommandPalette/VCommandPaletteItem.js +9 -0
  100. package/dist/components/VCommandPalette/VCommandPaletteItem.js.map +1 -0
  101. package/dist/components/VCommandPalette/VCommandPaletteItem.vue_vue_type_script_setup_true_lang.js +69 -0
  102. package/dist/components/VCommandPalette/VCommandPaletteItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
  103. package/dist/components/VContextMenu/VContextMenu.css +2 -0
  104. package/dist/components/VContextMenu/VContextMenu.d.ts +66 -0
  105. package/dist/components/VContextMenu/VContextMenu.js +9 -0
  106. package/dist/components/VContextMenu/VContextMenu.js.map +1 -0
  107. package/dist/components/VContextMenu/VContextMenu.vue_vue_type_script_setup_true_lang.js +148 -0
  108. package/dist/components/VContextMenu/VContextMenu.vue_vue_type_script_setup_true_lang.js.map +1 -0
  109. package/dist/components/VDataTable/VDataTable.css +1 -1
  110. package/dist/components/VDataTable/VDataTable.d.ts +41 -16
  111. package/dist/components/VDataTable/VDataTable.js.map +1 -1
  112. package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js +307 -194
  113. package/dist/components/VDataTable/VDataTable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  114. package/dist/components/VDateInput/VDateInput.d.ts +27 -7
  115. package/dist/components/VDateInput/VDateInput.js.map +1 -1
  116. package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js +170 -162
  117. package/dist/components/VDateInput/VDateInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  118. package/dist/components/VDatePicker/VDatePicker.d.ts +3 -3
  119. package/dist/components/VDatePicker/VDatePicker.js.map +1 -1
  120. package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js +228 -227
  121. package/dist/components/VDatePicker/VDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  122. package/dist/components/VDatePicker/keyboard.d.ts +7 -7
  123. package/dist/components/VDatePicker/keyboard.js +8 -6
  124. package/dist/components/VDatePicker/keyboard.js.map +1 -1
  125. package/dist/components/VDatePicker/names.js +16 -20
  126. package/dist/components/VDatePicker/names.js.map +1 -1
  127. package/dist/components/VDialog/VDialog.d.ts +2 -4
  128. package/dist/components/VDialog/VDialog.js.map +1 -1
  129. package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js +46 -77
  130. package/dist/components/VDialog/VDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  131. package/dist/components/VDrawer/VDrawer.css +2 -0
  132. package/dist/components/VDrawer/VDrawer.d.ts +102 -0
  133. package/dist/components/VDrawer/VDrawer.js +9 -0
  134. package/dist/components/VDrawer/VDrawer.js.map +1 -0
  135. package/dist/components/VDrawer/VDrawer.vue_vue_type_script_setup_true_lang.js +128 -0
  136. package/dist/components/VDrawer/VDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  137. package/dist/components/VEmptyState/VEmptyState.css +2 -0
  138. package/dist/components/VEmptyState/VEmptyState.d.ts +43 -0
  139. package/dist/components/VEmptyState/VEmptyState.js +9 -0
  140. package/dist/components/VEmptyState/VEmptyState.js.map +1 -0
  141. package/dist/components/VEmptyState/VEmptyState.vue_vue_type_script_setup_true_lang.js +48 -0
  142. package/dist/components/VEmptyState/VEmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -0
  143. package/dist/components/VField/VField.css +2 -0
  144. package/dist/components/VField/VField.d.ts +84 -0
  145. package/dist/components/VField/VField.js +9 -0
  146. package/dist/components/VField/VField.js.map +1 -0
  147. package/dist/components/VField/VField.vue_vue_type_script_setup_true_lang.js +99 -0
  148. package/dist/components/VField/VField.vue_vue_type_script_setup_true_lang.js.map +1 -0
  149. package/dist/components/VField/VFieldAnnouncer.d.ts +7 -0
  150. package/dist/components/VField/VFieldAnnouncer.js +7 -0
  151. package/dist/components/VField/VFieldAnnouncer.js.map +1 -0
  152. package/dist/components/VField/VFieldAnnouncer.vue_vue_type_script_setup_true_lang.js +19 -0
  153. package/dist/components/VField/VFieldAnnouncer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  154. package/dist/components/VField/VFieldMessage.d.ts +11 -0
  155. package/dist/components/VField/VFieldMessage.js +7 -0
  156. package/dist/components/VField/VFieldMessage.js.map +1 -0
  157. package/dist/components/VField/VFieldMessage.vue_vue_type_script_setup_true_lang.js +32 -0
  158. package/dist/components/VField/VFieldMessage.vue_vue_type_script_setup_true_lang.js.map +1 -0
  159. package/dist/components/VFieldset/VFieldset.css +2 -0
  160. package/dist/components/VFieldset/VFieldset.d.ts +52 -0
  161. package/dist/components/VFieldset/VFieldset.js +9 -0
  162. package/dist/components/VFieldset/VFieldset.js.map +1 -0
  163. package/dist/components/VFieldset/VFieldset.vue_vue_type_script_setup_true_lang.js +63 -0
  164. package/dist/components/VFieldset/VFieldset.vue_vue_type_script_setup_true_lang.js.map +1 -0
  165. package/dist/components/VFileInput/VFileInput.css +1 -1
  166. package/dist/components/VFileInput/VFileInput.d.ts +31 -7
  167. package/dist/components/VFileInput/VFileInput.js.map +1 -1
  168. package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js +168 -161
  169. package/dist/components/VFileInput/VFileInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  170. package/dist/components/VFilePicker/VFilePicker.d.ts +4 -4
  171. package/dist/components/VHotkeys/VHotkeys.css +1 -1
  172. package/dist/components/VHotkeys/VHotkeys.js.map +1 -1
  173. package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js +27 -30
  174. package/dist/components/VHotkeys/VHotkeys.vue_vue_type_script_setup_true_lang.js.map +1 -1
  175. package/dist/components/VHotkeys/platform.d.ts +2 -0
  176. package/dist/components/VHotkeys/platform.js +24 -5
  177. package/dist/components/VHotkeys/platform.js.map +1 -1
  178. package/dist/components/VHoverCard/VHoverCard.css +2 -0
  179. package/dist/components/VHoverCard/VHoverCard.d.ts +62 -0
  180. package/dist/components/VHoverCard/VHoverCard.js +9 -0
  181. package/dist/components/VHoverCard/VHoverCard.js.map +1 -0
  182. package/dist/components/VHoverCard/VHoverCard.vue_vue_type_script_setup_true_lang.js +97 -0
  183. package/dist/components/VHoverCard/VHoverCard.vue_vue_type_script_setup_true_lang.js.map +1 -0
  184. package/dist/components/VIcon/icons/add.d.ts +5 -0
  185. package/dist/components/VIcon/icons/add.js +9 -0
  186. package/dist/components/VIcon/icons/add.js.map +1 -0
  187. package/dist/components/VIcon/icons/colorize.d.ts +5 -0
  188. package/dist/components/VIcon/icons/colorize.js +9 -0
  189. package/dist/components/VIcon/icons/colorize.js.map +1 -0
  190. package/dist/components/VIcon/icons/inbox.d.ts +5 -0
  191. package/dist/components/VIcon/icons/inbox.js +9 -0
  192. package/dist/components/VIcon/icons/inbox.js.map +1 -0
  193. package/dist/components/VIcon/icons/index.d.ts +42 -2
  194. package/dist/components/VIcon/icons/index.js +88 -72
  195. package/dist/components/VIcon/icons/index.js.map +1 -1
  196. package/dist/components/VIcon/icons/names.d.ts +2 -2
  197. package/dist/components/VIcon/icons/names.js +1 -1
  198. package/dist/components/VIcon/icons/names.js.map +1 -1
  199. package/dist/components/VIcon/icons/open_in_new.d.ts +5 -0
  200. package/dist/components/VIcon/icons/open_in_new.js +9 -0
  201. package/dist/components/VIcon/icons/open_in_new.js.map +1 -0
  202. package/dist/components/VIcon/icons/priority_high.d.ts +5 -0
  203. package/dist/components/VIcon/icons/priority_high.js +9 -0
  204. package/dist/components/VIcon/icons/priority_high.js.map +1 -0
  205. package/dist/components/VIcon/icons/remove.d.ts +5 -0
  206. package/dist/components/VIcon/icons/remove.js +9 -0
  207. package/dist/components/VIcon/icons/remove.js.map +1 -0
  208. package/dist/components/VIcon/icons/search_off.d.ts +5 -0
  209. package/dist/components/VIcon/icons/search_off.js +9 -0
  210. package/dist/components/VIcon/icons/search_off.js.map +1 -0
  211. package/dist/components/VIcon/icons/star.d.ts +5 -0
  212. package/dist/components/VIcon/icons/star.js +9 -0
  213. package/dist/components/VIcon/icons/star.js.map +1 -0
  214. package/dist/components/VIconButton/VIconButton.d.ts +4 -4
  215. package/dist/components/VInput/VInput.css +1 -1
  216. package/dist/components/VInput/VInput.d.ts +51 -2
  217. package/dist/components/VInput/VInput.js.map +1 -1
  218. package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js +129 -106
  219. package/dist/components/VInput/VInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  220. package/dist/components/VInput/VInputGroup.css +1 -1
  221. package/dist/components/VInput/VInputGroup.d.ts +20 -0
  222. package/dist/components/VInput/VInputGroup.js.map +1 -1
  223. package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js +50 -51
  224. package/dist/components/VInput/VInputGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
  225. package/dist/components/VInputOTP/VInputOTP.css +1 -1
  226. package/dist/components/VInputOTP/VInputOTP.d.ts +27 -4
  227. package/dist/components/VInputOTP/VInputOTP.js.map +1 -1
  228. package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js +131 -113
  229. package/dist/components/VInputOTP/VInputOTP.vue_vue_type_script_setup_true_lang.js.map +1 -1
  230. package/dist/components/VLink/VLink.css +2 -0
  231. package/dist/components/VLink/VLink.d.ts +53 -0
  232. package/dist/components/VLink/VLink.js +9 -0
  233. package/dist/components/VLink/VLink.js.map +1 -0
  234. package/dist/components/VLink/VLink.vue_vue_type_script_setup_true_lang.js +58 -0
  235. package/dist/components/VLink/VLink.vue_vue_type_script_setup_true_lang.js.map +1 -0
  236. package/dist/components/VListbox/VListboxChevron.css +2 -0
  237. package/dist/components/VListbox/VListboxChevron.d.ts +12 -0
  238. package/dist/components/VListbox/VListboxChevron.js +9 -0
  239. package/dist/components/VListbox/VListboxChevron.js.map +1 -0
  240. package/dist/components/VListbox/VListboxChevron.vue_vue_type_script_setup_true_lang.js +25 -0
  241. package/dist/components/VListbox/VListboxChevron.vue_vue_type_script_setup_true_lang.js.map +1 -0
  242. package/dist/components/VListbox/VListboxGroup.css +2 -0
  243. package/dist/components/VListbox/VListboxGroup.d.ts +27 -0
  244. package/dist/components/VListbox/VListboxGroup.js +9 -0
  245. package/dist/components/VListbox/VListboxGroup.js.map +1 -0
  246. package/dist/components/VListbox/VListboxGroup.vue_vue_type_script_setup_true_lang.js +21 -0
  247. package/dist/components/VListbox/VListboxGroup.vue_vue_type_script_setup_true_lang.js.map +1 -0
  248. package/dist/components/VListbox/VListboxOption.css +2 -0
  249. package/dist/components/{VCombobox/VComboboxOption.d.ts → VListbox/VListboxOption.d.ts} +4 -4
  250. package/dist/components/VListbox/VListboxOption.js +9 -0
  251. package/dist/components/VListbox/VListboxOption.js.map +1 -0
  252. package/dist/components/{VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js → VListbox/VListboxOption.vue_vue_type_script_setup_true_lang.js} +6 -6
  253. package/dist/components/VListbox/VListboxOption.vue_vue_type_script_setup_true_lang.js.map +1 -0
  254. package/dist/components/VListbox/VListboxPanel.css +2 -0
  255. package/dist/components/VListbox/VListboxPanel.d.ts +59 -0
  256. package/dist/components/VListbox/VListboxPanel.js +9 -0
  257. package/dist/components/VListbox/VListboxPanel.js.map +1 -0
  258. package/dist/components/VListbox/VListboxPanel.vue_vue_type_script_setup_true_lang.js +123 -0
  259. package/dist/components/VListbox/VListboxPanel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  260. package/dist/components/VListbox/VListboxSeparator.css +2 -0
  261. package/dist/components/VListbox/VListboxSeparator.d.ts +3 -0
  262. package/dist/components/VListbox/VListboxSeparator.js +9 -0
  263. package/dist/components/VListbox/VListboxSeparator.js.map +1 -0
  264. package/dist/components/{VCombobox/VComboboxSeparator.vue_vue_type_script_setup_true_lang.js → VListbox/VListboxSeparator.vue_vue_type_script_setup_true_lang.js} +4 -4
  265. package/dist/components/VListbox/VListboxSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -0
  266. package/dist/components/VListbox/VListboxValues.css +2 -0
  267. package/dist/components/VListbox/VListboxValues.d.ts +52 -0
  268. package/dist/components/VListbox/VListboxValues.js +9 -0
  269. package/dist/components/VListbox/VListboxValues.js.map +1 -0
  270. package/dist/components/VListbox/VListboxValues.vue_vue_type_script_setup_true_lang.js +103 -0
  271. package/dist/components/VListbox/VListboxValues.vue_vue_type_script_setup_true_lang.js.map +1 -0
  272. package/dist/components/VMenu/VMenu.d.ts +1 -1
  273. package/dist/components/VMenu/VMenu.vue_vue_type_script_setup_true_lang.js +9 -9
  274. package/dist/components/VMenu/VMenuItem.d.ts +1 -1
  275. package/dist/components/VMenu/VMenuItem.vue_vue_type_script_setup_true_lang.js +16 -16
  276. package/dist/components/VMenu/VMenuPanel.d.ts +2 -2
  277. package/dist/components/VMenu/VMenuPanel.js.map +1 -1
  278. package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js +7 -7
  279. package/dist/components/VMenu/VMenuPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
  280. package/dist/components/VMeter/VMeter.css +2 -0
  281. package/dist/components/VMeter/VMeter.d.ts +77 -0
  282. package/dist/components/VMeter/VMeter.js +9 -0
  283. package/dist/components/VMeter/VMeter.js.map +1 -0
  284. package/dist/components/VMeter/VMeter.vue_vue_type_script_setup_true_lang.js +113 -0
  285. package/dist/components/VMeter/VMeter.vue_vue_type_script_setup_true_lang.js.map +1 -0
  286. package/dist/components/VNumberInput/VNumberInput.css +2 -0
  287. package/dist/components/VNumberInput/VNumberInput.d.ts +114 -0
  288. package/dist/components/VNumberInput/VNumberInput.js +9 -0
  289. package/dist/components/VNumberInput/VNumberInput.js.map +1 -0
  290. package/dist/components/VNumberInput/VNumberInput.vue_vue_type_script_setup_true_lang.js +251 -0
  291. package/dist/components/VNumberInput/VNumberInput.vue_vue_type_script_setup_true_lang.js.map +1 -0
  292. package/dist/components/VNumberInput/number.d.ts +30 -0
  293. package/dist/components/VNumberInput/number.js +38 -0
  294. package/dist/components/VNumberInput/number.js.map +1 -0
  295. package/dist/components/VPagination/VPagination.d.ts +1 -1
  296. package/dist/components/VPagination/VPagination.js.map +1 -1
  297. package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js +77 -77
  298. package/dist/components/VPagination/VPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  299. package/dist/components/VProgressCircular/VProgressCircular.d.ts +2 -2
  300. package/dist/components/VProgressLinear/VProgressLinear.css +1 -1
  301. package/dist/components/VProgressLinear/VProgressLinear.d.ts +10 -7
  302. package/dist/components/VProgressLinear/VProgressLinear.js.map +1 -1
  303. package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js +52 -34
  304. package/dist/components/VProgressLinear/VProgressLinear.vue_vue_type_script_setup_true_lang.js.map +1 -1
  305. package/dist/components/VRadio/VRadio.d.ts +8 -3
  306. package/dist/components/VRadio/VRadio.js.map +1 -1
  307. package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js +52 -46
  308. package/dist/components/VRadio/VRadio.vue_vue_type_script_setup_true_lang.js.map +1 -1
  309. package/dist/components/VRating/VRating.css +2 -0
  310. package/dist/components/VRating/VRating.d.ts +92 -0
  311. package/dist/components/VRating/VRating.js +9 -0
  312. package/dist/components/VRating/VRating.js.map +1 -0
  313. package/dist/components/VRating/VRating.vue_vue_type_script_setup_true_lang.js +158 -0
  314. package/dist/components/VRating/VRating.vue_vue_type_script_setup_true_lang.js.map +1 -0
  315. package/dist/components/VResizable/VResizable.css +2 -0
  316. package/dist/components/VResizable/VResizable.d.ts +50 -0
  317. package/dist/components/VResizable/VResizable.js +9 -0
  318. package/dist/components/VResizable/VResizable.js.map +1 -0
  319. package/dist/components/VResizable/VResizable.vue_vue_type_script_setup_true_lang.js +225 -0
  320. package/dist/components/VResizable/VResizable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  321. package/dist/components/VResizable/VResizablePanel.css +2 -0
  322. package/dist/components/VResizable/VResizablePanel.d.ts +60 -0
  323. package/dist/components/VResizable/VResizablePanel.js +9 -0
  324. package/dist/components/VResizable/VResizablePanel.js.map +1 -0
  325. package/dist/components/VResizable/VResizablePanel.vue_vue_type_script_setup_true_lang.js +83 -0
  326. package/dist/components/VResizable/VResizablePanel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  327. package/dist/components/VResizable/context.d.ts +24 -0
  328. package/dist/components/VResizable/context.js +6 -0
  329. package/dist/components/VResizable/context.js.map +1 -0
  330. package/dist/components/VResizable/layout.d.ts +28 -0
  331. package/dist/components/VResizable/layout.js +41 -0
  332. package/dist/components/VResizable/layout.js.map +1 -0
  333. package/dist/components/VSelect/VSelect.css +2 -0
  334. package/dist/components/VSelect/VSelect.d.ts +193 -0
  335. package/dist/components/VSelect/VSelect.js +9 -0
  336. package/dist/components/VSelect/VSelect.js.map +1 -0
  337. package/dist/components/VSelect/VSelect.vue_vue_type_script_setup_true_lang.js +418 -0
  338. package/dist/components/VSelect/VSelect.vue_vue_type_script_setup_true_lang.js.map +1 -0
  339. package/dist/components/VSeparator/VSeparator.js.map +1 -1
  340. package/dist/components/VSeparator/VSeparator.vue_vue_type_script_setup_true_lang.js.map +1 -1
  341. package/dist/components/VSideNavigation/VSideNavigation.vue_vue_type_script_setup_true_lang.js +8 -8
  342. package/dist/components/VSideNavigation/VSideNavigationItem.d.ts +2 -2
  343. package/dist/components/VSideNavigation/VSideNavigationItem.js.map +1 -1
  344. package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js +3 -3
  345. package/dist/components/VSideNavigation/VSideNavigationItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  346. package/dist/components/VSkeletonLoader/VSkeletonLoader.d.ts +3 -3
  347. package/dist/components/VSlider/VSlider.css +1 -1
  348. package/dist/components/VSlider/VSlider.d.ts +34 -8
  349. package/dist/components/VSlider/VSlider.js.map +1 -1
  350. package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js +236 -215
  351. package/dist/components/VSlider/VSlider.vue_vue_type_script_setup_true_lang.js.map +1 -1
  352. package/dist/components/VSnackbar/VSnackbar.vue_vue_type_script_setup_true_lang.js +4 -4
  353. package/dist/components/VSnackbar/state.js.map +1 -1
  354. package/dist/components/VSplitButton/VSplitButton.css +2 -0
  355. package/dist/components/VSplitButton/VSplitButton.d.ts +114 -0
  356. package/dist/components/VSplitButton/VSplitButton.js +9 -0
  357. package/dist/components/VSplitButton/VSplitButton.js.map +1 -0
  358. package/dist/components/VSplitButton/VSplitButton.vue_vue_type_script_setup_true_lang.js +148 -0
  359. package/dist/components/VSplitButton/VSplitButton.vue_vue_type_script_setup_true_lang.js.map +1 -0
  360. package/dist/components/VStepper/VStepper.css +2 -0
  361. package/dist/components/VStepper/VStepper.d.ts +73 -0
  362. package/dist/components/VStepper/VStepper.js +9 -0
  363. package/dist/components/VStepper/VStepper.js.map +1 -0
  364. package/dist/components/VStepper/VStepper.vue_vue_type_script_setup_true_lang.js +96 -0
  365. package/dist/components/VStepper/VStepper.vue_vue_type_script_setup_true_lang.js.map +1 -0
  366. package/dist/components/VSwitch/VSwitch.d.ts +8 -3
  367. package/dist/components/VSwitch/VSwitch.js.map +1 -1
  368. package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js +53 -47
  369. package/dist/components/VSwitch/VSwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  370. package/dist/components/VTabs/VTab.css +1 -1
  371. package/dist/components/VTabs/VTab.d.ts +1 -1
  372. package/dist/components/VTabs/VTab.js.map +1 -1
  373. package/dist/components/VTabs/VTab.vue_vue_type_script_setup_true_lang.js.map +1 -1
  374. package/dist/components/VTabs/VTabs.css +1 -1
  375. package/dist/components/VTabs/VTabs.d.ts +13 -5
  376. package/dist/components/VTabs/VTabs.js.map +1 -1
  377. package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js +20 -20
  378. package/dist/components/VTabs/VTabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  379. package/dist/components/VTextarea/VTextarea.css +1 -1
  380. package/dist/components/VTextarea/VTextarea.d.ts +22 -2
  381. package/dist/components/VTextarea/VTextarea.js.map +1 -1
  382. package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js +108 -100
  383. package/dist/components/VTextarea/VTextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  384. package/dist/components/VTimeInput/VTimeInput.d.ts +27 -7
  385. package/dist/components/VTimeInput/VTimeInput.js.map +1 -1
  386. package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js +187 -171
  387. package/dist/components/VTimeInput/VTimeInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  388. package/dist/components/VTimePicker/VTimePicker.d.ts +2 -2
  389. package/dist/components/VTimePicker/VTimePicker.js.map +1 -1
  390. package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js +16 -16
  391. package/dist/components/VTimePicker/VTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  392. package/dist/components/VTimeline/VTimeline.css +2 -0
  393. package/dist/components/VTimeline/VTimeline.d.ts +59 -0
  394. package/dist/components/VTimeline/VTimeline.js +9 -0
  395. package/dist/components/VTimeline/VTimeline.js.map +1 -0
  396. package/dist/components/VTimeline/VTimeline.vue_vue_type_script_setup_true_lang.js +53 -0
  397. package/dist/components/VTimeline/VTimeline.vue_vue_type_script_setup_true_lang.js.map +1 -0
  398. package/dist/components/VTimeline/VTimelineItem.css +2 -0
  399. package/dist/components/VTimeline/VTimelineItem.d.ts +48 -0
  400. package/dist/components/VTimeline/VTimelineItem.js +9 -0
  401. package/dist/components/VTimeline/VTimelineItem.js.map +1 -0
  402. package/dist/components/VTimeline/VTimelineItem.vue_vue_type_script_setup_true_lang.js +70 -0
  403. package/dist/components/VTimeline/VTimelineItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
  404. package/dist/components/VTimeline/context.d.ts +11 -0
  405. package/dist/components/VTimeline/context.js +6 -0
  406. package/dist/components/VTimeline/context.js.map +1 -0
  407. package/dist/components/VTimeline/datetime.d.ts +8 -0
  408. package/dist/components/VTimeline/datetime.js +36 -0
  409. package/dist/components/VTimeline/datetime.js.map +1 -0
  410. package/dist/components/VToast/VToast.vue_vue_type_script_setup_true_lang.js +8 -8
  411. package/dist/components/VToast/VToaster.vue_vue_type_script_setup_true_lang.js +12 -12
  412. package/dist/components/VToggle/VToggle.d.ts +4 -4
  413. package/dist/components/VToggle/VToggle.js.map +1 -1
  414. package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js +1 -1
  415. package/dist/components/VToggle/VToggle.vue_vue_type_script_setup_true_lang.js.map +1 -1
  416. package/dist/components/VToggle/VToggleItem.d.ts +1 -1
  417. package/dist/components/VTooltip/VTooltip.d.ts +8 -2
  418. package/dist/components/VTooltip/VTooltip.js.map +1 -1
  419. package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js +45 -43
  420. package/dist/components/VTooltip/VTooltip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  421. package/dist/components/VTreeView/VTreeView.css +2 -0
  422. package/dist/components/VTreeView/VTreeView.d.ts +112 -0
  423. package/dist/components/VTreeView/VTreeView.js +9 -0
  424. package/dist/components/VTreeView/VTreeView.js.map +1 -0
  425. package/dist/components/VTreeView/VTreeView.vue_vue_type_script_setup_true_lang.js +317 -0
  426. package/dist/components/VTreeView/VTreeView.vue_vue_type_script_setup_true_lang.js.map +1 -0
  427. package/dist/components/VTypography/VTypography.d.ts +1 -1
  428. package/dist/components/VVirtualList/VVirtualList.css +2 -0
  429. package/dist/components/VVirtualList/VVirtualList.d.ts +78 -0
  430. package/dist/components/VVirtualList/VVirtualList.js +9 -0
  431. package/dist/components/VVirtualList/VVirtualList.js.map +1 -0
  432. package/dist/components/VVirtualList/VVirtualList.vue_vue_type_script_setup_true_lang.js +114 -0
  433. package/dist/components/VVirtualList/VVirtualList.vue_vue_type_script_setup_true_lang.js.map +1 -0
  434. package/dist/composables/useChoice.d.ts +28 -0
  435. package/dist/composables/useChoice.js +28 -0
  436. package/dist/composables/useChoice.js.map +1 -0
  437. package/dist/composables/useDebouncedSearch.d.ts +17 -0
  438. package/dist/composables/useDebouncedSearch.js +18 -0
  439. package/dist/composables/useDebouncedSearch.js.map +1 -0
  440. package/dist/composables/useEscapeDismiss.d.ts +8 -0
  441. package/dist/composables/useEscapeDismiss.js +16 -0
  442. package/dist/composables/useEscapeDismiss.js.map +1 -0
  443. package/dist/composables/useFieldIds.d.ts +2 -1
  444. package/dist/composables/useFieldIds.js +7 -6
  445. package/dist/composables/useFieldIds.js.map +1 -1
  446. package/dist/composables/useFieldPanel.d.ts +1 -0
  447. package/dist/composables/useFieldPanel.js +52 -42
  448. package/dist/composables/useFieldPanel.js.map +1 -1
  449. package/dist/composables/useFileField.d.ts +1 -3
  450. package/dist/composables/useFileField.js +48 -50
  451. package/dist/composables/useFileField.js.map +1 -1
  452. package/dist/composables/useHotkeyListener.d.ts +17 -0
  453. package/dist/composables/useHotkeyListener.js +29 -0
  454. package/dist/composables/useHotkeyListener.js.map +1 -0
  455. package/dist/composables/useIconClickHandlers.d.ts +2 -10
  456. package/dist/composables/useIconClickHandlers.js +1 -1
  457. package/dist/composables/useIconClickHandlers.js.map +1 -1
  458. package/dist/{components/VCombobox/infiniteScroll.d.ts → composables/useInfiniteScroll.d.ts} +6 -0
  459. package/dist/{components/VCombobox/infiniteScroll.js → composables/useInfiniteScroll.js} +9 -9
  460. package/dist/composables/useInfiniteScroll.js.map +1 -0
  461. package/dist/composables/useListbox.d.ts +132 -0
  462. package/dist/composables/useListbox.js +227 -0
  463. package/dist/composables/useListbox.js.map +1 -0
  464. package/dist/composables/useModalDialog.d.ts +28 -0
  465. package/dist/composables/useModalDialog.js +60 -0
  466. package/dist/composables/useModalDialog.js.map +1 -0
  467. package/dist/composables/useRootAttrs.d.ts +2 -3
  468. package/dist/composables/useRootAttrs.js.map +1 -1
  469. package/dist/composables/useTypeahead.d.ts +13 -0
  470. package/dist/composables/useTypeahead.js +23 -0
  471. package/dist/composables/useTypeahead.js.map +1 -0
  472. package/dist/composables/useVirtualList.d.ts +46 -0
  473. package/dist/composables/useVirtualList.js +145 -0
  474. package/dist/composables/useVirtualList.js.map +1 -0
  475. package/dist/i18n/en.js +50 -0
  476. package/dist/i18n/en.js.map +1 -1
  477. package/dist/i18n/fr.js +50 -0
  478. package/dist/i18n/fr.js.map +1 -1
  479. package/dist/i18n/state.d.ts +1 -1
  480. package/dist/i18n/state.js +17 -6
  481. package/dist/i18n/state.js.map +1 -1
  482. package/dist/i18n/types.d.ts +103 -2
  483. package/dist/icons.js +45 -37
  484. package/dist/index.d.ts +49 -3
  485. package/dist/index.js +80 -56
  486. package/dist/styles.css +1 -1
  487. package/dist/tokens/index.d.ts +43 -0
  488. package/dist/tokens/semantic.d.ts +42 -0
  489. package/dist/tokens/semantic.js +43 -1
  490. package/dist/tokens/semantic.js.map +1 -1
  491. package/dist/tokens/themes/dark.d.ts +1 -0
  492. package/dist/tokens/themes/dark.js +1 -0
  493. package/dist/tokens/themes/dark.js.map +1 -1
  494. package/dist/tokens.json +215 -1
  495. package/dist/types.d.ts +57 -4
  496. package/dist/utils/arrowNav.js.map +1 -1
  497. package/dist/utils/attrs.d.ts +9 -0
  498. package/dist/utils/attrs.js +14 -0
  499. package/dist/utils/attrs.js.map +1 -0
  500. package/dist/utils/date.d.ts +1 -0
  501. package/dist/utils/date.js +5 -4
  502. package/dist/utils/date.js.map +1 -1
  503. package/package.json +1 -1
  504. package/dist/components/VCombobox/VComboboxGroup.css +0 -2
  505. package/dist/components/VCombobox/VComboboxGroup.d.ts +0 -17
  506. package/dist/components/VCombobox/VComboboxGroup.js +0 -9
  507. package/dist/components/VCombobox/VComboboxGroup.js.map +0 -1
  508. package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js +0 -21
  509. package/dist/components/VCombobox/VComboboxGroup.vue_vue_type_script_setup_true_lang.js.map +0 -1
  510. package/dist/components/VCombobox/VComboboxOption.css +0 -2
  511. package/dist/components/VCombobox/VComboboxOption.js +0 -9
  512. package/dist/components/VCombobox/VComboboxOption.js.map +0 -1
  513. package/dist/components/VCombobox/VComboboxOption.vue_vue_type_script_setup_true_lang.js.map +0 -1
  514. package/dist/components/VCombobox/VComboboxSeparator.css +0 -2
  515. package/dist/components/VCombobox/VComboboxSeparator.js +0 -9
  516. package/dist/components/VCombobox/VComboboxSeparator.js.map +0 -1
  517. package/dist/components/VCombobox/VComboboxSeparator.vue_vue_type_script_setup_true_lang.js.map +0 -1
  518. package/dist/components/VCombobox/infiniteScroll.js.map +0 -1
  519. /package/dist/components/{VCombobox/VComboboxSeparator.d.ts → VCheckbox/VCheckMark.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"VSideNavigationItem.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigationItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Branches use native details and leaves use links or buttons. JavaScript synchronizes open\n * state, disables summaries and makes disabled links inert.\n */\n\nimport { computed, inject, provide, ref, useId, useSlots } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport { sideNavigationKey } from './context'\n\nimport { useDetailsOpen } from '../../composables/useDetailsOpen'\nimport { useInertLink } from '../../composables/useInertLink'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\ninterface SideNavigationItemProps {\n /** What the row says, and where it goes. The default slot replaces it. */\n label?: string\n /** A second line under the label, for a status or a short explanation. */\n sublabel?: string\n /**\n * An icon before the label: an icon name, or an explicit render. The `#icon` slot\n * replaces it.\n */\n icon?: IconSource\n /**\n * Where this row leads, which makes it a link. It is IGNORED on a row that has\n * subitems: such a row opens and closes rather than navigating.\n */\n href?: string\n /**\n * Marks this row as the page currently being viewed. It is highlighted, and\n * announced as the current page (`aria-current`).\n */\n current?: boolean\n /**\n * Makes the row unusable: it greys out through the colour tokens and leaves the\n * keyboard path.\n */\n disabled?: boolean\n /** Renders a branch already open. Bind `v-model:open` to drive it instead. */\n defaultOpen?: boolean\n}\n\n// Without redirecting them, `target`, `rel`, `download` and the aria-* would land on that list\n// item instead of on the link or the branch header.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<SideNavigationItemProps>(), {\n label: undefined,\n sublabel: undefined,\n icon: undefined,\n href: undefined,\n current: false,\n disabled: false,\n defaultOpen: false,\n})\n\n// \"not bound\" is written as `null` and not `undefined`. A model typed as a plain boolean is\n// declared as such at runtime, and Vue casts an ABSENT boolean prop to `false`, which would\n// silently overwrite `defaultOpen` on every branch.\n/**\n * Whether the branch is open, when the consumer wants to drive or observe it. Left\n * unbound, the browser keeps that state to itself, `defaultOpen` giving only the initial\n * value. `null` means unbound.\n */\nconst open = defineModel<boolean | null>('open', { default: null })\n\nconst emit = defineEmits<{\n // Never declare a `click` emit alongside it. Vue removes a declared event from the forwarded\n // attributes, and a consumer's own `@click` would then stop reaching the link entirely.\n /** A row WITHOUT subitems was activated, by click or by keyboard. */\n select: []\n}>()\n\ndefineSlots<{\n /**\n * The label of the row, replacing the `label` prop. One of the two is REQUIRED: a\n * navigation row must say where it goes.\n */\n default?(): unknown\n /** A second line made of markup, replacing the `sublabel` prop. */\n sublabel?(): unknown\n /** Free content before the label, which takes the place of `icon`. */\n icon?(): unknown\n /**\n * Free content at the end of the row, before the chevron: a counter, a badge. On a\n * BRANCH it must not be focusable, a control inside the header being a control nested\n * inside another.\n */\n end?(): unknown\n /**\n * The subitems, which turn this row into a branch. Nesting is not limited. The slot\n * must be statically present or absent: whether a row is a branch is decided when it\n * is created.\n */\n children?(): unknown\n}>()\n\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\nconst slots = useSlots()\nconst tag = computed(() => (props.href !== undefined ? 'a' : 'button'))\n\nconst parent = inject(sideNavigationKey, null)\n\n/**\n * Both chevrons are chosen on the navigation as a whole. The fallback is what keeps an\n * item rendering correctly when it is used outside one.\n */\nconst expandIcon = computed(() => parent?.expandIcon ?? expandMoreIcon)\nconst collapseIcon = computed(() => parent?.collapseIcon)\n\n// @ssr\n// Each level owns its exclusive group, including children supplied after the first render.\nconst childrenName = useId()\nprovide(sideNavigationKey, {\n get name() {\n return parent?.exclusive ? childrenName : undefined\n },\n get exclusive() {\n return parent?.exclusive ?? false\n },\n get expandIcon() {\n return expandIcon.value\n },\n get collapseIcon() {\n return collapseIcon.value\n },\n})\n\nconst { openAttr, onToggle, onSummaryClick } = useDetailsOpen(open, {\n defaultOpen: () => props.defaultOpen,\n disabled: () => props.disabled,\n})\n\n/*\n * Stopping the event from travelling would not help: folding is not a listener anyone\n * registered, it is the click's default action, and only cancelling that prevents it. The\n * exception is a click that already landed on something activable.\n */\n// @core\nfunction onEndClick(event: MouseEvent) {\n const target = event.target as Element | null\n if (!target?.closest('button, a, input, select, textarea, [tabindex]')) event.preventDefault()\n}\n\n// A template ref on the item reaches the list item, a layout box; what is focused and\n// named is its row: the branch header, or the leaf's link or button.\nconst rowEl = ref<HTMLElement | null>(null)\nconst actionEl = ref<HTMLElement | null>(null)\nconst control = () => (slots.children ? rowEl.value : actionEl.value)\ndefineExpose({\n /** Moves the focus to the row: the branch header, or the leaf's link or button. */\n focus: (options?: FocusOptions) => control()?.focus(options),\n /** That element, which is also where the consumer's attributes land. */\n get el() {\n return control()\n },\n})\n\n// @a11y\n// A leaf link has no `disabled`: the address, the consumer's click listeners and the\n// generic role of an `<a>` without `href` are handled by the shared inert link.\nconst link = useInertLink({\n href: () => (tag.value === 'a' ? props.href : undefined),\n inert: () => props.disabled,\n attrs: () => forwardedAttrs.value,\n})\n\n// @core\nfunction onActionClick(event: MouseEvent) {\n // A disabled button never receives the click at all; an inert link does, so it is\n // cancelled here.\n if (props.disabled) {\n event.preventDefault()\n return\n }\n emit('select')\n}\n</script>\n\n<template>\n <li class=\"v-side-nav-item\" :class=\"rootClass\" :style=\"rootStyle\">\n <details\n v-if=\"$slots.children\"\n class=\"v-side-nav-branch v-disclosure\"\n :name=\"parent?.name\"\n :open=\"openAttr\"\n :data-swap=\"collapseIcon ? '' : undefined\"\n @toggle=\"onToggle\"\n >\n <summary\n ref=\"rowEl\"\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :aria-current=\"current ? 'true' : undefined\"\n :aria-disabled=\"disabled || undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n v-bind=\"forwardedAttrs\"\n @click=\"onSummaryClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-side-nav-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-side-nav-content\">\n <span class=\"v-side-nav-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-side-nav-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n <!-- This slot sits INSIDE the branch header, where ANY click folds the\n branch: without the handler, clicking a badge would close the section\n under it -->\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\" @click=\"onEndClick\"\n ><slot name=\"end\"\n /></span>\n <VIcon class=\"v-side-nav-chevron v-disclosure-chevron\" v-bind=\"iconProps(expandIcon)\" />\n <VIcon\n v-if=\"collapseIcon\"\n class=\"v-side-nav-chevron v-side-nav-chevron-open v-disclosure-chevron v-disclosure-chevron-open\"\n v-bind=\"iconProps(collapseIcon)\"\n />\n </summary>\n <ul class=\"v-side-nav-children\">\n <slot name=\"children\" />\n </ul>\n </details>\n\n <div\n v-else\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n >\n <component\n :is=\"tag\"\n ref=\"actionEl\"\n class=\"v-side-nav-action\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :aria-disabled=\"link.isInertLink.value ? 'true' : undefined\"\n :aria-current=\"current ? (tag === 'a' ? 'page' : 'true') : undefined\"\n v-bind=\"link.attrs.value\"\n :href=\"link.linkHref.value\"\n @click=\"onActionClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-side-nav-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-side-nav-content\">\n <span class=\"v-side-nav-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-side-nav-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n </component>\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\"><slot name=\"end\" /></span>\n </div>\n </li>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The obvious one-name form, incrementing a variable by reading itself, is a CYCLE as far as\n * CSS is concerned, even though the value being read is the inherited one. The property then\n * falls to invalid, every read falls back to zero, and the whole tree renders FLAT; with\n * nothing in the console to say why.\n */\n .v-side-nav-item {\n --side-nav-parent-level: var(--side-nav-level, 0);\n }\n\n .v-side-nav-children {\n --side-nav-level: calc(var(--side-nav-parent-level) + 1);\n }\n\n .v-side-nav-row {\n /*\n * The indent is computed here and not stored in a variable set higher up. A custom property\n * is substituted on the element that DECLARES it, so a padding computed on the nav would be\n * frozen at level zero for the whole tree.\n */\n\n /*\n * The cap has to stay derived from --control-height. A browser scales down any radius it\n * cannot fit, so a row exactly one control tall already paints half that height under a\n * pill override; min() applies the same reduction to a row that grew past it.\n */\n --side-nav-row-radius: min(var(--vectis-radius-interactive), calc(var(--control-height) / 2));\n\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: calc(\n var(--control-padding-inline) + var(--side-nav-level, 0) * var(--side-nav-indent)\n )\n var(--control-padding-inline);\n border-radius: var(--side-nav-row-radius);\n color: var(--vectis-color-text);\n font-size: var(--control-font-size);\n line-height: var(--vectis-text-body-md-leading);\n cursor: pointer;\n }\n\n .v-side-nav-action {\n /* On a leaf the link is a CHILD of the row, and the indent deliberately stays on\n the row itself: what has to run the full width is the hover background, not the\n link inside it. */\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n text-align: start;\n text-decoration: none;\n cursor: inherit;\n }\n\n /*\n * This is what stretches the link over the whole row without having to wrap the end slot\n * inside it. It is an invisible box, positioned, so it is painted above the chevron; which is\n * not positioned; while passing UNDER the end slot, which is positioned too and comes later\n * in the document.\n */\n .v-side-nav-action::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: var(--side-nav-row-radius);\n }\n\n .v-side-nav-content {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n flex-direction: column;\n }\n\n .v-side-nav-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-sublabel {\n overflow: hidden;\n font-size: var(--vectis-text-caption-size);\n color: var(--vectis-color-text-muted);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-icon {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* Positioned on purpose: that is what paints it above the stretched link, and\n therefore what keeps whatever it holds clickable. */\n .v-side-nav-end {\n position: relative;\n flex: none;\n display: flex;\n align-items: center;\n gap: var(--vectis-space-1);\n }\n\n .v-side-nav-row:hover:not([data-disabled]) {\n background: var(--vectis-color-surface-muted);\n }\n\n /*\n * A branch header takes focus itself; a leaf only takes it through its link, and the\n * ring is then drawn on the stretched box so that it frames the whole row rather than\n * just the text.\n *\n * The ring is pulled INWARDS in both cases: the content of a branch is clipped so it\n * can be animated open, and a ring drawn outside the row would be cut off there.\n */\n .v-side-nav-row:focus-visible,\n .v-side-nav-action:focus-visible::after {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(-1 * var(--vectis-focus-ring-width));\n }\n\n .v-side-nav-action:focus-visible {\n outline: none;\n }\n\n .v-side-nav-row[data-current] {\n background: var(--vectis-color-accent-surface);\n color: var(--vectis-color-accent-text);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-label {\n font-weight: var(--vectis-text-label-weight);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-icon,\n .v-side-nav-row[data-current] .v-side-nav-sublabel,\n .v-side-nav-row[data-current] .v-side-nav-chevron {\n color: inherit;\n }\n\n .v-side-nav-row[data-current]:not([data-disabled]):hover {\n /*\n * The current row is already tinted, so its hover deepens that tint rather than replacing\n * it with the neutral highlight; the VMenuItem idiom.\n */\n background: color-mix(\n in oklab,\n var(--vectis-color-accent-surface),\n var(--vectis-color-accent-text) 8%\n );\n }\n\n /* A CLOSED branch holding the current page keeps a mark of it, so the reader can see\n where they are without opening every section. The lookup is deliberately a\n descendant one: the page may be several levels down. */\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled]) {\n color: var(--vectis-color-accent-text);\n }\n\n /* A disabled row greys out through the colour tokens, never through opacity. */\n .v-side-nav-row[data-disabled] {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* The icon and the second line default to a colour DARKER than the one a disabled\n label takes: left alone they would come out stronger than the label itself, so they\n inherit it instead. The chevron gets the same treatment from `styles/disclosure.css`. */\n .v-side-nav-row[data-disabled] .v-side-nav-icon,\n .v-side-nav-row[data-disabled] .v-side-nav-sublabel {\n color: inherit;\n }\n\n /* Forced colours flatten the current row's tint to `Canvas` and its accent text to\n `CanvasText`, leaving a slightly bolder label as the only cue, and the mark on a closed\n branch is a colour alone. The current row takes the system selection pair, repeated to\n (0,4,0) above its own hover, and the closed branch underlines its label, a decoration\n the mode keeps. */\n @media (forced-colors: active) {\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current] {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current][data-disabled] {\n background: Canvas;\n color: GrayText;\n }\n\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled])\n .v-side-nav-label {\n text-decoration: underline;\n }\n }\n\n /* The disclosure animation, the chevron's rotation or swap and the WebKit marker come\n from `styles/disclosure.css`, reduced-motion block included. */\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"VSideNavigationItem.js","names":[],"sources":["../../../src/components/VSideNavigation/VSideNavigationItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Branches use native details and leaves use links or buttons. JavaScript synchronizes open\n * state, disables summaries and makes disabled links inert.\n */\n\nimport { computed, inject, provide, ref, useId, useSlots } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport { sideNavigationKey } from './context'\n\nimport { useDetailsOpen } from '../../composables/useDetailsOpen'\nimport { useInertLink } from '../../composables/useInertLink'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\ninterface SideNavigationItemProps {\n /** What the row says, and where it goes. The default slot replaces it. */\n label?: string\n /** A second line under the label, for a status or a short explanation. */\n sublabel?: string\n /**\n * An icon before the label: an icon name, or an explicit render. The `#icon` slot\n * replaces it.\n */\n icon?: IconSource\n /**\n * Where this row leads, which makes it a link. It is IGNORED on a row that has\n * subitems: such a row opens and closes rather than navigating.\n */\n href?: string\n /**\n * Marks this row as the page currently being viewed. It is highlighted, and\n * announced as the current page (`aria-current`).\n */\n current?: boolean\n /**\n * Makes the row unusable: it greys out through the colour tokens and leaves the\n * keyboard path.\n */\n disabled?: boolean\n /** Renders a branch already open. Bind `v-model:open` to drive it instead. */\n defaultOpen?: boolean\n}\n\n// Without redirecting them, `target`, `rel`, `download` and the aria-* would land on that list\n// item instead of on the link or the branch header.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<SideNavigationItemProps>(), {\n label: undefined,\n sublabel: undefined,\n icon: undefined,\n href: undefined,\n current: false,\n disabled: false,\n defaultOpen: false,\n})\n\n// \"not bound\" is written as `null` and not `undefined`. A model typed as a plain boolean is\n// declared as such at runtime, and Vue casts an ABSENT boolean prop to `false`, which would\n// silently overwrite `defaultOpen` on every branch.\n/**\n * Whether the branch is open, when the consumer wants to drive or observe it. Left\n * unbound, the browser keeps that state to itself, `defaultOpen` giving only the initial\n * value. `null` means unbound.\n */\nconst open = defineModel<boolean | null>('open', { default: null })\n\nconst emit = defineEmits<{\n // Never declare a `click` emit alongside it. Vue removes a declared event from the forwarded\n // attributes, and a consumer's own `@click` would then stop reaching the link entirely.\n /** A row WITHOUT subitems was activated, by click or by keyboard. */\n select: []\n}>()\n\ndefineSlots<{\n /**\n * The label of the row, replacing the `label` prop. One of the two is REQUIRED: a\n * navigation row must say where it goes.\n */\n default?(): unknown\n /** A second line made of markup, replacing the `sublabel` prop. */\n sublabel?(): unknown\n /** Free content before the label, which takes the place of `icon`. */\n icon?(): unknown\n /**\n * Free content at the end of the row, before the chevron: a counter, a badge. On a\n * BRANCH it must not be focusable, a control inside the header being a control nested\n * inside another.\n */\n end?(): unknown\n /**\n * The subitems, which turn this row into a branch. Nesting is not limited. The slot\n * must be statically present or absent: whether a row is a branch is decided when it\n * is created.\n */\n children?(): unknown\n}>()\n\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\nconst slots = useSlots()\nconst tag = computed(() => (props.href !== undefined ? 'a' : 'button'))\n\nconst parent = inject(sideNavigationKey, null)\n\n/**\n * Both chevrons are chosen on the navigation as a whole. The fallback is what keeps an\n * item rendering correctly when it is used outside one.\n */\nconst expandIcon = computed(() => parent?.expandIcon ?? expandMoreIcon)\nconst collapseIcon = computed(() => parent?.collapseIcon)\n\n// @ssr\n// Each level owns its exclusive group, including children supplied after the first render.\nconst childrenName = useId()\nprovide(sideNavigationKey, {\n get name() {\n return parent?.exclusive ? childrenName : undefined\n },\n get exclusive() {\n return parent?.exclusive ?? false\n },\n get expandIcon() {\n return expandIcon.value\n },\n get collapseIcon() {\n return collapseIcon.value\n },\n})\n\nconst { openAttr, onToggle, onSummaryClick } = useDetailsOpen(open, {\n defaultOpen: () => props.defaultOpen,\n disabled: () => props.disabled,\n})\n\n/*\n * Stopping the event from travelling would not help: folding is not a listener anyone\n * registered, it is the click's default action, and only cancelling that prevents it. The\n * exception is a click that already landed on something activable.\n */\n// @core\nfunction onEndClick(event: MouseEvent) {\n const target = event.target as Element | null\n if (!target?.closest('button, a, input, select, textarea, [tabindex]')) event.preventDefault()\n}\n\n// A template ref on the item reaches the list item, a layout box; what is focused and\n// named is its row: the branch header, or the leaf's link or button.\nconst rowEl = ref<HTMLElement | null>(null)\nconst actionEl = ref<HTMLElement | null>(null)\nconst control = () => (slots.children ? rowEl.value : actionEl.value)\ndefineExpose({\n /** Moves the focus to the row: the branch header, or the leaf's link or button. */\n focus: (options?: FocusOptions) => control()?.focus(options),\n /** The row, which is also where the consumer's attributes land. */\n get el() {\n return control()\n },\n})\n\n// @a11y\n// A leaf link has no `disabled`: the address, the consumer's click listeners and the\n// generic role of an `<a>` without `href` are handled by the shared inert link.\nconst link = useInertLink({\n href: () => (tag.value === 'a' ? props.href : undefined),\n inert: () => props.disabled,\n attrs: () => forwardedAttrs.value,\n})\n\n// @core\nfunction onActionClick(event: MouseEvent) {\n // A disabled button never receives the click at all; an inert link does, so it is\n // cancelled here.\n if (props.disabled) {\n event.preventDefault()\n return\n }\n emit('select')\n}\n</script>\n\n<template>\n <li class=\"v-side-nav-item\" :class=\"rootClass\" :style=\"rootStyle\">\n <details\n v-if=\"$slots.children\"\n class=\"v-side-nav-branch v-disclosure\"\n :name=\"parent?.name\"\n :open=\"openAttr\"\n :data-swap=\"collapseIcon ? '' : undefined\"\n @toggle=\"onToggle\"\n >\n <summary\n ref=\"rowEl\"\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :aria-current=\"current ? 'true' : undefined\"\n :aria-disabled=\"disabled || undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n v-bind=\"forwardedAttrs\"\n @click=\"onSummaryClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-side-nav-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-side-nav-content\">\n <span class=\"v-side-nav-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-side-nav-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n <!-- This slot sits INSIDE the branch header, where ANY click folds the\n branch: without the handler, clicking a badge would close the section\n under it -->\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\" @click=\"onEndClick\"\n ><slot name=\"end\"\n /></span>\n <VIcon class=\"v-side-nav-chevron v-disclosure-chevron\" v-bind=\"iconProps(expandIcon)\" />\n <VIcon\n v-if=\"collapseIcon\"\n class=\"v-side-nav-chevron v-side-nav-chevron-open v-disclosure-chevron v-disclosure-chevron-open\"\n v-bind=\"iconProps(collapseIcon)\"\n />\n </summary>\n <ul class=\"v-side-nav-children\">\n <slot name=\"children\" />\n </ul>\n </details>\n\n <div\n v-else\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n >\n <component\n :is=\"tag\"\n ref=\"actionEl\"\n class=\"v-side-nav-action\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :aria-disabled=\"link.isInertLink.value ? 'true' : undefined\"\n :aria-current=\"current ? (tag === 'a' ? 'page' : 'true') : undefined\"\n v-bind=\"link.attrs.value\"\n :href=\"link.linkHref.value\"\n @click=\"onActionClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-side-nav-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-side-nav-content\">\n <span class=\"v-side-nav-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-side-nav-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n </component>\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\"><slot name=\"end\" /></span>\n </div>\n </li>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The obvious one-name form, incrementing a variable by reading itself, is a CYCLE as far as\n * CSS is concerned, even though the value being read is the inherited one. The property then\n * falls to invalid, every read falls back to zero, and the whole tree renders FLAT; with\n * nothing in the console to say why.\n */\n .v-side-nav-item {\n --side-nav-parent-level: var(--side-nav-level, 0);\n }\n\n .v-side-nav-children {\n --side-nav-level: calc(var(--side-nav-parent-level) + 1);\n }\n\n .v-side-nav-row {\n /*\n * The indent is computed here and not stored in a variable set higher up. A custom property\n * is substituted on the element that DECLARES it, so a padding computed on the nav would be\n * frozen at level zero for the whole tree.\n */\n\n /*\n * The cap has to stay derived from --control-height. A browser scales down any radius it\n * cannot fit, so a row exactly one control tall already paints half that height under a\n * pill override; min() applies the same reduction to a row that grew past it.\n */\n --side-nav-row-radius: min(var(--vectis-radius-interactive), calc(var(--control-height) / 2));\n\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: calc(\n var(--control-padding-inline) + var(--side-nav-level, 0) * var(--side-nav-indent)\n )\n var(--control-padding-inline);\n border-radius: var(--side-nav-row-radius);\n color: var(--vectis-color-text);\n font-size: var(--control-font-size);\n line-height: var(--vectis-text-body-md-leading);\n cursor: pointer;\n }\n\n .v-side-nav-action {\n /* On a leaf the link is a CHILD of the row, and the indent deliberately stays on\n the row itself: what has to run the full width is the hover background, not the\n link inside it. */\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n text-align: start;\n text-decoration: none;\n cursor: inherit;\n }\n\n /*\n * This is what stretches the link over the whole row without having to wrap the end slot\n * inside it. It is an invisible box, positioned, so it is painted above the chevron; which is\n * not positioned; while passing UNDER the end slot, which is positioned too and comes later\n * in the document.\n */\n .v-side-nav-action::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: var(--side-nav-row-radius);\n }\n\n .v-side-nav-content {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n flex-direction: column;\n }\n\n .v-side-nav-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-sublabel {\n overflow: hidden;\n font-size: var(--vectis-text-caption-size);\n color: var(--vectis-color-text-muted);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-icon {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* Positioned on purpose: that is what paints it above the stretched link, and\n therefore what keeps whatever it holds clickable. */\n .v-side-nav-end {\n position: relative;\n flex: none;\n display: flex;\n align-items: center;\n gap: var(--vectis-space-1);\n }\n\n .v-side-nav-row:hover:not([data-disabled]) {\n background: var(--vectis-color-surface-muted);\n }\n\n /*\n * A branch header takes focus itself; a leaf only takes it through its link, and the\n * ring is then drawn on the stretched box so that it frames the whole row rather than\n * just the text.\n *\n * The ring is pulled INWARDS in both cases: the content of a branch is clipped so it\n * can be animated open, and a ring drawn outside the row would be cut off there.\n */\n .v-side-nav-row:focus-visible,\n .v-side-nav-action:focus-visible::after {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(-1 * var(--vectis-focus-ring-width));\n }\n\n .v-side-nav-action:focus-visible {\n outline: none;\n }\n\n .v-side-nav-row[data-current] {\n background: var(--vectis-color-accent-surface);\n color: var(--vectis-color-accent-text);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-label {\n font-weight: var(--vectis-text-label-weight);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-icon,\n .v-side-nav-row[data-current] .v-side-nav-sublabel,\n .v-side-nav-row[data-current] .v-side-nav-chevron {\n color: inherit;\n }\n\n .v-side-nav-row[data-current]:not([data-disabled]):hover {\n /*\n * The current row is already tinted, so its hover deepens that tint rather than replacing\n * it with the neutral highlight; the VMenuItem idiom.\n */\n background: color-mix(\n in oklab,\n var(--vectis-color-accent-surface),\n var(--vectis-color-accent-text) 8%\n );\n }\n\n /* A CLOSED branch holding the current page keeps a mark of it, so the reader can see\n where they are without opening every section. The lookup is deliberately a\n descendant one: the page may be several levels down. */\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled]) {\n color: var(--vectis-color-accent-text);\n }\n\n /* A disabled row greys out through the colour tokens, never through opacity. */\n .v-side-nav-row[data-disabled] {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* The icon and the second line default to a colour DARKER than the one a disabled\n label takes: left alone they would come out stronger than the label itself, so they\n inherit it instead. The chevron gets the same treatment from `styles/disclosure.css`. */\n .v-side-nav-row[data-disabled] .v-side-nav-icon,\n .v-side-nav-row[data-disabled] .v-side-nav-sublabel {\n color: inherit;\n }\n\n /* Forced colours flatten the current row's tint to `Canvas` and its accent text to\n `CanvasText`, leaving a slightly bolder label as the only cue, and the mark on a closed\n branch is a colour alone. The current row takes the system selection pair, repeated to\n (0,4,0) above its own hover, and the closed branch underlines its label, a decoration\n the mode keeps. */\n @media (forced-colors: active) {\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current] {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current][data-disabled] {\n background: Canvas;\n color: GrayText;\n }\n\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled])\n .v-side-nav-label {\n text-decoration: underline;\n }\n }\n\n /* The disclosure animation, the chevron's rotation or swap and the WebKit marker come\n from `styles/disclosure.css`, reduced-motion block included. */\n}\n</style>\n"],"mappings":""}
@@ -1,8 +1,8 @@
1
1
  import { iconProps as e } from "../VIcon/iconProps.js";
2
2
  import t from "../VIcon/VIcon.js";
3
3
  import { useInertLink as n } from "../../composables/useInertLink.js";
4
- import { expand_more as r } from "../VIcon/icons/expand_more.js";
5
- import { useRootAttrs as ee } from "../../composables/useRootAttrs.js";
4
+ import { useRootAttrs as r } from "../../composables/useRootAttrs.js";
5
+ import { expand_more as ee } from "../VIcon/icons/expand_more.js";
6
6
  import { useDetailsOpen as i } from "../../composables/useDetailsOpen.js";
7
7
  import { sideNavigationKey as a } from "./context.js";
8
8
  import { computed as o, createBlock as s, createCommentVNode as c, createElementBlock as l, createElementVNode as u, createTextVNode as d, createVNode as f, defineComponent as p, inject as m, mergeModels as h, mergeProps as g, normalizeClass as _, normalizeStyle as v, openBlock as y, provide as te, ref as b, renderSlot as x, resolveDynamicComponent as S, toDisplayString as C, unref as w, useId as T, useModel as E, useSlots as ne, withCtx as re } from "vue";
@@ -55,7 +55,7 @@ var ie = [
55
55
  }),
56
56
  emits: /*@__PURE__*/ h(["select"], ["update:open"]),
57
57
  setup(p, { expose: h, emit: F }) {
58
- let I = p, L = E(p, "open"), R = F, { rootClass: z, rootStyle: B, forwardedAttrs: V } = ee(), H = ne(), U = o(() => I.href === void 0 ? "button" : "a"), W = m(a, null), G = o(() => W?.expandIcon ?? r), K = o(() => W?.collapseIcon), se = T();
58
+ let I = p, L = E(p, "open"), R = F, { rootClass: z, rootStyle: B, forwardedAttrs: V } = r(), H = ne(), U = o(() => I.href === void 0 ? "button" : "a"), W = m(a, null), G = o(() => W?.expandIcon ?? ee), K = o(() => W?.collapseIcon), se = T();
59
59
  te(a, {
60
60
  get name() {
61
61
  return W?.exclusive ? se : void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"VSideNavigationItem.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VSideNavigation/VSideNavigationItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Branches use native details and leaves use links or buttons. JavaScript synchronizes open\n * state, disables summaries and makes disabled links inert.\n */\n\nimport { computed, inject, provide, ref, useId, useSlots } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport { sideNavigationKey } from './context'\n\nimport { useDetailsOpen } from '../../composables/useDetailsOpen'\nimport { useInertLink } from '../../composables/useInertLink'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\ninterface SideNavigationItemProps {\n /** What the row says, and where it goes. The default slot replaces it. */\n label?: string\n /** A second line under the label, for a status or a short explanation. */\n sublabel?: string\n /**\n * An icon before the label: an icon name, or an explicit render. The `#icon` slot\n * replaces it.\n */\n icon?: IconSource\n /**\n * Where this row leads, which makes it a link. It is IGNORED on a row that has\n * subitems: such a row opens and closes rather than navigating.\n */\n href?: string\n /**\n * Marks this row as the page currently being viewed. It is highlighted, and\n * announced as the current page (`aria-current`).\n */\n current?: boolean\n /**\n * Makes the row unusable: it greys out through the colour tokens and leaves the\n * keyboard path.\n */\n disabled?: boolean\n /** Renders a branch already open. Bind `v-model:open` to drive it instead. */\n defaultOpen?: boolean\n}\n\n// Without redirecting them, `target`, `rel`, `download` and the aria-* would land on that list\n// item instead of on the link or the branch header.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<SideNavigationItemProps>(), {\n label: undefined,\n sublabel: undefined,\n icon: undefined,\n href: undefined,\n current: false,\n disabled: false,\n defaultOpen: false,\n})\n\n// \"not bound\" is written as `null` and not `undefined`. A model typed as a plain boolean is\n// declared as such at runtime, and Vue casts an ABSENT boolean prop to `false`, which would\n// silently overwrite `defaultOpen` on every branch.\n/**\n * Whether the branch is open, when the consumer wants to drive or observe it. Left\n * unbound, the browser keeps that state to itself, `defaultOpen` giving only the initial\n * value. `null` means unbound.\n */\nconst open = defineModel<boolean | null>('open', { default: null })\n\nconst emit = defineEmits<{\n // Never declare a `click` emit alongside it. Vue removes a declared event from the forwarded\n // attributes, and a consumer's own `@click` would then stop reaching the link entirely.\n /** A row WITHOUT subitems was activated, by click or by keyboard. */\n select: []\n}>()\n\ndefineSlots<{\n /**\n * The label of the row, replacing the `label` prop. One of the two is REQUIRED: a\n * navigation row must say where it goes.\n */\n default?(): unknown\n /** A second line made of markup, replacing the `sublabel` prop. */\n sublabel?(): unknown\n /** Free content before the label, which takes the place of `icon`. */\n icon?(): unknown\n /**\n * Free content at the end of the row, before the chevron: a counter, a badge. On a\n * BRANCH it must not be focusable, a control inside the header being a control nested\n * inside another.\n */\n end?(): unknown\n /**\n * The subitems, which turn this row into a branch. Nesting is not limited. The slot\n * must be statically present or absent: whether a row is a branch is decided when it\n * is created.\n */\n children?(): unknown\n}>()\n\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\nconst slots = useSlots()\nconst tag = computed(() => (props.href !== undefined ? 'a' : 'button'))\n\nconst parent = inject(sideNavigationKey, null)\n\n/**\n * Both chevrons are chosen on the navigation as a whole. The fallback is what keeps an\n * item rendering correctly when it is used outside one.\n */\nconst expandIcon = computed(() => parent?.expandIcon ?? expandMoreIcon)\nconst collapseIcon = computed(() => parent?.collapseIcon)\n\n// @ssr\n// Each level owns its exclusive group, including children supplied after the first render.\nconst childrenName = useId()\nprovide(sideNavigationKey, {\n get name() {\n return parent?.exclusive ? childrenName : undefined\n },\n get exclusive() {\n return parent?.exclusive ?? false\n },\n get expandIcon() {\n return expandIcon.value\n },\n get collapseIcon() {\n return collapseIcon.value\n },\n})\n\nconst { openAttr, onToggle, onSummaryClick } = useDetailsOpen(open, {\n defaultOpen: () => props.defaultOpen,\n disabled: () => props.disabled,\n})\n\n/*\n * Stopping the event from travelling would not help: folding is not a listener anyone\n * registered, it is the click's default action, and only cancelling that prevents it. The\n * exception is a click that already landed on something activable.\n */\n// @core\nfunction onEndClick(event: MouseEvent) {\n const target = event.target as Element | null\n if (!target?.closest('button, a, input, select, textarea, [tabindex]')) event.preventDefault()\n}\n\n// A template ref on the item reaches the list item, a layout box; what is focused and\n// named is its row: the branch header, or the leaf's link or button.\nconst rowEl = ref<HTMLElement | null>(null)\nconst actionEl = ref<HTMLElement | null>(null)\nconst control = () => (slots.children ? rowEl.value : actionEl.value)\ndefineExpose({\n /** Moves the focus to the row: the branch header, or the leaf's link or button. */\n focus: (options?: FocusOptions) => control()?.focus(options),\n /** That element, which is also where the consumer's attributes land. */\n get el() {\n return control()\n },\n})\n\n// @a11y\n// A leaf link has no `disabled`: the address, the consumer's click listeners and the\n// generic role of an `<a>` without `href` are handled by the shared inert link.\nconst link = useInertLink({\n href: () => (tag.value === 'a' ? props.href : undefined),\n inert: () => props.disabled,\n attrs: () => forwardedAttrs.value,\n})\n\n// @core\nfunction onActionClick(event: MouseEvent) {\n // A disabled button never receives the click at all; an inert link does, so it is\n // cancelled here.\n if (props.disabled) {\n event.preventDefault()\n return\n }\n emit('select')\n}\n</script>\n\n<template>\n <li class=\"v-side-nav-item\" :class=\"rootClass\" :style=\"rootStyle\">\n <details\n v-if=\"$slots.children\"\n class=\"v-side-nav-branch v-disclosure\"\n :name=\"parent?.name\"\n :open=\"openAttr\"\n :data-swap=\"collapseIcon ? '' : undefined\"\n @toggle=\"onToggle\"\n >\n <summary\n ref=\"rowEl\"\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :aria-current=\"current ? 'true' : undefined\"\n :aria-disabled=\"disabled || undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n v-bind=\"forwardedAttrs\"\n @click=\"onSummaryClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-side-nav-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-side-nav-content\">\n <span class=\"v-side-nav-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-side-nav-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n <!-- This slot sits INSIDE the branch header, where ANY click folds the\n branch: without the handler, clicking a badge would close the section\n under it -->\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\" @click=\"onEndClick\"\n ><slot name=\"end\"\n /></span>\n <VIcon class=\"v-side-nav-chevron v-disclosure-chevron\" v-bind=\"iconProps(expandIcon)\" />\n <VIcon\n v-if=\"collapseIcon\"\n class=\"v-side-nav-chevron v-side-nav-chevron-open v-disclosure-chevron v-disclosure-chevron-open\"\n v-bind=\"iconProps(collapseIcon)\"\n />\n </summary>\n <ul class=\"v-side-nav-children\">\n <slot name=\"children\" />\n </ul>\n </details>\n\n <div\n v-else\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n >\n <component\n :is=\"tag\"\n ref=\"actionEl\"\n class=\"v-side-nav-action\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :aria-disabled=\"link.isInertLink.value ? 'true' : undefined\"\n :aria-current=\"current ? (tag === 'a' ? 'page' : 'true') : undefined\"\n v-bind=\"link.attrs.value\"\n :href=\"link.linkHref.value\"\n @click=\"onActionClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-side-nav-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-side-nav-content\">\n <span class=\"v-side-nav-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-side-nav-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n </component>\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\"><slot name=\"end\" /></span>\n </div>\n </li>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The obvious one-name form, incrementing a variable by reading itself, is a CYCLE as far as\n * CSS is concerned, even though the value being read is the inherited one. The property then\n * falls to invalid, every read falls back to zero, and the whole tree renders FLAT; with\n * nothing in the console to say why.\n */\n .v-side-nav-item {\n --side-nav-parent-level: var(--side-nav-level, 0);\n }\n\n .v-side-nav-children {\n --side-nav-level: calc(var(--side-nav-parent-level) + 1);\n }\n\n .v-side-nav-row {\n /*\n * The indent is computed here and not stored in a variable set higher up. A custom property\n * is substituted on the element that DECLARES it, so a padding computed on the nav would be\n * frozen at level zero for the whole tree.\n */\n\n /*\n * The cap has to stay derived from --control-height. A browser scales down any radius it\n * cannot fit, so a row exactly one control tall already paints half that height under a\n * pill override; min() applies the same reduction to a row that grew past it.\n */\n --side-nav-row-radius: min(var(--vectis-radius-interactive), calc(var(--control-height) / 2));\n\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: calc(\n var(--control-padding-inline) + var(--side-nav-level, 0) * var(--side-nav-indent)\n )\n var(--control-padding-inline);\n border-radius: var(--side-nav-row-radius);\n color: var(--vectis-color-text);\n font-size: var(--control-font-size);\n line-height: var(--vectis-text-body-md-leading);\n cursor: pointer;\n }\n\n .v-side-nav-action {\n /* On a leaf the link is a CHILD of the row, and the indent deliberately stays on\n the row itself: what has to run the full width is the hover background, not the\n link inside it. */\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n text-align: start;\n text-decoration: none;\n cursor: inherit;\n }\n\n /*\n * This is what stretches the link over the whole row without having to wrap the end slot\n * inside it. It is an invisible box, positioned, so it is painted above the chevron; which is\n * not positioned; while passing UNDER the end slot, which is positioned too and comes later\n * in the document.\n */\n .v-side-nav-action::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: var(--side-nav-row-radius);\n }\n\n .v-side-nav-content {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n flex-direction: column;\n }\n\n .v-side-nav-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-sublabel {\n overflow: hidden;\n font-size: var(--vectis-text-caption-size);\n color: var(--vectis-color-text-muted);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-icon {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* Positioned on purpose: that is what paints it above the stretched link, and\n therefore what keeps whatever it holds clickable. */\n .v-side-nav-end {\n position: relative;\n flex: none;\n display: flex;\n align-items: center;\n gap: var(--vectis-space-1);\n }\n\n .v-side-nav-row:hover:not([data-disabled]) {\n background: var(--vectis-color-surface-muted);\n }\n\n /*\n * A branch header takes focus itself; a leaf only takes it through its link, and the\n * ring is then drawn on the stretched box so that it frames the whole row rather than\n * just the text.\n *\n * The ring is pulled INWARDS in both cases: the content of a branch is clipped so it\n * can be animated open, and a ring drawn outside the row would be cut off there.\n */\n .v-side-nav-row:focus-visible,\n .v-side-nav-action:focus-visible::after {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(-1 * var(--vectis-focus-ring-width));\n }\n\n .v-side-nav-action:focus-visible {\n outline: none;\n }\n\n .v-side-nav-row[data-current] {\n background: var(--vectis-color-accent-surface);\n color: var(--vectis-color-accent-text);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-label {\n font-weight: var(--vectis-text-label-weight);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-icon,\n .v-side-nav-row[data-current] .v-side-nav-sublabel,\n .v-side-nav-row[data-current] .v-side-nav-chevron {\n color: inherit;\n }\n\n .v-side-nav-row[data-current]:not([data-disabled]):hover {\n /*\n * The current row is already tinted, so its hover deepens that tint rather than replacing\n * it with the neutral highlight; the VMenuItem idiom.\n */\n background: color-mix(\n in oklab,\n var(--vectis-color-accent-surface),\n var(--vectis-color-accent-text) 8%\n );\n }\n\n /* A CLOSED branch holding the current page keeps a mark of it, so the reader can see\n where they are without opening every section. The lookup is deliberately a\n descendant one: the page may be several levels down. */\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled]) {\n color: var(--vectis-color-accent-text);\n }\n\n /* A disabled row greys out through the colour tokens, never through opacity. */\n .v-side-nav-row[data-disabled] {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* The icon and the second line default to a colour DARKER than the one a disabled\n label takes: left alone they would come out stronger than the label itself, so they\n inherit it instead. The chevron gets the same treatment from `styles/disclosure.css`. */\n .v-side-nav-row[data-disabled] .v-side-nav-icon,\n .v-side-nav-row[data-disabled] .v-side-nav-sublabel {\n color: inherit;\n }\n\n /* Forced colours flatten the current row's tint to `Canvas` and its accent text to\n `CanvasText`, leaving a slightly bolder label as the only cue, and the mark on a closed\n branch is a colour alone. The current row takes the system selection pair, repeated to\n (0,4,0) above its own hover, and the closed branch underlines its label, a decoration\n the mode keeps. */\n @media (forced-colors: active) {\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current] {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current][data-disabled] {\n background: Canvas;\n color: GrayText;\n }\n\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled])\n .v-side-nav-label {\n text-decoration: underline;\n }\n }\n\n /* The disclosure animation, the chevron's rotation or swap and the WebKit marker come\n from `styles/disclosure.css`, reduced-motion block included. */\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmDA,IAAM,IAAQ,GAkBR,IAAO,EAA2B,GAAC,MAAyB,GAE5D,IAAO,GA+BP,EAAE,cAAW,cAAW,sBAAmB,GAAa,GAExD,IAAQ,GAAS,GACjB,IAAM,QAAgB,EAAM,SAAS,KAAA,IAAkB,WAAN,GAAe,GAEhE,IAAS,EAAO,GAAmB,IAAI,GAMvC,IAAa,QAAe,GAAQ,cAAc,CAAc,GAChE,IAAe,QAAe,GAAQ,YAAY,GAIlD,KAAe,EAAM;EAC3B,GAAQ,GAAmB;GACzB,IAAI,OAAO;IACT,OAAO,GAAQ,YAAY,KAAe,KAAA;GAC5C;GACA,IAAI,YAAY;IACd,OAAO,GAAQ,aAAa;GAC9B;GACA,IAAI,aAAa;IACf,OAAO,EAAW;GACpB;GACA,IAAI,eAAe;IACjB,OAAO,EAAa;GACtB;EACF,CAAC;EAED,IAAM,EAAE,cAAU,aAAU,sBAAmB,EAAe,GAAM;GAClE,mBAAmB,EAAM;GACzB,gBAAgB,EAAM;EACxB,CAAC;EAQD,SAAS,EAAW,GAAmB;GAErC,AADe,EAAM,QACR,QAAQ,gDAAgD,KAAG,EAAM,eAAe;EAC/F;EAIA,IAAM,IAAQ,EAAwB,IAAI,GACpC,IAAW,EAAwB,IAAI,GACvC,UAAiB,EAAM,WAAW,EAAM,QAAQ,EAAS;EAC/D,EAAa;GAEX,QAAQ,MAA2B,EAAQ,CAAC,EAAE,MAAM,CAAO;GAE3D,IAAI,KAAK;IACP,OAAO,EAAQ;GACjB;EACF,CAAC;EAKD,IAAM,IAAO,EAAa;GACxB,YAAa,EAAI,UAAU,MAAM,EAAM,OAAO,KAAA;GAC9C,aAAa,EAAM;GACnB,aAAa,EAAe;EAC9B,CAAC;EAGD,SAAS,GAAc,GAAmB;GAGxC,IAAI,EAAM,UAAU;IAClB,EAAM,eAAe;IACrB;GACF;GACA,EAAK,QAAQ;EACf;yBAIE,EAiFK,MAAA;GAjFD,OAAK,EAAA,CAAC,mBAA0B,EAAA,CAAA,CAAS,CAAA;GAAG,OAAK,EAAE,EAAA,CAAA,CAAS;MAEtDA,EAAAA,OAAO,YAAA,EAAA,GADf,EA8CU,WAAA;;GA5CR,OAAM;GACL,MAAM,EAAA,CAAA,CAAM,EAAE;GACd,MAAM,EAAA,EAAA;GACN,aAAW,EAAA,QAAY,KAAQ,KAAA;GAC/B,UAAM,AAAA,EAAA,QAAA,GAAA,MAAE,EAAA,CAAA,KAAA,EAAA,CAAA,CAAA,CAAA,GAAA,CAAA;MAET,EAkCU,WAlCV,EAkCU;YAjCJ;GAAJ,KAAI;GACJ,OAAM;GACL,gBAAc,EAAA,UAAO,KAAQ,KAAA;GAC7B,iBAAe,EAAA,WAAQ,KAAQ,KAAA;GAC/B,gBAAc,EAAA,UAAO,SAAY,KAAA;GACjC,iBAAe,EAAA,YAAY,KAAA;GAC3B,UAAU,EAAA,WAAQ,KAAQ,KAAA;KACnB,EAAA,CAAA,GAAc,EACrB,SAAK,AAAA,EAAA,QAAA,GAAA,MAAE,EAAA,CAAA,KAAA,EAAA,CAAA,CAAA,CAAA,GAAA,CAAA,EAAA,CAAA,GAAA;GAER,EAEO,EAAA,QAAA,QAAA,CAAA,SAAA,CADQ,EAAA,QAAA,EAAA,GAAb,EAAsE,GAAtE,EAAsE;;IAAnD,OAAM;MAA0B,EAAA,CAAA,CAAS,CAAC,EAAA,IAAI,CAAA,GAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA;GAEnE,EAOO,QAPP,IAOO,CANL,EAEC,QAFD,GAEC,CADE,EAAwB,EAAA,QAAA,WAAA,CAAA,SAAA,CAAA,EAAA,EAAf,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAEL,EAAA,aAAa,KAAA,KAAaA,EAAAA,OAAO,YAAA,EAAA,GAA7C,EAEO,QAFP,GAEO,CADL,EAA2C,EAAA,QAAA,YAAA,CAAA,SAAA,CAAA,EAAA,EAAlB,EAAA,QAAQ,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA;GAMzBA,EAAAA,OAAO,OAAA,EAAA,GAAnB,EAES,QAAA;;IAFe,OAAM;IAAkB,SAAO;OACpD,EACD,EAAA,QAAA,KAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA;GACF,EAAwF,GAAxF,EAAwF,EAAjF,OAAM,0CAAyC,GAAS,EAAA,CAAA,CAAS,CAAC,EAAA,KAAU,CAAA,GAAA,MAAA,EAAA;GAE3E,EAAA,SAAA,EAAA,GADR,EAIE,GAJF,EAIE;;IAFA,OAAM;MACE,EAAA,CAAA,CAAS,CAAC,EAAA,KAAY,CAAA,GAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA;cAGlC,EAEK,MAFL,GAEK,CADH,EAAwB,EAAA,QAAA,UAAA,CAAA,CAAA,CAAA,GAAA,IAAA,EAAA,MAAA,EAAA,GAI5B,EA+BM,OAAA;;GA7BJ,OAAM;GACL,gBAAc,EAAA,UAAO,KAAQ,KAAA;GAC7B,iBAAe,EAAA,WAAQ,KAAQ,KAAA;YAEhC,EAuBY,EAtBL,EAAA,KAAG,GADV,EAuBY;YArBN;GAAJ,KAAI;GACJ,OAAM;GACL,MAAM,EAAA,UAAG,WAAA,WAA2B,KAAA;GACpC,UAAU,EAAA,UAAG,WAAgB,EAAA,WAAW,KAAA;GACxC,iBAAe,EAAA,CAAA,CAAI,CAAC,YAAY,QAAK,SAAY,KAAA;GACjD,gBAAc,EAAA,UAAW,EAAA,UAAG,MAAA,SAAA,SAA8B,KAAA;KACnD,EAAA,CAAA,CAAI,CAAC,MAAM,OAAK;GACvB,MAAM,EAAA,CAAA,CAAI,CAAC,SAAS;GACpB,SAAO;;qBAID,CAFP,EAEO,EAAA,QAAA,QAAA,CAAA,SAAA,CADQ,EAAA,QAAA,EAAA,GAAb,EAAsE,GAAtE,EAAsE;;IAAnD,OAAM;MAA0B,EAAA,CAAA,CAAS,CAAC,EAAA,IAAI,CAAA,GAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA,GAEnE,EAOO,QAPP,GAOO,CANL,EAEC,QAFD,GAEC,CADE,EAAwB,EAAA,QAAA,WAAA,CAAA,SAAA,CAAA,EAAA,EAAf,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAEL,EAAA,aAAa,KAAA,KAAaA,EAAAA,OAAO,YAAA,EAAA,GAA7C,EAEO,QAFP,GAEO,CADL,EAA2C,EAAA,QAAA,YAAA,CAAA,SAAA,CAAA,EAAA,EAAlB,EAAA,QAAQ,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA,CAAA,CAAA;;;;;;;;OAI3BA,EAAAA,OAAO,OAAA,EAAA,GAAnB,EAAyE,QAAzE,GAAyE,CAA1B,EAAmB,EAAA,QAAA,KAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,GAAA,GAAA,CAAA,EAAA,GAAA,CAAA"}
1
+ {"version":3,"file":"VSideNavigationItem.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/VSideNavigation/VSideNavigationItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Branches use native details and leaves use links or buttons. JavaScript synchronizes open\n * state, disables summaries and makes disabled links inert.\n */\n\nimport { computed, inject, provide, ref, useId, useSlots } from 'vue'\n\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport { expand_more as expandMoreIcon } from '../VIcon/icons/expand_more'\nimport type { IconSource } from '../VIcon/types'\nimport { sideNavigationKey } from './context'\n\nimport { useDetailsOpen } from '../../composables/useDetailsOpen'\nimport { useInertLink } from '../../composables/useInertLink'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\n\ninterface SideNavigationItemProps {\n /** What the row says, and where it goes. The default slot replaces it. */\n label?: string\n /** A second line under the label, for a status or a short explanation. */\n sublabel?: string\n /**\n * An icon before the label: an icon name, or an explicit render. The `#icon` slot\n * replaces it.\n */\n icon?: IconSource\n /**\n * Where this row leads, which makes it a link. It is IGNORED on a row that has\n * subitems: such a row opens and closes rather than navigating.\n */\n href?: string\n /**\n * Marks this row as the page currently being viewed. It is highlighted, and\n * announced as the current page (`aria-current`).\n */\n current?: boolean\n /**\n * Makes the row unusable: it greys out through the colour tokens and leaves the\n * keyboard path.\n */\n disabled?: boolean\n /** Renders a branch already open. Bind `v-model:open` to drive it instead. */\n defaultOpen?: boolean\n}\n\n// Without redirecting them, `target`, `rel`, `download` and the aria-* would land on that list\n// item instead of on the link or the branch header.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<SideNavigationItemProps>(), {\n label: undefined,\n sublabel: undefined,\n icon: undefined,\n href: undefined,\n current: false,\n disabled: false,\n defaultOpen: false,\n})\n\n// \"not bound\" is written as `null` and not `undefined`. A model typed as a plain boolean is\n// declared as such at runtime, and Vue casts an ABSENT boolean prop to `false`, which would\n// silently overwrite `defaultOpen` on every branch.\n/**\n * Whether the branch is open, when the consumer wants to drive or observe it. Left\n * unbound, the browser keeps that state to itself, `defaultOpen` giving only the initial\n * value. `null` means unbound.\n */\nconst open = defineModel<boolean | null>('open', { default: null })\n\nconst emit = defineEmits<{\n // Never declare a `click` emit alongside it. Vue removes a declared event from the forwarded\n // attributes, and a consumer's own `@click` would then stop reaching the link entirely.\n /** A row WITHOUT subitems was activated, by click or by keyboard. */\n select: []\n}>()\n\ndefineSlots<{\n /**\n * The label of the row, replacing the `label` prop. One of the two is REQUIRED: a\n * navigation row must say where it goes.\n */\n default?(): unknown\n /** A second line made of markup, replacing the `sublabel` prop. */\n sublabel?(): unknown\n /** Free content before the label, which takes the place of `icon`. */\n icon?(): unknown\n /**\n * Free content at the end of the row, before the chevron: a counter, a badge. On a\n * BRANCH it must not be focusable, a control inside the header being a control nested\n * inside another.\n */\n end?(): unknown\n /**\n * The subitems, which turn this row into a branch. Nesting is not limited. The slot\n * must be statically present or absent: whether a row is a branch is decided when it\n * is created.\n */\n children?(): unknown\n}>()\n\nconst { rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\nconst slots = useSlots()\nconst tag = computed(() => (props.href !== undefined ? 'a' : 'button'))\n\nconst parent = inject(sideNavigationKey, null)\n\n/**\n * Both chevrons are chosen on the navigation as a whole. The fallback is what keeps an\n * item rendering correctly when it is used outside one.\n */\nconst expandIcon = computed(() => parent?.expandIcon ?? expandMoreIcon)\nconst collapseIcon = computed(() => parent?.collapseIcon)\n\n// @ssr\n// Each level owns its exclusive group, including children supplied after the first render.\nconst childrenName = useId()\nprovide(sideNavigationKey, {\n get name() {\n return parent?.exclusive ? childrenName : undefined\n },\n get exclusive() {\n return parent?.exclusive ?? false\n },\n get expandIcon() {\n return expandIcon.value\n },\n get collapseIcon() {\n return collapseIcon.value\n },\n})\n\nconst { openAttr, onToggle, onSummaryClick } = useDetailsOpen(open, {\n defaultOpen: () => props.defaultOpen,\n disabled: () => props.disabled,\n})\n\n/*\n * Stopping the event from travelling would not help: folding is not a listener anyone\n * registered, it is the click's default action, and only cancelling that prevents it. The\n * exception is a click that already landed on something activable.\n */\n// @core\nfunction onEndClick(event: MouseEvent) {\n const target = event.target as Element | null\n if (!target?.closest('button, a, input, select, textarea, [tabindex]')) event.preventDefault()\n}\n\n// A template ref on the item reaches the list item, a layout box; what is focused and\n// named is its row: the branch header, or the leaf's link or button.\nconst rowEl = ref<HTMLElement | null>(null)\nconst actionEl = ref<HTMLElement | null>(null)\nconst control = () => (slots.children ? rowEl.value : actionEl.value)\ndefineExpose({\n /** Moves the focus to the row: the branch header, or the leaf's link or button. */\n focus: (options?: FocusOptions) => control()?.focus(options),\n /** The row, which is also where the consumer's attributes land. */\n get el() {\n return control()\n },\n})\n\n// @a11y\n// A leaf link has no `disabled`: the address, the consumer's click listeners and the\n// generic role of an `<a>` without `href` are handled by the shared inert link.\nconst link = useInertLink({\n href: () => (tag.value === 'a' ? props.href : undefined),\n inert: () => props.disabled,\n attrs: () => forwardedAttrs.value,\n})\n\n// @core\nfunction onActionClick(event: MouseEvent) {\n // A disabled button never receives the click at all; an inert link does, so it is\n // cancelled here.\n if (props.disabled) {\n event.preventDefault()\n return\n }\n emit('select')\n}\n</script>\n\n<template>\n <li class=\"v-side-nav-item\" :class=\"rootClass\" :style=\"rootStyle\">\n <details\n v-if=\"$slots.children\"\n class=\"v-side-nav-branch v-disclosure\"\n :name=\"parent?.name\"\n :open=\"openAttr\"\n :data-swap=\"collapseIcon ? '' : undefined\"\n @toggle=\"onToggle\"\n >\n <summary\n ref=\"rowEl\"\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :aria-current=\"current ? 'true' : undefined\"\n :aria-disabled=\"disabled || undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n v-bind=\"forwardedAttrs\"\n @click=\"onSummaryClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-side-nav-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-side-nav-content\">\n <span class=\"v-side-nav-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-side-nav-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n <!-- This slot sits INSIDE the branch header, where ANY click folds the\n branch: without the handler, clicking a badge would close the section\n under it -->\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\" @click=\"onEndClick\"\n ><slot name=\"end\"\n /></span>\n <VIcon class=\"v-side-nav-chevron v-disclosure-chevron\" v-bind=\"iconProps(expandIcon)\" />\n <VIcon\n v-if=\"collapseIcon\"\n class=\"v-side-nav-chevron v-side-nav-chevron-open v-disclosure-chevron v-disclosure-chevron-open\"\n v-bind=\"iconProps(collapseIcon)\"\n />\n </summary>\n <ul class=\"v-side-nav-children\">\n <slot name=\"children\" />\n </ul>\n </details>\n\n <div\n v-else\n class=\"v-side-nav-row\"\n :data-current=\"current ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n >\n <component\n :is=\"tag\"\n ref=\"actionEl\"\n class=\"v-side-nav-action\"\n :type=\"tag === 'button' ? 'button' : undefined\"\n :disabled=\"tag === 'button' ? disabled : undefined\"\n :aria-disabled=\"link.isInertLink.value ? 'true' : undefined\"\n :aria-current=\"current ? (tag === 'a' ? 'page' : 'true') : undefined\"\n v-bind=\"link.attrs.value\"\n :href=\"link.linkHref.value\"\n @click=\"onActionClick\"\n >\n <slot name=\"icon\">\n <VIcon v-if=\"icon\" class=\"v-side-nav-icon\" v-bind=\"iconProps(icon)\" />\n </slot>\n <span class=\"v-side-nav-content\">\n <span class=\"v-side-nav-label\"\n ><slot>{{ label }}</slot></span\n >\n <span v-if=\"sublabel !== undefined || $slots.sublabel\" class=\"v-side-nav-sublabel\">\n <slot name=\"sublabel\">{{ sublabel }}</slot>\n </span>\n </span>\n </component>\n <span v-if=\"$slots.end\" class=\"v-side-nav-end\"><slot name=\"end\" /></span>\n </div>\n </li>\n</template>\n\n<style>\n@layer vectis.components {\n /*\n * The obvious one-name form, incrementing a variable by reading itself, is a CYCLE as far as\n * CSS is concerned, even though the value being read is the inherited one. The property then\n * falls to invalid, every read falls back to zero, and the whole tree renders FLAT; with\n * nothing in the console to say why.\n */\n .v-side-nav-item {\n --side-nav-parent-level: var(--side-nav-level, 0);\n }\n\n .v-side-nav-children {\n --side-nav-level: calc(var(--side-nav-parent-level) + 1);\n }\n\n .v-side-nav-row {\n /*\n * The indent is computed here and not stored in a variable set higher up. A custom property\n * is substituted on the element that DECLARES it, so a padding computed on the nav would be\n * frozen at level zero for the whole tree.\n */\n\n /*\n * The cap has to stay derived from --control-height. A browser scales down any radius it\n * cannot fit, so a row exactly one control tall already paints half that height under a\n * pill override; min() applies the same reduction to a row that grew past it.\n */\n --side-nav-row-radius: min(var(--vectis-radius-interactive), calc(var(--control-height) / 2));\n\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n min-block-size: var(--control-height);\n padding-block: var(--vectis-space-1);\n padding-inline: calc(\n var(--control-padding-inline) + var(--side-nav-level, 0) * var(--side-nav-indent)\n )\n var(--control-padding-inline);\n border-radius: var(--side-nav-row-radius);\n color: var(--vectis-color-text);\n font-size: var(--control-font-size);\n line-height: var(--vectis-text-body-md-leading);\n cursor: pointer;\n }\n\n .v-side-nav-action {\n /* On a leaf the link is a CHILD of the row, and the indent deliberately stays on\n the row itself: what has to run the full width is the hover background, not the\n link inside it. */\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: var(--control-gap);\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n text-align: start;\n text-decoration: none;\n cursor: inherit;\n }\n\n /*\n * This is what stretches the link over the whole row without having to wrap the end slot\n * inside it. It is an invisible box, positioned, so it is painted above the chevron; which is\n * not positioned; while passing UNDER the end slot, which is positioned too and comes later\n * in the document.\n */\n .v-side-nav-action::after {\n content: '';\n position: absolute;\n inset: 0;\n border-radius: var(--side-nav-row-radius);\n }\n\n .v-side-nav-content {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n flex-direction: column;\n }\n\n .v-side-nav-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-sublabel {\n overflow: hidden;\n font-size: var(--vectis-text-caption-size);\n color: var(--vectis-color-text-muted);\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .v-side-nav-icon {\n flex: none;\n color: var(--vectis-color-text-muted);\n }\n\n /* Positioned on purpose: that is what paints it above the stretched link, and\n therefore what keeps whatever it holds clickable. */\n .v-side-nav-end {\n position: relative;\n flex: none;\n display: flex;\n align-items: center;\n gap: var(--vectis-space-1);\n }\n\n .v-side-nav-row:hover:not([data-disabled]) {\n background: var(--vectis-color-surface-muted);\n }\n\n /*\n * A branch header takes focus itself; a leaf only takes it through its link, and the\n * ring is then drawn on the stretched box so that it frames the whole row rather than\n * just the text.\n *\n * The ring is pulled INWARDS in both cases: the content of a branch is clipped so it\n * can be animated open, and a ring drawn outside the row would be cut off there.\n */\n .v-side-nav-row:focus-visible,\n .v-side-nav-action:focus-visible::after {\n outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline-offset: calc(-1 * var(--vectis-focus-ring-width));\n }\n\n .v-side-nav-action:focus-visible {\n outline: none;\n }\n\n .v-side-nav-row[data-current] {\n background: var(--vectis-color-accent-surface);\n color: var(--vectis-color-accent-text);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-label {\n font-weight: var(--vectis-text-label-weight);\n }\n\n .v-side-nav-row[data-current] .v-side-nav-icon,\n .v-side-nav-row[data-current] .v-side-nav-sublabel,\n .v-side-nav-row[data-current] .v-side-nav-chevron {\n color: inherit;\n }\n\n .v-side-nav-row[data-current]:not([data-disabled]):hover {\n /*\n * The current row is already tinted, so its hover deepens that tint rather than replacing\n * it with the neutral highlight; the VMenuItem idiom.\n */\n background: color-mix(\n in oklab,\n var(--vectis-color-accent-surface),\n var(--vectis-color-accent-text) 8%\n );\n }\n\n /* A CLOSED branch holding the current page keeps a mark of it, so the reader can see\n where they are without opening every section. The lookup is deliberately a\n descendant one: the page may be several levels down. */\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled]) {\n color: var(--vectis-color-accent-text);\n }\n\n /* A disabled row greys out through the colour tokens, never through opacity. */\n .v-side-nav-row[data-disabled] {\n color: var(--vectis-color-text-subtle);\n cursor: not-allowed;\n }\n\n /* The icon and the second line default to a colour DARKER than the one a disabled\n label takes: left alone they would come out stronger than the label itself, so they\n inherit it instead. The chevron gets the same treatment from `styles/disclosure.css`. */\n .v-side-nav-row[data-disabled] .v-side-nav-icon,\n .v-side-nav-row[data-disabled] .v-side-nav-sublabel {\n color: inherit;\n }\n\n /* Forced colours flatten the current row's tint to `Canvas` and its accent text to\n `CanvasText`, leaving a slightly bolder label as the only cue, and the mark on a closed\n branch is a colour alone. The current row takes the system selection pair, repeated to\n (0,4,0) above its own hover, and the closed branch underlines its label, a decoration\n the mode keeps. */\n @media (forced-colors: active) {\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current] {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .v-side-nav-row.v-side-nav-row.v-side-nav-row[data-current][data-disabled] {\n background: Canvas;\n color: GrayText;\n }\n\n .v-side-nav-branch:not([open]):has(.v-side-nav-children [aria-current])\n > .v-side-nav-row:not([data-current], [data-disabled])\n .v-side-nav-label {\n text-decoration: underline;\n }\n }\n\n /* The disclosure animation, the chevron's rotation or swap and the WebKit marker come\n from `styles/disclosure.css`, reduced-motion block included. */\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmDA,IAAM,IAAQ,GAkBR,IAAO,EAA2B,GAAC,MAAyB,GAE5D,IAAO,GA+BP,EAAE,cAAW,cAAW,sBAAmB,EAAa,GAExD,IAAQ,GAAS,GACjB,IAAM,QAAgB,EAAM,SAAS,KAAA,IAAkB,WAAN,GAAe,GAEhE,IAAS,EAAO,GAAmB,IAAI,GAMvC,IAAa,QAAe,GAAQ,cAAc,EAAc,GAChE,IAAe,QAAe,GAAQ,YAAY,GAIlD,KAAe,EAAM;EAC3B,GAAQ,GAAmB;GACzB,IAAI,OAAO;IACT,OAAO,GAAQ,YAAY,KAAe,KAAA;GAC5C;GACA,IAAI,YAAY;IACd,OAAO,GAAQ,aAAa;GAC9B;GACA,IAAI,aAAa;IACf,OAAO,EAAW;GACpB;GACA,IAAI,eAAe;IACjB,OAAO,EAAa;GACtB;EACF,CAAC;EAED,IAAM,EAAE,cAAU,aAAU,sBAAmB,EAAe,GAAM;GAClE,mBAAmB,EAAM;GACzB,gBAAgB,EAAM;EACxB,CAAC;EAQD,SAAS,EAAW,GAAmB;GAErC,AADe,EAAM,QACR,QAAQ,gDAAgD,KAAG,EAAM,eAAe;EAC/F;EAIA,IAAM,IAAQ,EAAwB,IAAI,GACpC,IAAW,EAAwB,IAAI,GACvC,UAAiB,EAAM,WAAW,EAAM,QAAQ,EAAS;EAC/D,EAAa;GAEX,QAAQ,MAA2B,EAAQ,CAAC,EAAE,MAAM,CAAO;GAE3D,IAAI,KAAK;IACP,OAAO,EAAQ;GACjB;EACF,CAAC;EAKD,IAAM,IAAO,EAAa;GACxB,YAAa,EAAI,UAAU,MAAM,EAAM,OAAO,KAAA;GAC9C,aAAa,EAAM;GACnB,aAAa,EAAe;EAC9B,CAAC;EAGD,SAAS,GAAc,GAAmB;GAGxC,IAAI,EAAM,UAAU;IAClB,EAAM,eAAe;IACrB;GACF;GACA,EAAK,QAAQ;EACf;yBAIE,EAiFK,MAAA;GAjFD,OAAK,EAAA,CAAC,mBAA0B,EAAA,CAAA,CAAS,CAAA;GAAG,OAAK,EAAE,EAAA,CAAA,CAAS;MAEtDA,EAAAA,OAAO,YAAA,EAAA,GADf,EA8CU,WAAA;;GA5CR,OAAM;GACL,MAAM,EAAA,CAAA,CAAM,EAAE;GACd,MAAM,EAAA,EAAA;GACN,aAAW,EAAA,QAAY,KAAQ,KAAA;GAC/B,UAAM,AAAA,EAAA,QAAA,GAAA,MAAE,EAAA,CAAA,KAAA,EAAA,CAAA,CAAA,CAAA,GAAA,CAAA;MAET,EAkCU,WAlCV,EAkCU;YAjCJ;GAAJ,KAAI;GACJ,OAAM;GACL,gBAAc,EAAA,UAAO,KAAQ,KAAA;GAC7B,iBAAe,EAAA,WAAQ,KAAQ,KAAA;GAC/B,gBAAc,EAAA,UAAO,SAAY,KAAA;GACjC,iBAAe,EAAA,YAAY,KAAA;GAC3B,UAAU,EAAA,WAAQ,KAAQ,KAAA;KACnB,EAAA,CAAA,GAAc,EACrB,SAAK,AAAA,EAAA,QAAA,GAAA,MAAE,EAAA,CAAA,KAAA,EAAA,CAAA,CAAA,CAAA,GAAA,CAAA,EAAA,CAAA,GAAA;GAER,EAEO,EAAA,QAAA,QAAA,CAAA,SAAA,CADQ,EAAA,QAAA,EAAA,GAAb,EAAsE,GAAtE,EAAsE;;IAAnD,OAAM;MAA0B,EAAA,CAAA,CAAS,CAAC,EAAA,IAAI,CAAA,GAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA;GAEnE,EAOO,QAPP,IAOO,CANL,EAEC,QAFD,GAEC,CADE,EAAwB,EAAA,QAAA,WAAA,CAAA,SAAA,CAAA,EAAA,EAAf,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAEL,EAAA,aAAa,KAAA,KAAaA,EAAAA,OAAO,YAAA,EAAA,GAA7C,EAEO,QAFP,GAEO,CADL,EAA2C,EAAA,QAAA,YAAA,CAAA,SAAA,CAAA,EAAA,EAAlB,EAAA,QAAQ,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA;GAMzBA,EAAAA,OAAO,OAAA,EAAA,GAAnB,EAES,QAAA;;IAFe,OAAM;IAAkB,SAAO;OACpD,EACD,EAAA,QAAA,KAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA;GACF,EAAwF,GAAxF,EAAwF,EAAjF,OAAM,0CAAyC,GAAS,EAAA,CAAA,CAAS,CAAC,EAAA,KAAU,CAAA,GAAA,MAAA,EAAA;GAE3E,EAAA,SAAA,EAAA,GADR,EAIE,GAJF,EAIE;;IAFA,OAAM;MACE,EAAA,CAAA,CAAS,CAAC,EAAA,KAAY,CAAA,GAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA;cAGlC,EAEK,MAFL,GAEK,CADH,EAAwB,EAAA,QAAA,UAAA,CAAA,CAAA,CAAA,GAAA,IAAA,EAAA,MAAA,EAAA,GAI5B,EA+BM,OAAA;;GA7BJ,OAAM;GACL,gBAAc,EAAA,UAAO,KAAQ,KAAA;GAC7B,iBAAe,EAAA,WAAQ,KAAQ,KAAA;YAEhC,EAuBY,EAtBL,EAAA,KAAG,GADV,EAuBY;YArBN;GAAJ,KAAI;GACJ,OAAM;GACL,MAAM,EAAA,UAAG,WAAA,WAA2B,KAAA;GACpC,UAAU,EAAA,UAAG,WAAgB,EAAA,WAAW,KAAA;GACxC,iBAAe,EAAA,CAAA,CAAI,CAAC,YAAY,QAAK,SAAY,KAAA;GACjD,gBAAc,EAAA,UAAW,EAAA,UAAG,MAAA,SAAA,SAA8B,KAAA;KACnD,EAAA,CAAA,CAAI,CAAC,MAAM,OAAK;GACvB,MAAM,EAAA,CAAA,CAAI,CAAC,SAAS;GACpB,SAAO;;qBAID,CAFP,EAEO,EAAA,QAAA,QAAA,CAAA,SAAA,CADQ,EAAA,QAAA,EAAA,GAAb,EAAsE,GAAtE,EAAsE;;IAAnD,OAAM;MAA0B,EAAA,CAAA,CAAS,CAAC,EAAA,IAAI,CAAA,GAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA,GAEnE,EAOO,QAPP,GAOO,CANL,EAEC,QAFD,GAEC,CADE,EAAwB,EAAA,QAAA,WAAA,CAAA,SAAA,CAAA,EAAA,EAAf,EAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAEL,EAAA,aAAa,KAAA,KAAaA,EAAAA,OAAO,YAAA,EAAA,GAA7C,EAEO,QAFP,GAEO,CADL,EAA2C,EAAA,QAAA,YAAA,CAAA,SAAA,CAAA,EAAA,EAAlB,EAAA,QAAQ,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA,CAAA,CAAA;;;;;;;;OAI3BA,EAAAA,OAAO,OAAA,EAAA,GAAnB,EAAyE,QAAzE,GAAyE,CAA1B,EAAmB,EAAA,QAAA,KAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,GAAA,GAAA,CAAA,EAAA,GAAA,CAAA"}
@@ -52,12 +52,12 @@ interface SkeletonLoaderProps {
52
52
  declare const __VLS_export: import('vue').DefineComponent<SkeletonLoaderProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<SkeletonLoaderProps> & Readonly<{}>, {
53
53
  label: string;
54
54
  size: SkeletonLoaderSize;
55
- compact: boolean;
56
- shape: SkeletonLoaderShape;
57
55
  color: string;
56
+ shape: SkeletonLoaderShape;
57
+ compact: boolean;
58
58
  width: number | string;
59
- announce: boolean;
60
59
  height: number | string;
60
+ announce: boolean;
61
61
  lines: number;
62
62
  animation: SkeletonLoaderAnimation;
63
63
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
@@ -1,2 +1,2 @@
1
1
  @layer vectis.reset, vectis.tokens, vectis.components, vectis.utilities;
2
- @layer vectis.components{.v-slider{--slider-thumb:var(--vectis-control-size-slider-thumb);--slider-track:var(--vectis-control-size-slider-track);align-items:center;column-gap:var(--vectis-space-2);row-gap:var(--vectis-space-1);inline-size:100%;font-family:var(--vectis-text-family);grid-template-columns:minmax(0,1fr);grid-template-areas:"rail";display:grid}.v-slider:has(.v-slider-labels){grid-template-areas:"rail""labels"}.v-slider[data-inputs=ends]{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"rail field-end"}.v-slider[data-inputs=ends]:has(.v-slider-labels){grid-template-areas:"rail field-end""labels."}.v-slider[data-inputs=ends][data-range]{grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:"field-start rail field-end"}.v-slider[data-inputs=ends][data-range]:has(.v-slider-labels){grid-template-areas:"field-start rail field-end"".labels."}.v-slider[data-inputs=top]{grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:"field-start.field-end""rail rail rail"}.v-slider[data-inputs=top]:has(.v-slider-labels){grid-template-areas:"field-start.field-end""rail rail rail""labels labels labels"}.v-slider[data-inputs=bottom]{grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:"rail rail rail""field-start.field-end"}.v-slider[data-inputs=bottom]:has(.v-slider-labels){grid-template-areas:"rail rail rail""labels labels labels""field-start.field-end"}.v-slider-rail{block-size:var(--slider-thumb);grid-area:rail;position:relative}.v-slider-control{position:absolute;inset:0}.v-slider-track{block-size:var(--slider-track);border-radius:var(--vectis-radius-pill);background:var(--vectis-color-border);margin-block:auto;position:absolute;inset-block:0;inset-inline:0;overflow:hidden}.v-slider-fill,.v-slider-tick,.v-slider-tooltip,.v-slider-label{--slider-at:calc(var(--slider-thumb) / 2 + (100% - var(--slider-thumb)) * var(--fill-fraction))}.v-slider-fill{--fill-fraction:var(--slider-end-fraction);inline-size:var(--slider-at);background:var(--vectis-color-accent);position:absolute;inset-block:0;inset-inline-start:0}.v-slider[data-range] .v-slider-fill{--fill-fraction:var(--slider-start-fraction);inline-size:calc((100% - var(--slider-thumb)) * (var(--slider-end-fraction) - var(--slider-start-fraction)));inset-inline-start:var(--slider-at)}.v-slider-tick{--slider-tick:calc(var(--slider-track) / 3 * 2);inline-size:var(--slider-tick);block-size:var(--slider-tick);border-radius:var(--vectis-radius-pill);background:var(--vectis-color-border-strong);margin-block:auto;position:absolute;inset-block:0;inset-inline-start:calc(var(--slider-at) - var(--slider-tick) / 2)}.v-slider-tick[data-filled]{background:var(--vectis-color-text-on-accent)}.v-slider-input{--slider-thumb-bg:var(--vectis-color-text-on-accent);--slider-thumb-border:var(--vectis-color-accent);--slider-thumb-shadow:var(--vectis-shadow-xs);--slider-thumb-outline:none;--slider-thumb-cursor:pointer;--slider-thumb-transition:background-color var(--vectis-duration-fast) var(--vectis-ease-default);appearance:none;pointer-events:none;background:0 0;width:100%;height:100%;margin:0;position:absolute;inset:0}.v-slider:not([data-range]) .v-slider-input{pointer-events:auto;cursor:pointer}.v-slider-input::-webkit-slider-thumb{appearance:none;pointer-events:auto;width:var(--slider-thumb);height:var(--slider-thumb);border-radius:var(--vectis-radius-pill);background:var(--slider-thumb-bg);border:var(--vectis-control-border-width) solid var(--slider-thumb-border);box-shadow:var(--slider-thumb-shadow);outline:var(--slider-thumb-outline);outline-offset:var(--vectis-focus-ring-offset);cursor:var(--slider-thumb-cursor);transition:var(--slider-thumb-transition)}.v-slider-input::-moz-range-thumb{pointer-events:auto;width:var(--slider-thumb);height:var(--slider-thumb);border-radius:var(--vectis-radius-pill);background:var(--slider-thumb-bg);border:var(--vectis-control-border-width) solid var(--slider-thumb-border);box-shadow:var(--slider-thumb-shadow);outline:var(--slider-thumb-outline);outline-offset:var(--vectis-focus-ring-offset);cursor:var(--slider-thumb-cursor);transition:var(--slider-thumb-transition)}.v-slider-input:is(:hover,:active):not(:disabled){--slider-thumb-bg:color-mix(in oklab, var(--vectis-color-text-on-accent), var(--vectis-color-accent) 10%)}.v-slider-input:focus-visible{--slider-thumb-outline:var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);outline:none}.v-slider[data-readonly] .v-slider-input{--slider-thumb-bg:var(--vectis-color-surface);--slider-thumb-border:var(--vectis-color-text-muted);--slider-thumb-cursor:default;cursor:default}.v-slider[data-readonly] .v-slider-fill{background:var(--vectis-color-text-muted)}.v-slider[data-readonly] .v-slider-tick[data-filled]{background:var(--vectis-color-surface)}.v-slider[data-invalid] .v-slider-input{--slider-thumb-border:var(--vectis-color-danger)}.v-slider-tooltip{opacity:0;visibility:hidden;inline-size:0;transition:opacity var(--vectis-duration-fast) var(--vectis-ease-default), visibility var(--vectis-duration-fast) var(--vectis-ease-default);justify-content:center;display:flex;position:absolute;inset-block-end:calc(100% + var(--vectis-space-2));inset-inline-start:var(--slider-at)}.v-slider-tooltip-start{--fill-fraction:var(--slider-start-fraction)}.v-slider-tooltip-end{--fill-fraction:var(--slider-end-fraction)}.v-slider:has(.v-slider-input-start:active) .v-slider-tooltip-start,.v-slider:has(.v-slider-input-start:focus-visible) .v-slider-tooltip-start,.v-slider:has(.v-slider-input-end:active) .v-slider-tooltip-end,.v-slider:has(.v-slider-input-end:focus-visible) .v-slider-tooltip-end{opacity:1;visibility:visible}.v-slider-tooltip-bubble{padding:var(--vectis-space-1) var(--vectis-space-2);background:var(--vectis-color-surface-inverse);color:var(--vectis-color-text-on-inverse);font-size:var(--vectis-text-caption-size);line-height:var(--vectis-text-caption-leading);border-radius:min(var(--vectis-radius-interactive), calc(.5lh + var(--vectis-space-1)));box-shadow:var(--vectis-shadow-sm);white-space:nowrap}.v-slider-labels{min-block-size:var(--vectis-icon-size-md);--vectis-icon-size:var(--vectis-icon-size-md);--vectis-icon-opsz:20;font-size:var(--vectis-text-caption-size);color:var(--vectis-color-text-muted);grid-area:labels;position:relative}.v-slider-label{white-space:nowrap;justify-content:center;inline-size:0;display:flex;position:absolute;inset-block-start:0;inset-inline-start:var(--slider-at)}.v-slider-hint{font-size:var(--vectis-text-caption-size);line-height:var(--vectis-text-caption-leading);color:var(--vectis-color-text-muted);grid-column:1/-1}.v-slider[data-disabled] .v-slider-hint{color:var(--vectis-color-text-subtle)}.v-slider-field.v-input{inline-size:var(--vectis-control-size-slider-field)}.v-slider-field-start.v-input{grid-area:field-start}.v-slider-field-end.v-input{grid-area:field-end}.v-slider[data-orientation=vertical]{grid-template-columns:none;grid-template-areas:"rail";justify-items:center;inline-size:fit-content}.v-slider[data-orientation=vertical]:has(.v-slider-labels){grid-template-columns:auto auto;grid-template-areas:"rail labels"}.v-slider[data-orientation=vertical][data-inputs=ends]{grid-template-columns:none;grid-template-areas:"field-end""rail"}.v-slider[data-orientation=vertical][data-inputs=ends]:has(.v-slider-labels){grid-template-columns:auto auto;grid-template-areas:"field-end.""rail labels"}.v-slider[data-orientation=vertical][data-inputs=ends][data-range]{grid-template-columns:none;grid-template-areas:"field-end""rail""field-start"}.v-slider[data-orientation=vertical][data-inputs=ends][data-range]:has(.v-slider-labels){grid-template-columns:auto auto;grid-template-areas:"field-end.""rail labels""field-start."}.v-slider[data-orientation=vertical][data-inputs=top]{grid-template:"field-end rail"".rail"1fr"field-start rail"/auto auto}.v-slider[data-orientation=vertical][data-inputs=top]:has(.v-slider-labels){grid-template-columns:auto auto auto;grid-template-areas:"field-end rail labels"".rail labels""field-start rail labels"}.v-slider[data-orientation=vertical][data-inputs=bottom]{grid-template:"rail field-end""rail."1fr"rail field-start"/auto auto}.v-slider[data-orientation=vertical][data-inputs=bottom]:has(.v-slider-labels){grid-template-columns:auto auto auto;grid-template-areas:"rail labels field-end""rail labels.""rail labels field-start"}.v-slider[data-orientation=vertical] .v-slider-rail{inline-size:var(--slider-thumb);block-size:var(--vectis-control-size-slider-length)}.v-slider[data-orientation=vertical] .v-slider-control{writing-mode:vertical-lr;direction:rtl}.v-slider[data-orientation=vertical] .v-slider-tooltip{justify-content:flex-end;align-items:center;block-size:0;inline-size:auto;inset-block-end:var(--slider-at);inset-inline-start:auto;inset-inline-end:calc(100% + var(--vectis-space-2))}.v-slider[data-orientation=vertical] .v-slider-labels{align-self:stretch;min-block-size:auto}.v-slider[data-orientation=vertical] .v-slider-label{justify-content:flex-start;align-items:center;block-size:0;inline-size:auto;inset-block-start:auto;inset-block-end:var(--slider-at);inset-inline-start:0}.v-slider[data-disabled]{cursor:not-allowed}.v-slider[data-disabled] .v-slider-track{background:var(--vectis-color-surface-muted)}.v-slider[data-disabled] .v-slider-fill,.v-slider[data-disabled] .v-slider-tick{background:var(--vectis-color-text-subtle)}.v-slider[data-disabled] .v-slider-tick[data-filled]{background:var(--vectis-color-surface-muted)}.v-slider[data-disabled] .v-slider-labels{color:var(--vectis-color-text-subtle)}.v-slider[data-disabled] .v-slider-input{--slider-thumb-bg:var(--vectis-color-surface-muted);--slider-thumb-border:var(--vectis-color-text-subtle);--slider-thumb-shadow:none;--slider-thumb-cursor:not-allowed;cursor:not-allowed}@media (forced-colors:active){.v-slider .v-slider-track{forced-color-adjust:none;box-shadow:inset 0 0 0 var(--vectis-control-border-width) CanvasText;background:canvas}.v-slider .v-slider-fill{forced-color-adjust:none;background:highlight}.v-slider .v-slider-tick{forced-color-adjust:none;background:canvastext}.v-slider .v-slider-tick[data-filled]{background:highlighttext}.v-slider .v-slider-input{forced-color-adjust:none;--slider-thumb-bg:Canvas;--slider-thumb-border:CanvasText;--slider-thumb-shadow:none}.v-slider[data-disabled] .v-slider-track{box-shadow:inset 0 0 0 var(--vectis-control-border-width) GrayText}.v-slider[data-disabled] .v-slider-fill,.v-slider[data-disabled] .v-slider-tick{background:graytext}.v-slider[data-disabled] .v-slider-input{--slider-thumb-border:GrayText}}@media (prefers-reduced-motion:reduce){.v-slider-input{--slider-thumb-transition:none}.v-slider-tooltip{transition:none}}}
2
+ @layer vectis.components{.v-slider-body{--slider-thumb:var(--vectis-control-size-slider-thumb);--slider-track:var(--vectis-control-size-slider-track);align-items:center;column-gap:var(--vectis-space-2);row-gap:var(--vectis-space-1);inline-size:100%;font-family:var(--vectis-text-family);grid-template-columns:minmax(0,1fr);grid-template-areas:"rail";display:grid}.v-slider-body:has(.v-slider-labels){grid-template-areas:"rail""labels"}.v-slider-body[data-inputs=ends]{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"rail field-end"}.v-slider-body[data-inputs=ends]:has(.v-slider-labels){grid-template-areas:"rail field-end""labels."}.v-slider-body[data-inputs=ends][data-range]{grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:"field-start rail field-end"}.v-slider-body[data-inputs=ends][data-range]:has(.v-slider-labels){grid-template-areas:"field-start rail field-end"".labels."}.v-slider-body[data-inputs=top]{grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:"field-start.field-end""rail rail rail"}.v-slider-body[data-inputs=top]:has(.v-slider-labels){grid-template-areas:"field-start.field-end""rail rail rail""labels labels labels"}.v-slider-body[data-inputs=bottom]{grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:"rail rail rail""field-start.field-end"}.v-slider-body[data-inputs=bottom]:has(.v-slider-labels){grid-template-areas:"rail rail rail""labels labels labels""field-start.field-end"}.v-slider-rail{block-size:var(--slider-thumb);grid-area:rail;position:relative}.v-slider-control{position:absolute;inset:0}.v-slider-track{block-size:var(--slider-track);border-radius:var(--vectis-radius-pill);background:var(--vectis-color-border);margin-block:auto;position:absolute;inset-block:0;inset-inline:0;overflow:hidden}.v-slider-fill,.v-slider-tick,.v-slider-tooltip,.v-slider-label{--slider-at:calc(var(--slider-thumb) / 2 + (100% - var(--slider-thumb)) * var(--fill-fraction))}.v-slider-fill{--fill-fraction:var(--slider-end-fraction);inline-size:var(--slider-at);background:var(--vectis-color-accent);position:absolute;inset-block:0;inset-inline-start:0}.v-slider-body[data-range] .v-slider-fill{--fill-fraction:var(--slider-start-fraction);inline-size:calc((100% - var(--slider-thumb)) * (var(--slider-end-fraction) - var(--slider-start-fraction)));inset-inline-start:var(--slider-at)}.v-slider-tick{--slider-tick:calc(var(--slider-track) / 3 * 2);inline-size:var(--slider-tick);block-size:var(--slider-tick);border-radius:var(--vectis-radius-pill);background:var(--vectis-color-border-strong);margin-block:auto;position:absolute;inset-block:0;inset-inline-start:calc(var(--slider-at) - var(--slider-tick) / 2)}.v-slider-tick[data-filled]{background:var(--vectis-color-text-on-accent)}.v-slider-input{--slider-thumb-bg:var(--vectis-color-text-on-accent);--slider-thumb-border:var(--vectis-color-accent);--slider-thumb-shadow:var(--vectis-shadow-xs);--slider-thumb-outline:none;--slider-thumb-cursor:pointer;--slider-thumb-transition:background-color var(--vectis-duration-fast) var(--vectis-ease-default);appearance:none;pointer-events:none;background:0 0;width:100%;height:100%;margin:0;position:absolute;inset:0}.v-slider-body:not([data-range]) .v-slider-input{pointer-events:auto;cursor:pointer}.v-slider-input::-webkit-slider-thumb{appearance:none;pointer-events:auto;width:var(--slider-thumb);height:var(--slider-thumb);border-radius:var(--vectis-radius-pill);background:var(--slider-thumb-bg);border:var(--vectis-control-border-width) solid var(--slider-thumb-border);box-shadow:var(--slider-thumb-shadow);outline:var(--slider-thumb-outline);outline-offset:var(--vectis-focus-ring-offset);cursor:var(--slider-thumb-cursor);transition:var(--slider-thumb-transition)}.v-slider-input::-moz-range-thumb{pointer-events:auto;width:var(--slider-thumb);height:var(--slider-thumb);border-radius:var(--vectis-radius-pill);background:var(--slider-thumb-bg);border:var(--vectis-control-border-width) solid var(--slider-thumb-border);box-shadow:var(--slider-thumb-shadow);outline:var(--slider-thumb-outline);outline-offset:var(--vectis-focus-ring-offset);cursor:var(--slider-thumb-cursor);transition:var(--slider-thumb-transition)}.v-slider-input:is(:hover,:active):not(:disabled){--slider-thumb-bg:color-mix(in oklab, var(--vectis-color-text-on-accent), var(--vectis-color-accent) 10%)}.v-slider-input:focus-visible{--slider-thumb-outline:var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);outline:none}.v-slider-body[data-readonly] .v-slider-input{--slider-thumb-bg:var(--vectis-color-surface);--slider-thumb-border:var(--vectis-color-text-muted);--slider-thumb-cursor:default;cursor:default}.v-slider-body[data-readonly] .v-slider-fill{background:var(--vectis-color-text-muted)}.v-slider-body[data-readonly] .v-slider-tick[data-filled]{background:var(--vectis-color-surface)}.v-slider-body[data-invalid] .v-slider-input{--slider-thumb-border:var(--vectis-color-danger)}.v-slider-tooltip{opacity:0;visibility:hidden;inline-size:0;transition:opacity var(--vectis-duration-fast) var(--vectis-ease-default), visibility var(--vectis-duration-fast) var(--vectis-ease-default);justify-content:center;display:flex;position:absolute;inset-block-end:calc(100% + var(--vectis-space-2));inset-inline-start:var(--slider-at)}.v-slider-tooltip-start{--fill-fraction:var(--slider-start-fraction)}.v-slider-tooltip-end{--fill-fraction:var(--slider-end-fraction)}.v-slider-body:has(.v-slider-input-start:active) .v-slider-tooltip-start,.v-slider-body:has(.v-slider-input-start:focus-visible) .v-slider-tooltip-start,.v-slider-body:has(.v-slider-input-end:active) .v-slider-tooltip-end,.v-slider-body:has(.v-slider-input-end:focus-visible) .v-slider-tooltip-end{opacity:1;visibility:visible}.v-slider-tooltip-bubble{padding:var(--vectis-space-1) var(--vectis-space-2);background:var(--vectis-color-surface-inverse);color:var(--vectis-color-text-on-inverse);font-size:var(--vectis-text-caption-size);line-height:var(--vectis-text-caption-leading);border-radius:min(var(--vectis-radius-interactive), calc(.5lh + var(--vectis-space-1)));box-shadow:var(--vectis-shadow-sm);white-space:nowrap}.v-slider-labels{min-block-size:var(--vectis-icon-size-md);--vectis-icon-size:var(--vectis-icon-size-md);--vectis-icon-opsz:20;font-size:var(--vectis-text-caption-size);color:var(--vectis-color-text-muted);grid-area:labels;position:relative}.v-slider-label{white-space:nowrap;justify-content:center;inline-size:0;display:flex;position:absolute;inset-block-start:0;inset-inline-start:var(--slider-at)}.v-slider-field.v-input{inline-size:var(--vectis-control-size-slider-field)}.v-slider-field-start.v-input{grid-area:field-start}.v-slider-field-end.v-input{grid-area:field-end}.v-slider-body[data-orientation=vertical]{grid-template-columns:none;grid-template-areas:"rail";justify-items:center;inline-size:fit-content}.v-slider-body[data-orientation=vertical]:has(.v-slider-labels){grid-template-columns:auto auto;grid-template-areas:"rail labels"}.v-slider-body[data-orientation=vertical][data-inputs=ends]{grid-template-columns:none;grid-template-areas:"field-end""rail"}.v-slider-body[data-orientation=vertical][data-inputs=ends]:has(.v-slider-labels){grid-template-columns:auto auto;grid-template-areas:"field-end.""rail labels"}.v-slider-body[data-orientation=vertical][data-inputs=ends][data-range]{grid-template-columns:none;grid-template-areas:"field-end""rail""field-start"}.v-slider-body[data-orientation=vertical][data-inputs=ends][data-range]:has(.v-slider-labels){grid-template-columns:auto auto;grid-template-areas:"field-end.""rail labels""field-start."}.v-slider-body[data-orientation=vertical][data-inputs=top]{grid-template:"field-end rail"".rail"1fr"field-start rail"/auto auto}.v-slider-body[data-orientation=vertical][data-inputs=top]:has(.v-slider-labels){grid-template-columns:auto auto auto;grid-template-areas:"field-end rail labels"".rail labels""field-start rail labels"}.v-slider-body[data-orientation=vertical][data-inputs=bottom]{grid-template:"rail field-end""rail."1fr"rail field-start"/auto auto}.v-slider-body[data-orientation=vertical][data-inputs=bottom]:has(.v-slider-labels){grid-template-columns:auto auto auto;grid-template-areas:"rail labels field-end""rail labels.""rail labels field-start"}.v-slider-body[data-orientation=vertical] .v-slider-rail{inline-size:var(--slider-thumb);block-size:var(--vectis-control-size-slider-length)}.v-slider-body[data-orientation=vertical] .v-slider-control{writing-mode:vertical-lr;direction:rtl}.v-slider-body[data-orientation=vertical] .v-slider-tooltip{justify-content:flex-end;align-items:center;block-size:0;inline-size:auto;inset-block-end:var(--slider-at);inset-inline-start:auto;inset-inline-end:calc(100% + var(--vectis-space-2))}.v-slider-body[data-orientation=vertical] .v-slider-labels{align-self:stretch;min-block-size:auto}.v-slider-body[data-orientation=vertical] .v-slider-label{justify-content:flex-start;align-items:center;block-size:0;inline-size:auto;inset-block-start:auto;inset-block-end:var(--slider-at);inset-inline-start:0}.v-slider-body[data-disabled]{cursor:not-allowed}.v-slider-body[data-disabled] .v-slider-track{background:var(--vectis-color-surface-muted)}.v-slider-body[data-disabled] .v-slider-fill,.v-slider-body[data-disabled] .v-slider-tick{background:var(--vectis-color-text-subtle)}.v-slider-body[data-disabled] .v-slider-tick[data-filled]{background:var(--vectis-color-surface-muted)}.v-slider-body[data-disabled] .v-slider-labels{color:var(--vectis-color-text-subtle)}.v-slider-body[data-disabled] .v-slider-input{--slider-thumb-bg:var(--vectis-color-surface-muted);--slider-thumb-border:var(--vectis-color-text-subtle);--slider-thumb-shadow:none;--slider-thumb-cursor:not-allowed;cursor:not-allowed}@media (forced-colors:active){.v-slider-body .v-slider-track{forced-color-adjust:none;box-shadow:inset 0 0 0 var(--vectis-control-border-width) CanvasText;background:canvas}.v-slider-body .v-slider-fill{forced-color-adjust:none;background:highlight}.v-slider-body .v-slider-tick{forced-color-adjust:none;background:canvastext}.v-slider-body .v-slider-tick[data-filled]{background:highlighttext}.v-slider-body .v-slider-input{forced-color-adjust:none;--slider-thumb-bg:Canvas;--slider-thumb-border:CanvasText;--slider-thumb-shadow:none}.v-slider-body[data-disabled] .v-slider-track{box-shadow:inset 0 0 0 var(--vectis-control-border-width) GrayText}.v-slider-body[data-disabled] .v-slider-fill,.v-slider-body[data-disabled] .v-slider-tick{background:graytext}.v-slider-body[data-disabled] .v-slider-input{--slider-thumb-border:GrayText}}@media (prefers-reduced-motion:reduce){.v-slider-input{--slider-thumb-transition:none}.v-slider-tooltip{transition:none}}}
@@ -1,3 +1,4 @@
1
+ import { FieldLabelPosition } from '../VField/VField.js';
1
2
  import { IconSource } from '../VIcon/types.js';
2
3
  /**
3
4
  * What one step of the track is called: a piece of text, or an icon paired with the words that
@@ -49,17 +50,29 @@ interface SliderProps {
49
50
  */
50
51
  size?: SliderSize;
51
52
  /**
52
- * What screen readers announce for the slider. It is an accessible name and draws
53
- * nothing on screen. In range mode the two thumbs are announced as the start and the
54
- * end of it.
53
+ * The label above the slider, which also names its thumbs: in range mode they are announced
54
+ * as the start and the end of it.
55
55
  */
56
56
  label?: string;
57
+ /** Hides the label visually. It still names the thumbs for assistive technology. */
58
+ hideLabel?: boolean;
59
+ /**
60
+ * Where the label sits: above the slider (`top`, the default), or at its start, in a column of
61
+ * its own, moving back above when there is not room for both.
62
+ */
63
+ labelPosition?: FieldLabelPosition;
57
64
  /**
58
65
  * A line of help under the track, stating what the numbers mean or where they may go. It
59
66
  * is tied to the slider for assistive technology, so it is read out after the name rather
60
67
  * than as part of it.
61
68
  */
62
69
  hint?: string;
70
+ /**
71
+ * A message saying what is wrong with the value, shown in place of the hint so that the field
72
+ * does not grow. It marks the field invalid, is read along with it, and is announced when it
73
+ * appears or changes.
74
+ */
75
+ error?: string;
63
76
  /** Turns the slider upright, with the lowest value at the bottom. */
64
77
  orientation?: SliderOrientation;
65
78
  /**
@@ -80,6 +93,14 @@ interface SliderProps {
80
93
  labels?: SliderLabel[];
81
94
  /** Shows the value in a bubble above the thumb while it is being moved or focused. */
82
95
  tooltip?: boolean;
96
+ /**
97
+ * How the value is written in the bubble, the number fields and what the thumbs announce: the
98
+ * options of `Intl.NumberFormat`, for a price, a unit or a percentage. `min`, `max` and `step`
99
+ * stay in the model's unit: with `style: 'percent'`, 0.25 is written 25%.
100
+ */
101
+ formatOptions?: Intl.NumberFormatOptions;
102
+ /** The locale the value is written and read in. It defaults to the design system's. */
103
+ locale?: string;
83
104
  }
84
105
  type __VLS_Props = SliderProps;
85
106
  type __VLS_ModelProps = {
@@ -103,19 +124,24 @@ declare const __VLS_export: import('vue').DefineComponent<__VLS_PublicProps, {
103
124
  }>, {
104
125
  label: string;
105
126
  range: boolean;
127
+ error: string;
106
128
  size: SliderSize;
107
- orientation: SliderOrientation;
108
129
  disabled: boolean;
130
+ tooltip: boolean;
131
+ orientation: SliderOrientation;
132
+ step: number;
109
133
  invalid: boolean;
110
134
  hint: string;
135
+ hideLabel: boolean;
136
+ labelPosition: FieldLabelPosition;
111
137
  readonly: boolean;
112
- tooltip: boolean;
113
- max: number;
114
- step: number;
115
138
  min: number;
139
+ max: number;
140
+ formatOptions: Intl.NumberFormatOptions;
141
+ locale: string;
142
+ labels: SliderLabel[];
116
143
  inputs: SliderInputs;
117
144
  ticks: boolean;
118
- labels: SliderLabel[];
119
145
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
120
146
  declare const _default: typeof __VLS_export;
121
147
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"VSlider.js","names":[],"sources":["../../../src/components/VSlider/VSlider.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * Native range inputs own thumb interaction. JavaScript keeps range endpoints ordered and\n * synchronizes optional number fields, labels and ARIA values.\n */\n\nimport { computed, inject, reactive, ref, watch, watchEffect } from 'vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\nimport VInput from '../VInput/VInput.vue'\nimport { inputGroupKey } from '../VInput/context'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useControlShape } from '../../composables/useControlShape'\nimport { useFieldIds } from '../../composables/useFieldIds'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport { isDev } from '../../utils/env'\nimport { clamp } from '../../utils/number'\nimport { useMessages } from '../../i18n/state'\n\n/**\n * What one step of the track is called: a piece of text, or an icon paired with the words that\n * name it, which a screen reader reads in place of the raw number.\n */\nexport type SliderLabel = string | { icon: IconSource; label: string }\n\n/** The value of a slider: one number, or an ordered pair of them in range mode. */\nexport type SliderValue = number | [number, number]\n\n/** Which way the track runs. */\nexport type SliderOrientation = 'horizontal' | 'vertical'\n\n/** The height of the number fields: 32, 40 or 48 pixels. */\nexport type SliderSize = 'sm' | 'md' | 'lg'\n\n/**\n * Where the number fields sit: none, at the ends of the track, or in a row above or below\n * it. On an upright slider, above and below become the two sides of it.\n */\nexport type SliderInputs = false | 'ends' | 'top' | 'bottom'\n\ninterface SliderProps {\n /** The lowest value the thumb can reach. It is 0 by default. */\n min?: number\n /** The highest value the thumb can reach. It is 100 by default. */\n max?: number\n /**\n * The gap between two values the thumb can stop on, 1 by default. It is also what the\n * arrow keys move by, and what a value typed into the companion field is snapped to.\n */\n step?: number\n /** Offers two thumbs to pick a range, which makes the v-model a pair of values. */\n range?: boolean\n /** Makes the slider unusable. */\n disabled?: boolean\n /**\n * Shows the value without allowing it to be changed. The thumbs can still be focused and\n * are announced as read-only, but neither the pointer nor the keyboard moves them, and the\n * number fields turn read-only with them.\n */\n readonly?: boolean\n /**\n * Marks the value as invalid, which colours the thumbs and tells assistive technology\n * so. It is for a rule the browser cannot check by itself.\n */\n invalid?: boolean\n /**\n * The height of the number fields `inputs` adds. Inside a VInputGroup the group's size\n * wins, as it does for every field of the row.\n */\n size?: SliderSize\n /**\n * What screen readers announce for the slider. It is an accessible name and draws\n * nothing on screen. In range mode the two thumbs are announced as the start and the\n * end of it.\n */\n label?: string\n /**\n * A line of help under the track, stating what the numbers mean or where they may go. It\n * is tied to the slider for assistive technology, so it is read out after the name rather\n * than as part of it.\n */\n hint?: string\n /** Turns the slider upright, with the lowest value at the bottom. */\n orientation?: SliderOrientation\n /**\n * Adds a number field for setting the value exactly: one, or one per end in range mode. No\n * field is drawn by default.\n */\n inputs?: SliderInputs\n /**\n * Marks each step on the track. Providing labels implies it. Past fifty steps the\n * marks would be an unreadable comb and are not drawn at all.\n */\n ticks?: boolean\n /**\n * A label for every step, in order: a piece of text, or an icon with the words that\n * name it for screen readers. They also become what a screen reader announces in\n * place of the raw number.\n */\n labels?: SliderLabel[]\n /** Shows the value in a bubble above the thumb while it is being moved or focused. */\n tooltip?: boolean\n}\n\nconst props = withDefaults(defineProps<SliderProps>(), {\n min: 0,\n max: 100,\n step: 1,\n range: false,\n disabled: false,\n readonly: false,\n invalid: false,\n size: 'md',\n label: undefined,\n hint: undefined,\n orientation: 'horizontal',\n inputs: false,\n ticks: false,\n labels: undefined,\n tooltip: false,\n})\n\n/** The value: a single number, 0 to begin with, or an ordered pair once `range` is set. */\nconst model = defineModel<SliderValue>({ default: 0 })\n\nconst emit = defineEmits<{\n /** The value is BEING changed: every step of a drag, and every key that moves a thumb. */\n input: [value: SliderValue]\n /**\n * The reader has SETTLED on a value: a thumb was released or moved by a key, or a number\n * field was committed.\n */\n change: [value: SliderValue]\n}>()\n\n// The number fields are fields of a VInputGroup row like any other, so the row's size and\n// its disabled state reach them through the same arbitration. A slider has no `compact` of\n// its own: only the row's can apply.\nconst group = inject(inputGroupKey, null)\nconst {\n size: resolvedSize,\n compact: resolvedCompact,\n disabled: resolvedDisabled,\n} = useControlShape(\n {\n get size() {\n return props.size\n },\n compact: false,\n get disabled() {\n return props.disabled\n },\n },\n group,\n)\n\ntype Thumb = 'start' | 'end'\n\nconst startValue = computed(() => (Array.isArray(model.value) ? model.value[0] : props.min))\nconst endValue = computed(() =>\n Array.isArray(model.value) ? model.value[1] : (model.value as number),\n)\n\nconst thumbValue = (which: Thumb) => (which === 'start' ? startValue.value : endValue.value)\n\n/**\n * Where a value sits along the run, as a fraction between 0 and 1. The guard covers a\n * slider whose two bounds are equal, which would otherwise divide by zero.\n */\nconst frac = (v: number) => clamp((v - props.min) / (props.max - props.min || 1), 0, 1)\n\n// @core\n// The thumb being held PUSHES its sibling; it must not stop against it. Two thumbs resting on\n// the same value are one thumb as far as the pointer is concerned, the end one being last in\n// the DOM and therefore the only one it can reach; so a range stopped at `[100, 100]` could\n// only ever be raised, and at the maximum it could not move at all.\nfunction writeThumb(which: Thumb, n: number): SliderValue {\n const next: SliderValue = !props.range\n ? n\n : which === 'start'\n ? [n, Math.max(n, endValue.value)]\n : [Math.min(n, startValue.value), n]\n model.value = next\n return next\n}\n\nconst writtenFor = (value: SliderValue, which: Thumb) =>\n Array.isArray(value) ? value[which === 'start' ? 0 : 1] : value\n\nfunction onThumbInput(which: Thumb, event: Event) {\n const el = event.target as HTMLInputElement\n // @core\n // A drag or a click on the track has ALREADY moved the native thumb when `input` fires,\n // and the event cannot be cancelled: putting the value back is the only refusal there is.\n // It lands before the browser paints, so the thumb never visibly leaves its place, and\n // since the value at release is the one it started from, no `change` follows either.\n if (props.readonly) {\n el.value = String(thumbValue(which))\n return\n }\n const next = writeThumb(which, Number(el.value))\n el.value = String(writtenFor(next, which))\n emit('input', next)\n}\n\n// @keyboard @core\n// The keys that move a range input, cancelled before the browser applies them when the\n// slider is read-only. Tab and every other key pass, so the thumbs stay reachable.\nconst VALUE_KEYS = new Set([\n 'ArrowUp',\n 'ArrowDown',\n 'ArrowLeft',\n 'ArrowRight',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n])\n\nfunction onThumbKeydown(event: KeyboardEvent) {\n if (props.readonly && VALUE_KEYS.has(event.key)) event.preventDefault()\n}\n\n// @core\n/*\n * The settled value is read off the THUMB, never off the model. A key press fires `input` and\n * `change` back to back in one task, and under a parent `v-model` the model's local copy only\n * catches up when the parent re-renders, so it would still hold the value from before the key.\n */\nfunction onThumbChange(which: Thumb, event: Event) {\n if (props.readonly) return\n const value = Number((event.target as HTMLInputElement).value)\n if (!props.range) emit('change', value)\n else if (which === 'start') emit('change', [value, Math.max(value, endValue.value)])\n else emit('change', [Math.min(value, startValue.value), value])\n}\n\n/** How many whole steps the thumb can actually stop on. */\nconst stepCount = computed(() =>\n props.step > 0 ? Math.floor((props.max - props.min) / props.step + 1e-9) : 0,\n)\n\n/**\n * The highest value a thumb can actually stop on, which is the last whole step and not\n * necessarily the maximum: with `min=0 max=95 step=10` the native control stops at 90.\n */\nconst lastStop = computed(() =>\n props.step > 0 ? props.min + stepCount.value * props.step : props.max,\n)\n\nconst showTicks = computed(\n () =>\n (props.ticks || props.labels !== undefined) && stepCount.value >= 1 && stepCount.value <= 50,\n)\n\n/** Each step's value and the style that places it, shared by the ticks and the labels. */\nconst stepPlaces = computed(() => {\n const length = Math.max(showTicks.value ? stepCount.value + 1 : 0, props.labels?.length ?? 0)\n return Array.from({ length }, (_, i) => {\n const value = props.min + i * props.step\n return { value, style: { '--fill-fraction': String(frac(value)) } }\n })\n})\n\nconst tickPlaces = computed(() =>\n showTicks.value ? stepPlaces.value.slice(0, stepCount.value + 1) : [],\n)\n\nconst isFilled = (value: number) =>\n props.range ? value >= startValue.value && value <= endValue.value : value <= endValue.value\n\n/** What a value is called, if the consumer named its step; failing that, the number itself. */\nfunction labelTextAt(value: number): string {\n const item = props.labels?.[Math.round((value - props.min) / props.step)]\n if (item === undefined) return String(value)\n return typeof item === 'string' ? item : item.label\n}\n\n// @a11y\n/*\n * Resolve the label against consumer ARIA attributes before deriving distinct range-thumb\n * names; an undefined prop must not erase their accessible name.\n */\nconst m = useMessages()\nconst resolvedLabel = useAriaLabel(() => props.label)\nconst startLabel = computed(() =>\n resolvedLabel.value ? m.value.slider.rangeStart(resolvedLabel.value) : m.value.slider.start,\n)\nconst endLabel = computed(() =>\n resolvedLabel.value ? m.value.slider.rangeEnd(resolvedLabel.value) : m.value.slider.end,\n)\nconst thumbEndLabel = computed(() => (props.range ? endLabel.value : resolvedLabel.value))\nconst fieldEndLabel = computed(() =>\n props.range ? endLabel.value : (resolvedLabel.value ?? m.value.slider.value),\n)\n\nconst startValueText = computed(() =>\n props.range && props.labels ? labelTextAt(startValue.value) : undefined,\n)\nconst endValueText = computed(() => (props.labels ? labelTextAt(endValue.value) : undefined))\n\n// @a11y\n/*\n * The wrapper-root split. The root here is a layout box holding the labels, the track and the\n * optional number fields, so a consumer's `name`, `id`, `required` and `aria-*` have to be\n * redirected onto the real `<input type=\"range\">`; left on the wrapper, a `name` submits\n * nothing and a `<label for>` points at a div.\n */\ndefineOptions({ inheritAttrs: false })\nconst { attrs, rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\n// The hint is APPENDED to whatever the consumer already pointed at rather than replacing\n// it, which is why the binding below sits after the forwarded attributes, as on every\n// other field of the design system.\nconst { hintId, describedBy } = useFieldIds(attrs, () => !!props.hint)\n\n/**\n * Where the fields go, `ends` standing in for any other truthy value: a bare `inputs`\n * attribute reaches the component as `true`, the prop being part boolean.\n */\nconst inputsPlace = computed(() =>\n props.inputs === 'top' || props.inputs === 'bottom' ? props.inputs : props.inputs && 'ends',\n)\n\n// @devwarn\n/*\n * Every guard here describes something that fails SILENTLY. They sit in an effect, so a\n * bound that only becomes wrong on a later render is still caught, and each sentence is\n * given once per instance: the same warning repeated on every keystroke is how a warning\n * stops being read (the `useFileField` arrangement).\n */\nif (isDev) {\n // Keyed by a short id rather than by the sentence: each of these embeds a count, so the\n // same guard reported twice would read as two different messages and warn again.\n const warned = new Set<string>()\n const warn = (id: string, message: string) => {\n if (warned.has(id)) return\n warned.add(id)\n console.warn(`[VSlider] ${message}`)\n }\n watchEffect(() => {\n if (props.step <= 0)\n warn(\n 'step',\n `step=\"${props.step}\" cannot move a thumb: the arrow keys do nothing and a value typed into a field is committed as it stands. Give a positive step.`,\n )\n if ((props.ticks || props.labels) && stepCount.value > 50)\n warn(\n 'ticks',\n `${stepCount.value} steps: no tick is drawn past 50, the comb being unreadable.`,\n )\n if (props.labels && props.labels.length !== stepCount.value + 1)\n warn(\n 'labels',\n `${props.labels.length} labels for ${stepCount.value + 1} steps: one label per step expected.`,\n )\n if (props.inputs !== false && props.inputs !== inputsPlace.value)\n warn(\n 'inputs',\n `inputs=\"${String(props.inputs)}\" is not a placement: the fields are drawn at the ends. Write inputs=\"ends\", \"top\" or \"bottom\".`,\n )\n if (props.range && attrs.name !== undefined)\n warn(\n 'name',\n `name=\"${String(attrs.name)}\" on a range: only the end thumb carries it, so the form receives one value of the two. Bind the model to two inputs of your own instead.`,\n )\n })\n}\n\n// @core\n// It is typed as text or a number because these are number fields, whose value Vue converts to\n// a number as soon as it can be read as one; while an empty field, or one holding a half-typed\n// \"1-\", stays text. That is why the value is turned back into text when it is committed.\nconst fieldText = reactive<Record<Thumb, string | number>>({\n start: String(startValue.value),\n end: String(endValue.value),\n})\n\nwatch(startValue, (v) => {\n if (props.range) fieldText.start = String(v)\n})\nwatch(endValue, (v) => (fieldText.end = String(v)))\n\n// @a11y\n/*\n * The fields are rendered in the order they are SEEN, before or after the track, so that\n * the tab order follows the screen. Laid out by the grid alone from a fixed DOM order, a\n * row of fields above the track would be reached one on each side of the thumbs.\n */\nconst fieldsBefore = computed<Thumb[]>(() => {\n if (inputsPlace.value === 'ends') return props.range ? ['start'] : []\n if (inputsPlace.value === 'top') return props.range ? ['start', 'end'] : ['end']\n return []\n})\nconst fieldsAfter = computed<Thumb[]>(() => {\n if (inputsPlace.value === 'ends') return ['end']\n if (inputsPlace.value === 'bottom') return props.range ? ['start', 'end'] : ['end']\n return []\n})\n\nconst fieldLabel = (which: Thumb) => (which === 'start' ? startLabel.value : fieldEndLabel.value)\n\n// @core\n/**\n * Takes what was typed in a field and makes it the value; but only once the reader has\n * finished, on leaving the field or on Enter.\n */\nfunction commitField(which: Thumb) {\n const raw = fieldText[which]\n // Parsed rather than converted: an empty string parses to nothing, which triggers the revert\n // below, where converting it would give ZERO and quietly overwrite the value with it.\n const parsed = Number.parseFloat(String(raw))\n if (Number.isNaN(parsed)) {\n resyncFields()\n return\n }\n // The ceiling is the last step that FITS, never `max` itself. A native range stops there\n // (that is what `stepCount` counts), so clipped to a `max` the step does not reach, the model\n // held a value the thumb could not: the browser sanitized its input back down, and the\n // number, the thumb and the fill then said three different things.\n const clamped = clamp(parsed, props.min, props.max)\n const snapped =\n props.step > 0\n ? props.min + Math.round((clamped - props.min) / props.step) * props.step\n : clamped\n const value = Math.min(lastStop.value, Math.round(snapped * 1e10) / 1e10)\n const previous = thumbValue(which)\n const next = writeThumb(which, value)\n // Emitted only when the value MOVED, as a native range emits nothing for a key that cannot\n // move its thumb; and the payload is `next`, the model's local copy lagging a parent\n // `v-model` (see `onThumbChange`).\n if (writtenFor(next, which) !== previous) emit('change', next)\n // Put back explicitly, because a commit that does not change the value; typing 200 where the\n // maximum is 100; changes nothing for the watchers to react to, and the field would go on\n // showing what was typed.\n resyncFields()\n}\n\nfunction resyncFields() {\n if (props.range) fieldText.start = String(startValue.value)\n fieldText.end = String(endValue.value)\n}\n\nconst endThumbEl = ref<HTMLInputElement | null>(null)\n\n// Both members point at the END thumb: it is the one always rendered, and the one the\n// consumer's `id` lands on, so `focus()` goes where a `<label for>` would send it.\ndefineExpose({\n /** Moves the focus to the end thumb, the only thumb outside range mode. */\n focus: (options?: FocusOptions) => endThumbEl.value?.focus(options),\n /** The end thumb's real `<input type=\"range\">`, for what `focus` does not cover. */\n el: endThumbEl,\n})\n</script>\n\n<template>\n <div\n class=\"v-slider\"\n :class=\"rootClass\"\n :data-range=\"range ? '' : undefined\"\n :data-disabled=\"resolvedDisabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n :data-invalid=\"invalid ? '' : undefined\"\n :data-size=\"resolvedSize\"\n :data-orientation=\"orientation\"\n :data-inputs=\"inputsPlace || undefined\"\n :style=\"[\n rootStyle,\n {\n '--slider-start-fraction': range ? String(frac(startValue)) : undefined,\n '--slider-end-fraction': String(frac(endValue)),\n },\n ]\"\n >\n <VInput\n v-for=\"which in fieldsBefore\"\n :key=\"which\"\n v-model=\"fieldText[which]\"\n :class=\"['v-slider-field', `v-slider-field-${which}`]\"\n type=\"number\"\n :size=\"resolvedSize\"\n :compact=\"resolvedCompact\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"resolvedDisabled\"\n :readonly=\"readonly\"\n :invalid=\"invalid\"\n :aria-label=\"fieldLabel(which)\"\n @change=\"commitField(which)\"\n />\n <div class=\"v-slider-rail\">\n <span class=\"v-slider-control\">\n <span class=\"v-slider-track\" aria-hidden=\"true\">\n <span class=\"v-slider-fill\" />\n <span\n v-for=\"(tick, i) in tickPlaces\"\n :key=\"i\"\n class=\"v-slider-tick\"\n :data-filled=\"isFilled(tick.value) ? '' : undefined\"\n :style=\"tick.style\"\n />\n </span>\n <input\n v-if=\"range\"\n type=\"range\"\n class=\"v-slider-input v-slider-input-start\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"resolvedDisabled\"\n :value=\"startValue\"\n :aria-label=\"startLabel\"\n :aria-valuetext=\"startValueText\"\n :aria-invalid=\"invalid || undefined\"\n :aria-readonly=\"readonly || undefined\"\n @keydown=\"onThumbKeydown\"\n @input=\"onThumbInput('start', $event)\"\n @change=\"onThumbChange('start', $event)\"\n />\n <!--\n The consumer's attributes come first, so what the component decides for itself; the\n bounds, the value and the disabled state; cannot be overwritten by one of them, and so\n that an ARIA state the consumer sets is not erased by an `undefined` of ours.\n `aria-valuetext` is one of those: the component has one to say only when `labels` was\n given.\n -->\n <input\n ref=\"endThumbEl\"\n :aria-invalid=\"invalid || undefined\"\n :aria-readonly=\"readonly || undefined\"\n :aria-valuetext=\"endValueText\"\n v-bind=\"forwardedAttrs\"\n type=\"range\"\n class=\"v-slider-input v-slider-input-end\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"resolvedDisabled\"\n :value=\"endValue\"\n :aria-label=\"thumbEndLabel\"\n :aria-describedby=\"describedBy\"\n @keydown=\"onThumbKeydown\"\n @input=\"onThumbInput('end', $event)\"\n @change=\"onThumbChange('end', $event)\"\n />\n </span>\n <span\n v-if=\"tooltip && range\"\n class=\"v-slider-tooltip v-slider-tooltip-start\"\n aria-hidden=\"true\"\n >\n <span class=\"v-slider-tooltip-bubble\">{{ startValueText ?? startValue }}</span>\n </span>\n <span v-if=\"tooltip\" class=\"v-slider-tooltip v-slider-tooltip-end\" aria-hidden=\"true\">\n <span class=\"v-slider-tooltip-bubble\">{{ endValueText ?? endValue }}</span>\n </span>\n </div>\n <div v-if=\"labels\" class=\"v-slider-labels\">\n <span\n v-for=\"(item, i) in labels\"\n :key=\"i\"\n class=\"v-slider-label\"\n :style=\"stepPlaces[i]?.style\"\n >\n <template v-if=\"typeof item === 'string'\">{{ item }}</template>\n <VIcon v-else v-bind=\"iconProps(item.icon)\" :label=\"item.label\" />\n </span>\n </div>\n <VInput\n v-for=\"which in fieldsAfter\"\n :key=\"which\"\n v-model=\"fieldText[which]\"\n :class=\"['v-slider-field', `v-slider-field-${which}`]\"\n type=\"number\"\n :size=\"resolvedSize\"\n :compact=\"resolvedCompact\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"resolvedDisabled\"\n :readonly=\"readonly\"\n :invalid=\"invalid\"\n :aria-label=\"fieldLabel(which)\"\n @change=\"commitField(which)\"\n />\n <span v-if=\"hint\" :id=\"hintId\" class=\"v-slider-hint\">{{ hint }}</span>\n </div>\n</template>\n\n<style>\n@layer vectis.components {\n .v-slider {\n --slider-thumb: var(--vectis-control-size-slider-thumb);\n --slider-track: var(--vectis-control-size-slider-track);\n display: grid;\n grid-template-areas: 'rail';\n grid-template-columns: minmax(0, 1fr);\n align-items: center;\n column-gap: var(--vectis-space-2);\n row-gap: var(--vectis-space-1);\n inline-size: 100%;\n font-family: var(--vectis-text-family);\n }\n\n /*\n * Each combination is written with exactly the conditions that define it, so a richer one\n * always carries one condition more than the poorer ones it also matches and wins on WEIGHT,\n * never on source order: `[data-inputs='ends'][data-range]:has(.v-slider-labels)` is (0,4,0)\n * against the (0,3,0) of the two it builds on. `:has()` weighs its argument.\n */\n .v-slider:has(.v-slider-labels) {\n grid-template-areas: 'rail' 'labels';\n }\n\n .v-slider[data-inputs='ends'] {\n grid-template-areas: 'rail field-end';\n grid-template-columns: minmax(0, 1fr) auto;\n }\n\n .v-slider[data-inputs='ends']:has(.v-slider-labels) {\n grid-template-areas: 'rail field-end' 'labels .';\n }\n\n .v-slider[data-inputs='ends'][data-range] {\n grid-template-areas: 'field-start rail field-end';\n grid-template-columns: auto minmax(0, 1fr) auto;\n }\n\n .v-slider[data-inputs='ends'][data-range]:has(.v-slider-labels) {\n grid-template-areas: 'field-start rail field-end' '. labels .';\n }\n\n .v-slider[data-inputs='top'] {\n grid-template-areas: 'field-start . field-end' 'rail rail rail';\n grid-template-columns: auto minmax(0, 1fr) auto;\n }\n\n .v-slider[data-inputs='top']:has(.v-slider-labels) {\n grid-template-areas: 'field-start . field-end' 'rail rail rail' 'labels labels labels';\n }\n\n .v-slider[data-inputs='bottom'] {\n grid-template-areas: 'rail rail rail' 'field-start . field-end';\n grid-template-columns: auto minmax(0, 1fr) auto;\n }\n\n .v-slider[data-inputs='bottom']:has(.v-slider-labels) {\n grid-template-areas: 'rail rail rail' 'labels labels labels' 'field-start . field-end';\n }\n\n .v-slider-rail {\n grid-area: rail;\n position: relative;\n block-size: var(--slider-thumb);\n }\n\n .v-slider-control {\n position: absolute;\n inset: 0;\n }\n\n .v-slider-track {\n position: absolute;\n inset-inline: 0;\n inset-block: 0;\n margin-block: auto;\n block-size: var(--slider-track);\n border-radius: var(--vectis-radius-pill);\n background: var(--vectis-color-border);\n overflow: hidden;\n }\n\n /*\n * It must be declared on the element that CARRIES the fraction, never on an ancestor. A\n * custom property's `var()` is resolved where the property is declared, so set on the root it\n * would read a `--fill-fraction` the root does not have and turn invalid, and every tick,\n * label and bubble would drop to its static position at the start of the track, with no\n * error.\n */\n .v-slider-fill,\n .v-slider-tick,\n .v-slider-tooltip,\n .v-slider-label {\n --slider-at: calc(\n var(--slider-thumb) / 2 + (100% - var(--slider-thumb)) * var(--fill-fraction)\n );\n }\n\n .v-slider-fill {\n --fill-fraction: var(--slider-end-fraction);\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n inline-size: var(--slider-at);\n background: var(--vectis-color-accent);\n }\n\n .v-slider[data-range] .v-slider-fill {\n --fill-fraction: var(--slider-start-fraction);\n inset-inline-start: var(--slider-at);\n inline-size: calc(\n (100% - var(--slider-thumb)) * (var(--slider-end-fraction) - var(--slider-start-fraction))\n );\n }\n\n .v-slider-tick {\n --slider-tick: calc(var(--slider-track) / 3 * 2);\n position: absolute;\n inset-block: 0;\n margin-block: auto;\n inset-inline-start: calc(var(--slider-at) - var(--slider-tick) / 2);\n inline-size: var(--slider-tick);\n block-size: var(--slider-tick);\n border-radius: var(--vectis-radius-pill);\n background: var(--vectis-color-border-strong);\n }\n\n .v-slider-tick[data-filled] {\n background: var(--vectis-color-text-on-accent);\n }\n\n /*\n * Without that, the one on top would swallow every click and the other thumb could never be\n * grabbed. The thumb's paint lives in variables set here, on the control, and read once by\n * each vendor pseudo-element below.\n */\n .v-slider-input {\n --slider-thumb-bg: var(--vectis-color-text-on-accent);\n --slider-thumb-border: var(--vectis-color-accent);\n --slider-thumb-shadow: var(--vectis-shadow-xs);\n --slider-thumb-outline: none;\n --slider-thumb-cursor: pointer;\n --slider-thumb-transition: background-color var(--vectis-duration-fast)\n var(--vectis-ease-default);\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n appearance: none;\n background: transparent;\n pointer-events: none;\n }\n\n /*\n * With a single thumb there is nothing underneath to protect, so the whole control takes the\n * pointer again; which makes clicking the track jump the value there and start dragging at\n * once, natively and with no code at all. The accepted side effect is that the thumb lights\n * up when the pointer is anywhere over the track.\n */\n .v-slider:not([data-range]) .v-slider-input {\n pointer-events: auto;\n cursor: pointer;\n }\n\n /*\n * The two vendor pseudo-elements stay in two separate rules. A selector list holding one a\n * browser does not know is dropped whole, so merged, each engine would throw away the other's\n * thumb and draw its native one.\n */\n .v-slider-input::-webkit-slider-thumb {\n appearance: none;\n pointer-events: auto;\n width: var(--slider-thumb);\n height: var(--slider-thumb);\n border-radius: var(--vectis-radius-pill);\n background: var(--slider-thumb-bg);\n border: var(--vectis-control-border-width) solid var(--slider-thumb-border);\n box-shadow: var(--slider-thumb-shadow);\n outline: var(--slider-thumb-outline);\n outline-offset: var(--vectis-focus-ring-offset);\n cursor: var(--slider-thumb-cursor);\n transition: var(--slider-thumb-transition);\n }\n\n .v-slider-input::-moz-range-thumb {\n pointer-events: auto;\n width: var(--slider-thumb);\n height: var(--slider-thumb);\n border-radius: var(--vectis-radius-pill);\n background: var(--slider-thumb-bg);\n border: var(--vectis-control-border-width) solid var(--slider-thumb-border);\n box-shadow: var(--slider-thumb-shadow);\n outline: var(--slider-thumb-outline);\n outline-offset: var(--vectis-focus-ring-offset);\n cursor: var(--slider-thumb-cursor);\n transition: var(--slider-thumb-transition);\n }\n\n /* The states, all at (0,3,0) but the base, so their ORDER arbitrates them: hover, then\n read-only, invalid and disabled, each overriding what came before on a thumb that is\n several at once.\n\n The hover tint is mixed from the thumb's own white rather than read from\n `accent-surface`: that token turns dark in the dark theme, and a white thumb would\n flash nearly black under the pointer. */\n .v-slider-input:is(:hover, :active):not(:disabled) {\n --slider-thumb-bg: color-mix(\n in oklab,\n var(--vectis-color-text-on-accent),\n var(--vectis-color-accent) 10%\n );\n }\n\n .v-slider-input:focus-visible {\n --slider-thumb-outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline: none;\n }\n\n .v-slider[data-readonly] .v-slider-input {\n --slider-thumb-bg: var(--vectis-color-surface);\n --slider-thumb-border: var(--vectis-color-text-muted);\n --slider-thumb-cursor: default;\n cursor: default;\n }\n\n .v-slider[data-readonly] .v-slider-fill {\n background: var(--vectis-color-text-muted);\n }\n\n .v-slider[data-readonly] .v-slider-tick[data-filled] {\n background: var(--vectis-color-surface);\n }\n\n .v-slider[data-invalid] .v-slider-input {\n --slider-thumb-border: var(--vectis-color-danger);\n }\n\n /*\n * It looks like a VTooltip but is placed by arithmetic rather than anchored to the thumb: a\n * native thumb is a pseudo-element, and the browser's anchoring cannot attach anything to\n * one. The fraction it follows is the one the root already carries for the fill.\n */\n .v-slider-tooltip {\n position: absolute;\n inset-block-end: calc(100% + var(--vectis-space-2));\n inset-inline-start: var(--slider-at);\n inline-size: 0;\n display: flex;\n justify-content: center;\n opacity: 0;\n visibility: hidden;\n transition:\n opacity var(--vectis-duration-fast) var(--vectis-ease-default),\n visibility var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-slider-tooltip-start {\n --fill-fraction: var(--slider-start-fraction);\n }\n\n .v-slider-tooltip-end {\n --fill-fraction: var(--slider-end-fraction);\n }\n\n .v-slider:has(.v-slider-input-start:active) .v-slider-tooltip-start,\n .v-slider:has(.v-slider-input-start:focus-visible) .v-slider-tooltip-start,\n .v-slider:has(.v-slider-input-end:active) .v-slider-tooltip-end,\n .v-slider:has(.v-slider-input-end:focus-visible) .v-slider-tooltip-end {\n opacity: 1;\n visibility: visible;\n }\n\n .v-slider-tooltip-bubble {\n padding: var(--vectis-space-1) var(--vectis-space-2);\n background: var(--vectis-color-surface-inverse);\n color: var(--vectis-color-text-on-inverse);\n font-size: var(--vectis-text-caption-size);\n line-height: var(--vectis-text-caption-leading);\n border-radius: min(var(--vectis-radius-interactive), calc(0.5lh + var(--vectis-space-1)));\n box-shadow: var(--vectis-shadow-sm);\n white-space: nowrap;\n }\n\n .v-slider-labels {\n grid-area: labels;\n position: relative;\n /* The labels are positioned individually and therefore contribute no height of\n their own; this reserves enough room for either kind, a small line of text or an\n icon. */\n min-block-size: var(--vectis-icon-size-md);\n /* The pair travels together, as it does in every `[data-size]` block of\n control-size.css: the size applies to every source, the optical size only to the\n ligature, and setting one without the other draws a 20px glyph cut for 24. */\n --vectis-icon-size: var(--vectis-icon-size-md);\n --vectis-icon-opsz: 20;\n font-size: var(--vectis-text-caption-size);\n color: var(--vectis-color-text-muted);\n }\n\n /* A box of zero width placed exactly on the step: its content then overflows equally\n on both sides, which centres it there. Centring it with a transform would be the\n usual trick, but a transform is physical and would have to be undone for the\n vertical orientation and again for a right-to-left page. */\n .v-slider-label {\n position: absolute;\n inset-block-start: 0;\n inset-inline-start: var(--slider-at);\n inline-size: 0;\n display: flex;\n justify-content: center;\n white-space: nowrap;\n }\n\n /* The hint takes no area of its own: it spans every column and is AUTO-PLACED, which\n drops it into an implicit row under whichever zone template is in force.\n Given a row in each of them instead, the `row-gap` would open under every slider that\n has no hint at all. */\n .v-slider-hint {\n grid-column: 1 / -1;\n font-size: var(--vectis-text-caption-size);\n line-height: var(--vectis-text-caption-leading);\n color: var(--vectis-color-text-muted);\n }\n\n .v-slider[data-disabled] .v-slider-hint {\n color: var(--vectis-color-text-subtle);\n }\n\n .v-slider-field.v-input {\n inline-size: var(--vectis-control-size-slider-field);\n }\n\n /* Qualify number-field selectors so their layout cannot depend on VInput stylesheet order. */\n .v-slider-field-start.v-input {\n grid-area: field-start;\n }\n\n .v-slider-field-end.v-input {\n grid-area: field-end;\n }\n\n .v-slider[data-orientation='vertical'] {\n grid-template-areas: 'rail';\n grid-template-columns: none;\n inline-size: fit-content;\n justify-items: center;\n }\n\n .v-slider[data-orientation='vertical']:has(.v-slider-labels) {\n grid-template-areas: 'rail labels';\n grid-template-columns: auto auto;\n }\n\n .v-slider[data-orientation='vertical'][data-inputs='ends'] {\n grid-template-areas: 'field-end' 'rail';\n grid-template-columns: none;\n }\n\n .v-slider[data-orientation='vertical'][data-inputs='ends']:has(.v-slider-labels) {\n grid-template-areas: 'field-end .' 'rail labels';\n grid-template-columns: auto auto;\n }\n\n .v-slider[data-orientation='vertical'][data-inputs='ends'][data-range] {\n grid-template-areas: 'field-end' 'rail' 'field-start';\n grid-template-columns: none;\n }\n\n .v-slider[data-orientation='vertical'][data-inputs='ends'][data-range]:has(.v-slider-labels) {\n grid-template-areas: 'field-end .' 'rail labels' 'field-start .';\n grid-template-columns: auto auto;\n }\n\n /*\n * Upright, `top` and `bottom` become the two SIDES, the inline start and the inline end: the\n * fields stack in a column beside the track, the end field level with its top and the start\n * field with its bottom, where the values they hold sit. The track spans the three rows and\n * gives them their height, the middle one taking whatever the fields leave.\n */\n .v-slider[data-orientation='vertical'][data-inputs='top'] {\n grid-template-areas: 'field-end rail' '. rail' 'field-start rail';\n grid-template-columns: auto auto;\n grid-template-rows: auto 1fr auto;\n }\n\n .v-slider[data-orientation='vertical'][data-inputs='top']:has(.v-slider-labels) {\n grid-template-areas:\n 'field-end rail labels'\n '. rail labels'\n 'field-start rail labels';\n grid-template-columns: auto auto auto;\n }\n\n .v-slider[data-orientation='vertical'][data-inputs='bottom'] {\n grid-template-areas: 'rail field-end' 'rail .' 'rail field-start';\n grid-template-columns: auto auto;\n grid-template-rows: auto 1fr auto;\n }\n\n .v-slider[data-orientation='vertical'][data-inputs='bottom']:has(.v-slider-labels) {\n grid-template-areas:\n 'rail labels field-end'\n 'rail labels .'\n 'rail labels field-start';\n grid-template-columns: auto auto auto;\n }\n\n .v-slider[data-orientation='vertical'] .v-slider-rail {\n inline-size: var(--slider-thumb);\n block-size: var(--vectis-control-size-slider-length);\n }\n\n /*\n * Rotate only the track box and reverse its direction; labels remain horizontal and the\n * minimum value stays at the bottom.\n */\n .v-slider[data-orientation='vertical'] .v-slider-control {\n writing-mode: vertical-lr;\n direction: rtl;\n }\n\n .v-slider[data-orientation='vertical'] .v-slider-tooltip {\n inset-block-end: var(--slider-at);\n inset-inline-start: auto;\n inset-inline-end: calc(100% + var(--vectis-space-2));\n inline-size: auto;\n block-size: 0;\n align-items: center;\n justify-content: flex-end;\n }\n\n .v-slider[data-orientation='vertical'] .v-slider-labels {\n align-self: stretch;\n min-block-size: auto;\n }\n\n .v-slider[data-orientation='vertical'] .v-slider-label {\n inset-block-start: auto;\n inset-block-end: var(--slider-at);\n inset-inline-start: 0;\n inline-size: auto;\n block-size: 0;\n align-items: center;\n justify-content: flex-start;\n }\n\n /*\n * A disabled slider greys out through the colour tokens, the same ones VCheckbox and VSwitch\n * use, and never through opacity. It comes last among the states, so a slider both disabled\n * and read-only or invalid is drawn disabled.\n */\n .v-slider[data-disabled] {\n cursor: not-allowed;\n }\n\n .v-slider[data-disabled] .v-slider-track {\n background: var(--vectis-color-surface-muted);\n }\n\n .v-slider[data-disabled] .v-slider-fill {\n background: var(--vectis-color-text-subtle);\n }\n\n .v-slider[data-disabled] .v-slider-tick {\n background: var(--vectis-color-text-subtle);\n }\n\n /*\n * A tick sitting on the greyed fill takes the light colour back, so that it stays visible\n * against it; the same inversion VCheckbox applies to its disabled tick.\n */\n .v-slider[data-disabled] .v-slider-tick[data-filled] {\n background: var(--vectis-color-surface-muted);\n }\n\n .v-slider[data-disabled] .v-slider-labels {\n color: var(--vectis-color-text-subtle);\n }\n\n .v-slider[data-disabled] .v-slider-input {\n --slider-thumb-bg: var(--vectis-color-surface-muted);\n --slider-thumb-border: var(--vectis-color-text-subtle);\n --slider-thumb-shadow: none;\n --slider-thumb-cursor: not-allowed;\n cursor: not-allowed;\n }\n\n /*\n * Forced colours erase background-only tracks and ticks. Restore the track edge and use\n * system Highlight/HighlightText for selected portions.\n */\n @media (forced-colors: active) {\n .v-slider .v-slider-track {\n forced-color-adjust: none;\n background: Canvas;\n box-shadow: inset 0 0 0 var(--vectis-control-border-width) CanvasText;\n }\n\n .v-slider .v-slider-fill {\n forced-color-adjust: none;\n background: Highlight;\n }\n\n .v-slider .v-slider-tick {\n forced-color-adjust: none;\n background: CanvasText;\n }\n\n .v-slider .v-slider-tick[data-filled] {\n background: HighlightText;\n }\n\n .v-slider .v-slider-input {\n forced-color-adjust: none;\n --slider-thumb-bg: Canvas;\n --slider-thumb-border: CanvasText;\n --slider-thumb-shadow: none;\n }\n\n .v-slider[data-disabled] .v-slider-track {\n box-shadow: inset 0 0 0 var(--vectis-control-border-width) GrayText;\n }\n\n .v-slider[data-disabled] .v-slider-fill,\n .v-slider[data-disabled] .v-slider-tick {\n background: GrayText;\n }\n\n .v-slider[data-disabled] .v-slider-input {\n --slider-thumb-border: GrayText;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-slider-input {\n --slider-thumb-transition: none;\n }\n\n .v-slider-tooltip {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"VSlider.js","names":[],"sources":["../../../src/components/VSlider/VSlider.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// @core\n/**\n * Native range inputs own thumb interaction. JavaScript keeps range endpoints ordered and\n * synchronizes optional number fields, labels and ARIA values.\n */\n\nimport { computed, inject, ref, watchEffect } from 'vue'\nimport VField from '../VField/VField.vue'\nimport type { FieldControlProps, FieldLabelPosition } from '../VField/VField.vue'\nimport VIcon from '../VIcon/VIcon.vue'\nimport { iconProps } from '../VIcon/iconProps'\nimport type { IconSource } from '../VIcon/types'\nimport { inputGroupKey } from '../VInput/context'\nimport VNumberInput from '../VNumberInput/VNumberInput.vue'\n\nimport { useAriaLabel } from '../../composables/useAriaLabel'\nimport { useControlShape } from '../../composables/useControlShape'\nimport { useRootAttrs } from '../../composables/useRootAttrs'\nimport { isDev } from '../../utils/env'\nimport { clamp } from '../../utils/number'\nimport { useMessages, useResolvedLocale } from '../../i18n/state'\n\n/**\n * What one step of the track is called: a piece of text, or an icon paired with the words that\n * name it, which a screen reader reads in place of the raw number.\n */\nexport type SliderLabel = string | { icon: IconSource; label: string }\n\n/** The value of a slider: one number, or an ordered pair of them in range mode. */\nexport type SliderValue = number | [number, number]\n\n/** Which way the track runs. */\nexport type SliderOrientation = 'horizontal' | 'vertical'\n\n/** The height of the number fields: 32, 40 or 48 pixels. */\nexport type SliderSize = 'sm' | 'md' | 'lg'\n\n/**\n * Where the number fields sit: none, at the ends of the track, or in a row above or below\n * it. On an upright slider, above and below become the two sides of it.\n */\nexport type SliderInputs = false | 'ends' | 'top' | 'bottom'\n\ninterface SliderProps {\n /** The lowest value the thumb can reach. It is 0 by default. */\n min?: number\n /** The highest value the thumb can reach. It is 100 by default. */\n max?: number\n /**\n * The gap between two values the thumb can stop on, 1 by default. It is also what the\n * arrow keys move by, and what a value typed into the companion field is snapped to.\n */\n step?: number\n /** Offers two thumbs to pick a range, which makes the v-model a pair of values. */\n range?: boolean\n /** Makes the slider unusable. */\n disabled?: boolean\n /**\n * Shows the value without allowing it to be changed. The thumbs can still be focused and\n * are announced as read-only, but neither the pointer nor the keyboard moves them, and the\n * number fields turn read-only with them.\n */\n readonly?: boolean\n /**\n * Marks the value as invalid, which colours the thumbs and tells assistive technology\n * so. It is for a rule the browser cannot check by itself.\n */\n invalid?: boolean\n /**\n * The height of the number fields `inputs` adds. Inside a VInputGroup the group's size\n * wins, as it does for every field of the row.\n */\n size?: SliderSize\n /**\n * The label above the slider, which also names its thumbs: in range mode they are announced\n * as the start and the end of it.\n */\n label?: string\n /** Hides the label visually. It still names the thumbs for assistive technology. */\n hideLabel?: boolean\n /**\n * Where the label sits: above the slider (`top`, the default), or at its start, in a column of\n * its own, moving back above when there is not room for both.\n */\n labelPosition?: FieldLabelPosition\n /**\n * A line of help under the track, stating what the numbers mean or where they may go. It\n * is tied to the slider for assistive technology, so it is read out after the name rather\n * than as part of it.\n */\n hint?: string\n /**\n * A message saying what is wrong with the value, shown in place of the hint so that the field\n * does not grow. It marks the field invalid, is read along with it, and is announced when it\n * appears or changes.\n */\n error?: string\n /** Turns the slider upright, with the lowest value at the bottom. */\n orientation?: SliderOrientation\n /**\n * Adds a number field for setting the value exactly: one, or one per end in range mode. No\n * field is drawn by default.\n */\n inputs?: SliderInputs\n /**\n * Marks each step on the track. Providing labels implies it. Past fifty steps the\n * marks would be an unreadable comb and are not drawn at all.\n */\n ticks?: boolean\n /**\n * A label for every step, in order: a piece of text, or an icon with the words that\n * name it for screen readers. They also become what a screen reader announces in\n * place of the raw number.\n */\n labels?: SliderLabel[]\n /** Shows the value in a bubble above the thumb while it is being moved or focused. */\n tooltip?: boolean\n /**\n * How the value is written in the bubble, the number fields and what the thumbs announce: the\n * options of `Intl.NumberFormat`, for a price, a unit or a percentage. `min`, `max` and `step`\n * stay in the model's unit: with `style: 'percent'`, 0.25 is written 25%.\n */\n formatOptions?: Intl.NumberFormatOptions\n /** The locale the value is written and read in. It defaults to the design system's. */\n locale?: string\n}\n\nconst props = withDefaults(defineProps<SliderProps>(), {\n min: 0,\n max: 100,\n step: 1,\n range: false,\n disabled: false,\n readonly: false,\n invalid: false,\n size: 'md',\n label: undefined,\n hideLabel: false,\n labelPosition: 'top',\n hint: undefined,\n error: undefined,\n orientation: 'horizontal',\n inputs: false,\n ticks: false,\n labels: undefined,\n tooltip: false,\n formatOptions: undefined,\n locale: undefined,\n})\n\n/** The value: a single number, 0 to begin with, or an ordered pair once `range` is set. */\nconst model = defineModel<SliderValue>({ default: 0 })\n\nconst emit = defineEmits<{\n /** The value is BEING changed: every step of a drag, and every key that moves a thumb. */\n input: [value: SliderValue]\n /**\n * The reader has SETTLED on a value: a thumb was released or moved by a key, or a number\n * field was committed.\n */\n change: [value: SliderValue]\n}>()\n\n// The number fields are fields of a VInputGroup row like any other, so the row's size and\n// its disabled state reach them through the same arbitration. A slider has no `compact` of\n// its own: only the row's can apply.\nconst group = inject(inputGroupKey, null)\nconst {\n size: resolvedSize,\n compact: resolvedCompact,\n disabled: resolvedDisabled,\n} = useControlShape(\n {\n get size() {\n return props.size\n },\n compact: false,\n get disabled() {\n return props.disabled\n },\n },\n group,\n)\n\ntype Thumb = 'start' | 'end'\n\nconst startValue = computed(() => (Array.isArray(model.value) ? model.value[0] : props.min))\nconst endValue = computed(() =>\n Array.isArray(model.value) ? model.value[1] : (model.value as number),\n)\n\nconst thumbValue = (which: Thumb) => (which === 'start' ? startValue.value : endValue.value)\n\n/**\n * Where a value sits along the run, as a fraction between 0 and 1. The guard covers a\n * slider whose two bounds are equal, which would otherwise divide by zero.\n */\nconst frac = (v: number) => clamp((v - props.min) / (props.max - props.min || 1), 0, 1)\n\n// @core\n// The thumb being held PUSHES its sibling; it must not stop against it. Two thumbs resting on\n// the same value are one thumb as far as the pointer is concerned, the end one being last in\n// the DOM and therefore the only one it can reach; so a range stopped at `[100, 100]` could\n// only ever be raised, and at the maximum it could not move at all.\nfunction writeThumb(which: Thumb, n: number): SliderValue {\n const next: SliderValue = !props.range\n ? n\n : which === 'start'\n ? [n, Math.max(n, endValue.value)]\n : [Math.min(n, startValue.value), n]\n model.value = next\n return next\n}\n\nconst writtenFor = (value: SliderValue, which: Thumb) =>\n Array.isArray(value) ? value[which === 'start' ? 0 : 1] : value\n\nfunction onThumbInput(which: Thumb, event: Event) {\n const el = event.target as HTMLInputElement\n // @core\n // A drag or a click on the track has ALREADY moved the native thumb when `input` fires,\n // and the event cannot be cancelled: putting the value back is the only refusal there is.\n // It lands before the browser paints, so the thumb never visibly leaves its place, and\n // since the value at release is the one it started from, no `change` follows either.\n if (props.readonly) {\n el.value = String(thumbValue(which))\n return\n }\n const next = writeThumb(which, Number(el.value))\n el.value = String(writtenFor(next, which))\n emit('input', next)\n}\n\n// @keyboard @core\n// The keys that move a range input, cancelled before the browser applies them when the\n// slider is read-only. Tab and every other key pass, so the thumbs stay reachable.\nconst VALUE_KEYS = new Set([\n 'ArrowUp',\n 'ArrowDown',\n 'ArrowLeft',\n 'ArrowRight',\n 'Home',\n 'End',\n 'PageUp',\n 'PageDown',\n])\n\nfunction onThumbKeydown(event: KeyboardEvent) {\n if (props.readonly && VALUE_KEYS.has(event.key)) event.preventDefault()\n}\n\n// @core\n/*\n * The settled value is read off the THUMB, never off the model. A key press fires `input` and\n * `change` back to back in one task, and under a parent `v-model` the model's local copy only\n * catches up when the parent re-renders, so it would still hold the value from before the key.\n */\nfunction onThumbChange(which: Thumb, event: Event) {\n if (props.readonly) return\n const value = Number((event.target as HTMLInputElement).value)\n if (!props.range) emit('change', value)\n else if (which === 'start') emit('change', [value, Math.max(value, endValue.value)])\n else emit('change', [Math.min(value, startValue.value), value])\n}\n\n/** How many whole steps the thumb can actually stop on. */\nconst stepCount = computed(() =>\n props.step > 0 ? Math.floor((props.max - props.min) / props.step + 1e-9) : 0,\n)\n\n/**\n * The highest value a thumb can actually stop on, which is the last whole step and not\n * necessarily the maximum: with `min=0 max=95 step=10` the native control stops at 90.\n */\nconst lastStop = computed(() =>\n props.step > 0 ? props.min + stepCount.value * props.step : props.max,\n)\n\nconst showTicks = computed(\n () =>\n (props.ticks || props.labels !== undefined) && stepCount.value >= 1 && stepCount.value <= 50,\n)\n\n/** Each step's value and the style that places it, shared by the ticks and the labels. */\nconst stepPlaces = computed(() => {\n const length = Math.max(showTicks.value ? stepCount.value + 1 : 0, props.labels?.length ?? 0)\n return Array.from({ length }, (_, i) => {\n const value = props.min + i * props.step\n return { value, style: { '--fill-fraction': String(frac(value)) } }\n })\n})\n\nconst tickPlaces = computed(() =>\n showTicks.value ? stepPlaces.value.slice(0, stepCount.value + 1) : [],\n)\n\nconst isFilled = (value: number) =>\n props.range ? value >= startValue.value && value <= endValue.value : value <= endValue.value\n\n// Resolved once here and handed to the number fields as the result, so the fields and the\n// bubble can never read the value in two different languages.\nconst resolvedLocale = useResolvedLocale(() => props.locale)\nconst numberFormat = computed(\n () => new Intl.NumberFormat(resolvedLocale.value, props.formatOptions),\n)\nconst formatValue = (value: number) => numberFormat.value.format(value)\n\n/** What a value is called, if the consumer named its step; failing that, the number written. */\nfunction labelTextAt(value: number): string {\n const item = props.labels?.[Math.round((value - props.min) / props.step)]\n if (item === undefined) return formatValue(value)\n return typeof item === 'string' ? item : item.label\n}\n\n// @a11y\n/*\n * Resolve the label against consumer ARIA attributes before deriving distinct range-thumb\n * names; an undefined prop must not erase their accessible name.\n */\nconst m = useMessages()\nconst resolvedLabel = useAriaLabel(() => props.label)\nconst startLabel = computed(() =>\n resolvedLabel.value ? m.value.slider.rangeStart(resolvedLabel.value) : m.value.slider.start,\n)\nconst endLabel = computed(() =>\n resolvedLabel.value ? m.value.slider.rangeEnd(resolvedLabel.value) : m.value.slider.end,\n)\nconst thumbEndLabel = computed(() => (props.range ? endLabel.value : resolvedLabel.value))\nconst fieldEndLabel = computed(() =>\n props.range ? endLabel.value : (resolvedLabel.value ?? m.value.slider.value),\n)\n\n// @a11y\n// Said only when it adds something to the bare number a range announces: a step label, or a\n// value written with `formatOptions` (\"120 €\" rather than \"120\").\nconst spokenText = (value: number) =>\n props.labels || props.formatOptions ? labelTextAt(value) : undefined\nconst startValueText = computed(() => (props.range ? spokenText(startValue.value) : undefined))\nconst endValueText = computed(() => spokenText(endValue.value))\n\n// @a11y\n/*\n * The wrapper-root split. The root here is a layout box holding the labels, the track and the\n * optional number fields, so a consumer's `name`, `id`, `required` and `aria-*` have to be\n * redirected onto the real `<input type=\"range\">`; left on the wrapper, a `name` submits\n * nothing and a `<label for>` points at a div.\n */\ndefineOptions({ inheritAttrs: false })\nconst { attrs, rootClass, rootStyle, forwardedAttrs } = useRootAttrs()\n\n/**\n * What reaches the end thumb from VField: the consumer's attributes and the description. The\n * thumbs are named by `aria-label`, carrying the label's words, so VField's reference to the\n * label text gives way to the consumer's own `aria-labelledby`, if any. A `required` attribute\n * is VField's prop on the way, which group mode keeps for its asterisk: it is handed on here.\n */\nfunction thumbAttrs(fieldProps: FieldControlProps): FieldControlProps {\n return {\n ...fieldProps,\n 'aria-labelledby': attrs['aria-labelledby'] as string | undefined,\n required: attrs.required as true | undefined,\n }\n}\nconst isInvalid = computed(() => props.invalid || !!props.error)\n\n/**\n * Where the fields go, `ends` standing in for any other truthy value: a bare `inputs`\n * attribute reaches the component as `true`, the prop being part boolean.\n */\nconst inputsPlace = computed(() =>\n props.inputs === 'top' || props.inputs === 'bottom' ? props.inputs : props.inputs && 'ends',\n)\n\n// @devwarn\n/*\n * Every guard here describes something that fails SILENTLY. They sit in an effect, so a\n * bound that only becomes wrong on a later render is still caught, and each sentence is\n * given once per instance: the same warning repeated on every keystroke is how a warning\n * stops being read (the `useFileField` arrangement).\n */\nif (isDev) {\n // Keyed by a short id rather than by the sentence: each of these embeds a count, so the\n // same guard reported twice would read as two different messages and warn again.\n const warned = new Set<string>()\n const warn = (id: string, message: string) => {\n if (warned.has(id)) return\n warned.add(id)\n console.warn(`[VSlider] ${message}`)\n }\n watchEffect(() => {\n if (props.step <= 0)\n warn(\n 'step',\n `step=\"${props.step}\" cannot move a thumb: the arrow keys do nothing and a value typed into a field is committed as it stands. Give a positive step.`,\n )\n if ((props.ticks || props.labels) && stepCount.value > 50)\n warn(\n 'ticks',\n `${stepCount.value} steps: no tick is drawn past 50, the comb being unreadable.`,\n )\n if (props.labels && props.labels.length !== stepCount.value + 1)\n warn(\n 'labels',\n `${props.labels.length} labels for ${stepCount.value + 1} steps: one label per step expected.`,\n )\n if (props.inputs !== false && props.inputs !== inputsPlace.value)\n warn(\n 'inputs',\n `inputs=\"${String(props.inputs)}\" is not a placement: the fields are drawn at the ends. Write inputs=\"ends\", \"top\" or \"bottom\".`,\n )\n if (props.range && attrs.name !== undefined)\n warn(\n 'name',\n `name=\"${String(attrs.name)}\" on a range: only the end thumb carries it, so the form receives one value of the two. Bind the model to two inputs of your own instead.`,\n )\n })\n}\n\n// @a11y\n/*\n * The fields are rendered in the order they are SEEN, before or after the track, so that\n * the tab order follows the screen. Laid out by the grid alone from a fixed DOM order, a\n * row of fields above the track would be reached one on each side of the thumbs.\n */\nconst fieldsBefore = computed<Thumb[]>(() => {\n if (inputsPlace.value === 'ends') return props.range ? ['start'] : []\n if (inputsPlace.value === 'top') return props.range ? ['start', 'end'] : ['end']\n return []\n})\nconst fieldsAfter = computed<Thumb[]>(() => {\n if (inputsPlace.value === 'ends') return ['end']\n if (inputsPlace.value === 'bottom') return props.range ? ['start', 'end'] : ['end']\n return []\n})\n\nconst fieldLabel = (which: Thumb) => (which === 'start' ? startLabel.value : fieldEndLabel.value)\n\n// @core\n/**\n * What a number field commits, on leaving it or on Enter. VNumberInput has already parsed and\n * bounded it, and puts its text back to the value it is given when this refuses or changes\n * what was typed; an emptied field is refused.\n */\nfunction commitField(which: Thumb, typed: number | null) {\n if (typed === null) return\n // The ceiling is the last step that FITS, never `max` itself: a native range stops there\n // (what `stepCount` counts), so a value past it would put the thumb, the fill and the number\n // out of step.\n const snapped =\n props.step > 0 ? props.min + Math.round((typed - props.min) / props.step) * props.step : typed\n const value = Math.min(lastStop.value, Math.round(snapped * 1e10) / 1e10)\n const previous = thumbValue(which)\n const next = writeThumb(which, value)\n // Emitted only when the value MOVED, as a native range emits nothing for a key that cannot\n // move its thumb; and the payload is `next`, the model's local copy lagging a parent\n // `v-model` (see `onThumbChange`).\n if (writtenFor(next, which) !== previous) emit('change', next)\n}\n\nconst endThumbEl = ref<HTMLInputElement | null>(null)\n\n// Both members point at the END thumb: it is the one always rendered, and the one the\n// consumer's `id` lands on, so `focus()` goes where a `<label for>` would send it.\ndefineExpose({\n /** Moves the focus to the end thumb, the only thumb outside range mode. */\n focus: (options?: FocusOptions) => endThumbEl.value?.focus(options),\n /** The end thumb's real `<input type=\"range\">`, for what `focus` does not cover. */\n el: endThumbEl,\n})\n</script>\n\n<template>\n <VField\n v-bind=\"forwardedAttrs\"\n class=\"v-slider\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n :label=\"label\"\n :hint=\"hint\"\n :error=\"error\"\n :disabled=\"resolvedDisabled\"\n :hide-label=\"hideLabel\"\n :label-position=\"labelPosition\"\n group\n >\n <!-- The label is text only: the thumbs carry the same words as their accessible names. -->\n <template #default=\"{ fieldProps }\">\n <div\n class=\"v-slider-body\"\n :data-range=\"range ? '' : undefined\"\n :data-disabled=\"resolvedDisabled ? '' : undefined\"\n :data-readonly=\"readonly ? '' : undefined\"\n :data-invalid=\"isInvalid ? '' : undefined\"\n :data-size=\"resolvedSize\"\n :data-orientation=\"orientation\"\n :data-inputs=\"inputsPlace || undefined\"\n :style=\"{\n '--slider-start-fraction': range ? String(frac(startValue)) : undefined,\n '--slider-end-fraction': String(frac(endValue)),\n }\"\n >\n <VNumberInput\n v-for=\"which in fieldsBefore\"\n :key=\"which\"\n :model-value=\"thumbValue(which)\"\n :class=\"['v-slider-field', `v-slider-field-${which}`]\"\n controls=\"none\"\n :format-options=\"formatOptions\"\n :locale=\"resolvedLocale\"\n :size=\"resolvedSize\"\n :compact=\"resolvedCompact\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"resolvedDisabled\"\n :readonly=\"readonly\"\n :invalid=\"isInvalid\"\n :aria-label=\"fieldLabel(which)\"\n @update:model-value=\"commitField(which, $event)\"\n />\n <div class=\"v-slider-rail\">\n <span class=\"v-slider-control\">\n <span class=\"v-slider-track\" aria-hidden=\"true\">\n <span class=\"v-slider-fill\" />\n <span\n v-for=\"(tick, i) in tickPlaces\"\n :key=\"i\"\n class=\"v-slider-tick\"\n :data-filled=\"isFilled(tick.value) ? '' : undefined\"\n :style=\"tick.style\"\n />\n </span>\n <input\n v-if=\"range\"\n type=\"range\"\n class=\"v-slider-input v-slider-input-start\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"resolvedDisabled\"\n :value=\"startValue\"\n :aria-label=\"startLabel\"\n :aria-valuetext=\"startValueText\"\n :aria-invalid=\"isInvalid || undefined\"\n :aria-readonly=\"readonly || undefined\"\n @keydown=\"onThumbKeydown\"\n @input=\"onThumbInput('start', $event)\"\n @change=\"onThumbChange('start', $event)\"\n />\n <!--\n The consumer's attributes come first, so what the component decides for itself; the\n bounds, the value and the disabled state; cannot be overwritten by one of them, and so\n that an ARIA state the consumer sets is not erased by an `undefined` of ours.\n `aria-valuetext` is one of those: the component has one to say only when `labels` or\n `formatOptions` was given.\n -->\n <input\n ref=\"endThumbEl\"\n :aria-invalid=\"isInvalid || undefined\"\n :aria-readonly=\"readonly || undefined\"\n :aria-valuetext=\"endValueText\"\n v-bind=\"thumbAttrs(fieldProps)\"\n type=\"range\"\n class=\"v-slider-input v-slider-input-end\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"resolvedDisabled\"\n :value=\"endValue\"\n :aria-label=\"thumbEndLabel\"\n @keydown=\"onThumbKeydown\"\n @input=\"onThumbInput('end', $event)\"\n @change=\"onThumbChange('end', $event)\"\n />\n </span>\n <span\n v-if=\"tooltip && range\"\n class=\"v-slider-tooltip v-slider-tooltip-start\"\n aria-hidden=\"true\"\n >\n <span class=\"v-slider-tooltip-bubble\">{{ labelTextAt(startValue) }}</span>\n </span>\n <span v-if=\"tooltip\" class=\"v-slider-tooltip v-slider-tooltip-end\" aria-hidden=\"true\">\n <span class=\"v-slider-tooltip-bubble\">{{ labelTextAt(endValue) }}</span>\n </span>\n </div>\n <div v-if=\"labels\" class=\"v-slider-labels\">\n <span\n v-for=\"(item, i) in labels\"\n :key=\"i\"\n class=\"v-slider-label\"\n :style=\"stepPlaces[i]?.style\"\n >\n <template v-if=\"typeof item === 'string'\">{{ item }}</template>\n <VIcon v-else v-bind=\"iconProps(item.icon)\" :label=\"item.label\" />\n </span>\n </div>\n <VNumberInput\n v-for=\"which in fieldsAfter\"\n :key=\"which\"\n :model-value=\"thumbValue(which)\"\n :class=\"['v-slider-field', `v-slider-field-${which}`]\"\n controls=\"none\"\n :format-options=\"formatOptions\"\n :locale=\"resolvedLocale\"\n :size=\"resolvedSize\"\n :compact=\"resolvedCompact\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"resolvedDisabled\"\n :readonly=\"readonly\"\n :invalid=\"isInvalid\"\n :aria-label=\"fieldLabel(which)\"\n @update:model-value=\"commitField(which, $event)\"\n />\n </div>\n </template>\n </VField>\n</template>\n\n<style>\n@layer vectis.components {\n .v-slider-body {\n --slider-thumb: var(--vectis-control-size-slider-thumb);\n --slider-track: var(--vectis-control-size-slider-track);\n display: grid;\n grid-template-areas: 'rail';\n grid-template-columns: minmax(0, 1fr);\n align-items: center;\n column-gap: var(--vectis-space-2);\n row-gap: var(--vectis-space-1);\n inline-size: 100%;\n font-family: var(--vectis-text-family);\n }\n\n /*\n * Each combination is written with exactly the conditions that define it, so a richer one\n * always carries one condition more than the poorer ones it also matches and wins on WEIGHT,\n * never on source order: `[data-inputs='ends'][data-range]:has(.v-slider-labels)` is (0,4,0)\n * against the (0,3,0) of the two it builds on. `:has()` weighs its argument.\n */\n .v-slider-body:has(.v-slider-labels) {\n grid-template-areas: 'rail' 'labels';\n }\n\n .v-slider-body[data-inputs='ends'] {\n grid-template-areas: 'rail field-end';\n grid-template-columns: minmax(0, 1fr) auto;\n }\n\n .v-slider-body[data-inputs='ends']:has(.v-slider-labels) {\n grid-template-areas: 'rail field-end' 'labels .';\n }\n\n .v-slider-body[data-inputs='ends'][data-range] {\n grid-template-areas: 'field-start rail field-end';\n grid-template-columns: auto minmax(0, 1fr) auto;\n }\n\n .v-slider-body[data-inputs='ends'][data-range]:has(.v-slider-labels) {\n grid-template-areas: 'field-start rail field-end' '. labels .';\n }\n\n .v-slider-body[data-inputs='top'] {\n grid-template-areas: 'field-start . field-end' 'rail rail rail';\n grid-template-columns: auto minmax(0, 1fr) auto;\n }\n\n .v-slider-body[data-inputs='top']:has(.v-slider-labels) {\n grid-template-areas: 'field-start . field-end' 'rail rail rail' 'labels labels labels';\n }\n\n .v-slider-body[data-inputs='bottom'] {\n grid-template-areas: 'rail rail rail' 'field-start . field-end';\n grid-template-columns: auto minmax(0, 1fr) auto;\n }\n\n .v-slider-body[data-inputs='bottom']:has(.v-slider-labels) {\n grid-template-areas: 'rail rail rail' 'labels labels labels' 'field-start . field-end';\n }\n\n .v-slider-rail {\n grid-area: rail;\n position: relative;\n block-size: var(--slider-thumb);\n }\n\n .v-slider-control {\n position: absolute;\n inset: 0;\n }\n\n .v-slider-track {\n position: absolute;\n inset-inline: 0;\n inset-block: 0;\n margin-block: auto;\n block-size: var(--slider-track);\n border-radius: var(--vectis-radius-pill);\n background: var(--vectis-color-border);\n overflow: hidden;\n }\n\n /*\n * It must be declared on the element that CARRIES the fraction, never on an ancestor. A\n * custom property's `var()` is resolved where the property is declared, so set on the root it\n * would read a `--fill-fraction` the root does not have and turn invalid, and every tick,\n * label and bubble would drop to its static position at the start of the track, with no\n * error.\n */\n .v-slider-fill,\n .v-slider-tick,\n .v-slider-tooltip,\n .v-slider-label {\n --slider-at: calc(\n var(--slider-thumb) / 2 + (100% - var(--slider-thumb)) * var(--fill-fraction)\n );\n }\n\n .v-slider-fill {\n --fill-fraction: var(--slider-end-fraction);\n position: absolute;\n inset-block: 0;\n inset-inline-start: 0;\n inline-size: var(--slider-at);\n background: var(--vectis-color-accent);\n }\n\n .v-slider-body[data-range] .v-slider-fill {\n --fill-fraction: var(--slider-start-fraction);\n inset-inline-start: var(--slider-at);\n inline-size: calc(\n (100% - var(--slider-thumb)) * (var(--slider-end-fraction) - var(--slider-start-fraction))\n );\n }\n\n .v-slider-tick {\n --slider-tick: calc(var(--slider-track) / 3 * 2);\n position: absolute;\n inset-block: 0;\n margin-block: auto;\n inset-inline-start: calc(var(--slider-at) - var(--slider-tick) / 2);\n inline-size: var(--slider-tick);\n block-size: var(--slider-tick);\n border-radius: var(--vectis-radius-pill);\n background: var(--vectis-color-border-strong);\n }\n\n .v-slider-tick[data-filled] {\n background: var(--vectis-color-text-on-accent);\n }\n\n /*\n * Without that, the one on top would swallow every click and the other thumb could never be\n * grabbed. The thumb's paint lives in variables set here, on the control, and read once by\n * each vendor pseudo-element below.\n */\n .v-slider-input {\n --slider-thumb-bg: var(--vectis-color-text-on-accent);\n --slider-thumb-border: var(--vectis-color-accent);\n --slider-thumb-shadow: var(--vectis-shadow-xs);\n --slider-thumb-outline: none;\n --slider-thumb-cursor: pointer;\n --slider-thumb-transition: background-color var(--vectis-duration-fast)\n var(--vectis-ease-default);\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n appearance: none;\n background: transparent;\n pointer-events: none;\n }\n\n /*\n * With a single thumb there is nothing underneath to protect, so the whole control takes the\n * pointer again; which makes clicking the track jump the value there and start dragging at\n * once, natively and with no code at all. The accepted side effect is that the thumb lights\n * up when the pointer is anywhere over the track.\n */\n .v-slider-body:not([data-range]) .v-slider-input {\n pointer-events: auto;\n cursor: pointer;\n }\n\n /*\n * The two vendor pseudo-elements stay in two separate rules. A selector list holding one a\n * browser does not know is dropped whole, so merged, each engine would throw away the other's\n * thumb and draw its native one.\n */\n .v-slider-input::-webkit-slider-thumb {\n appearance: none;\n pointer-events: auto;\n width: var(--slider-thumb);\n height: var(--slider-thumb);\n border-radius: var(--vectis-radius-pill);\n background: var(--slider-thumb-bg);\n border: var(--vectis-control-border-width) solid var(--slider-thumb-border);\n box-shadow: var(--slider-thumb-shadow);\n outline: var(--slider-thumb-outline);\n outline-offset: var(--vectis-focus-ring-offset);\n cursor: var(--slider-thumb-cursor);\n transition: var(--slider-thumb-transition);\n }\n\n .v-slider-input::-moz-range-thumb {\n pointer-events: auto;\n width: var(--slider-thumb);\n height: var(--slider-thumb);\n border-radius: var(--vectis-radius-pill);\n background: var(--slider-thumb-bg);\n border: var(--vectis-control-border-width) solid var(--slider-thumb-border);\n box-shadow: var(--slider-thumb-shadow);\n outline: var(--slider-thumb-outline);\n outline-offset: var(--vectis-focus-ring-offset);\n cursor: var(--slider-thumb-cursor);\n transition: var(--slider-thumb-transition);\n }\n\n /* The states, all at (0,3,0) but the base, so their ORDER arbitrates them: hover, then\n read-only, invalid and disabled, each overriding what came before on a thumb that is\n several at once.\n\n The hover tint is mixed from the thumb's own white rather than read from\n `accent-surface`: that token turns dark in the dark theme, and a white thumb would\n flash nearly black under the pointer. */\n .v-slider-input:is(:hover, :active):not(:disabled) {\n --slider-thumb-bg: color-mix(\n in oklab,\n var(--vectis-color-text-on-accent),\n var(--vectis-color-accent) 10%\n );\n }\n\n .v-slider-input:focus-visible {\n --slider-thumb-outline: var(--vectis-focus-ring-width) solid var(--vectis-focus-ring-color);\n outline: none;\n }\n\n .v-slider-body[data-readonly] .v-slider-input {\n --slider-thumb-bg: var(--vectis-color-surface);\n --slider-thumb-border: var(--vectis-color-text-muted);\n --slider-thumb-cursor: default;\n cursor: default;\n }\n\n .v-slider-body[data-readonly] .v-slider-fill {\n background: var(--vectis-color-text-muted);\n }\n\n .v-slider-body[data-readonly] .v-slider-tick[data-filled] {\n background: var(--vectis-color-surface);\n }\n\n .v-slider-body[data-invalid] .v-slider-input {\n --slider-thumb-border: var(--vectis-color-danger);\n }\n\n /*\n * It looks like a VTooltip but is placed by arithmetic rather than anchored to the thumb: a\n * native thumb is a pseudo-element, and the browser's anchoring cannot attach anything to\n * one. The fraction it follows is the one the root already carries for the fill.\n */\n .v-slider-tooltip {\n position: absolute;\n inset-block-end: calc(100% + var(--vectis-space-2));\n inset-inline-start: var(--slider-at);\n inline-size: 0;\n display: flex;\n justify-content: center;\n opacity: 0;\n visibility: hidden;\n transition:\n opacity var(--vectis-duration-fast) var(--vectis-ease-default),\n visibility var(--vectis-duration-fast) var(--vectis-ease-default);\n }\n\n .v-slider-tooltip-start {\n --fill-fraction: var(--slider-start-fraction);\n }\n\n .v-slider-tooltip-end {\n --fill-fraction: var(--slider-end-fraction);\n }\n\n .v-slider-body:has(.v-slider-input-start:active) .v-slider-tooltip-start,\n .v-slider-body:has(.v-slider-input-start:focus-visible) .v-slider-tooltip-start,\n .v-slider-body:has(.v-slider-input-end:active) .v-slider-tooltip-end,\n .v-slider-body:has(.v-slider-input-end:focus-visible) .v-slider-tooltip-end {\n opacity: 1;\n visibility: visible;\n }\n\n .v-slider-tooltip-bubble {\n padding: var(--vectis-space-1) var(--vectis-space-2);\n background: var(--vectis-color-surface-inverse);\n color: var(--vectis-color-text-on-inverse);\n font-size: var(--vectis-text-caption-size);\n line-height: var(--vectis-text-caption-leading);\n border-radius: min(var(--vectis-radius-interactive), calc(0.5lh + var(--vectis-space-1)));\n box-shadow: var(--vectis-shadow-sm);\n white-space: nowrap;\n }\n\n .v-slider-labels {\n grid-area: labels;\n position: relative;\n /* The labels are positioned individually and therefore contribute no height of\n their own; this reserves enough room for either kind, a small line of text or an\n icon. */\n min-block-size: var(--vectis-icon-size-md);\n /* The pair travels together, as it does in every `[data-size]` block of\n control-size.css: the size applies to every source, the optical size only to the\n ligature, and setting one without the other draws a 20px glyph cut for 24. */\n --vectis-icon-size: var(--vectis-icon-size-md);\n --vectis-icon-opsz: 20;\n font-size: var(--vectis-text-caption-size);\n color: var(--vectis-color-text-muted);\n }\n\n /* A box of zero width placed exactly on the step: its content then overflows equally\n on both sides, which centres it there. Centring it with a transform would be the\n usual trick, but a transform is physical and would have to be undone for the\n vertical orientation and again for a right-to-left page. */\n .v-slider-label {\n position: absolute;\n inset-block-start: 0;\n inset-inline-start: var(--slider-at);\n inline-size: 0;\n display: flex;\n justify-content: center;\n white-space: nowrap;\n }\n\n .v-slider-field.v-input {\n inline-size: var(--vectis-control-size-slider-field);\n }\n\n /* Qualify number-field selectors so their layout cannot depend on VInput stylesheet order. */\n .v-slider-field-start.v-input {\n grid-area: field-start;\n }\n\n .v-slider-field-end.v-input {\n grid-area: field-end;\n }\n\n .v-slider-body[data-orientation='vertical'] {\n grid-template-areas: 'rail';\n grid-template-columns: none;\n inline-size: fit-content;\n justify-items: center;\n }\n\n .v-slider-body[data-orientation='vertical']:has(.v-slider-labels) {\n grid-template-areas: 'rail labels';\n grid-template-columns: auto auto;\n }\n\n .v-slider-body[data-orientation='vertical'][data-inputs='ends'] {\n grid-template-areas: 'field-end' 'rail';\n grid-template-columns: none;\n }\n\n .v-slider-body[data-orientation='vertical'][data-inputs='ends']:has(.v-slider-labels) {\n grid-template-areas: 'field-end .' 'rail labels';\n grid-template-columns: auto auto;\n }\n\n .v-slider-body[data-orientation='vertical'][data-inputs='ends'][data-range] {\n grid-template-areas: 'field-end' 'rail' 'field-start';\n grid-template-columns: none;\n }\n\n .v-slider-body[data-orientation='vertical'][data-inputs='ends'][data-range]:has(\n .v-slider-labels\n ) {\n grid-template-areas: 'field-end .' 'rail labels' 'field-start .';\n grid-template-columns: auto auto;\n }\n\n /*\n * Upright, `top` and `bottom` become the two SIDES, the inline start and the inline end: the\n * fields stack in a column beside the track, the end field level with its top and the start\n * field with its bottom, where the values they hold sit. The track spans the three rows and\n * gives them their height, the middle one taking whatever the fields leave.\n */\n .v-slider-body[data-orientation='vertical'][data-inputs='top'] {\n grid-template-areas: 'field-end rail' '. rail' 'field-start rail';\n grid-template-columns: auto auto;\n grid-template-rows: auto 1fr auto;\n }\n\n .v-slider-body[data-orientation='vertical'][data-inputs='top']:has(.v-slider-labels) {\n grid-template-areas:\n 'field-end rail labels'\n '. rail labels'\n 'field-start rail labels';\n grid-template-columns: auto auto auto;\n }\n\n .v-slider-body[data-orientation='vertical'][data-inputs='bottom'] {\n grid-template-areas: 'rail field-end' 'rail .' 'rail field-start';\n grid-template-columns: auto auto;\n grid-template-rows: auto 1fr auto;\n }\n\n .v-slider-body[data-orientation='vertical'][data-inputs='bottom']:has(.v-slider-labels) {\n grid-template-areas:\n 'rail labels field-end'\n 'rail labels .'\n 'rail labels field-start';\n grid-template-columns: auto auto auto;\n }\n\n .v-slider-body[data-orientation='vertical'] .v-slider-rail {\n inline-size: var(--slider-thumb);\n block-size: var(--vectis-control-size-slider-length);\n }\n\n /*\n * Rotate only the track box and reverse its direction; labels remain horizontal and the\n * minimum value stays at the bottom.\n */\n .v-slider-body[data-orientation='vertical'] .v-slider-control {\n writing-mode: vertical-lr;\n direction: rtl;\n }\n\n .v-slider-body[data-orientation='vertical'] .v-slider-tooltip {\n inset-block-end: var(--slider-at);\n inset-inline-start: auto;\n inset-inline-end: calc(100% + var(--vectis-space-2));\n inline-size: auto;\n block-size: 0;\n align-items: center;\n justify-content: flex-end;\n }\n\n .v-slider-body[data-orientation='vertical'] .v-slider-labels {\n align-self: stretch;\n min-block-size: auto;\n }\n\n .v-slider-body[data-orientation='vertical'] .v-slider-label {\n inset-block-start: auto;\n inset-block-end: var(--slider-at);\n inset-inline-start: 0;\n inline-size: auto;\n block-size: 0;\n align-items: center;\n justify-content: flex-start;\n }\n\n /*\n * A disabled slider greys out through the colour tokens, the same ones VCheckbox and VSwitch\n * use, and never through opacity. It comes last among the states, so a slider both disabled\n * and read-only or invalid is drawn disabled.\n */\n .v-slider-body[data-disabled] {\n cursor: not-allowed;\n }\n\n .v-slider-body[data-disabled] .v-slider-track {\n background: var(--vectis-color-surface-muted);\n }\n\n .v-slider-body[data-disabled] .v-slider-fill {\n background: var(--vectis-color-text-subtle);\n }\n\n .v-slider-body[data-disabled] .v-slider-tick {\n background: var(--vectis-color-text-subtle);\n }\n\n /*\n * A tick sitting on the greyed fill takes the light colour back, so that it stays visible\n * against it; the same inversion VCheckbox applies to its disabled tick.\n */\n .v-slider-body[data-disabled] .v-slider-tick[data-filled] {\n background: var(--vectis-color-surface-muted);\n }\n\n .v-slider-body[data-disabled] .v-slider-labels {\n color: var(--vectis-color-text-subtle);\n }\n\n .v-slider-body[data-disabled] .v-slider-input {\n --slider-thumb-bg: var(--vectis-color-surface-muted);\n --slider-thumb-border: var(--vectis-color-text-subtle);\n --slider-thumb-shadow: none;\n --slider-thumb-cursor: not-allowed;\n cursor: not-allowed;\n }\n\n /*\n * Forced colours erase background-only tracks and ticks. Restore the track edge and use\n * system Highlight/HighlightText for selected portions.\n */\n @media (forced-colors: active) {\n .v-slider-body .v-slider-track {\n forced-color-adjust: none;\n background: Canvas;\n box-shadow: inset 0 0 0 var(--vectis-control-border-width) CanvasText;\n }\n\n .v-slider-body .v-slider-fill {\n forced-color-adjust: none;\n background: Highlight;\n }\n\n .v-slider-body .v-slider-tick {\n forced-color-adjust: none;\n background: CanvasText;\n }\n\n .v-slider-body .v-slider-tick[data-filled] {\n background: HighlightText;\n }\n\n .v-slider-body .v-slider-input {\n forced-color-adjust: none;\n --slider-thumb-bg: Canvas;\n --slider-thumb-border: CanvasText;\n --slider-thumb-shadow: none;\n }\n\n .v-slider-body[data-disabled] .v-slider-track {\n box-shadow: inset 0 0 0 var(--vectis-control-border-width) GrayText;\n }\n\n .v-slider-body[data-disabled] .v-slider-fill,\n .v-slider-body[data-disabled] .v-slider-tick {\n background: GrayText;\n }\n\n .v-slider-body[data-disabled] .v-slider-input {\n --slider-thumb-border: GrayText;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .v-slider-input {\n --slider-thumb-transition: none;\n }\n\n .v-slider-tooltip {\n transition: none;\n }\n }\n}\n</style>\n"],"mappings":""}