vuetify 3.9.0-beta.1 → 3.9.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 (314) hide show
  1. package/dist/_component-variables-labs.sass +1 -0
  2. package/dist/json/attributes.json +3362 -3274
  3. package/dist/json/importMap-labs.json +20 -16
  4. package/dist/json/importMap.json +158 -158
  5. package/dist/json/tags.json +31 -4
  6. package/dist/json/web-types.json +6150 -5916
  7. package/dist/vuetify-labs.cjs +1035 -151
  8. package/dist/vuetify-labs.css +5736 -5417
  9. package/dist/vuetify-labs.d.ts +708 -377
  10. package/dist/vuetify-labs.esm.js +1035 -152
  11. package/dist/vuetify-labs.esm.js.map +1 -1
  12. package/dist/vuetify-labs.js +1035 -151
  13. package/dist/vuetify-labs.min.css +2 -2
  14. package/dist/vuetify.cjs +616 -126
  15. package/dist/vuetify.cjs.map +1 -1
  16. package/dist/vuetify.css +3902 -3825
  17. package/dist/vuetify.d.ts +338 -233
  18. package/dist/vuetify.esm.js +616 -127
  19. package/dist/vuetify.esm.js.map +1 -1
  20. package/dist/vuetify.js +616 -126
  21. package/dist/vuetify.js.map +1 -1
  22. package/dist/vuetify.min.css +2 -2
  23. package/dist/vuetify.min.js +1176 -1120
  24. package/dist/vuetify.min.js.map +1 -1
  25. package/lib/components/VAutocomplete/VAutocomplete.d.ts +39 -14
  26. package/lib/components/VAutocomplete/VAutocomplete.js +2 -2
  27. package/lib/components/VAutocomplete/VAutocomplete.js.map +1 -1
  28. package/lib/components/VCombobox/VCombobox.d.ts +39 -14
  29. package/lib/components/VCombobox/VCombobox.js +2 -2
  30. package/lib/components/VCombobox/VCombobox.js.map +1 -1
  31. package/lib/components/VDataIterator/composables/items.d.ts +2 -1
  32. package/lib/components/VDataIterator/composables/items.js.map +1 -1
  33. package/lib/components/VDataTable/VDataTable.css +12 -1
  34. package/lib/components/VDataTable/VDataTable.d.ts +20 -38
  35. package/lib/components/VDataTable/VDataTable.sass +12 -2
  36. package/lib/components/VDataTable/VDataTableColumn.d.ts +9 -3
  37. package/lib/components/VDataTable/VDataTableColumn.js +12 -4
  38. package/lib/components/VDataTable/VDataTableColumn.js.map +1 -1
  39. package/lib/components/VDataTable/VDataTableHeaders.d.ts +0 -13
  40. package/lib/components/VDataTable/VDataTableHeaders.js +10 -9
  41. package/lib/components/VDataTable/VDataTableHeaders.js.map +1 -1
  42. package/lib/components/VDataTable/VDataTableRow.js +2 -0
  43. package/lib/components/VDataTable/VDataTableRow.js.map +1 -1
  44. package/lib/components/VDataTable/VDataTableServer.d.ts +10 -23
  45. package/lib/components/VDataTable/VDataTableVirtual.d.ts +10 -23
  46. package/lib/components/VDataTable/composables/headers.d.ts +22 -14
  47. package/lib/components/VDataTable/composables/headers.js +51 -22
  48. package/lib/components/VDataTable/composables/headers.js.map +1 -1
  49. package/lib/components/VDataTable/composables/sort.js +2 -1
  50. package/lib/components/VDataTable/composables/sort.js.map +1 -1
  51. package/lib/components/VDataTable/types.d.ts +4 -2
  52. package/lib/components/VDataTable/types.js.map +1 -1
  53. package/lib/components/VDatePicker/VDatePicker.js +2 -1
  54. package/lib/components/VDatePicker/VDatePicker.js.map +1 -1
  55. package/lib/components/VDatePicker/VDatePickerMonth.js +1 -2
  56. package/lib/components/VDatePicker/VDatePickerMonth.js.map +1 -1
  57. package/lib/components/VKbd/VKbd.css +14 -5
  58. package/lib/components/VKbd/VKbd.js.map +1 -1
  59. package/lib/components/VKbd/VKbd.scss +26 -0
  60. package/lib/components/VKbd/_variables.scss +12 -6
  61. package/lib/components/VKbd/index.js.map +1 -1
  62. package/lib/components/VList/VList.d.ts +24 -27
  63. package/lib/components/VList/VList.js +0 -4
  64. package/lib/components/VList/VList.js.map +1 -1
  65. package/lib/components/VList/VListGroup.d.ts +13 -0
  66. package/lib/components/VList/VListGroup.js +2 -1
  67. package/lib/components/VList/VListGroup.js.map +1 -1
  68. package/lib/components/VList/VListItem.d.ts +6 -3
  69. package/lib/components/VList/VListItem.js +1 -1
  70. package/lib/components/VList/VListItem.js.map +1 -1
  71. package/lib/components/VOtpInput/VOtpInput.js +17 -14
  72. package/lib/components/VOtpInput/VOtpInput.js.map +1 -1
  73. package/lib/components/VOverlay/locationStrategies.js +1 -1
  74. package/lib/components/VOverlay/locationStrategies.js.map +1 -1
  75. package/lib/components/VSelect/VSelect.d.ts +58 -22
  76. package/lib/components/VSelect/VSelect.js +2 -2
  77. package/lib/components/VSelect/VSelect.js.map +1 -1
  78. package/lib/components/VTextField/VTextField.js +1 -1
  79. package/lib/components/VTextField/VTextField.js.map +1 -1
  80. package/lib/components/VTreeview/VTreeview.d.ts +235 -188
  81. package/lib/components/VTreeview/VTreeview.js +13 -12
  82. package/lib/components/VTreeview/VTreeview.js.map +1 -1
  83. package/lib/components/VTreeview/VTreeviewChildren.d.ts +81 -10
  84. package/lib/components/VTreeview/VTreeviewChildren.js +50 -11
  85. package/lib/components/VTreeview/VTreeviewChildren.js.map +1 -1
  86. package/lib/components/VTreeview/VTreeviewGroup.d.ts +13 -0
  87. package/lib/components/VTreeview/VTreeviewItem.css +57 -0
  88. package/lib/components/VTreeview/VTreeviewItem.d.ts +137 -103
  89. package/lib/components/VTreeview/VTreeviewItem.js +14 -4
  90. package/lib/components/VTreeview/VTreeviewItem.js.map +1 -1
  91. package/lib/components/VTreeview/VTreeviewItem.sass +60 -0
  92. package/lib/components/VTreeview/_variables.scss +15 -0
  93. package/lib/composables/calendar.d.ts +0 -1
  94. package/lib/composables/calendar.js +6 -10
  95. package/lib/composables/calendar.js.map +1 -1
  96. package/lib/composables/date/adapters/vuetify.js +1 -1
  97. package/lib/composables/date/adapters/vuetify.js.map +1 -1
  98. package/lib/composables/filter.d.ts +1 -0
  99. package/lib/composables/filter.js +1 -1
  100. package/lib/composables/filter.js.map +1 -1
  101. package/lib/composables/hotkey/hotkey-parsing.d.ts +15 -0
  102. package/lib/composables/hotkey/hotkey-parsing.js +154 -0
  103. package/lib/composables/hotkey/hotkey-parsing.js.map +1 -0
  104. package/lib/composables/hotkey/hotkey.d.ts +9 -0
  105. package/lib/composables/{hotkey.js → hotkey/hotkey.js} +31 -39
  106. package/lib/composables/hotkey/hotkey.js.map +1 -0
  107. package/lib/composables/hotkey/index.d.ts +1 -0
  108. package/lib/composables/hotkey/index.js +2 -0
  109. package/lib/composables/hotkey/index.js.map +1 -0
  110. package/lib/composables/hotkey/key-aliases.d.ts +14 -0
  111. package/lib/composables/hotkey/key-aliases.js +38 -0
  112. package/lib/composables/hotkey/key-aliases.js.map +1 -0
  113. package/lib/composables/icons.d.ts +11 -0
  114. package/lib/composables/icons.js.map +1 -1
  115. package/lib/composables/index.d.ts +1 -0
  116. package/lib/composables/index.js +1 -0
  117. package/lib/composables/index.js.map +1 -1
  118. package/lib/composables/list-items.d.ts +14 -1
  119. package/lib/composables/list-items.js +9 -3
  120. package/lib/composables/list-items.js.map +1 -1
  121. package/lib/composables/nested/nested.d.ts +7 -4
  122. package/lib/composables/nested/nested.js +16 -6
  123. package/lib/composables/nested/nested.js.map +1 -1
  124. package/lib/composables/nested/selectStrategies.d.ts +2 -1
  125. package/lib/composables/nested/selectStrategies.js +22 -11
  126. package/lib/composables/nested/selectStrategies.js.map +1 -1
  127. package/lib/composables/virtual.js +1 -1
  128. package/lib/composables/virtual.js.map +1 -1
  129. package/lib/entry-bundler.js +1 -1
  130. package/lib/entry-bundler.js.map +1 -1
  131. package/lib/framework.d.ts +79 -54
  132. package/lib/framework.js +1 -1
  133. package/lib/framework.js.map +1 -1
  134. package/lib/iconsets/fa.js +12 -1
  135. package/lib/iconsets/fa.js.map +1 -1
  136. package/lib/iconsets/fa4.js +12 -1
  137. package/lib/iconsets/fa4.js.map +1 -1
  138. package/lib/iconsets/md.js +12 -1
  139. package/lib/iconsets/md.js.map +1 -1
  140. package/lib/iconsets/mdi-svg.js +12 -1
  141. package/lib/iconsets/mdi-svg.js.map +1 -1
  142. package/lib/iconsets/mdi.js +12 -1
  143. package/lib/iconsets/mdi.js.map +1 -1
  144. package/lib/labs/VCalendar/VCalendar.d.ts +33 -33
  145. package/lib/labs/VCalendar/VCalendar.js +10 -10
  146. package/lib/labs/VCalendar/VCalendar.js.map +1 -1
  147. package/lib/labs/VCalendar/VCalendarDay.d.ts +33 -33
  148. package/lib/labs/VCalendar/VCalendarDay.js +1 -1
  149. package/lib/labs/VCalendar/VCalendarDay.js.map +1 -1
  150. package/lib/labs/VCalendar/VCalendarInterval.d.ts +36 -36
  151. package/lib/labs/VCalendar/VCalendarInterval.js +9 -9
  152. package/lib/labs/VCalendar/VCalendarInterval.js.map +1 -1
  153. package/lib/labs/VCalendar/VCalendarIntervalEvent.d.ts +12 -12
  154. package/lib/labs/VCalendar/VCalendarIntervalEvent.js +1 -1
  155. package/lib/labs/VCalendar/VCalendarIntervalEvent.js.map +1 -1
  156. package/lib/labs/VCalendar/VCalendarMonthDay.d.ts +36 -36
  157. package/lib/labs/VCalendar/VCalendarMonthDay.js +4 -4
  158. package/lib/labs/VCalendar/VCalendarMonthDay.js.map +1 -1
  159. package/lib/labs/VHotkey/VHotkey.css +242 -0
  160. package/lib/labs/VHotkey/VHotkey.d.ts +387 -0
  161. package/lib/labs/VHotkey/VHotkey.js +432 -0
  162. package/lib/labs/VHotkey/VHotkey.js.map +1 -0
  163. package/lib/labs/VHotkey/VHotkey.scss +253 -0
  164. package/lib/labs/VHotkey/_variables.scss +43 -0
  165. package/lib/labs/VHotkey/index.d.ts +1 -0
  166. package/lib/labs/VHotkey/index.js +2 -0
  167. package/lib/labs/VHotkey/index.js.map +1 -0
  168. package/lib/labs/VIconBtn/VIconBtn.js +1 -0
  169. package/lib/labs/VIconBtn/VIconBtn.js.map +1 -1
  170. package/lib/labs/components.d.ts +1 -0
  171. package/lib/labs/components.js +1 -0
  172. package/lib/labs/components.js.map +1 -1
  173. package/lib/locale/af.d.ts +18 -0
  174. package/lib/locale/af.js +18 -0
  175. package/lib/locale/af.js.map +1 -1
  176. package/lib/locale/ar.d.ts +18 -0
  177. package/lib/locale/ar.js +18 -0
  178. package/lib/locale/ar.js.map +1 -1
  179. package/lib/locale/az.d.ts +18 -0
  180. package/lib/locale/az.js +18 -0
  181. package/lib/locale/az.js.map +1 -1
  182. package/lib/locale/bg.d.ts +18 -0
  183. package/lib/locale/bg.js +18 -0
  184. package/lib/locale/bg.js.map +1 -1
  185. package/lib/locale/ca.d.ts +18 -0
  186. package/lib/locale/ca.js +18 -0
  187. package/lib/locale/ca.js.map +1 -1
  188. package/lib/locale/ckb.d.ts +18 -0
  189. package/lib/locale/ckb.js +18 -0
  190. package/lib/locale/ckb.js.map +1 -1
  191. package/lib/locale/cs.d.ts +18 -0
  192. package/lib/locale/cs.js +18 -0
  193. package/lib/locale/cs.js.map +1 -1
  194. package/lib/locale/da.d.ts +18 -0
  195. package/lib/locale/da.js +18 -0
  196. package/lib/locale/da.js.map +1 -1
  197. package/lib/locale/de.d.ts +18 -0
  198. package/lib/locale/de.js +18 -0
  199. package/lib/locale/de.js.map +1 -1
  200. package/lib/locale/el.d.ts +18 -0
  201. package/lib/locale/el.js +18 -0
  202. package/lib/locale/el.js.map +1 -1
  203. package/lib/locale/en.d.ts +18 -0
  204. package/lib/locale/en.js +18 -0
  205. package/lib/locale/en.js.map +1 -1
  206. package/lib/locale/es.d.ts +18 -0
  207. package/lib/locale/es.js +18 -0
  208. package/lib/locale/es.js.map +1 -1
  209. package/lib/locale/et.d.ts +18 -0
  210. package/lib/locale/et.js +18 -0
  211. package/lib/locale/et.js.map +1 -1
  212. package/lib/locale/fa.d.ts +18 -0
  213. package/lib/locale/fa.js +18 -0
  214. package/lib/locale/fa.js.map +1 -1
  215. package/lib/locale/fi.d.ts +18 -0
  216. package/lib/locale/fi.js +18 -0
  217. package/lib/locale/fi.js.map +1 -1
  218. package/lib/locale/fr.d.ts +18 -0
  219. package/lib/locale/fr.js +18 -0
  220. package/lib/locale/fr.js.map +1 -1
  221. package/lib/locale/he.d.ts +18 -0
  222. package/lib/locale/he.js +18 -0
  223. package/lib/locale/he.js.map +1 -1
  224. package/lib/locale/hr.d.ts +18 -0
  225. package/lib/locale/hr.js +18 -0
  226. package/lib/locale/hr.js.map +1 -1
  227. package/lib/locale/hu.d.ts +18 -0
  228. package/lib/locale/hu.js +18 -0
  229. package/lib/locale/hu.js.map +1 -1
  230. package/lib/locale/id.d.ts +18 -0
  231. package/lib/locale/id.js +18 -0
  232. package/lib/locale/id.js.map +1 -1
  233. package/lib/locale/it.d.ts +18 -0
  234. package/lib/locale/it.js +18 -0
  235. package/lib/locale/it.js.map +1 -1
  236. package/lib/locale/ja.d.ts +18 -0
  237. package/lib/locale/ja.js +18 -0
  238. package/lib/locale/ja.js.map +1 -1
  239. package/lib/locale/km.d.ts +18 -0
  240. package/lib/locale/km.js +18 -0
  241. package/lib/locale/km.js.map +1 -1
  242. package/lib/locale/ko.d.ts +18 -0
  243. package/lib/locale/ko.js +18 -0
  244. package/lib/locale/ko.js.map +1 -1
  245. package/lib/locale/lt.d.ts +18 -0
  246. package/lib/locale/lt.js +18 -0
  247. package/lib/locale/lt.js.map +1 -1
  248. package/lib/locale/lv.d.ts +18 -0
  249. package/lib/locale/lv.js +18 -0
  250. package/lib/locale/lv.js.map +1 -1
  251. package/lib/locale/nl.d.ts +18 -0
  252. package/lib/locale/nl.js +18 -0
  253. package/lib/locale/nl.js.map +1 -1
  254. package/lib/locale/no.d.ts +18 -0
  255. package/lib/locale/no.js +18 -0
  256. package/lib/locale/no.js.map +1 -1
  257. package/lib/locale/pl.d.ts +18 -0
  258. package/lib/locale/pl.js +18 -0
  259. package/lib/locale/pl.js.map +1 -1
  260. package/lib/locale/pt.d.ts +18 -0
  261. package/lib/locale/pt.js +18 -0
  262. package/lib/locale/pt.js.map +1 -1
  263. package/lib/locale/ro.d.ts +18 -0
  264. package/lib/locale/ro.js +18 -0
  265. package/lib/locale/ro.js.map +1 -1
  266. package/lib/locale/ru.d.ts +18 -0
  267. package/lib/locale/ru.js +18 -0
  268. package/lib/locale/ru.js.map +1 -1
  269. package/lib/locale/sk.d.ts +18 -0
  270. package/lib/locale/sk.js +18 -0
  271. package/lib/locale/sk.js.map +1 -1
  272. package/lib/locale/sl.d.ts +18 -0
  273. package/lib/locale/sl.js +18 -0
  274. package/lib/locale/sl.js.map +1 -1
  275. package/lib/locale/sr-Cyrl.d.ts +18 -0
  276. package/lib/locale/sr-Cyrl.js +18 -0
  277. package/lib/locale/sr-Cyrl.js.map +1 -1
  278. package/lib/locale/sr-Latn.d.ts +18 -0
  279. package/lib/locale/sr-Latn.js +18 -0
  280. package/lib/locale/sr-Latn.js.map +1 -1
  281. package/lib/locale/sv.d.ts +18 -0
  282. package/lib/locale/sv.js +18 -0
  283. package/lib/locale/sv.js.map +1 -1
  284. package/lib/locale/th.d.ts +18 -0
  285. package/lib/locale/th.js +18 -0
  286. package/lib/locale/th.js.map +1 -1
  287. package/lib/locale/tr.d.ts +18 -0
  288. package/lib/locale/tr.js +18 -0
  289. package/lib/locale/tr.js.map +1 -1
  290. package/lib/locale/uk.d.ts +18 -0
  291. package/lib/locale/uk.js +18 -0
  292. package/lib/locale/uk.js.map +1 -1
  293. package/lib/locale/vi.d.ts +18 -0
  294. package/lib/locale/vi.js +18 -0
  295. package/lib/locale/vi.js.map +1 -1
  296. package/lib/locale/zh-Hans.d.ts +18 -0
  297. package/lib/locale/zh-Hans.js +18 -0
  298. package/lib/locale/zh-Hans.js.map +1 -1
  299. package/lib/locale/zh-Hant.d.ts +18 -0
  300. package/lib/locale/zh-Hant.js +18 -0
  301. package/lib/locale/zh-Hant.js.map +1 -1
  302. package/lib/util/helpers.d.ts +3 -0
  303. package/lib/util/helpers.js +4 -0
  304. package/lib/util/helpers.js.map +1 -1
  305. package/lib/util/indentLines.d.ts +17 -0
  306. package/lib/util/indentLines.js +34 -0
  307. package/lib/util/indentLines.js.map +1 -0
  308. package/lib/util/index.d.ts +1 -0
  309. package/lib/util/index.js +1 -0
  310. package/lib/util/index.js.map +1 -1
  311. package/package.json +2 -2
  312. package/lib/components/VKbd/VKbd.sass +0 -15
  313. package/lib/composables/hotkey.d.ts +0 -9
  314. package/lib/composables/hotkey.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Vuetify v3.9.0-beta.1
2
+ * Vuetify v3.9.0
3
3
  * Forged by John Leider
4
4
  * Released under the MIT License.
5
5
  */
@@ -550,6 +550,10 @@
550
550
  return child.type !== vue.Fragment || ensureValidVNode(child.children);
551
551
  }) ? vnodes : null;
552
552
  }
553
+ function renderSlot(slot, props, fallback) {
554
+ // TODO: check if slot returns elements: #18308
555
+ return slot?.(props) ?? fallback?.(props);
556
+ }
553
557
  function defer(timeout, cb) {
554
558
  if (!IN_BROWSER || timeout === 0) {
555
559
  cb();
@@ -1624,6 +1628,40 @@
1624
1628
  return ['scroll', 'auto'].includes(style.overflowY);
1625
1629
  }
1626
1630
 
1631
+ // Types
1632
+
1633
+ function getIndentLines(_ref) {
1634
+ let {
1635
+ depth,
1636
+ isLast,
1637
+ isLastGroup,
1638
+ leafLinks,
1639
+ separateRoots,
1640
+ parentIndentLines,
1641
+ variant
1642
+ } = _ref;
1643
+ if (!parentIndentLines || !depth) {
1644
+ return {
1645
+ leaf: undefined,
1646
+ node: undefined,
1647
+ children: parentIndentLines
1648
+ };
1649
+ }
1650
+ if (variant === 'simple') {
1651
+ return {
1652
+ leaf: [...parentIndentLines, 'line'],
1653
+ node: [...parentIndentLines, 'line'],
1654
+ children: [...parentIndentLines, 'line']
1655
+ };
1656
+ }
1657
+ const isLastLeaf = isLast && (!isLastGroup || separateRoots || depth > 1);
1658
+ return {
1659
+ leaf: [...parentIndentLines, isLastLeaf ? 'last-leaf' : 'leaf', ...(leafLinks ? ['leaf-link'] : [])],
1660
+ node: [...parentIndentLines, isLastLeaf ? 'last-leaf' : 'leaf'],
1661
+ children: [...parentIndentLines, isLastLeaf ? 'none' : 'line']
1662
+ };
1663
+ }
1664
+
1627
1665
  function isFixedPosition(el) {
1628
1666
  while (el) {
1629
1667
  if (window.getComputedStyle(el).position === 'fixed') {
@@ -2145,6 +2183,24 @@
2145
2183
  exclude: 'The {0} character is not allowed',
2146
2184
  notEmpty: 'Please choose at least one value',
2147
2185
  pattern: 'Invalid format'
2186
+ },
2187
+ hotkey: {
2188
+ then: 'then',
2189
+ ctrl: 'Ctrl',
2190
+ command: 'Command',
2191
+ space: 'Space',
2192
+ shift: 'Shift',
2193
+ alt: 'Alt',
2194
+ enter: 'Enter',
2195
+ escape: 'Escape',
2196
+ upArrow: 'Up Arrow',
2197
+ downArrow: 'Down Arrow',
2198
+ leftArrow: 'Left Arrow',
2199
+ rightArrow: 'Right Arrow',
2200
+ backspace: 'Backspace',
2201
+ option: 'Option',
2202
+ plus: 'plus',
2203
+ shortcut: 'Keyboard shortcut: {0}'
2148
2204
  }
2149
2205
  };
2150
2206
 
@@ -4655,7 +4711,18 @@
4655
4711
  treeviewExpand: 'mdi-menu-right',
4656
4712
  eyeDropper: 'mdi-eyedropper',
4657
4713
  upload: 'mdi-cloud-upload',
4658
- color: 'mdi-palette'
4714
+ color: 'mdi-palette',
4715
+ command: 'mdi-apple-keyboard-command',
4716
+ ctrl: 'mdi-apple-keyboard-control',
4717
+ space: 'mdi-keyboard-space',
4718
+ shift: 'mdi-apple-keyboard-shift',
4719
+ alt: 'mdi-apple-keyboard-option',
4720
+ enter: 'mdi-keyboard-return',
4721
+ arrowup: 'mdi-arrow-up',
4722
+ arrowdown: 'mdi-arrow-down',
4723
+ arrowleft: 'mdi-arrow-left',
4724
+ arrowright: 'mdi-arrow-right',
4725
+ backspace: 'mdi-backspace'
4659
4726
  };
4660
4727
  const mdi = {
4661
4728
  // Not using mergeProps here, functional components merge props by default (?)
@@ -8797,7 +8864,7 @@
8797
8864
  selected.set(id, value ? 'on' : 'off');
8798
8865
  return selected;
8799
8866
  },
8800
- in: (v, children, parents) => {
8867
+ in: (v, children, parents, disabled) => {
8801
8868
  const map = new Map();
8802
8869
  for (const id of v || []) {
8803
8870
  strategy.select({
@@ -8805,7 +8872,8 @@
8805
8872
  value: true,
8806
8873
  selected: map,
8807
8874
  children,
8808
- parents
8875
+ parents,
8876
+ disabled
8809
8877
  });
8810
8878
  }
8811
8879
  return map;
@@ -8837,9 +8905,9 @@
8837
8905
  selected: singleSelected
8838
8906
  });
8839
8907
  },
8840
- in: (v, children, parents) => {
8908
+ in: (v, children, parents, disabled) => {
8841
8909
  if (v?.length) {
8842
- return parentStrategy.in(v.slice(0, 1), children, parents);
8910
+ return parentStrategy.in(v.slice(0, 1), children, parents, disabled);
8843
8911
  }
8844
8912
  return new Map();
8845
8913
  },
@@ -8905,23 +8973,32 @@
8905
8973
  value,
8906
8974
  selected,
8907
8975
  children,
8908
- parents
8976
+ parents,
8977
+ disabled
8909
8978
  } = _ref6;
8910
8979
  id = vue.toRaw(id);
8911
8980
  const original = new Map(selected);
8912
8981
  const items = [id];
8913
8982
  while (items.length) {
8914
8983
  const item = items.shift();
8915
- selected.set(vue.toRaw(item), value ? 'on' : 'off');
8984
+ if (!disabled.has(item)) {
8985
+ selected.set(vue.toRaw(item), value ? 'on' : 'off');
8986
+ }
8916
8987
  if (children.has(item)) {
8917
8988
  items.push(...children.get(item));
8918
8989
  }
8919
8990
  }
8920
8991
  let parent = vue.toRaw(parents.get(id));
8921
8992
  while (parent) {
8922
- const childrenIds = children.get(parent);
8923
- const everySelected = childrenIds.every(cid => selected.get(vue.toRaw(cid)) === 'on');
8924
- const noneSelected = childrenIds.every(cid => !selected.has(vue.toRaw(cid)) || selected.get(vue.toRaw(cid)) === 'off');
8993
+ let everySelected = true;
8994
+ let noneSelected = true;
8995
+ for (const child of children.get(parent)) {
8996
+ const cid = vue.toRaw(child);
8997
+ if (disabled.has(cid)) continue;
8998
+ if (selected.get(cid) !== 'on') everySelected = false;
8999
+ if (selected.has(cid) && selected.get(cid) !== 'off') noneSelected = false;
9000
+ if (!everySelected && !noneSelected) break;
9001
+ }
8925
9002
  selected.set(parent, everySelected ? 'on' : noneSelected ? 'off' : 'indeterminate');
8926
9003
  parent = vue.toRaw(parents.get(parent));
8927
9004
  }
@@ -8938,7 +9015,7 @@
8938
9015
  }
8939
9016
  return selected;
8940
9017
  },
8941
- in: (v, children, parents) => {
9018
+ in: (v, children, parents, disabled) => {
8942
9019
  let map = new Map();
8943
9020
  for (const id of v || []) {
8944
9021
  map = strategy.select({
@@ -8946,7 +9023,8 @@
8946
9023
  value: true,
8947
9024
  selected: map,
8948
9025
  children,
8949
- parents
9026
+ parents,
9027
+ disabled
8950
9028
  });
8951
9029
  }
8952
9030
  return map;
@@ -8993,8 +9071,9 @@
8993
9071
  root: {
8994
9072
  register: () => null,
8995
9073
  unregister: () => null,
8996
- parents: vue.ref(new Map()),
8997
9074
  children: vue.ref(new Map()),
9075
+ parents: vue.ref(new Map()),
9076
+ disabled: vue.ref(new Set()),
8998
9077
  open: () => null,
8999
9078
  openOnSelect: () => null,
9000
9079
  activate: () => null,
@@ -9023,6 +9102,7 @@
9023
9102
  let isUnmounted = false;
9024
9103
  const children = vue.shallowRef(new Map());
9025
9104
  const parents = vue.shallowRef(new Map());
9105
+ const disabled = vue.shallowRef(new Set());
9026
9106
  const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(Array.isArray(v) ? v.map(i => vue.toRaw(i)) : v), v => [...v.values()]);
9027
9107
  const activeStrategy = vue.computed(() => {
9028
9108
  if (typeof props.activeStrategy === 'object') return props.activeStrategy;
@@ -9071,7 +9151,7 @@
9071
9151
  }
9072
9152
  });
9073
9153
  const activated = useProxiedModel(props, 'activated', props.activated, v => activeStrategy.value.in(v, children.value, parents.value), v => activeStrategy.value.out(v, children.value, parents.value));
9074
- const selected = useProxiedModel(props, 'selected', props.selected, v => selectStrategy.value.in(v, children.value, parents.value), v => selectStrategy.value.out(v, children.value, parents.value));
9154
+ const selected = useProxiedModel(props, 'selected', props.selected, v => selectStrategy.value.in(v, children.value, parents.value, disabled.value), v => selectStrategy.value.out(v, children.value, parents.value));
9075
9155
  vue.onBeforeUnmount(() => {
9076
9156
  isUnmounted = true;
9077
9157
  });
@@ -9101,7 +9181,7 @@
9101
9181
  }
9102
9182
  return arr;
9103
9183
  }),
9104
- register: (id, parentId, isGroup) => {
9184
+ register: (id, parentId, isDisabled, isGroup) => {
9105
9185
  if (nodeIds.has(id)) {
9106
9186
  const path = getPath(id).map(String).join(' -> ');
9107
9187
  const newPath = getPath(parentId).concat(id).map(String).join(' -> ');
@@ -9111,6 +9191,7 @@
9111
9191
  nodeIds.add(id);
9112
9192
  }
9113
9193
  parentId && id !== parentId && parents.value.set(id, parentId);
9194
+ isDisabled && disabled.value.add(id);
9114
9195
  isGroup && children.value.set(id, []);
9115
9196
  if (parentId != null) {
9116
9197
  children.value.set(parentId, [...(children.value.get(parentId) || []), id]);
@@ -9120,6 +9201,7 @@
9120
9201
  if (isUnmounted) return;
9121
9202
  nodeIds.delete(id);
9122
9203
  children.value.delete(id);
9204
+ disabled.value.delete(id);
9123
9205
  const parent = parents.value.get(id);
9124
9206
  if (parent) {
9125
9207
  const list = children.value.get(parent) ?? [];
@@ -9169,6 +9251,7 @@
9169
9251
  selected: new Map(selected.value),
9170
9252
  children: children.value,
9171
9253
  parents: parents.value,
9254
+ disabled: disabled.value,
9172
9255
  event
9173
9256
  });
9174
9257
  newSelected && (selected.value = newSelected);
@@ -9211,13 +9294,14 @@
9211
9294
  },
9212
9295
  children,
9213
9296
  parents,
9297
+ disabled,
9214
9298
  getPath
9215
9299
  }
9216
9300
  };
9217
9301
  vue.provide(VNestedSymbol, nested);
9218
9302
  return nested.root;
9219
9303
  };
9220
- const useNestedItem = (id, isGroup) => {
9304
+ const useNestedItem = (id, isDisabled, isGroup) => {
9221
9305
  const parent = vue.inject(VNestedSymbol, emptyNested);
9222
9306
  const uidSymbol = Symbol('nested item');
9223
9307
  const computedId = vue.computed(() => vue.toRaw(vue.toValue(id)) ?? uidSymbol);
@@ -9237,10 +9321,14 @@
9237
9321
  isGroupActivator: parent.isGroupActivator
9238
9322
  };
9239
9323
  vue.onBeforeMount(() => {
9240
- !parent.isGroupActivator && parent.root.register(computedId.value, parent.id.value, isGroup);
9324
+ if (!parent.isGroupActivator) {
9325
+ parent.root.register(computedId.value, parent.id.value, vue.toValue(isDisabled), isGroup);
9326
+ }
9241
9327
  });
9242
9328
  vue.onBeforeUnmount(() => {
9243
- !parent.isGroupActivator && parent.root.unregister(computedId.value);
9329
+ if (!parent.isGroupActivator) {
9330
+ parent.root.unregister(computedId.value);
9331
+ }
9244
9332
  });
9245
9333
  isGroup && vue.provide(VNestedSymbol, item);
9246
9334
  return item;
@@ -9272,6 +9360,7 @@
9272
9360
  type: IconValue,
9273
9361
  default: '$collapse'
9274
9362
  },
9363
+ disabled: Boolean,
9275
9364
  expandIcon: {
9276
9365
  type: IconValue,
9277
9366
  default: '$expand'
@@ -9297,7 +9386,7 @@
9297
9386
  isOpen,
9298
9387
  open,
9299
9388
  id: _id
9300
- } = useNestedItem(() => props.value, true);
9389
+ } = useNestedItem(() => props.value, () => props.disabled, true);
9301
9390
  const id = vue.computed(() => `v-list-group--id-${String(props.rawId ?? _id.value)}`);
9302
9391
  const list = useList();
9303
9392
  const {
@@ -9467,7 +9556,7 @@
9467
9556
  parent,
9468
9557
  openOnSelect,
9469
9558
  id: uid
9470
- } = useNestedItem(id, false);
9559
+ } = useNestedItem(id, () => props.disabled, false);
9471
9560
  const list = useList();
9472
9561
  const isActive = vue.computed(() => props.active !== false && (props.active || link.isActive?.value || (root.activatable.value ? isActivated.value : isSelected.value)));
9473
9562
  const isLink = vue.toRef(() => props.link !== false && link.isLink.value);
@@ -9819,6 +9908,10 @@
9819
9908
  type: [Boolean, String, Array, Function],
9820
9909
  default: 'props'
9821
9910
  },
9911
+ itemType: {
9912
+ type: [Boolean, String, Array, Function],
9913
+ default: 'type'
9914
+ },
9822
9915
  returnObject: Boolean,
9823
9916
  valueComparator: Function
9824
9917
  }, 'list-items');
@@ -9826,6 +9919,7 @@
9826
9919
  const title = getPropertyFromItem(item, props.itemTitle, item);
9827
9920
  const value = getPropertyFromItem(item, props.itemValue, title);
9828
9921
  const children = getPropertyFromItem(item, props.itemChildren);
9922
+ const type = getPropertyFromItem(item, props.itemType, 'item');
9829
9923
  const itemProps = props.itemProps === true ? typeof item === 'object' && item != null && !Array.isArray(item) ? 'children' in item ? omit(item, ['children']) : item : undefined : getPropertyFromItem(item, props.itemProps);
9830
9924
  const _props = {
9831
9925
  title,
@@ -9833,15 +9927,16 @@
9833
9927
  ...itemProps
9834
9928
  };
9835
9929
  return {
9930
+ type,
9836
9931
  title: String(_props.title ?? ''),
9837
9932
  value: _props.value,
9838
9933
  props: _props,
9839
- children: Array.isArray(children) ? transformItems$3(props, children) : undefined,
9934
+ children: type === 'item' && Array.isArray(children) ? transformItems$3(props, children) : undefined,
9840
9935
  raw: item
9841
9936
  };
9842
9937
  }
9843
9938
  function transformItems$3(props, items) {
9844
- const _props = pick(props, ['itemTitle', 'itemValue', 'itemChildren', 'itemProps', 'returnObject', 'valueComparator']);
9939
+ const _props = pick(props, ['itemTitle', 'itemValue', 'itemChildren', 'itemProps', 'itemType', 'returnObject', 'valueComparator']);
9845
9940
  const array = [];
9846
9941
  for (const item of items) {
9847
9942
  array.push(transformItem$3(_props, item));
@@ -9883,7 +9978,7 @@
9883
9978
  const _returnObject = props.returnObject;
9884
9979
  const hasValueComparator = !!props.valueComparator;
9885
9980
  const valueComparator = props.valueComparator || deepEqual;
9886
- const _props = pick(props, ['itemTitle', 'itemValue', 'itemChildren', 'itemProps', 'returnObject', 'valueComparator']);
9981
+ const _props = pick(props, ['itemTitle', 'itemValue', 'itemChildren', 'itemProps', 'itemType', 'returnObject', 'valueComparator']);
9887
9982
  const returnValue = [];
9888
9983
  main: for (const v of value) {
9889
9984
  // When the model value is null, return an InternalItem
@@ -10003,10 +10098,6 @@
10003
10098
  ...makeDensityProps(),
10004
10099
  ...makeDimensionProps(),
10005
10100
  ...makeElevationProps(),
10006
- itemType: {
10007
- type: String,
10008
- default: 'type'
10009
- },
10010
10101
  ...makeItemsProps(),
10011
10102
  ...makeRoundedProps(),
10012
10103
  ...makeTagProps(),
@@ -10427,7 +10518,7 @@
10427
10518
  });
10428
10519
  if (flipped.isFull) {
10429
10520
  const values = flipped.values();
10430
- if (deepEqual(values.at(-1), values.at(-3))) {
10521
+ if (deepEqual(values.at(-1), values.at(-3)) && !deepEqual(values.at(-1), values.at(-2))) {
10431
10522
  // Flipping is causing a container resize loop
10432
10523
  return;
10433
10524
  }
@@ -12277,7 +12368,7 @@
12277
12368
  if (!isFocused.value) focus();
12278
12369
  vue.nextTick(() => {
12279
12370
  if (inputRef.value !== document.activeElement) {
12280
- inputRef.value?.focus();
12371
+ vue.nextTick(() => inputRef.value?.focus());
12281
12372
  }
12282
12373
  });
12283
12374
  }
@@ -12616,7 +12707,7 @@
12616
12707
  raf = requestAnimationFrame(_calculateVisibleItems);
12617
12708
  }
12618
12709
  function _calculateVisibleItems() {
12619
- if (!containerRef.value || !viewportHeight.value) return;
12710
+ if (!containerRef.value || !viewportHeight.value || !itemHeight.value) return;
12620
12711
  const scrollTop = lastScrollTop - markerOffset;
12621
12712
  const direction = Math.sign(scrollVelocity);
12622
12713
  const startPx = Math.max(0, scrollTop - BUFFER_PX);
@@ -13225,7 +13316,7 @@
13225
13316
  key: item.value,
13226
13317
  onClick: () => select(item, null)
13227
13318
  });
13228
- if (item.raw.type === 'divider') {
13319
+ if (item.type === 'divider') {
13229
13320
  return slots.divider?.({
13230
13321
  props: item.raw,
13231
13322
  index
@@ -13233,7 +13324,7 @@
13233
13324
  "key": `divider-${index}`
13234
13325
  }), null);
13235
13326
  }
13236
- if (item.raw.type === 'subheader') {
13327
+ if (item.type === 'subheader') {
13237
13328
  return slots.subheader?.({
13238
13329
  props: item.raw,
13239
13330
  index
@@ -13401,7 +13492,7 @@
13401
13492
  let match = -1;
13402
13493
  if ((query || customFiltersLength > 0) && !options?.noFilter) {
13403
13494
  if (typeof item === 'object') {
13404
- if (['divider', 'subheader'].includes(item.raw?.type)) {
13495
+ if (item.type === 'divider' || item.type === 'subheader') {
13405
13496
  continue;
13406
13497
  }
13407
13498
  const filterKeys = keys || Object.keys(transformed);
@@ -13843,7 +13934,7 @@
13843
13934
  active: highlightFirst.value && index === 0 ? true : undefined,
13844
13935
  onClick: () => select(item, null)
13845
13936
  });
13846
- if (item.raw.type === 'divider') {
13937
+ if (item.type === 'divider') {
13847
13938
  return slots.divider?.({
13848
13939
  props: item.raw,
13849
13940
  index
@@ -13851,7 +13942,7 @@
13851
13942
  "key": `divider-${index}`
13852
13943
  }), null);
13853
13944
  }
13854
- if (item.raw.type === 'subheader') {
13945
+ if (item.type === 'subheader') {
13855
13946
  return slots.subheader?.({
13856
13947
  props: item.raw,
13857
13948
  index
@@ -17499,7 +17590,7 @@
17499
17590
  case 'fullDate':
17500
17591
  options = {
17501
17592
  year: 'numeric',
17502
- month: 'long',
17593
+ month: 'short',
17503
17594
  day: 'numeric'
17504
17595
  };
17505
17596
  break;
@@ -18077,6 +18168,317 @@
18077
18168
  return createInstance(options, locale);
18078
18169
  }
18079
18170
 
18171
+ /**
18172
+ * Centralized key alias mapping for consistent key normalization across the hotkey system.
18173
+ *
18174
+ * This maps various user-friendly aliases to canonical key names that match
18175
+ * KeyboardEvent.key values (in lowercase) where possible.
18176
+ */
18177
+ const keyAliasMap = {
18178
+ // Modifier aliases (from vue-use, other libraries, and current implementation)
18179
+ control: 'ctrl',
18180
+ command: 'cmd',
18181
+ option: 'alt',
18182
+ // Arrow key aliases (common abbreviations)
18183
+ up: 'arrowup',
18184
+ down: 'arrowdown',
18185
+ left: 'arrowleft',
18186
+ right: 'arrowright',
18187
+ // Other common key aliases
18188
+ esc: 'escape',
18189
+ spacebar: ' ',
18190
+ space: ' ',
18191
+ return: 'enter',
18192
+ del: 'delete',
18193
+ // Symbol aliases (existing from hotkey-parsing.ts)
18194
+ minus: '-',
18195
+ hyphen: '-'
18196
+ };
18197
+
18198
+ /**
18199
+ * Normalizes a key string to its canonical form using the alias map.
18200
+ *
18201
+ * @param key - The key string to normalize
18202
+ * @returns The canonical key name in lowercase
18203
+ */
18204
+ function normalizeKey(key) {
18205
+ const lowerKey = key.toLowerCase();
18206
+ return keyAliasMap[lowerKey] || lowerKey;
18207
+ }
18208
+
18209
+ // Utilities
18210
+
18211
+ /**
18212
+ * Splits a single combination string into individual key parts.
18213
+ *
18214
+ * A combination is a set of keys that must be pressed simultaneously.
18215
+ * e.g. `ctrl+k`, `shift--`
18216
+ */
18217
+ function splitKeyCombination(combination) {
18218
+ let isInternal = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
18219
+ if (!combination) {
18220
+ if (!isInternal) consoleWarn('Invalid hotkey combination: empty string provided');
18221
+ return [];
18222
+ }
18223
+
18224
+ // --- VALIDATION ---
18225
+ const startsWithPlusOrUnderscore = combination.startsWith('+') || combination.startsWith('_');
18226
+ const hasInvalidLeadingSeparator =
18227
+ // Starts with a single '+' or '_' followed by a non-separator character (e.g. '+a', '_a')
18228
+ startsWithPlusOrUnderscore && !(combination.startsWith('++') || combination.startsWith('__'));
18229
+ const hasInvalidStructure =
18230
+ // Invalid leading separator patterns
18231
+ combination.length > 1 && hasInvalidLeadingSeparator ||
18232
+ // Disallow literal + or _ keys (they require shift)
18233
+ combination.includes('++') || combination.includes('__') || combination === '+' || combination === '_' ||
18234
+ // Ends with a separator that is not part of a doubled literal
18235
+ combination.length > 1 && (combination.endsWith('+') || combination.endsWith('_')) && combination.at(-2) !== combination.at(-1) ||
18236
+ // Stand-alone doubled separators (dangling)
18237
+ combination === '++' || combination === '--' || combination === '__';
18238
+ if (hasInvalidStructure) {
18239
+ if (!isInternal) consoleWarn(`Invalid hotkey combination: "${combination}" has invalid structure`);
18240
+ return [];
18241
+ }
18242
+ const keys = [];
18243
+ let buffer = '';
18244
+ const flushBuffer = () => {
18245
+ if (buffer) {
18246
+ keys.push(normalizeKey(buffer));
18247
+ buffer = '';
18248
+ }
18249
+ };
18250
+ for (let i = 0; i < combination.length; i++) {
18251
+ const char = combination[i];
18252
+ const nextChar = combination[i + 1];
18253
+ if (char === '+' || char === '_' || char === '-') {
18254
+ if (char === nextChar) {
18255
+ flushBuffer();
18256
+ keys.push(char);
18257
+ i++;
18258
+ } else if (char === '+' || char === '_') {
18259
+ flushBuffer();
18260
+ } else {
18261
+ buffer += char;
18262
+ }
18263
+ } else {
18264
+ buffer += char;
18265
+ }
18266
+ }
18267
+ flushBuffer();
18268
+
18269
+ // Within a combination, `-` is only valid as a literal key (e.g., `ctrl+-`).
18270
+ // `-` cannot be part of a longer key name within a combination.
18271
+ const hasInvalidMinus = keys.some(key => key.length > 1 && key.includes('-') && key !== '--');
18272
+ if (hasInvalidMinus) {
18273
+ if (!isInternal) consoleWarn(`Invalid hotkey combination: "${combination}" has invalid structure`);
18274
+ return [];
18275
+ }
18276
+ if (keys.length === 0 && combination) {
18277
+ return [normalizeKey(combination)];
18278
+ }
18279
+ return keys;
18280
+ }
18281
+
18282
+ /**
18283
+ * Splits a hotkey string into its constituent combination groups.
18284
+ *
18285
+ * A sequence is a series of combinations that must be pressed in order.
18286
+ * e.g. `a-b`, `ctrl+k-p`
18287
+ */
18288
+ function splitKeySequence(str) {
18289
+ if (!str) {
18290
+ consoleWarn('Invalid hotkey sequence: empty string provided');
18291
+ return [];
18292
+ }
18293
+
18294
+ // A sequence is invalid if it starts or ends with a separator,
18295
+ // unless it is part of a combination (e.g., `shift+-`).
18296
+ const hasInvalidStart = str.startsWith('-') && !['---', '--+'].includes(str);
18297
+ const hasInvalidEnd = str.endsWith('-') && !str.endsWith('+-') && !str.endsWith('_-') && str !== '-' && str !== '---';
18298
+ if (hasInvalidStart || hasInvalidEnd) {
18299
+ consoleWarn(`Invalid hotkey sequence: "${str}" contains invalid combinations`);
18300
+ return [];
18301
+ }
18302
+ const result = [];
18303
+ let buffer = '';
18304
+ let i = 0;
18305
+ while (i < str.length) {
18306
+ const char = str[i];
18307
+ if (char === '-') {
18308
+ // Determine if this hyphen is part of the current combination
18309
+ const prevChar = str[i - 1];
18310
+ const prevPrevChar = i > 1 ? str[i - 2] : undefined;
18311
+ const precededBySinglePlusOrUnderscore = (prevChar === '+' || prevChar === '_') && prevPrevChar !== '+';
18312
+ if (precededBySinglePlusOrUnderscore) {
18313
+ // Treat as part of the combination (e.g., 'ctrl+-')
18314
+ buffer += char;
18315
+ i++;
18316
+ } else {
18317
+ // Treat as sequence separator
18318
+ if (buffer) {
18319
+ result.push(buffer);
18320
+ buffer = '';
18321
+ } else {
18322
+ // Empty buffer means we have a literal '-' key
18323
+ result.push('-');
18324
+ }
18325
+ i++;
18326
+ }
18327
+ } else {
18328
+ buffer += char;
18329
+ i++;
18330
+ }
18331
+ }
18332
+
18333
+ // Add final buffer if it exists
18334
+ if (buffer) {
18335
+ result.push(buffer);
18336
+ }
18337
+
18338
+ // Collapse runs of '-' so that every second '-' is removed
18339
+ const collapsed = [];
18340
+ let minusCount = 0;
18341
+ for (const part of result) {
18342
+ if (part === '-') {
18343
+ if (minusCount % 2 === 0) collapsed.push('-');
18344
+ minusCount++;
18345
+ } else {
18346
+ minusCount = 0;
18347
+ collapsed.push(part);
18348
+ }
18349
+ }
18350
+
18351
+ // Validate that each part of the sequence is a valid combination
18352
+ const areAllValid = collapsed.every(s => splitKeyCombination(s, true).length > 0);
18353
+ if (!areAllValid) {
18354
+ consoleWarn(`Invalid hotkey sequence: "${str}" contains invalid combinations`);
18355
+ return [];
18356
+ }
18357
+ return collapsed;
18358
+ }
18359
+
18360
+ // Composables
18361
+
18362
+ // Types
18363
+
18364
+ function useHotkey(keys, callback) {
18365
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
18366
+ if (!IN_BROWSER) return function () {};
18367
+ const {
18368
+ event = 'keydown',
18369
+ inputs = false,
18370
+ preventDefault = true,
18371
+ sequenceTimeout = 1000
18372
+ } = options;
18373
+ const isMac = navigator?.userAgent?.includes('Macintosh') ?? false;
18374
+ let timeout = 0;
18375
+ let keyGroups;
18376
+ let isSequence = false;
18377
+ let groupIndex = 0;
18378
+ function clearTimer() {
18379
+ if (!timeout) return;
18380
+ clearTimeout(timeout);
18381
+ timeout = 0;
18382
+ }
18383
+ function isInputFocused() {
18384
+ if (vue.toValue(inputs)) return false;
18385
+ const activeElement = document.activeElement;
18386
+ return activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA' || activeElement.isContentEditable || activeElement.contentEditable === 'true');
18387
+ }
18388
+ function resetSequence() {
18389
+ groupIndex = 0;
18390
+ clearTimer();
18391
+ }
18392
+ function handler(e) {
18393
+ const group = keyGroups[groupIndex];
18394
+ if (!group || isInputFocused()) return;
18395
+ if (!matchesKeyGroup(e, group)) {
18396
+ if (isSequence) resetSequence();
18397
+ return;
18398
+ }
18399
+ if (vue.toValue(preventDefault)) e.preventDefault();
18400
+ if (!isSequence) {
18401
+ callback(e);
18402
+ return;
18403
+ }
18404
+ clearTimer();
18405
+ groupIndex++;
18406
+ if (groupIndex === keyGroups.length) {
18407
+ callback(e);
18408
+ resetSequence();
18409
+ return;
18410
+ }
18411
+ timeout = window.setTimeout(resetSequence, vue.toValue(sequenceTimeout));
18412
+ }
18413
+ function cleanup() {
18414
+ window.removeEventListener(vue.toValue(event), handler);
18415
+ clearTimer();
18416
+ }
18417
+ vue.watch(() => vue.toValue(keys), function (unrefKeys) {
18418
+ cleanup();
18419
+ if (unrefKeys) {
18420
+ const groups = splitKeySequence(unrefKeys.toLowerCase());
18421
+ isSequence = groups.length > 1;
18422
+ keyGroups = groups;
18423
+ resetSequence();
18424
+ window.addEventListener(vue.toValue(event), handler);
18425
+ }
18426
+ }, {
18427
+ immediate: true
18428
+ });
18429
+
18430
+ // Watch for changes in the event type to re-register the listener
18431
+ vue.watch(() => vue.toValue(event), function (newEvent, oldEvent) {
18432
+ if (oldEvent && keyGroups && keyGroups.length > 0) {
18433
+ window.removeEventListener(oldEvent, handler);
18434
+ window.addEventListener(newEvent, handler);
18435
+ }
18436
+ });
18437
+ try {
18438
+ getCurrentInstance('useHotkey');
18439
+ vue.onBeforeUnmount(cleanup);
18440
+ } catch {
18441
+ // Not in Vue setup context
18442
+ }
18443
+ function parseKeyGroup(group) {
18444
+ const MODIFIERS = ['ctrl', 'shift', 'alt', 'meta', 'cmd'];
18445
+
18446
+ // Use the shared combination splitting logic
18447
+ const parts = splitKeyCombination(group.toLowerCase());
18448
+
18449
+ // If the combination is invalid, return empty result
18450
+ if (parts.length === 0) {
18451
+ return {
18452
+ modifiers: Object.fromEntries(MODIFIERS.map(m => [m, false])),
18453
+ actualKey: undefined
18454
+ };
18455
+ }
18456
+ const modifiers = Object.fromEntries(MODIFIERS.map(m => [m, false]));
18457
+ let actualKey;
18458
+ for (const part of parts) {
18459
+ if (MODIFIERS.includes(part)) {
18460
+ modifiers[part] = true;
18461
+ } else {
18462
+ actualKey = part;
18463
+ }
18464
+ }
18465
+ return {
18466
+ modifiers,
18467
+ actualKey
18468
+ };
18469
+ }
18470
+ function matchesKeyGroup(e, group) {
18471
+ const {
18472
+ modifiers,
18473
+ actualKey
18474
+ } = parseKeyGroup(group);
18475
+ const expectCtrl = modifiers.ctrl || !isMac && (modifiers.cmd || modifiers.meta);
18476
+ const expectMeta = isMac && (modifiers.cmd || modifiers.meta);
18477
+ return e.ctrlKey === expectCtrl && e.metaKey === expectMeta && e.shiftKey === modifiers.shift && e.altKey === modifiers.alt && e.key.toLowerCase() === actualKey?.toLowerCase();
18478
+ }
18479
+ return cleanup;
18480
+ }
18481
+
18080
18482
  // Types
18081
18483
 
18082
18484
  const makeVColorPickerProps = propsFactory({
@@ -18623,7 +19025,7 @@
18623
19025
  active: highlightFirst.value && index === 0 ? true : undefined,
18624
19026
  onClick: () => select(item, null)
18625
19027
  });
18626
- if (item.raw.type === 'divider') {
19028
+ if (item.type === 'divider') {
18627
19029
  return slots.divider?.({
18628
19030
  props: item.raw,
18629
19031
  index
@@ -18631,7 +19033,7 @@
18631
19033
  "key": `divider-${index}`
18632
19034
  }), null);
18633
19035
  }
18634
- if (item.raw.type === 'subheader') {
19036
+ if (item.type === 'subheader') {
18635
19037
  return slots.subheader?.({
18636
19038
  props: item.raw,
18637
19039
  index
@@ -19505,7 +19907,8 @@
19505
19907
 
19506
19908
  // Dates should be compared numerically
19507
19909
  if (sortA instanceof Date && sortB instanceof Date) {
19508
- return sortA.getTime() - sortB.getTime();
19910
+ sortA = sortA.getTime();
19911
+ sortB = sortB.getTime();
19509
19912
  }
19510
19913
  [sortA, sortB] = [sortA, sortB].map(s => s != null ? s.toString().toLocaleLowerCase() : s);
19511
19914
  if (sortA !== sortB) {
@@ -20214,10 +20617,15 @@
20214
20617
  type: String,
20215
20618
  default: 'start'
20216
20619
  },
20217
- fixed: Boolean,
20620
+ fixed: {
20621
+ type: [Boolean, String],
20622
+ default: false
20623
+ },
20218
20624
  fixedOffset: [Number, String],
20625
+ fixedEndOffset: [Number, String],
20219
20626
  height: [Number, String],
20220
20627
  lastFixed: Boolean,
20628
+ firstFixedEnd: Boolean,
20221
20629
  noPadding: Boolean,
20222
20630
  tag: String,
20223
20631
  width: [Number, String],
@@ -20228,11 +20636,13 @@
20228
20636
  slots
20229
20637
  } = _ref;
20230
20638
  const Tag = props.tag ?? 'td';
20639
+ const fixedSide = typeof props.fixed === 'string' ? props.fixed : props.fixed ? 'start' : 'none';
20231
20640
  return vue.createVNode(Tag, {
20232
- "tabindex": "0",
20233
20641
  "class": vue.normalizeClass(['v-data-table__td', {
20234
- 'v-data-table-column--fixed': props.fixed,
20642
+ 'v-data-table-column--fixed': fixedSide === 'start',
20643
+ 'v-data-table-column--fixed-end': fixedSide === 'end',
20235
20644
  'v-data-table-column--last-fixed': props.lastFixed,
20645
+ 'v-data-table-column--first-fixed-end': props.firstFixedEnd,
20236
20646
  'v-data-table-column--no-padding': props.noPadding,
20237
20647
  'v-data-table-column--nowrap': props.nowrap
20238
20648
  }, `v-data-table-column--align-${props.align}`]),
@@ -20240,7 +20650,8 @@
20240
20650
  height: convertToUnit(props.height),
20241
20651
  width: convertToUnit(props.width),
20242
20652
  maxWidth: convertToUnit(props.maxWidth),
20243
- left: convertToUnit(props.fixedOffset || null)
20653
+ left: fixedSide === 'start' ? convertToUnit(props.fixedOffset || null) : undefined,
20654
+ right: fixedSide === 'end' ? convertToUnit(props.fixedEndOffset || null) : undefined
20244
20655
  }
20245
20656
  }, {
20246
20657
  default: () => [slots.default?.()]
@@ -20337,20 +20748,28 @@
20337
20748
  }
20338
20749
  function parseFixedColumns(items) {
20339
20750
  let seenFixed = false;
20340
- function setFixed(item) {
20341
- let parentFixed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
20751
+ function setFixed(item, side) {
20752
+ let parentFixedSide = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'none';
20342
20753
  if (!item) return;
20343
- if (parentFixed) {
20344
- item.fixed = true;
20754
+ if (parentFixedSide !== 'none') {
20755
+ item.fixed = parentFixedSide;
20345
20756
  }
20346
- if (item.fixed) {
20347
- if (item.children) {
20348
- for (let i = item.children.length - 1; i >= 0; i--) {
20349
- setFixed(item.children[i], true);
20757
+
20758
+ // normalize to simplify logic below
20759
+ if (item.fixed === true) {
20760
+ item.fixed = 'start';
20761
+ }
20762
+ const orderedChildren = side === 'start' ? item.children?.toReversed() : item.children;
20763
+ if (item.fixed === side) {
20764
+ if (orderedChildren) {
20765
+ for (const child of orderedChildren) {
20766
+ setFixed(child, side, side);
20350
20767
  }
20351
20768
  } else {
20352
- if (!seenFixed) {
20769
+ if (!seenFixed && side === 'start') {
20353
20770
  item.lastFixed = true;
20771
+ } else if (!seenFixed && side === 'end') {
20772
+ item.firstFixedEnd = true;
20354
20773
  } else if (isNaN(Number(item.width))) {
20355
20774
  consoleError(`Multiple fixed columns should have a static width (key: ${item.key})`);
20356
20775
  } else {
@@ -20359,36 +20778,57 @@
20359
20778
  seenFixed = true;
20360
20779
  }
20361
20780
  } else {
20362
- if (item.children) {
20363
- for (let i = item.children.length - 1; i >= 0; i--) {
20364
- setFixed(item.children[i]);
20781
+ if (orderedChildren) {
20782
+ for (const child of orderedChildren) {
20783
+ setFixed(child, side);
20365
20784
  }
20366
20785
  } else {
20367
20786
  seenFixed = false;
20368
20787
  }
20369
20788
  }
20370
20789
  }
20371
- for (let i = items.length - 1; i >= 0; i--) {
20372
- setFixed(items[i]);
20790
+ for (const item of items.toReversed()) {
20791
+ setFixed(item, 'start');
20792
+ }
20793
+ for (const item of items) {
20794
+ setFixed(item, 'end');
20373
20795
  }
20374
20796
  function setFixedOffset(item) {
20375
- let fixedOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
20376
- if (!item) return fixedOffset;
20797
+ let offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
20798
+ if (!item) return offset;
20377
20799
  if (item.children) {
20378
- item.fixedOffset = fixedOffset;
20800
+ item.fixedOffset = offset;
20379
20801
  for (const child of item.children) {
20380
- fixedOffset = setFixedOffset(child, fixedOffset);
20802
+ offset = setFixedOffset(child, offset);
20381
20803
  }
20382
- } else if (item.fixed) {
20383
- item.fixedOffset = fixedOffset;
20384
- fixedOffset += parseFloat(item.width || '0') || 0;
20804
+ } else if (item.fixed && item.fixed !== 'end') {
20805
+ item.fixedOffset = offset;
20806
+ offset += parseFloat(item.width || '0') || 0;
20385
20807
  }
20386
- return fixedOffset;
20808
+ return offset;
20387
20809
  }
20388
20810
  let fixedOffset = 0;
20389
20811
  for (const item of items) {
20390
20812
  fixedOffset = setFixedOffset(item, fixedOffset);
20391
20813
  }
20814
+ function setFixedEndOffset(item) {
20815
+ let offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
20816
+ if (!item) return offset;
20817
+ if (item.children) {
20818
+ item.fixedEndOffset = offset;
20819
+ for (const child of item.children) {
20820
+ offset = setFixedEndOffset(child, offset);
20821
+ }
20822
+ } else if (item.fixed === 'end') {
20823
+ item.fixedEndOffset = offset;
20824
+ offset += parseFloat(item.width || '0') || 0;
20825
+ }
20826
+ return offset;
20827
+ }
20828
+ let fixedEndOffset = 0;
20829
+ for (const item of items.toReversed()) {
20830
+ fixedEndOffset = setFixedEndOffset(item, fixedEndOffset);
20831
+ }
20392
20832
  }
20393
20833
  function parse(items, maxDepth) {
20394
20834
  const headers = [];
@@ -20521,7 +20961,6 @@
20521
20961
  color: String,
20522
20962
  disableSort: Boolean,
20523
20963
  fixedHeader: Boolean,
20524
- lastFixed: Boolean,
20525
20964
  multiSort: Boolean,
20526
20965
  sortAscIcon: {
20527
20966
  type: IconValue,
@@ -20568,11 +21007,12 @@
20568
21007
  loaderClasses
20569
21008
  } = useLoader(props);
20570
21009
  function getFixedStyles(column, y) {
20571
- if (!(props.sticky || props.fixedHeader) && !(column.fixed || column.lastFixed)) return undefined;
21010
+ if (!(props.sticky || props.fixedHeader) && !column.fixed) return undefined;
21011
+ const fixedSide = typeof column.fixed === 'string' ? column.fixed : column.fixed ? 'start' : 'none';
20572
21012
  return {
20573
21013
  position: 'sticky',
20574
- left: column.fixed || column.lastFixed ? convertToUnit(column.fixedOffset) : undefined,
20575
- right: column.lastFixed ? convertToUnit(column.fixedOffset ?? 0) : undefined,
21014
+ left: fixedSide === 'start' ? convertToUnit(column.fixedOffset) : undefined,
21015
+ right: fixedSide === 'end' ? convertToUnit(column.fixedEndOffset) : undefined,
20576
21016
  top: props.sticky || props.fixedHeader ? `calc(var(--v-table-header-height) * ${y})` : undefined
20577
21017
  };
20578
21018
  }
@@ -20632,14 +21072,15 @@
20632
21072
  },
20633
21073
  "colspan": column.colspan,
20634
21074
  "rowspan": column.rowspan,
20635
- "onClick": column.sortable ? () => toggleSort(column) : undefined,
20636
21075
  "fixed": column.fixed,
20637
21076
  "nowrap": column.nowrap,
20638
21077
  "lastFixed": column.lastFixed,
20639
- "noPadding": noPadding
20640
- }, headerProps, {
20641
- "onKeydown": event => column.sortable && handleEnterKeyPress(event, column)
20642
- }), {
21078
+ "firstFixedEnd": column.firstFixedEnd,
21079
+ "noPadding": noPadding,
21080
+ "tabindex": column.sortable ? 0 : undefined,
21081
+ "onClick": column.sortable ? () => toggleSort(column) : undefined,
21082
+ "onKeydown": column.sortable ? event => handleEnterKeyPress(event, column) : undefined
21083
+ }, headerProps), {
20643
21084
  default: () => {
20644
21085
  const columnSlotName = `header.${column.key}`;
20645
21086
  const columnSlotProps = {
@@ -20915,7 +21356,9 @@
20915
21356
  },
20916
21357
  "fixed": column.fixed,
20917
21358
  "fixedOffset": column.fixedOffset,
21359
+ "fixedEndOffset": column.fixedEndOffset,
20918
21360
  "lastFixed": column.lastFixed,
21361
+ "firstFixedEnd": column.firstFixedEnd,
20919
21362
  "maxWidth": !mobile.value ? column.maxWidth : undefined,
20920
21363
  "noPadding": column.key === 'data-table-select' || column.key === 'data-table-expand',
20921
21364
  "nowrap": column.nowrap,
@@ -22325,13 +22768,9 @@
22325
22768
  const date = adapter.setYear(adapter.startOfMonth(adapter.date()), adapter.getYear(year.value));
22326
22769
  return adapter.setMonth(date, value);
22327
22770
  }, v => adapter.getMonth(v));
22328
- const weekDays = vue.computed(() => {
22329
- const firstDayOfWeek = adapter.toJsDate(adapter.startOfWeek(adapter.date(), props.firstDayOfWeek)).getDay();
22330
- return props.weekdays.map(day => (day + firstDayOfWeek) % 7);
22331
- });
22332
22771
  const weekdayLabels = vue.computed(() => {
22333
- const labels = adapter.getWeekdays(props.firstDayOfWeek, props.weekdayFormat);
22334
- return weekDays.value.map(day => labels[day]);
22772
+ const firstDayOfWeek = adapter.toJsDate(adapter.startOfWeek(adapter.date(), props.firstDayOfWeek)).getDay();
22773
+ return adapter.getWeekdays(props.firstDayOfWeek, props.weekdayFormat).filter((_, i) => props.weekdays.includes((i + firstDayOfWeek) % 7));
22335
22774
  });
22336
22775
  const weeksInMonth = vue.computed(() => {
22337
22776
  const weeks = adapter.getWeekArray(month.value, props.firstDayOfWeek);
@@ -22355,13 +22794,14 @@
22355
22794
  });
22356
22795
  function genDays(days, today) {
22357
22796
  return days.filter(date => {
22358
- return weekDays.value.includes(adapter.toJsDate(date).getDay());
22797
+ return props.weekdays.includes(adapter.toJsDate(date).getDay());
22359
22798
  }).map((date, index) => {
22360
22799
  const isoDate = adapter.toISO(date);
22361
22800
  const isAdjacent = !adapter.isSameMonth(date, month.value);
22362
22801
  const isStart = adapter.isSameDay(date, adapter.startOfMonth(month.value));
22363
22802
  const isEnd = adapter.isSameDay(date, adapter.endOfMonth(month.value));
22364
22803
  const isSame = adapter.isSameDay(date, month.value);
22804
+ const weekdaysCount = props.weekdays.length;
22365
22805
  return {
22366
22806
  date,
22367
22807
  formatted: adapter.format(date, 'keyboardDate'),
@@ -22373,8 +22813,8 @@
22373
22813
  isSelected: model.value.some(value => adapter.isSameDay(date, value)),
22374
22814
  isStart,
22375
22815
  isToday: adapter.isSameDay(date, today),
22376
- isWeekEnd: index % 7 === 6,
22377
- isWeekStart: index % 7 === 0,
22816
+ isWeekEnd: index % weekdaysCount === weekdaysCount - 1,
22817
+ isWeekStart: index % weekdaysCount === 0,
22378
22818
  isoDate,
22379
22819
  localized: adapter.format(date, 'dayOfMonth'),
22380
22820
  month: adapter.getMonth(date),
@@ -22421,7 +22861,6 @@
22421
22861
  genDays,
22422
22862
  model,
22423
22863
  weeksInMonth,
22424
- weekDays,
22425
22864
  weekdayLabels,
22426
22865
  weekNumbers
22427
22866
  };
@@ -22462,7 +22901,6 @@
22462
22901
  daysInMonth,
22463
22902
  model,
22464
22903
  weekNumbers,
22465
- weekDays,
22466
22904
  weekdayLabels
22467
22905
  } = useCalendar(props);
22468
22906
  const adapter = useDate();
@@ -22537,7 +22975,7 @@
22537
22975
  useRender(() => vue.createElementVNode("div", {
22538
22976
  "class": "v-date-picker-month",
22539
22977
  "style": {
22540
- '--v-date-picker-days-in-week': weekDays.value.length
22978
+ '--v-date-picker-days-in-week': props.weekdays.length
22541
22979
  }
22542
22980
  }, [props.showWeek && vue.createElementVNode("div", {
22543
22981
  "key": "weeks",
@@ -22937,7 +23375,8 @@
22937
23375
  }
22938
23376
  function allowedMonths(month) {
22939
23377
  if (typeof props.allowedDates === 'function') {
22940
- const startOfMonth = adapter.parseISO(`${year.value}-${month + 1}-01`);
23378
+ const monthTwoDigits = String(month + 1).padStart(2, '0');
23379
+ const startOfMonth = adapter.parseISO(`${year.value}-${monthTwoDigits}-01`);
22941
23380
  return isAllowedInRange(startOfMonth, adapter.endOfMonth(startOfMonth));
22942
23381
  }
22943
23382
  if (Array.isArray(props.allowedDates) && props.allowedDates.length) {
@@ -25708,19 +26147,21 @@
25708
26147
  const contentRef = vue.ref();
25709
26148
  const inputRef = vue.ref([]);
25710
26149
  const current = vue.computed(() => inputRef.value[focusIndex.value]);
25711
- const intersectScope = vue.effectScope();
25712
- intersectScope.run(() => {
25713
- const {
25714
- intersectionRef,
25715
- isIntersecting
25716
- } = useIntersectionObserver();
25717
- vue.watch(isIntersecting, v => {
25718
- if (!v) return;
25719
- intersectionRef.value?.focus();
25720
- intersectScope.stop();
25721
- });
25722
- vue.watchEffect(() => {
25723
- intersectionRef.value = inputRef.value[0];
26150
+ useToggleScope(() => props.autofocus, () => {
26151
+ const intersectScope = vue.effectScope();
26152
+ intersectScope.run(() => {
26153
+ const {
26154
+ intersectionRef,
26155
+ isIntersecting
26156
+ } = useIntersectionObserver();
26157
+ vue.watchEffect(() => {
26158
+ intersectionRef.value = inputRef.value[0];
26159
+ });
26160
+ vue.watch(isIntersecting, v => {
26161
+ if (!v) return;
26162
+ intersectionRef.value?.focus();
26163
+ intersectScope.stop();
26164
+ });
25724
26165
  });
25725
26166
  });
25726
26167
  function onInput() {
@@ -29731,6 +30172,8 @@
29731
30172
 
29732
30173
  const makeVTreeviewItemProps = propsFactory({
29733
30174
  loading: Boolean,
30175
+ hideActions: Boolean,
30176
+ indentLines: Array,
29734
30177
  toggleIcon: IconValue,
29735
30178
  ...makeVListItemProps({
29736
30179
  slim: true
@@ -29767,11 +30210,11 @@
29767
30210
  }
29768
30211
  useRender(() => {
29769
30212
  const listItemProps = VListItem.filterProps(props);
29770
- const hasPrepend = slots.prepend || props.toggleIcon;
30213
+ const hasPrepend = slots.prepend || props.toggleIcon || props.indentLines;
29771
30214
  return vue.createVNode(VListItem, vue.mergeProps({
29772
30215
  "ref": vListItemRef
29773
30216
  }, listItemProps, {
29774
- "active": vListItemRef.value?.isActivated,
30217
+ "active": vListItemRef.value?.isActivated || undefined,
29775
30218
  "class": ['v-treeview-item', {
29776
30219
  'v-treeview-item--activatable-group-activator': isActivatableGroupActivator.value,
29777
30220
  'v-treeview-item--filtered': isFiltered.value
@@ -29781,7 +30224,15 @@
29781
30224
  }), {
29782
30225
  ...slots,
29783
30226
  prepend: hasPrepend ? slotProps => {
29784
- return vue.createElementVNode(vue.Fragment, null, [vue.createVNode(VListItemAction, {
30227
+ return vue.createElementVNode(vue.Fragment, null, [props.indentLines && props.indentLines.length > 0 ? vue.createElementVNode("div", {
30228
+ "key": "indent-lines",
30229
+ "class": "v-treeview-indent-lines",
30230
+ "style": {
30231
+ '--v-indent-parts': props.indentLines.length
30232
+ }
30233
+ }, [props.indentLines.map(type => vue.createElementVNode("div", {
30234
+ "class": vue.normalizeClass(`v-treeview-indent-line v-treeview-indent-line--${type}`)
30235
+ }, null))]) : '', !props.hideActions && vue.createVNode(VListItemAction, {
29785
30236
  "start": true
29786
30237
  }, {
29787
30238
  default: () => [props.toggleIcon ? vue.createVNode(VBtn, {
@@ -29833,10 +30284,15 @@
29833
30284
  selectedColor: String,
29834
30285
  selectStrategy: [String, Function, Object],
29835
30286
  index: Number,
30287
+ isLastGroup: Boolean,
30288
+ separateRoots: Boolean,
30289
+ parentIndentLines: Array,
30290
+ indentLinesVariant: String,
29836
30291
  path: {
29837
30292
  type: Array,
29838
30293
  default: () => []
29839
30294
  },
30295
+ ...pick(makeVTreeviewItemProps(), ['hideActions']),
29840
30296
  ...makeDensityProps()
29841
30297
  }, 'VTreeviewChildren');
29842
30298
  const VTreeviewChildren = genericComponent()({
@@ -29865,19 +30321,32 @@
29865
30321
  select(isSelected);
29866
30322
  }
29867
30323
  }
29868
- return () => slots.default?.() ?? props.items?.map((item, index) => {
30324
+ return () => slots.default?.() ?? props.items?.map((item, index, items) => {
29869
30325
  const {
29870
30326
  children,
29871
30327
  props: itemProps
29872
30328
  } = item;
29873
30329
  const loading = isLoading.has(item.value);
30330
+ const nextItemHasChildren = !!items.at(index + 1)?.children;
30331
+ const depth = props.path?.length ?? 0;
30332
+ const isLast = items.length - 1 === index;
29874
30333
  const treeItemProps = {
29875
30334
  index,
29876
- depth: props.path?.length ?? 0,
30335
+ depth,
29877
30336
  isFirst: index === 0,
29878
- isLast: props.items ? props.items.length - 1 === index : false,
29879
- path: [...props.path, index]
30337
+ isLast,
30338
+ path: [...props.path, index],
30339
+ hideAction: props.hideActions
29880
30340
  };
30341
+ const indentLines = getIndentLines({
30342
+ depth,
30343
+ isLast,
30344
+ isLastGroup: props.isLastGroup,
30345
+ leafLinks: !props.hideActions,
30346
+ separateRoots: props.separateRoots,
30347
+ parentIndentLines: props.parentIndentLines,
30348
+ variant: props.indentLinesVariant
30349
+ });
29881
30350
  const slotsWithItem = {
29882
30351
  prepend: slotProps => vue.createElementVNode(vue.Fragment, null, [props.selectable && (!children || children && !['leaf', 'single-leaf'].includes(props.selectStrategy)) && vue.createElementVNode("div", null, [vue.createVNode(VCheckboxBtn, {
29883
30352
  "key": item.value,
@@ -29943,21 +30412,40 @@
29943
30412
  return vue.createVNode(VTreeviewItem, vue.mergeProps({
29944
30413
  "ref": el => activatorItems.value[index] = el
29945
30414
  }, listItemProps, {
30415
+ "hideActions": props.hideActions,
30416
+ "indentLines": indentLines.node,
29946
30417
  "value": props.returnObject ? item.raw : itemProps.value,
29947
30418
  "loading": loading
29948
30419
  }), slotsWithItem);
29949
30420
  },
29950
30421
  default: () => vue.createVNode(VTreeviewChildren, vue.mergeProps(treeviewChildrenProps, {
29951
30422
  "items": children,
30423
+ "indentLinesVariant": props.indentLinesVariant,
30424
+ "parentIndentLines": indentLines.children,
30425
+ "isLastGroup": nextItemHasChildren,
29952
30426
  "returnObject": props.returnObject
29953
30427
  }), slots)
29954
- }) : slots.item?.({
30428
+ }) : renderSlot(slots.item, {
29955
30429
  props: itemProps,
29956
30430
  item: item.raw,
29957
30431
  internalItem: item
29958
- }) ?? vue.createVNode(VTreeviewItem, vue.mergeProps(itemProps, {
29959
- "value": props.returnObject ? vue.toRaw(item.raw) : itemProps.value
29960
- }), slotsWithItem);
30432
+ }, () => {
30433
+ if (item.type === 'divider') {
30434
+ return renderSlot(slots.divider, {
30435
+ props: item.raw
30436
+ }, () => vue.createVNode(VDivider, item.props, null));
30437
+ }
30438
+ if (item.type === 'subheader') {
30439
+ return renderSlot(slots.subheader, {
30440
+ props: item.raw
30441
+ }, () => vue.createVNode(VListSubheader, item.props, null));
30442
+ }
30443
+ return vue.createVNode(VTreeviewItem, vue.mergeProps(itemProps, {
30444
+ "hideActions": props.hideActions,
30445
+ "indentLines": indentLines.leaf,
30446
+ "value": props.returnObject ? vue.toRaw(item.raw) : itemProps.value
30447
+ }), slotsWithItem);
30448
+ });
29961
30449
  });
29962
30450
  }
29963
30451
  });
@@ -29973,20 +30461,18 @@
29973
30461
  const makeVTreeviewProps = propsFactory({
29974
30462
  fluid: Boolean,
29975
30463
  openAll: Boolean,
30464
+ indentLines: [Boolean, String],
29976
30465
  search: String,
29977
30466
  ...makeFilterProps({
29978
30467
  filterKeys: ['title']
29979
30468
  }),
29980
- ...omit(makeVTreeviewChildrenProps(), ['index', 'path']),
30469
+ ...omit(makeVTreeviewChildrenProps(), ['index', 'path', 'indentLinesVariant', 'parentIndentLines', 'isLastGroup']),
29981
30470
  ...omit(makeVListProps({
29982
30471
  collapseIcon: '$treeviewCollapse',
29983
30472
  expandIcon: '$treeviewExpand',
29984
30473
  slim: true
29985
- }), ['itemType', 'nav', 'openStrategy']),
29986
- modelValue: {
29987
- type: Array,
29988
- default: () => []
29989
- }
30474
+ }), ['nav', 'openStrategy']),
30475
+ modelValue: Array
29990
30476
  }, 'VTreeview');
29991
30477
  const VTreeview = genericComponent()({
29992
30478
  name: 'VTreeview',
@@ -30001,7 +30487,8 @@
30001
30487
  },
30002
30488
  setup(props, _ref) {
30003
30489
  let {
30004
- slots
30490
+ slots,
30491
+ emit
30005
30492
  } = _ref;
30006
30493
  const {
30007
30494
  items
@@ -30010,13 +30497,12 @@
30010
30497
  const baseColor = vue.toRef(() => props.baseColor);
30011
30498
  const color = vue.toRef(() => props.color);
30012
30499
  const activated = useProxiedModel(props, 'activated');
30013
- const model = useProxiedModel(props, 'modelValue');
30014
- const _selected = useProxiedModel(props, 'selected', props.modelValue);
30500
+ const _selected = useProxiedModel(props, 'selected');
30015
30501
  const selected = vue.computed({
30016
- get: () => _selected.value,
30502
+ get: () => props.modelValue ?? _selected.value,
30017
30503
  set(val) {
30018
30504
  _selected.value = val;
30019
- model.value = val;
30505
+ emit('update:modelValue', val);
30020
30506
  }
30021
30507
  });
30022
30508
  const vListRef = vue.ref();
@@ -30082,6 +30568,7 @@
30082
30568
  useRender(() => {
30083
30569
  const listProps = VList.filterProps(props);
30084
30570
  const treeviewChildrenProps = VTreeviewChildren.filterProps(props);
30571
+ const indentLinesVariant = typeof props.indentLines === 'boolean' ? 'default' : props.indentLines;
30085
30572
  return vue.createVNode(VList, vue.mergeProps({
30086
30573
  "ref": vListRef
30087
30574
  }, listProps, {
@@ -30099,7 +30586,9 @@
30099
30586
  default: () => [vue.createVNode(VTreeviewChildren, vue.mergeProps(treeviewChildrenProps, {
30100
30587
  "density": props.density,
30101
30588
  "returnObject": props.returnObject,
30102
- "items": items.value
30589
+ "items": items.value,
30590
+ "parentIndentLines": props.indentLines ? [] : undefined,
30591
+ "indentLinesVariant": indentLinesVariant
30103
30592
  }), slots)]
30104
30593
  });
30105
30594
  });
@@ -30188,7 +30677,7 @@
30188
30677
  }
30189
30678
  };
30190
30679
  useRender(() => {
30191
- return vue.createElementVNode("div", null, [slots.intervalEvent?.({
30680
+ return vue.createElementVNode("div", null, [slots['interval-event']?.({
30192
30681
  height: calcHeight().height,
30193
30682
  margin: calcHeight().margin,
30194
30683
  eventClass: 'v-calendar-internal-event',
@@ -30285,13 +30774,13 @@
30285
30774
  "style": vue.normalizeStyle(`height: ${convertToUnit(props.intervalHeight)}`)
30286
30775
  }, [vue.createElementVNode("div", vue.mergeProps({
30287
30776
  "class": "v-calendar-day__row-label"
30288
- }, getPrefixedEventHandlers(attrs, ':time', () => props)), [slots.intervalTitle?.({
30777
+ }, getPrefixedEventHandlers(attrs, ':time', () => props)), [slots['interval-title']?.({
30289
30778
  interval: interval.value
30290
30779
  }) ?? (props.index ? props.intervalFormat ? typeof props.intervalFormat === 'string' ? adapter.format(interval.value.start, 'hours12h') : props.intervalFormat(interval.value) : interval.value.label : '12 AM')]), vue.createElementVNode("div", {
30291
30780
  "class": "v-calendar-day__row-hairline"
30292
30781
  }, null), vue.createElementVNode("div", vue.mergeProps({
30293
30782
  "class": ['v-calendar-day__row-content', interval.value.events.some(e => !e.last) ? 'v-calendar-day__row-content-through' : '']
30294
- }, getPrefixedEventHandlers(attrs, ':interval', () => interval.value)), [slots.intervalBody?.({
30783
+ }, getPrefixedEventHandlers(attrs, ':interval', () => interval.value)), [slots['interval-body']?.({
30295
30784
  interval: interval.value
30296
30785
  }) ?? vue.createElementVNode("div", null, [interval.value.events?.map(event => vue.createVNode(VCalendarIntervalEvent, vue.mergeProps({
30297
30786
  "event": event,
@@ -30300,8 +30789,8 @@
30300
30789
  "intervalDuration": props.intervalDuration,
30301
30790
  "intervalHeight": props.intervalHeight
30302
30791
  }, attrs), {
30303
- ...(slots.intervalEvent ? {
30304
- intervalEvent: _ref2 => {
30792
+ ...(slots['interval-event'] ? {
30793
+ 'interval-event': _ref2 => {
30305
30794
  let {
30306
30795
  height,
30307
30796
  margin,
@@ -30309,7 +30798,7 @@
30309
30798
  event,
30310
30799
  interval
30311
30800
  } = _ref2;
30312
- return slots.intervalEvent?.({
30801
+ return slots['interval-event']?.({
30313
30802
  height,
30314
30803
  margin,
30315
30804
  eventClass,
@@ -30323,7 +30812,7 @@
30323
30812
  "style": vue.normalizeStyle(`height: ${convertToUnit(props.intervalHeight)}`)
30324
30813
  }, [vue.createElementVNode("div", vue.mergeProps({
30325
30814
  "class": ['v-calendar-day__row-content', interval.value.events.some(e => !e.last) ? 'v-calendar-day__row-content-through' : '']
30326
- }, getPrefixedEventHandlers(attrs, ':interval', () => interval.value)), [slots.intervalBody?.({
30815
+ }, getPrefixedEventHandlers(attrs, ':interval', () => interval.value)), [slots['interval-body']?.({
30327
30816
  interval: interval.value
30328
30817
  }) ?? interval.value.events?.map(event => vue.createVNode(VCalendarIntervalEvent, vue.mergeProps({
30329
30818
  "event": event,
@@ -30332,8 +30821,8 @@
30332
30821
  "intervalDuration": props.intervalDuration,
30333
30822
  "intervalHeight": props.intervalHeight
30334
30823
  }, attrs), {
30335
- ...(slots.intervalEvent ? {
30336
- intervalEvent: _ref3 => {
30824
+ ...(slots['interval-event'] ? {
30825
+ 'interval-event': _ref3 => {
30337
30826
  let {
30338
30827
  height,
30339
30828
  margin,
@@ -30341,7 +30830,7 @@
30341
30830
  event,
30342
30831
  interval
30343
30832
  } = _ref3;
30344
- return slots.intervalEvent?.({
30833
+ return slots['interval-event']?.({
30345
30834
  height,
30346
30835
  margin,
30347
30836
  eventClass,
@@ -30396,7 +30885,7 @@
30396
30885
  }), null)])]), intervals.value.map((_, index) => slots.interval?.(calendarIntervalProps) ?? vue.createVNode(VCalendarInterval, vue.mergeProps({
30397
30886
  "index": index
30398
30887
  }, calendarIntervalProps, attrs, getPrefixedEventHandlers(attrs, ':interval', () => calendarIntervalProps)), {
30399
- ...pick(slots, ['intervalBody', 'intervalEvent', 'intervalTitle'])
30888
+ ...pick(slots, ['interval-body', 'interval-event', 'interval-title'])
30400
30889
  }))]);
30401
30890
  });
30402
30891
  return {
@@ -30540,7 +31029,7 @@
30540
31029
  }, getPrefixedEventHandlers(attrs, ':day', () => props)), [!props.day?.isHidden ? vue.createElementVNode("div", {
30541
31030
  "key": "title",
30542
31031
  "class": "v-calendar-weekly__day-label"
30543
- }, [slots.dayTitle?.({
31032
+ }, [slots['day-title']?.({
30544
31033
  title: props.title
30545
31034
  }) ?? vue.createVNode(VBtn, vue.mergeProps({
30546
31035
  "class": props.day?.isToday ? 'v-calendar-weekly__day-label__today' : undefined,
@@ -30553,12 +31042,12 @@
30553
31042
  }, getPrefixedEventHandlers(attrs, ':date', () => props)), null)]) : undefined, !props.day?.isHidden ? vue.createElementVNode("div", {
30554
31043
  "key": "content",
30555
31044
  "class": "v-calendar-weekly__day-content"
30556
- }, [slots.dayBody?.({
31045
+ }, [slots['day-body']?.({
30557
31046
  day: props.day,
30558
31047
  events: props.events
30559
31048
  }) ?? vue.createElementVNode("div", null, [vue.createElementVNode("div", {
30560
31049
  "class": "v-calendar-weekly__day-alldayevents-container"
30561
- }, [props.events?.filter(event => event.allDay).map(event => slots.dayEvent ? slots.dayEvent({
31050
+ }, [props.events?.filter(event => event.allDay).map(event => slots['day-event'] ? slots['day-event']({
30562
31051
  day: props.day,
30563
31052
  allDay: true,
30564
31053
  event
@@ -30568,7 +31057,7 @@
30568
31057
  "allDay": true
30569
31058
  }, attrs), null))]), vue.createElementVNode("div", {
30570
31059
  "class": "v-calendar-weekly__day-events-container"
30571
- }, [props.events?.filter(event => !event.allDay).map(event => slots.dayEvent ? slots.dayEvent({
31060
+ }, [props.events?.filter(event => !event.allDay).map(event => slots['day-event'] ? slots['day-event']({
30572
31061
  day: props.day,
30573
31062
  event,
30574
31063
  allDay: false
@@ -30613,9 +31102,8 @@
30613
31102
  model,
30614
31103
  displayValue,
30615
31104
  weekNumbers,
30616
- weekDays
31105
+ weekdayLabels
30617
31106
  } = useCalendar(props);
30618
- const dayNames = adapter.getWeekdays();
30619
31107
  function onClickNext() {
30620
31108
  if (props.viewMode === 'month') {
30621
31109
  model.value = [adapter.addMonths(displayValue.value, 1)];
@@ -30653,6 +31141,7 @@
30653
31141
  useRender(() => {
30654
31142
  const calendarDayProps = VCalendarDay.filterProps(props);
30655
31143
  const calendarHeaderProps = VCalendarHeader.filterProps(props);
31144
+ const weekdaysCount = daysInWeek.value.length;
30656
31145
  return vue.createElementVNode("div", {
30657
31146
  "class": vue.normalizeClass(['v-calendar', {
30658
31147
  'v-calendar-monthly': props.viewMode === 'month',
@@ -30674,25 +31163,25 @@
30674
31163
  }), {
30675
31164
  title: slots.title
30676
31165
  }))]), vue.createElementVNode("div", {
30677
- "class": vue.normalizeClass(['v-calendar__container', `days__${weekDays.value.length}`])
31166
+ "class": vue.normalizeClass(['v-calendar__container', `days__${weekdaysCount}`])
30678
31167
  }, [props.viewMode === 'month' && !props.hideDayHeader && vue.createElementVNode("div", {
30679
- "class": vue.normalizeClass(['v-calendar-weekly__head', `days__${weekDays.value.length}`, ...(!props.hideWeekNumber ? ['v-calendar-weekly__head-weeknumbers'] : [])]),
31168
+ "class": vue.normalizeClass(['v-calendar-weekly__head', `days__${weekdaysCount}`, ...(!props.hideWeekNumber ? ['v-calendar-weekly__head-weeknumbers'] : [])]),
30680
31169
  "key": "calendarWeeklyHead"
30681
31170
  }, [!props.hideWeekNumber ? vue.createElementVNode("div", {
30682
31171
  "key": "weekNumber0",
30683
31172
  "class": "v-calendar-weekly__head-weeknumber"
30684
- }, null) : '', weekDays.value.map(weekday => vue.createElementVNode("div", {
31173
+ }, null) : '', weekdayLabels.value.map(weekday => vue.createElementVNode("div", {
30685
31174
  "class": vue.normalizeClass(`v-calendar-weekly__head-weekday${!props.hideWeekNumber ? '-with-weeknumber' : ''}`)
30686
- }, [dayNames[weekday]]))]), props.viewMode === 'month' && vue.createElementVNode("div", {
31175
+ }, [weekday]))]), props.viewMode === 'month' && vue.createElementVNode("div", {
30687
31176
  "key": "VCalendarMonth",
30688
- "class": vue.normalizeClass(['v-calendar-month__days', `days${!props.hideWeekNumber ? '-with-weeknumbers' : ''}__${weekDays.value.length}`, ...(!props.hideWeekNumber ? ['v-calendar-month__weeknumbers'] : [])])
30689
- }, [chunkArray(daysInMonth.value, weekDays.value.length).map((week, wi) => [!props.hideWeekNumber ? vue.createElementVNode("div", vue.mergeProps({
31177
+ "class": vue.normalizeClass(['v-calendar-month__days', `days${!props.hideWeekNumber ? '-with-weeknumbers' : ''}__${weekdaysCount}`, ...(!props.hideWeekNumber ? ['v-calendar-month__weeknumbers'] : [])])
31178
+ }, [chunkArray(daysInMonth.value, weekdaysCount).map((week, wi) => [!props.hideWeekNumber ? vue.createElementVNode("div", vue.mergeProps({
30690
31179
  "class": "v-calendar-month__weeknumber"
30691
31180
  }, getPrefixedEventHandlers(attrs, ':weekNumber', () => ({
30692
31181
  weekNumber: weekNumbers.value[wi],
30693
31182
  week
30694
31183
  }))), [weekNumbers.value[wi]]) : '', week.map(day => vue.createVNode(VCalendarMonthDay, vue.mergeProps({
30695
- "key": day.date.getTime()
31184
+ "key": adapter.toJsDate(day.date).getTime()
30696
31185
  }, calendarDayProps, {
30697
31186
  "day": day,
30698
31187
  "title": adapter.format(day.date, 'dayOfMonth'),
@@ -30709,7 +31198,7 @@
30709
31198
  "dayIndex": i,
30710
31199
  "events": props.events?.filter(e => adapter.isSameDay(e.start, day.date) || adapter.isSameDay(e.end, day.date))
30711
31200
  }, attrs), {
30712
- ...pick(slots, ['interval', 'intervalBody', 'intervalEvent', 'intervalTitle'])
31201
+ ...pick(slots, ['interval', 'interval-body', 'interval-event', 'interval-title'])
30713
31202
  })), props.viewMode === 'day' && (slots['day-interval'] ? slots['day-interval']({
30714
31203
  day: genDays([displayValue.value], adapter.date())[0],
30715
31204
  dayIndex: 0,
@@ -31624,6 +32113,7 @@
31624
32113
  opacity: props.opacity
31625
32114
  };
31626
32115
  return vue.createVNode(props.tag, {
32116
+ "type": props.tag === 'button' ? 'button' : undefined,
31627
32117
  "class": vue.normalizeClass([{
31628
32118
  'v-icon-btn': true,
31629
32119
  'v-icon-btn--active': isActive.value,
@@ -32282,6 +32772,398 @@
32282
32772
  }
32283
32773
  });
32284
32774
 
32775
+ // Types
32776
+
32777
+ // Display mode types for different visual representations
32778
+
32779
+ // Extended variant type that includes our custom 'contained' variant
32780
+
32781
+ // Key display tuple: [mode, content] where content is string or IconValue
32782
+
32783
+ // Key tuple: [mode, content] where content is string or IconValue
32784
+
32785
+ function processKey(config, requestedMode, isMac) {
32786
+ const keyCfg = isMac && config.mac ? config.mac : config.default;
32787
+
32788
+ // 1. Resolve the safest display mode for the current platform
32789
+ const mode = (() => {
32790
+ // Non-Mac platforms rarely use icons – prefer text
32791
+ if (requestedMode === 'icon' && !isMac) return 'text';
32792
+
32793
+ // If the requested mode lacks an asset, fall back to text
32794
+ if (requestedMode === 'icon' && !keyCfg.icon) return 'text';
32795
+ if (requestedMode === 'symbol' && !keyCfg.symbol) return 'text';
32796
+ return requestedMode;
32797
+ })();
32798
+
32799
+ // 2. Pick value for the chosen mode, defaulting to text representation
32800
+ let value = keyCfg[mode] ?? keyCfg.text;
32801
+
32802
+ // 3. Guard against icon tokens leaking into text mode (e.g. "$ctrl")
32803
+ if (mode === 'text' && typeof value === 'string' && value.startsWith('$') && !value.startsWith('$vuetify.')) {
32804
+ value = value.slice(1).toUpperCase(); // "$ctrl" → "CTRL"
32805
+ }
32806
+ return mode === 'icon' ? ['icon', value] : [mode, value];
32807
+ }
32808
+ const hotkeyMap = {
32809
+ ctrl: {
32810
+ mac: {
32811
+ symbol: '⌃',
32812
+ icon: '$ctrl',
32813
+ text: '$vuetify.hotkey.ctrl'
32814
+ },
32815
+ default: {
32816
+ text: 'Ctrl'
32817
+ }
32818
+ },
32819
+ meta: {
32820
+ mac: {
32821
+ symbol: '⌘',
32822
+ icon: '$command',
32823
+ text: '$vuetify.hotkey.command'
32824
+ },
32825
+ default: {
32826
+ text: 'Ctrl'
32827
+ }
32828
+ },
32829
+ cmd: {
32830
+ mac: {
32831
+ symbol: '⌘',
32832
+ icon: '$command',
32833
+ text: '$vuetify.hotkey.command'
32834
+ },
32835
+ default: {
32836
+ text: 'Ctrl'
32837
+ }
32838
+ },
32839
+ shift: {
32840
+ mac: {
32841
+ symbol: '⇧',
32842
+ icon: '$shift',
32843
+ text: '$vuetify.hotkey.shift'
32844
+ },
32845
+ default: {
32846
+ text: 'Shift'
32847
+ }
32848
+ },
32849
+ alt: {
32850
+ mac: {
32851
+ symbol: '⌥',
32852
+ icon: '$alt',
32853
+ text: '$vuetify.hotkey.option'
32854
+ },
32855
+ default: {
32856
+ text: 'Alt'
32857
+ }
32858
+ },
32859
+ enter: {
32860
+ default: {
32861
+ symbol: '↵',
32862
+ icon: '$enter',
32863
+ text: '$vuetify.hotkey.enter'
32864
+ }
32865
+ },
32866
+ arrowup: {
32867
+ default: {
32868
+ symbol: '↑',
32869
+ icon: '$arrowup',
32870
+ text: '$vuetify.hotkey.upArrow'
32871
+ }
32872
+ },
32873
+ arrowdown: {
32874
+ default: {
32875
+ symbol: '↓',
32876
+ icon: '$arrowdown',
32877
+ text: '$vuetify.hotkey.downArrow'
32878
+ }
32879
+ },
32880
+ arrowleft: {
32881
+ default: {
32882
+ symbol: '←',
32883
+ icon: '$arrowleft',
32884
+ text: '$vuetify.hotkey.leftArrow'
32885
+ }
32886
+ },
32887
+ arrowright: {
32888
+ default: {
32889
+ symbol: '→',
32890
+ icon: '$arrowright',
32891
+ text: '$vuetify.hotkey.rightArrow'
32892
+ }
32893
+ },
32894
+ backspace: {
32895
+ default: {
32896
+ symbol: '⌫',
32897
+ icon: '$backspace',
32898
+ text: '$vuetify.hotkey.backspace'
32899
+ }
32900
+ },
32901
+ escape: {
32902
+ default: {
32903
+ text: '$vuetify.hotkey.escape'
32904
+ }
32905
+ },
32906
+ ' ': {
32907
+ mac: {
32908
+ symbol: '␣',
32909
+ icon: '$space',
32910
+ text: '$vuetify.hotkey.space'
32911
+ },
32912
+ default: {
32913
+ text: '$vuetify.hotkey.space'
32914
+ }
32915
+ },
32916
+ '-': {
32917
+ default: {
32918
+ text: '-'
32919
+ }
32920
+ }
32921
+ };
32922
+
32923
+ // Create custom variant props that extend the base variant props with our 'contained' option
32924
+ const makeVHotkeyVariantProps = propsFactory({
32925
+ variant: {
32926
+ type: String,
32927
+ default: 'elevated',
32928
+ validator: v => ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain', 'contained'].includes(v)
32929
+ }
32930
+ }, 'VHotkeyVariant');
32931
+ const makeVHotkeyProps = propsFactory({
32932
+ // String representing keyboard shortcuts (e.g., "ctrl+k", "meta+shift+p")
32933
+ keys: String,
32934
+ // How to display keys: 'symbol' uses special characters (⌘, ⌃), 'icon' uses SVG icons, 'text' uses words
32935
+ displayMode: {
32936
+ type: String,
32937
+ default: 'icon'
32938
+ },
32939
+ // Custom key mapping configuration. Users can import and modify the exported hotkeyMap as needed
32940
+ keyMap: {
32941
+ type: Object,
32942
+ default: () => hotkeyMap
32943
+ },
32944
+ platform: {
32945
+ type: String,
32946
+ default: 'auto'
32947
+ },
32948
+ inline: Boolean,
32949
+ disabled: Boolean,
32950
+ prefix: String,
32951
+ suffix: String,
32952
+ ...makeComponentProps(),
32953
+ ...makeThemeProps(),
32954
+ ...makeBorderProps(),
32955
+ ...makeRoundedProps(),
32956
+ ...makeElevationProps(),
32957
+ ...makeVHotkeyVariantProps(),
32958
+ color: String
32959
+ }, 'VHotkey');
32960
+ class Delineator {
32961
+ constructor(delineator) {
32962
+ if (['and', 'then'].includes(delineator)) this.val = delineator;else {
32963
+ throw new Error('Not a valid delineator');
32964
+ }
32965
+ }
32966
+ isEqual(d) {
32967
+ return this.val === d.val;
32968
+ }
32969
+ }
32970
+ function isDelineator(value) {
32971
+ return value instanceof Delineator;
32972
+ }
32973
+ function isString(value) {
32974
+ return typeof value === 'string';
32975
+ }
32976
+ function getKeyText(keyMap, key, isMac) {
32977
+ const lowerKey = key.toLowerCase();
32978
+ if (lowerKey in keyMap) {
32979
+ const result = processKey(keyMap[lowerKey], 'text', isMac);
32980
+ return typeof result[1] === 'string' ? result[1] : String(result[1]);
32981
+ }
32982
+ return key.toUpperCase();
32983
+ }
32984
+ function applyDisplayModeToKey(keyMap, mode, key, isMac) {
32985
+ const lowerKey = key.toLowerCase();
32986
+ if (lowerKey in keyMap) {
32987
+ const result = processKey(keyMap[lowerKey], mode, isMac);
32988
+ if (result[0] === 'text' && typeof result[1] === 'string' && result[1].startsWith('$') && !result[1].startsWith('$vuetify.')) {
32989
+ return ['text', result[1].replace('$', '').toUpperCase(), key];
32990
+ }
32991
+ return [...result, key];
32992
+ }
32993
+ return ['text', key.toUpperCase(), key];
32994
+ }
32995
+ const VHotkey = genericComponent()({
32996
+ name: 'VHotkey',
32997
+ props: makeVHotkeyProps(),
32998
+ setup(props) {
32999
+ const {
33000
+ t
33001
+ } = useLocale();
33002
+ const {
33003
+ themeClasses
33004
+ } = provideTheme(props);
33005
+ const {
33006
+ rtlClasses
33007
+ } = useRtl();
33008
+ const {
33009
+ borderClasses
33010
+ } = useBorder(props);
33011
+ const {
33012
+ roundedClasses
33013
+ } = useRounded(props);
33014
+ const {
33015
+ elevationClasses
33016
+ } = useElevation(props);
33017
+ const isContainedVariant = vue.computed(() => props.variant === 'contained');
33018
+ const effectiveVariantProps = vue.computed(() => ({
33019
+ ...props,
33020
+ variant: isContainedVariant.value ? 'elevated' : props.variant
33021
+ }));
33022
+ const {
33023
+ colorClasses,
33024
+ colorStyles,
33025
+ variantClasses
33026
+ } = useVariant(effectiveVariantProps);
33027
+ const isMac = vue.computed(() => props.platform === 'auto' ? typeof navigator !== 'undefined' && /macintosh/i.test(navigator.userAgent) : props.platform === 'mac');
33028
+ const effectiveDisplayMode = vue.computed(() => props.displayMode);
33029
+ const AND_DELINEATOR = new Delineator('and'); // For + separators
33030
+ const THEN_DELINEATOR = new Delineator('then'); // For - separators
33031
+
33032
+ const effectiveKeyMap = vue.computed(() => props.keyMap);
33033
+ const keyCombinations = vue.computed(() => {
33034
+ if (!props.keys) return [];
33035
+
33036
+ // Split by spaces to handle multiple key combinations
33037
+ // Example: "ctrl+k meta+p" -> ["ctrl+k", "meta+p"]
33038
+ return props.keys.split(' ').map(combination => {
33039
+ // Use the shared sequence splitting logic
33040
+ const sequenceGroups = splitKeySequence(combination);
33041
+
33042
+ // Process each sequence group
33043
+ return sequenceGroups.flatMap((group, groupIndex) => {
33044
+ // Use the shared key combination splitting logic
33045
+ const keyParts = splitKeyCombination(group);
33046
+ const parts = keyParts.reduce((acc, part, index) => {
33047
+ if (index !== 0) {
33048
+ // Add AND delineator between keys
33049
+ return [...acc, AND_DELINEATOR, part];
33050
+ }
33051
+ return [...acc, part];
33052
+ }, []);
33053
+
33054
+ // Add THEN delineator between sequence groups
33055
+ const result = parts.map(key => {
33056
+ if (isString(key)) {
33057
+ return applyDisplayModeToKey(effectiveKeyMap.value, effectiveDisplayMode.value, key, isMac.value);
33058
+ }
33059
+ return key;
33060
+ });
33061
+
33062
+ // Add sequence separator if not the last group
33063
+ if (groupIndex < sequenceGroups.length - 1) {
33064
+ result.push(THEN_DELINEATOR);
33065
+ }
33066
+ return result;
33067
+ });
33068
+ });
33069
+ });
33070
+ const accessibleLabel = vue.computed(() => {
33071
+ if (!props.keys) return '';
33072
+
33073
+ // Convert the parsed key combinations into readable text
33074
+ const readableShortcuts = keyCombinations.value.map(combination => {
33075
+ const readableParts = [];
33076
+ for (const key of combination) {
33077
+ if (isDelineator(key)) {
33078
+ if (AND_DELINEATOR.isEqual(key)) {
33079
+ readableParts.push(t('$vuetify.hotkey.plus'));
33080
+ } else if (THEN_DELINEATOR.isEqual(key)) {
33081
+ readableParts.push(t('$vuetify.hotkey.then'));
33082
+ }
33083
+ } else {
33084
+ // Always use text representation for screen readers
33085
+ const textKey = key[0] === 'icon' || key[0] === 'symbol' ? applyDisplayModeToKey(mergeDeep(hotkeyMap, props.keyMap), 'text', String(key[1]), isMac.value)[1] : key[1];
33086
+ readableParts.push(translateKey(textKey));
33087
+ }
33088
+ }
33089
+ return readableParts.join(' ');
33090
+ });
33091
+ const shortcutText = readableShortcuts.join(', ');
33092
+ return t('$vuetify.hotkey.shortcut', shortcutText);
33093
+ });
33094
+ function translateKey(key) {
33095
+ return key.startsWith('$vuetify.') ? t(key) : key;
33096
+ }
33097
+ function getKeyTooltip(key) {
33098
+ if (effectiveDisplayMode.value === 'text') return undefined;
33099
+ const textKey = getKeyText(effectiveKeyMap.value, String(key[2]), isMac.value);
33100
+ return translateKey(textKey);
33101
+ }
33102
+ function renderKey(key, keyIndex, isContained) {
33103
+ const KeyComponent = isContained ? 'kbd' : VKbd;
33104
+ const keyClasses = ['v-hotkey__key', `v-hotkey__key-${key[0]}`, ...(isContained ? ['v-hotkey__key--nested'] : [borderClasses.value, roundedClasses.value, elevationClasses.value, colorClasses.value])];
33105
+ return vue.createVNode(KeyComponent, {
33106
+ "key": keyIndex,
33107
+ "class": vue.normalizeClass(keyClasses),
33108
+ "style": vue.normalizeStyle(isContained ? undefined : colorStyles.value),
33109
+ "aria-hidden": "true",
33110
+ "title": getKeyTooltip(key)
33111
+ }, {
33112
+ default: () => [key[0] === 'icon' ? vue.createVNode(VIcon, {
33113
+ "icon": key[1],
33114
+ "aria-hidden": "true"
33115
+ }, null) : translateKey(key[1])]
33116
+ });
33117
+ }
33118
+ function renderDivider(key, keyIndex) {
33119
+ return vue.createElementVNode("span", {
33120
+ "key": keyIndex,
33121
+ "class": "v-hotkey__divider",
33122
+ "aria-hidden": "true"
33123
+ }, [AND_DELINEATOR.isEqual(key) ? '+' : t('$vuetify.hotkey.then')]);
33124
+ }
33125
+ useRender(() => vue.createElementVNode("div", {
33126
+ "class": vue.normalizeClass(['v-hotkey', {
33127
+ 'v-hotkey--disabled': props.disabled,
33128
+ 'v-hotkey--inline': props.inline,
33129
+ 'v-hotkey--contained': isContainedVariant.value
33130
+ }, themeClasses.value, rtlClasses.value, variantClasses.value, props.class]),
33131
+ "style": vue.normalizeStyle(props.style),
33132
+ "role": "img",
33133
+ "aria-label": accessibleLabel.value
33134
+ }, [isContainedVariant.value ? vue.createVNode(VKbd, {
33135
+ "key": "contained",
33136
+ "class": vue.normalizeClass(['v-hotkey__contained-wrapper', borderClasses.value, roundedClasses.value, elevationClasses.value, colorClasses.value]),
33137
+ "style": vue.normalizeStyle(colorStyles.value),
33138
+ "aria-hidden": "true"
33139
+ }, {
33140
+ default: () => [props.prefix && vue.createElementVNode("span", {
33141
+ "key": "contained-prefix",
33142
+ "class": "v-hotkey__prefix"
33143
+ }, [props.prefix]), keyCombinations.value.map((combination, comboIndex) => vue.createElementVNode("span", {
33144
+ "class": "v-hotkey__combination",
33145
+ "key": comboIndex
33146
+ }, [combination.map((key, keyIndex) => isDelineator(key) ? renderDivider(key, keyIndex) : renderKey(key, keyIndex, true)), comboIndex < keyCombinations.value.length - 1 && vue.createElementVNode("span", {
33147
+ "aria-hidden": "true"
33148
+ }, [vue.createTextVNode("\xA0")])])), props.suffix && vue.createElementVNode("span", {
33149
+ "key": "contained-suffix",
33150
+ "class": "v-hotkey__suffix"
33151
+ }, [props.suffix])]
33152
+ }) : vue.createElementVNode(vue.Fragment, null, [props.prefix && vue.createElementVNode("span", {
33153
+ "key": "prefix",
33154
+ "class": "v-hotkey__prefix"
33155
+ }, [props.prefix]), keyCombinations.value.map((combination, comboIndex) => vue.createElementVNode("span", {
33156
+ "class": "v-hotkey__combination",
33157
+ "key": comboIndex
33158
+ }, [combination.map((key, keyIndex) => isDelineator(key) ? renderDivider(key, keyIndex) : renderKey(key, keyIndex, false)), comboIndex < keyCombinations.value.length - 1 && vue.createElementVNode("span", {
33159
+ "aria-hidden": "true"
33160
+ }, [vue.createTextVNode("\xA0")])])), props.suffix && vue.createElementVNode("span", {
33161
+ "key": "suffix",
33162
+ "class": "v-hotkey__suffix"
33163
+ }, [props.suffix])])]));
33164
+ }
33165
+ });
33166
+
32285
33167
  var components = /*#__PURE__*/Object.freeze({
32286
33168
  __proto__: null,
32287
33169
  VAlert: VAlert,
@@ -32370,6 +33252,7 @@
32370
33252
  VFileUploadItem: VFileUploadItem,
32371
33253
  VFooter: VFooter,
32372
33254
  VForm: VForm,
33255
+ VHotkey: VHotkey,
32373
33256
  VHover: VHover,
32374
33257
  VIcon: VIcon,
32375
33258
  VIconBtn: VIconBtn,
@@ -32793,7 +33676,7 @@
32793
33676
  };
32794
33677
  });
32795
33678
  }
32796
- const version$1 = "3.9.0-beta.1";
33679
+ const version$1 = "3.9.0";
32797
33680
  createVuetify$1.version = version$1;
32798
33681
 
32799
33682
  // Vue's inject() can only be used in setup
@@ -33091,7 +33974,7 @@
33091
33974
 
33092
33975
  /* eslint-disable local-rules/sort-imports */
33093
33976
 
33094
- const version = "3.9.0-beta.1";
33977
+ const version = "3.9.0";
33095
33978
 
33096
33979
  /* eslint-disable local-rules/sort-imports */
33097
33980
 
@@ -33112,6 +33995,7 @@
33112
33995
  exports.useDefaults = useDefaults;
33113
33996
  exports.useDisplay = useDisplay;
33114
33997
  exports.useGoTo = useGoTo;
33998
+ exports.useHotkey = useHotkey;
33115
33999
  exports.useLayout = useLayout;
33116
34000
  exports.useLocale = useLocale;
33117
34001
  exports.useRtl = useRtl;