@vuetify/nightly 3.9.0-beta.0-dev.2025-06-24 → 3.9.0-beta.1-dev.2025-06-28

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 (212) hide show
  1. package/CHANGELOG.md +4 -83
  2. package/dist/_component-variables-labs.sass +1 -0
  3. package/dist/json/attributes.json +2471 -2411
  4. package/dist/json/importMap-labs.json +34 -30
  5. package/dist/json/importMap.json +146 -146
  6. package/dist/json/tags.json +20 -0
  7. package/dist/json/web-types.json +4808 -4642
  8. package/dist/vuetify-labs.cjs +750 -15
  9. package/dist/vuetify-labs.css +5609 -5358
  10. package/dist/vuetify-labs.d.ts +300 -54
  11. package/dist/vuetify-labs.esm.js +750 -16
  12. package/dist/vuetify-labs.esm.js.map +1 -1
  13. package/dist/vuetify-labs.js +750 -15
  14. package/dist/vuetify-labs.min.css +2 -2
  15. package/dist/vuetify.cjs +357 -15
  16. package/dist/vuetify.cjs.map +1 -1
  17. package/dist/vuetify.css +3235 -3226
  18. package/dist/vuetify.d.ts +73 -53
  19. package/dist/vuetify.esm.js +357 -16
  20. package/dist/vuetify.esm.js.map +1 -1
  21. package/dist/vuetify.js +357 -15
  22. package/dist/vuetify.js.map +1 -1
  23. package/dist/vuetify.min.css +2 -2
  24. package/dist/vuetify.min.js +292 -253
  25. package/dist/vuetify.min.js.map +1 -1
  26. package/lib/components/VKbd/VKbd.css +14 -5
  27. package/lib/components/VKbd/VKbd.js.map +1 -1
  28. package/lib/components/VKbd/VKbd.scss +26 -0
  29. package/lib/components/VKbd/_variables.scss +12 -6
  30. package/lib/components/VKbd/index.js.map +1 -1
  31. package/lib/components/VTreeview/VTreeviewChildren.d.ts +13 -0
  32. package/lib/components/VTreeview/VTreeviewChildren.js +2 -1
  33. package/lib/components/VTreeview/VTreeviewChildren.js.map +1 -1
  34. package/lib/components/VTreeview/VTreeviewItem.js +3 -3
  35. package/lib/components/VTreeview/VTreeviewItem.js.map +1 -1
  36. package/lib/composables/hotkey/hotkey-parsing.d.ts +15 -0
  37. package/lib/composables/hotkey/hotkey-parsing.js +154 -0
  38. package/lib/composables/hotkey/hotkey-parsing.js.map +1 -0
  39. package/lib/composables/hotkey/hotkey.d.ts +9 -0
  40. package/lib/composables/{hotkey.js → hotkey/hotkey.js} +31 -39
  41. package/lib/composables/hotkey/hotkey.js.map +1 -0
  42. package/lib/composables/hotkey/index.d.ts +1 -0
  43. package/lib/composables/hotkey/index.js +2 -0
  44. package/lib/composables/hotkey/index.js.map +1 -0
  45. package/lib/composables/hotkey/key-aliases.d.ts +14 -0
  46. package/lib/composables/hotkey/key-aliases.js +38 -0
  47. package/lib/composables/hotkey/key-aliases.js.map +1 -0
  48. package/lib/composables/icons.d.ts +11 -0
  49. package/lib/composables/icons.js.map +1 -1
  50. package/lib/composables/index.d.ts +1 -0
  51. package/lib/composables/index.js +1 -0
  52. package/lib/composables/index.js.map +1 -1
  53. package/lib/composables/nested/nested.js +8 -8
  54. package/lib/composables/nested/nested.js.map +1 -1
  55. package/lib/entry-bundler.js +1 -1
  56. package/lib/framework.d.ts +74 -53
  57. package/lib/framework.js +1 -1
  58. package/lib/iconsets/fa.js +12 -1
  59. package/lib/iconsets/fa.js.map +1 -1
  60. package/lib/iconsets/fa4.js +12 -1
  61. package/lib/iconsets/fa4.js.map +1 -1
  62. package/lib/iconsets/md.js +12 -1
  63. package/lib/iconsets/md.js.map +1 -1
  64. package/lib/iconsets/mdi-svg.js +12 -1
  65. package/lib/iconsets/mdi-svg.js.map +1 -1
  66. package/lib/iconsets/mdi.js +12 -1
  67. package/lib/iconsets/mdi.js.map +1 -1
  68. package/lib/labs/VHotkey/VHotkey.css +242 -0
  69. package/lib/labs/VHotkey/VHotkey.d.ts +387 -0
  70. package/lib/labs/VHotkey/VHotkey.js +432 -0
  71. package/lib/labs/VHotkey/VHotkey.js.map +1 -0
  72. package/lib/labs/VHotkey/VHotkey.scss +253 -0
  73. package/lib/labs/VHotkey/_variables.scss +43 -0
  74. package/lib/labs/VHotkey/index.d.ts +1 -0
  75. package/lib/labs/VHotkey/index.js +2 -0
  76. package/lib/labs/VHotkey/index.js.map +1 -0
  77. package/lib/labs/components.d.ts +1 -0
  78. package/lib/labs/components.js +1 -0
  79. package/lib/labs/components.js.map +1 -1
  80. package/lib/locale/af.d.ts +18 -0
  81. package/lib/locale/af.js +18 -0
  82. package/lib/locale/af.js.map +1 -1
  83. package/lib/locale/ar.d.ts +18 -0
  84. package/lib/locale/ar.js +18 -0
  85. package/lib/locale/ar.js.map +1 -1
  86. package/lib/locale/az.d.ts +18 -0
  87. package/lib/locale/az.js +18 -0
  88. package/lib/locale/az.js.map +1 -1
  89. package/lib/locale/bg.d.ts +18 -0
  90. package/lib/locale/bg.js +18 -0
  91. package/lib/locale/bg.js.map +1 -1
  92. package/lib/locale/ca.d.ts +18 -0
  93. package/lib/locale/ca.js +18 -0
  94. package/lib/locale/ca.js.map +1 -1
  95. package/lib/locale/ckb.d.ts +18 -0
  96. package/lib/locale/ckb.js +18 -0
  97. package/lib/locale/ckb.js.map +1 -1
  98. package/lib/locale/cs.d.ts +18 -0
  99. package/lib/locale/cs.js +18 -0
  100. package/lib/locale/cs.js.map +1 -1
  101. package/lib/locale/da.d.ts +18 -0
  102. package/lib/locale/da.js +18 -0
  103. package/lib/locale/da.js.map +1 -1
  104. package/lib/locale/de.d.ts +18 -0
  105. package/lib/locale/de.js +18 -0
  106. package/lib/locale/de.js.map +1 -1
  107. package/lib/locale/el.d.ts +18 -0
  108. package/lib/locale/el.js +18 -0
  109. package/lib/locale/el.js.map +1 -1
  110. package/lib/locale/en.d.ts +18 -0
  111. package/lib/locale/en.js +18 -0
  112. package/lib/locale/en.js.map +1 -1
  113. package/lib/locale/es.d.ts +18 -0
  114. package/lib/locale/es.js +18 -0
  115. package/lib/locale/es.js.map +1 -1
  116. package/lib/locale/et.d.ts +18 -0
  117. package/lib/locale/et.js +18 -0
  118. package/lib/locale/et.js.map +1 -1
  119. package/lib/locale/fa.d.ts +18 -0
  120. package/lib/locale/fa.js +18 -0
  121. package/lib/locale/fa.js.map +1 -1
  122. package/lib/locale/fi.d.ts +18 -0
  123. package/lib/locale/fi.js +18 -0
  124. package/lib/locale/fi.js.map +1 -1
  125. package/lib/locale/fr.d.ts +18 -0
  126. package/lib/locale/fr.js +18 -0
  127. package/lib/locale/fr.js.map +1 -1
  128. package/lib/locale/he.d.ts +18 -0
  129. package/lib/locale/he.js +18 -0
  130. package/lib/locale/he.js.map +1 -1
  131. package/lib/locale/hr.d.ts +18 -0
  132. package/lib/locale/hr.js +18 -0
  133. package/lib/locale/hr.js.map +1 -1
  134. package/lib/locale/hu.d.ts +18 -0
  135. package/lib/locale/hu.js +18 -0
  136. package/lib/locale/hu.js.map +1 -1
  137. package/lib/locale/id.d.ts +18 -0
  138. package/lib/locale/id.js +18 -0
  139. package/lib/locale/id.js.map +1 -1
  140. package/lib/locale/it.d.ts +18 -0
  141. package/lib/locale/it.js +18 -0
  142. package/lib/locale/it.js.map +1 -1
  143. package/lib/locale/ja.d.ts +18 -0
  144. package/lib/locale/ja.js +18 -0
  145. package/lib/locale/ja.js.map +1 -1
  146. package/lib/locale/km.d.ts +18 -0
  147. package/lib/locale/km.js +18 -0
  148. package/lib/locale/km.js.map +1 -1
  149. package/lib/locale/ko.d.ts +18 -0
  150. package/lib/locale/ko.js +18 -0
  151. package/lib/locale/ko.js.map +1 -1
  152. package/lib/locale/lt.d.ts +18 -0
  153. package/lib/locale/lt.js +18 -0
  154. package/lib/locale/lt.js.map +1 -1
  155. package/lib/locale/lv.d.ts +18 -0
  156. package/lib/locale/lv.js +18 -0
  157. package/lib/locale/lv.js.map +1 -1
  158. package/lib/locale/nl.d.ts +18 -0
  159. package/lib/locale/nl.js +18 -0
  160. package/lib/locale/nl.js.map +1 -1
  161. package/lib/locale/no.d.ts +18 -0
  162. package/lib/locale/no.js +18 -0
  163. package/lib/locale/no.js.map +1 -1
  164. package/lib/locale/pl.d.ts +18 -0
  165. package/lib/locale/pl.js +18 -0
  166. package/lib/locale/pl.js.map +1 -1
  167. package/lib/locale/pt.d.ts +18 -0
  168. package/lib/locale/pt.js +18 -0
  169. package/lib/locale/pt.js.map +1 -1
  170. package/lib/locale/ro.d.ts +18 -0
  171. package/lib/locale/ro.js +18 -0
  172. package/lib/locale/ro.js.map +1 -1
  173. package/lib/locale/ru.d.ts +18 -0
  174. package/lib/locale/ru.js +18 -0
  175. package/lib/locale/ru.js.map +1 -1
  176. package/lib/locale/sk.d.ts +18 -0
  177. package/lib/locale/sk.js +18 -0
  178. package/lib/locale/sk.js.map +1 -1
  179. package/lib/locale/sl.d.ts +18 -0
  180. package/lib/locale/sl.js +18 -0
  181. package/lib/locale/sl.js.map +1 -1
  182. package/lib/locale/sr-Cyrl.d.ts +18 -0
  183. package/lib/locale/sr-Cyrl.js +18 -0
  184. package/lib/locale/sr-Cyrl.js.map +1 -1
  185. package/lib/locale/sr-Latn.d.ts +18 -0
  186. package/lib/locale/sr-Latn.js +18 -0
  187. package/lib/locale/sr-Latn.js.map +1 -1
  188. package/lib/locale/sv.d.ts +18 -0
  189. package/lib/locale/sv.js +18 -0
  190. package/lib/locale/sv.js.map +1 -1
  191. package/lib/locale/th.d.ts +18 -0
  192. package/lib/locale/th.js +18 -0
  193. package/lib/locale/th.js.map +1 -1
  194. package/lib/locale/tr.d.ts +18 -0
  195. package/lib/locale/tr.js +18 -0
  196. package/lib/locale/tr.js.map +1 -1
  197. package/lib/locale/uk.d.ts +18 -0
  198. package/lib/locale/uk.js +18 -0
  199. package/lib/locale/uk.js.map +1 -1
  200. package/lib/locale/vi.d.ts +18 -0
  201. package/lib/locale/vi.js +18 -0
  202. package/lib/locale/vi.js.map +1 -1
  203. package/lib/locale/zh-Hans.d.ts +18 -0
  204. package/lib/locale/zh-Hans.js +18 -0
  205. package/lib/locale/zh-Hans.js.map +1 -1
  206. package/lib/locale/zh-Hant.d.ts +18 -0
  207. package/lib/locale/zh-Hant.js +18 -0
  208. package/lib/locale/zh-Hant.js.map +1 -1
  209. package/package.json +1 -1
  210. package/lib/components/VKbd/VKbd.sass +0 -15
  211. package/lib/composables/hotkey.d.ts +0 -9
  212. package/lib/composables/hotkey.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Vuetify v3.9.0-beta.0-dev.2025-06-24
2
+ * Vuetify v3.9.0-beta.1-dev.2025-06-28
3
3
  * Forged by John Leider
4
4
  * Released under the MIT License.
5
5
  */
@@ -2141,6 +2141,24 @@ var en = {
2141
2141
  exclude: 'The {0} character is not allowed',
2142
2142
  notEmpty: 'Please choose at least one value',
2143
2143
  pattern: 'Invalid format'
2144
+ },
2145
+ hotkey: {
2146
+ then: 'then',
2147
+ ctrl: 'Ctrl',
2148
+ command: 'Command',
2149
+ space: 'Space',
2150
+ shift: 'Shift',
2151
+ alt: 'Alt',
2152
+ enter: 'Enter',
2153
+ escape: 'Escape',
2154
+ upArrow: 'Up Arrow',
2155
+ downArrow: 'Down Arrow',
2156
+ leftArrow: 'Left Arrow',
2157
+ rightArrow: 'Right Arrow',
2158
+ backspace: 'Backspace',
2159
+ option: 'Option',
2160
+ plus: 'plus',
2161
+ shortcut: 'Keyboard shortcut: {0}'
2144
2162
  }
2145
2163
  };
2146
2164
 
@@ -4651,7 +4669,18 @@ const aliases = {
4651
4669
  treeviewExpand: 'mdi-menu-right',
4652
4670
  eyeDropper: 'mdi-eyedropper',
4653
4671
  upload: 'mdi-cloud-upload',
4654
- color: 'mdi-palette'
4672
+ color: 'mdi-palette',
4673
+ command: 'mdi-apple-keyboard-command',
4674
+ ctrl: 'mdi-apple-keyboard-control',
4675
+ space: 'mdi-keyboard-space',
4676
+ shift: 'mdi-apple-keyboard-shift',
4677
+ alt: 'mdi-apple-keyboard-option',
4678
+ enter: 'mdi-keyboard-return',
4679
+ arrowup: 'mdi-arrow-up',
4680
+ arrowdown: 'mdi-arrow-down',
4681
+ arrowleft: 'mdi-arrow-left',
4682
+ arrowright: 'mdi-arrow-right',
4683
+ backspace: 'mdi-backspace'
4655
4684
  };
4656
4685
  const mdi = {
4657
4686
  // Not using mergeProps here, functional components merge props by default (?)
@@ -9017,9 +9046,9 @@ const makeNestedProps = propsFactory({
9017
9046
  }, 'nested');
9018
9047
  const useNested = props => {
9019
9048
  let isUnmounted = false;
9020
- const children = ref(new Map());
9021
- const parents = ref(new Map());
9022
- const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(v), v => [...v.values()]);
9049
+ const children = shallowRef(new Map());
9050
+ const parents = shallowRef(new Map());
9051
+ const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(Array.isArray(v) ? v.map(i => toRaw(i)) : v), v => [...v.values()]);
9023
9052
  const activeStrategy = computed(() => {
9024
9053
  if (typeof props.activeStrategy === 'object') return props.activeStrategy;
9025
9054
  if (typeof props.activeStrategy === 'function') return props.activeStrategy(props.mandatory);
@@ -9073,7 +9102,7 @@ const useNested = props => {
9073
9102
  });
9074
9103
  function getPath(id) {
9075
9104
  const path = [];
9076
- let parent = id;
9105
+ let parent = toRaw(id);
9077
9106
  while (parent != null) {
9078
9107
  path.unshift(parent);
9079
9108
  parent = parents.value.get(parent);
@@ -9216,7 +9245,7 @@ const useNested = props => {
9216
9245
  const useNestedItem = (id, isGroup) => {
9217
9246
  const parent = inject$1(VNestedSymbol, emptyNested);
9218
9247
  const uidSymbol = Symbol('nested item');
9219
- const computedId = computed(() => toValue(id) ?? uidSymbol);
9248
+ const computedId = computed(() => toRaw(toValue(id)) ?? uidSymbol);
9220
9249
  const item = {
9221
9250
  ...parent,
9222
9251
  id: computedId,
@@ -9225,10 +9254,10 @@ const useNestedItem = (id, isGroup) => {
9225
9254
  isOpen: computed(() => parent.root.opened.value.has(computedId.value)),
9226
9255
  parent: computed(() => parent.root.parents.value.get(computedId.value)),
9227
9256
  activate: (activated, e) => parent.root.activate(computedId.value, activated, e),
9228
- isActivated: computed(() => parent.root.activated.value.has(toRaw(computedId.value))),
9257
+ isActivated: computed(() => parent.root.activated.value.has(computedId.value)),
9229
9258
  select: (selected, e) => parent.root.select(computedId.value, selected, e),
9230
- isSelected: computed(() => parent.root.selected.value.get(toRaw(computedId.value)) === 'on'),
9231
- isIndeterminate: computed(() => parent.root.selected.value.get(toRaw(computedId.value)) === 'indeterminate'),
9259
+ isSelected: computed(() => parent.root.selected.value.get(computedId.value) === 'on'),
9260
+ isIndeterminate: computed(() => parent.root.selected.value.get(computedId.value) === 'indeterminate'),
9232
9261
  isLeaf: computed(() => !parent.root.children.value.get(computedId.value)),
9233
9262
  isGroupActivator: parent.isGroupActivator
9234
9263
  };
@@ -18073,6 +18102,317 @@ function useDate() {
18073
18102
  return createInstance(options, locale);
18074
18103
  }
18075
18104
 
18105
+ /**
18106
+ * Centralized key alias mapping for consistent key normalization across the hotkey system.
18107
+ *
18108
+ * This maps various user-friendly aliases to canonical key names that match
18109
+ * KeyboardEvent.key values (in lowercase) where possible.
18110
+ */
18111
+ const keyAliasMap = {
18112
+ // Modifier aliases (from vue-use, other libraries, and current implementation)
18113
+ control: 'ctrl',
18114
+ command: 'cmd',
18115
+ option: 'alt',
18116
+ // Arrow key aliases (common abbreviations)
18117
+ up: 'arrowup',
18118
+ down: 'arrowdown',
18119
+ left: 'arrowleft',
18120
+ right: 'arrowright',
18121
+ // Other common key aliases
18122
+ esc: 'escape',
18123
+ spacebar: ' ',
18124
+ space: ' ',
18125
+ return: 'enter',
18126
+ del: 'delete',
18127
+ // Symbol aliases (existing from hotkey-parsing.ts)
18128
+ minus: '-',
18129
+ hyphen: '-'
18130
+ };
18131
+
18132
+ /**
18133
+ * Normalizes a key string to its canonical form using the alias map.
18134
+ *
18135
+ * @param key - The key string to normalize
18136
+ * @returns The canonical key name in lowercase
18137
+ */
18138
+ function normalizeKey(key) {
18139
+ const lowerKey = key.toLowerCase();
18140
+ return keyAliasMap[lowerKey] || lowerKey;
18141
+ }
18142
+
18143
+ // Utilities
18144
+
18145
+ /**
18146
+ * Splits a single combination string into individual key parts.
18147
+ *
18148
+ * A combination is a set of keys that must be pressed simultaneously.
18149
+ * e.g. `ctrl+k`, `shift--`
18150
+ */
18151
+ function splitKeyCombination(combination) {
18152
+ let isInternal = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
18153
+ if (!combination) {
18154
+ if (!isInternal) consoleWarn('Invalid hotkey combination: empty string provided');
18155
+ return [];
18156
+ }
18157
+
18158
+ // --- VALIDATION ---
18159
+ const startsWithPlusOrUnderscore = combination.startsWith('+') || combination.startsWith('_');
18160
+ const hasInvalidLeadingSeparator =
18161
+ // Starts with a single '+' or '_' followed by a non-separator character (e.g. '+a', '_a')
18162
+ startsWithPlusOrUnderscore && !(combination.startsWith('++') || combination.startsWith('__'));
18163
+ const hasInvalidStructure =
18164
+ // Invalid leading separator patterns
18165
+ combination.length > 1 && hasInvalidLeadingSeparator ||
18166
+ // Disallow literal + or _ keys (they require shift)
18167
+ combination.includes('++') || combination.includes('__') || combination === '+' || combination === '_' ||
18168
+ // Ends with a separator that is not part of a doubled literal
18169
+ combination.length > 1 && (combination.endsWith('+') || combination.endsWith('_')) && combination.at(-2) !== combination.at(-1) ||
18170
+ // Stand-alone doubled separators (dangling)
18171
+ combination === '++' || combination === '--' || combination === '__';
18172
+ if (hasInvalidStructure) {
18173
+ if (!isInternal) consoleWarn(`Invalid hotkey combination: "${combination}" has invalid structure`);
18174
+ return [];
18175
+ }
18176
+ const keys = [];
18177
+ let buffer = '';
18178
+ const flushBuffer = () => {
18179
+ if (buffer) {
18180
+ keys.push(normalizeKey(buffer));
18181
+ buffer = '';
18182
+ }
18183
+ };
18184
+ for (let i = 0; i < combination.length; i++) {
18185
+ const char = combination[i];
18186
+ const nextChar = combination[i + 1];
18187
+ if (char === '+' || char === '_' || char === '-') {
18188
+ if (char === nextChar) {
18189
+ flushBuffer();
18190
+ keys.push(char);
18191
+ i++;
18192
+ } else if (char === '+' || char === '_') {
18193
+ flushBuffer();
18194
+ } else {
18195
+ buffer += char;
18196
+ }
18197
+ } else {
18198
+ buffer += char;
18199
+ }
18200
+ }
18201
+ flushBuffer();
18202
+
18203
+ // Within a combination, `-` is only valid as a literal key (e.g., `ctrl+-`).
18204
+ // `-` cannot be part of a longer key name within a combination.
18205
+ const hasInvalidMinus = keys.some(key => key.length > 1 && key.includes('-') && key !== '--');
18206
+ if (hasInvalidMinus) {
18207
+ if (!isInternal) consoleWarn(`Invalid hotkey combination: "${combination}" has invalid structure`);
18208
+ return [];
18209
+ }
18210
+ if (keys.length === 0 && combination) {
18211
+ return [normalizeKey(combination)];
18212
+ }
18213
+ return keys;
18214
+ }
18215
+
18216
+ /**
18217
+ * Splits a hotkey string into its constituent combination groups.
18218
+ *
18219
+ * A sequence is a series of combinations that must be pressed in order.
18220
+ * e.g. `a-b`, `ctrl+k-p`
18221
+ */
18222
+ function splitKeySequence(str) {
18223
+ if (!str) {
18224
+ consoleWarn('Invalid hotkey sequence: empty string provided');
18225
+ return [];
18226
+ }
18227
+
18228
+ // A sequence is invalid if it starts or ends with a separator,
18229
+ // unless it is part of a combination (e.g., `shift+-`).
18230
+ const hasInvalidStart = str.startsWith('-') && !['---', '--+'].includes(str);
18231
+ const hasInvalidEnd = str.endsWith('-') && !str.endsWith('+-') && !str.endsWith('_-') && str !== '-' && str !== '---';
18232
+ if (hasInvalidStart || hasInvalidEnd) {
18233
+ consoleWarn(`Invalid hotkey sequence: "${str}" contains invalid combinations`);
18234
+ return [];
18235
+ }
18236
+ const result = [];
18237
+ let buffer = '';
18238
+ let i = 0;
18239
+ while (i < str.length) {
18240
+ const char = str[i];
18241
+ if (char === '-') {
18242
+ // Determine if this hyphen is part of the current combination
18243
+ const prevChar = str[i - 1];
18244
+ const prevPrevChar = i > 1 ? str[i - 2] : undefined;
18245
+ const precededBySinglePlusOrUnderscore = (prevChar === '+' || prevChar === '_') && prevPrevChar !== '+';
18246
+ if (precededBySinglePlusOrUnderscore) {
18247
+ // Treat as part of the combination (e.g., 'ctrl+-')
18248
+ buffer += char;
18249
+ i++;
18250
+ } else {
18251
+ // Treat as sequence separator
18252
+ if (buffer) {
18253
+ result.push(buffer);
18254
+ buffer = '';
18255
+ } else {
18256
+ // Empty buffer means we have a literal '-' key
18257
+ result.push('-');
18258
+ }
18259
+ i++;
18260
+ }
18261
+ } else {
18262
+ buffer += char;
18263
+ i++;
18264
+ }
18265
+ }
18266
+
18267
+ // Add final buffer if it exists
18268
+ if (buffer) {
18269
+ result.push(buffer);
18270
+ }
18271
+
18272
+ // Collapse runs of '-' so that every second '-' is removed
18273
+ const collapsed = [];
18274
+ let minusCount = 0;
18275
+ for (const part of result) {
18276
+ if (part === '-') {
18277
+ if (minusCount % 2 === 0) collapsed.push('-');
18278
+ minusCount++;
18279
+ } else {
18280
+ minusCount = 0;
18281
+ collapsed.push(part);
18282
+ }
18283
+ }
18284
+
18285
+ // Validate that each part of the sequence is a valid combination
18286
+ const areAllValid = collapsed.every(s => splitKeyCombination(s, true).length > 0);
18287
+ if (!areAllValid) {
18288
+ consoleWarn(`Invalid hotkey sequence: "${str}" contains invalid combinations`);
18289
+ return [];
18290
+ }
18291
+ return collapsed;
18292
+ }
18293
+
18294
+ // Composables
18295
+
18296
+ // Types
18297
+
18298
+ function useHotkey(keys, callback) {
18299
+ let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
18300
+ if (!IN_BROWSER) return function () {};
18301
+ const {
18302
+ event = 'keydown',
18303
+ inputs = false,
18304
+ preventDefault = true,
18305
+ sequenceTimeout = 1000
18306
+ } = options;
18307
+ const isMac = navigator?.userAgent?.includes('Macintosh') ?? false;
18308
+ let timeout = 0;
18309
+ let keyGroups;
18310
+ let isSequence = false;
18311
+ let groupIndex = 0;
18312
+ function clearTimer() {
18313
+ if (!timeout) return;
18314
+ clearTimeout(timeout);
18315
+ timeout = 0;
18316
+ }
18317
+ function isInputFocused() {
18318
+ if (toValue(inputs)) return false;
18319
+ const activeElement = document.activeElement;
18320
+ return activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA' || activeElement.isContentEditable || activeElement.contentEditable === 'true');
18321
+ }
18322
+ function resetSequence() {
18323
+ groupIndex = 0;
18324
+ clearTimer();
18325
+ }
18326
+ function handler(e) {
18327
+ const group = keyGroups[groupIndex];
18328
+ if (!group || isInputFocused()) return;
18329
+ if (!matchesKeyGroup(e, group)) {
18330
+ if (isSequence) resetSequence();
18331
+ return;
18332
+ }
18333
+ if (toValue(preventDefault)) e.preventDefault();
18334
+ if (!isSequence) {
18335
+ callback(e);
18336
+ return;
18337
+ }
18338
+ clearTimer();
18339
+ groupIndex++;
18340
+ if (groupIndex === keyGroups.length) {
18341
+ callback(e);
18342
+ resetSequence();
18343
+ return;
18344
+ }
18345
+ timeout = window.setTimeout(resetSequence, toValue(sequenceTimeout));
18346
+ }
18347
+ function cleanup() {
18348
+ window.removeEventListener(toValue(event), handler);
18349
+ clearTimer();
18350
+ }
18351
+ watch(() => toValue(keys), function (unrefKeys) {
18352
+ cleanup();
18353
+ if (unrefKeys) {
18354
+ const groups = splitKeySequence(unrefKeys.toLowerCase());
18355
+ isSequence = groups.length > 1;
18356
+ keyGroups = groups;
18357
+ resetSequence();
18358
+ window.addEventListener(toValue(event), handler);
18359
+ }
18360
+ }, {
18361
+ immediate: true
18362
+ });
18363
+
18364
+ // Watch for changes in the event type to re-register the listener
18365
+ watch(() => toValue(event), function (newEvent, oldEvent) {
18366
+ if (oldEvent && keyGroups && keyGroups.length > 0) {
18367
+ window.removeEventListener(oldEvent, handler);
18368
+ window.addEventListener(newEvent, handler);
18369
+ }
18370
+ });
18371
+ try {
18372
+ getCurrentInstance('useHotkey');
18373
+ onBeforeUnmount(cleanup);
18374
+ } catch {
18375
+ // Not in Vue setup context
18376
+ }
18377
+ function parseKeyGroup(group) {
18378
+ const MODIFIERS = ['ctrl', 'shift', 'alt', 'meta', 'cmd'];
18379
+
18380
+ // Use the shared combination splitting logic
18381
+ const parts = splitKeyCombination(group.toLowerCase());
18382
+
18383
+ // If the combination is invalid, return empty result
18384
+ if (parts.length === 0) {
18385
+ return {
18386
+ modifiers: Object.fromEntries(MODIFIERS.map(m => [m, false])),
18387
+ actualKey: undefined
18388
+ };
18389
+ }
18390
+ const modifiers = Object.fromEntries(MODIFIERS.map(m => [m, false]));
18391
+ let actualKey;
18392
+ for (const part of parts) {
18393
+ if (MODIFIERS.includes(part)) {
18394
+ modifiers[part] = true;
18395
+ } else {
18396
+ actualKey = part;
18397
+ }
18398
+ }
18399
+ return {
18400
+ modifiers,
18401
+ actualKey
18402
+ };
18403
+ }
18404
+ function matchesKeyGroup(e, group) {
18405
+ const {
18406
+ modifiers,
18407
+ actualKey
18408
+ } = parseKeyGroup(group);
18409
+ const expectCtrl = modifiers.ctrl || !isMac && (modifiers.cmd || modifiers.meta);
18410
+ const expectMeta = isMac && (modifiers.cmd || modifiers.meta);
18411
+ return e.ctrlKey === expectCtrl && e.metaKey === expectMeta && e.shiftKey === modifiers.shift && e.altKey === modifiers.alt && e.key.toLowerCase() === actualKey?.toLowerCase();
18412
+ }
18413
+ return cleanup;
18414
+ }
18415
+
18076
18416
  // Types
18077
18417
 
18078
18418
  const makeVColorPickerProps = propsFactory({
@@ -29762,7 +30102,7 @@ const VTreeviewItem = genericComponent()({
29762
30102
  emit('toggleExpand', e);
29763
30103
  }
29764
30104
  useRender(() => {
29765
- const listItemProps = omit(VListItem.filterProps(props), ['onClick']);
30105
+ const listItemProps = VListItem.filterProps(props);
29766
30106
  const hasPrepend = slots.prepend || props.toggleIcon;
29767
30107
  return createVNode(VListItem, mergeProps({
29768
30108
  "ref": vListItemRef
@@ -29773,7 +30113,7 @@ const VTreeviewItem = genericComponent()({
29773
30113
  'v-treeview-item--filtered': isFiltered.value
29774
30114
  }, props.class],
29775
30115
  "ripple": false,
29776
- "onClick": props.onClick ?? activateGroupActivator
30116
+ "onClick": activateGroupActivator
29777
30117
  }), {
29778
30118
  ...slots,
29779
30119
  prepend: hasPrepend ? slotProps => {
@@ -29824,6 +30164,7 @@ const makeVTreeviewChildrenProps = propsFactory({
29824
30164
  falseIcon: IconValue,
29825
30165
  trueIcon: IconValue,
29826
30166
  returnObject: Boolean,
30167
+ activatable: Boolean,
29827
30168
  selectable: Boolean,
29828
30169
  selectedColor: String,
29829
30170
  selectStrategy: [String, Function, Object],
@@ -29843,7 +30184,7 @@ const VTreeviewChildren = genericComponent()({
29843
30184
  } = _ref;
29844
30185
  const isLoading = reactive(new Set());
29845
30186
  const activatorItems = ref([]);
29846
- const isClickOnOpen = computed(() => !props.disabled && (props.openOnClick != null ? props.openOnClick : props.selectable));
30187
+ const isClickOnOpen = computed(() => !props.disabled && (props.openOnClick != null ? props.openOnClick : props.selectable && !props.activatable));
29847
30188
  async function checkChildren(item) {
29848
30189
  try {
29849
30190
  if (!props.items?.length || !props.loadChildren) return;
@@ -32277,6 +32618,398 @@ const VPullToRefresh = genericComponent()({
32277
32618
  }
32278
32619
  });
32279
32620
 
32621
+ // Types
32622
+
32623
+ // Display mode types for different visual representations
32624
+
32625
+ // Extended variant type that includes our custom 'contained' variant
32626
+
32627
+ // Key display tuple: [mode, content] where content is string or IconValue
32628
+
32629
+ // Key tuple: [mode, content] where content is string or IconValue
32630
+
32631
+ function processKey(config, requestedMode, isMac) {
32632
+ const keyCfg = isMac && config.mac ? config.mac : config.default;
32633
+
32634
+ // 1. Resolve the safest display mode for the current platform
32635
+ const mode = (() => {
32636
+ // Non-Mac platforms rarely use icons – prefer text
32637
+ if (requestedMode === 'icon' && !isMac) return 'text';
32638
+
32639
+ // If the requested mode lacks an asset, fall back to text
32640
+ if (requestedMode === 'icon' && !keyCfg.icon) return 'text';
32641
+ if (requestedMode === 'symbol' && !keyCfg.symbol) return 'text';
32642
+ return requestedMode;
32643
+ })();
32644
+
32645
+ // 2. Pick value for the chosen mode, defaulting to text representation
32646
+ let value = keyCfg[mode] ?? keyCfg.text;
32647
+
32648
+ // 3. Guard against icon tokens leaking into text mode (e.g. "$ctrl")
32649
+ if (mode === 'text' && typeof value === 'string' && value.startsWith('$') && !value.startsWith('$vuetify.')) {
32650
+ value = value.slice(1).toUpperCase(); // "$ctrl" → "CTRL"
32651
+ }
32652
+ return mode === 'icon' ? ['icon', value] : [mode, value];
32653
+ }
32654
+ const hotkeyMap = {
32655
+ ctrl: {
32656
+ mac: {
32657
+ symbol: '⌃',
32658
+ icon: '$ctrl',
32659
+ text: '$vuetify.hotkey.ctrl'
32660
+ },
32661
+ default: {
32662
+ text: 'Ctrl'
32663
+ }
32664
+ },
32665
+ meta: {
32666
+ mac: {
32667
+ symbol: '⌘',
32668
+ icon: '$command',
32669
+ text: '$vuetify.hotkey.command'
32670
+ },
32671
+ default: {
32672
+ text: 'Ctrl'
32673
+ }
32674
+ },
32675
+ cmd: {
32676
+ mac: {
32677
+ symbol: '⌘',
32678
+ icon: '$command',
32679
+ text: '$vuetify.hotkey.command'
32680
+ },
32681
+ default: {
32682
+ text: 'Ctrl'
32683
+ }
32684
+ },
32685
+ shift: {
32686
+ mac: {
32687
+ symbol: '⇧',
32688
+ icon: '$shift',
32689
+ text: '$vuetify.hotkey.shift'
32690
+ },
32691
+ default: {
32692
+ text: 'Shift'
32693
+ }
32694
+ },
32695
+ alt: {
32696
+ mac: {
32697
+ symbol: '⌥',
32698
+ icon: '$alt',
32699
+ text: '$vuetify.hotkey.option'
32700
+ },
32701
+ default: {
32702
+ text: 'Alt'
32703
+ }
32704
+ },
32705
+ enter: {
32706
+ default: {
32707
+ symbol: '↵',
32708
+ icon: '$enter',
32709
+ text: '$vuetify.hotkey.enter'
32710
+ }
32711
+ },
32712
+ arrowup: {
32713
+ default: {
32714
+ symbol: '↑',
32715
+ icon: '$arrowup',
32716
+ text: '$vuetify.hotkey.upArrow'
32717
+ }
32718
+ },
32719
+ arrowdown: {
32720
+ default: {
32721
+ symbol: '↓',
32722
+ icon: '$arrowdown',
32723
+ text: '$vuetify.hotkey.downArrow'
32724
+ }
32725
+ },
32726
+ arrowleft: {
32727
+ default: {
32728
+ symbol: '←',
32729
+ icon: '$arrowleft',
32730
+ text: '$vuetify.hotkey.leftArrow'
32731
+ }
32732
+ },
32733
+ arrowright: {
32734
+ default: {
32735
+ symbol: '→',
32736
+ icon: '$arrowright',
32737
+ text: '$vuetify.hotkey.rightArrow'
32738
+ }
32739
+ },
32740
+ backspace: {
32741
+ default: {
32742
+ symbol: '⌫',
32743
+ icon: '$backspace',
32744
+ text: '$vuetify.hotkey.backspace'
32745
+ }
32746
+ },
32747
+ escape: {
32748
+ default: {
32749
+ text: '$vuetify.hotkey.escape'
32750
+ }
32751
+ },
32752
+ ' ': {
32753
+ mac: {
32754
+ symbol: '␣',
32755
+ icon: '$space',
32756
+ text: '$vuetify.hotkey.space'
32757
+ },
32758
+ default: {
32759
+ text: '$vuetify.hotkey.space'
32760
+ }
32761
+ },
32762
+ '-': {
32763
+ default: {
32764
+ text: '-'
32765
+ }
32766
+ }
32767
+ };
32768
+
32769
+ // Create custom variant props that extend the base variant props with our 'contained' option
32770
+ const makeVHotkeyVariantProps = propsFactory({
32771
+ variant: {
32772
+ type: String,
32773
+ default: 'elevated',
32774
+ validator: v => ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain', 'contained'].includes(v)
32775
+ }
32776
+ }, 'VHotkeyVariant');
32777
+ const makeVHotkeyProps = propsFactory({
32778
+ // String representing keyboard shortcuts (e.g., "ctrl+k", "meta+shift+p")
32779
+ keys: String,
32780
+ // How to display keys: 'symbol' uses special characters (⌘, ⌃), 'icon' uses SVG icons, 'text' uses words
32781
+ displayMode: {
32782
+ type: String,
32783
+ default: 'icon'
32784
+ },
32785
+ // Custom key mapping configuration. Users can import and modify the exported hotkeyMap as needed
32786
+ keyMap: {
32787
+ type: Object,
32788
+ default: () => hotkeyMap
32789
+ },
32790
+ platform: {
32791
+ type: String,
32792
+ default: 'auto'
32793
+ },
32794
+ inline: Boolean,
32795
+ disabled: Boolean,
32796
+ prefix: String,
32797
+ suffix: String,
32798
+ ...makeComponentProps(),
32799
+ ...makeThemeProps(),
32800
+ ...makeBorderProps(),
32801
+ ...makeRoundedProps(),
32802
+ ...makeElevationProps(),
32803
+ ...makeVHotkeyVariantProps(),
32804
+ color: String
32805
+ }, 'VHotkey');
32806
+ class Delineator {
32807
+ constructor(delineator) {
32808
+ if (['and', 'then'].includes(delineator)) this.val = delineator;else {
32809
+ throw new Error('Not a valid delineator');
32810
+ }
32811
+ }
32812
+ isEqual(d) {
32813
+ return this.val === d.val;
32814
+ }
32815
+ }
32816
+ function isDelineator(value) {
32817
+ return value instanceof Delineator;
32818
+ }
32819
+ function isString(value) {
32820
+ return typeof value === 'string';
32821
+ }
32822
+ function getKeyText(keyMap, key, isMac) {
32823
+ const lowerKey = key.toLowerCase();
32824
+ if (lowerKey in keyMap) {
32825
+ const result = processKey(keyMap[lowerKey], 'text', isMac);
32826
+ return typeof result[1] === 'string' ? result[1] : String(result[1]);
32827
+ }
32828
+ return key.toUpperCase();
32829
+ }
32830
+ function applyDisplayModeToKey(keyMap, mode, key, isMac) {
32831
+ const lowerKey = key.toLowerCase();
32832
+ if (lowerKey in keyMap) {
32833
+ const result = processKey(keyMap[lowerKey], mode, isMac);
32834
+ if (result[0] === 'text' && typeof result[1] === 'string' && result[1].startsWith('$') && !result[1].startsWith('$vuetify.')) {
32835
+ return ['text', result[1].replace('$', '').toUpperCase(), key];
32836
+ }
32837
+ return [...result, key];
32838
+ }
32839
+ return ['text', key.toUpperCase(), key];
32840
+ }
32841
+ const VHotkey = genericComponent()({
32842
+ name: 'VHotkey',
32843
+ props: makeVHotkeyProps(),
32844
+ setup(props) {
32845
+ const {
32846
+ t
32847
+ } = useLocale();
32848
+ const {
32849
+ themeClasses
32850
+ } = provideTheme(props);
32851
+ const {
32852
+ rtlClasses
32853
+ } = useRtl();
32854
+ const {
32855
+ borderClasses
32856
+ } = useBorder(props);
32857
+ const {
32858
+ roundedClasses
32859
+ } = useRounded(props);
32860
+ const {
32861
+ elevationClasses
32862
+ } = useElevation(props);
32863
+ const isContainedVariant = computed(() => props.variant === 'contained');
32864
+ const effectiveVariantProps = computed(() => ({
32865
+ ...props,
32866
+ variant: isContainedVariant.value ? 'elevated' : props.variant
32867
+ }));
32868
+ const {
32869
+ colorClasses,
32870
+ colorStyles,
32871
+ variantClasses
32872
+ } = useVariant(effectiveVariantProps);
32873
+ const isMac = computed(() => props.platform === 'auto' ? typeof navigator !== 'undefined' && /macintosh/i.test(navigator.userAgent) : props.platform === 'mac');
32874
+ const effectiveDisplayMode = computed(() => props.displayMode);
32875
+ const AND_DELINEATOR = new Delineator('and'); // For + separators
32876
+ const THEN_DELINEATOR = new Delineator('then'); // For - separators
32877
+
32878
+ const effectiveKeyMap = computed(() => props.keyMap);
32879
+ const keyCombinations = computed(() => {
32880
+ if (!props.keys) return [];
32881
+
32882
+ // Split by spaces to handle multiple key combinations
32883
+ // Example: "ctrl+k meta+p" -> ["ctrl+k", "meta+p"]
32884
+ return props.keys.split(' ').map(combination => {
32885
+ // Use the shared sequence splitting logic
32886
+ const sequenceGroups = splitKeySequence(combination);
32887
+
32888
+ // Process each sequence group
32889
+ return sequenceGroups.flatMap((group, groupIndex) => {
32890
+ // Use the shared key combination splitting logic
32891
+ const keyParts = splitKeyCombination(group);
32892
+ const parts = keyParts.reduce((acc, part, index) => {
32893
+ if (index !== 0) {
32894
+ // Add AND delineator between keys
32895
+ return [...acc, AND_DELINEATOR, part];
32896
+ }
32897
+ return [...acc, part];
32898
+ }, []);
32899
+
32900
+ // Add THEN delineator between sequence groups
32901
+ const result = parts.map(key => {
32902
+ if (isString(key)) {
32903
+ return applyDisplayModeToKey(effectiveKeyMap.value, effectiveDisplayMode.value, key, isMac.value);
32904
+ }
32905
+ return key;
32906
+ });
32907
+
32908
+ // Add sequence separator if not the last group
32909
+ if (groupIndex < sequenceGroups.length - 1) {
32910
+ result.push(THEN_DELINEATOR);
32911
+ }
32912
+ return result;
32913
+ });
32914
+ });
32915
+ });
32916
+ const accessibleLabel = computed(() => {
32917
+ if (!props.keys) return '';
32918
+
32919
+ // Convert the parsed key combinations into readable text
32920
+ const readableShortcuts = keyCombinations.value.map(combination => {
32921
+ const readableParts = [];
32922
+ for (const key of combination) {
32923
+ if (isDelineator(key)) {
32924
+ if (AND_DELINEATOR.isEqual(key)) {
32925
+ readableParts.push(t('$vuetify.hotkey.plus'));
32926
+ } else if (THEN_DELINEATOR.isEqual(key)) {
32927
+ readableParts.push(t('$vuetify.hotkey.then'));
32928
+ }
32929
+ } else {
32930
+ // Always use text representation for screen readers
32931
+ const textKey = key[0] === 'icon' || key[0] === 'symbol' ? applyDisplayModeToKey(mergeDeep(hotkeyMap, props.keyMap), 'text', String(key[1]), isMac.value)[1] : key[1];
32932
+ readableParts.push(translateKey(textKey));
32933
+ }
32934
+ }
32935
+ return readableParts.join(' ');
32936
+ });
32937
+ const shortcutText = readableShortcuts.join(', ');
32938
+ return t('$vuetify.hotkey.shortcut', shortcutText);
32939
+ });
32940
+ function translateKey(key) {
32941
+ return key.startsWith('$vuetify.') ? t(key) : key;
32942
+ }
32943
+ function getKeyTooltip(key) {
32944
+ if (effectiveDisplayMode.value === 'text') return undefined;
32945
+ const textKey = getKeyText(effectiveKeyMap.value, String(key[2]), isMac.value);
32946
+ return translateKey(textKey);
32947
+ }
32948
+ function renderKey(key, keyIndex, isContained) {
32949
+ const KeyComponent = isContained ? 'kbd' : VKbd;
32950
+ const keyClasses = ['v-hotkey__key', `v-hotkey__key-${key[0]}`, ...(isContained ? ['v-hotkey__key--nested'] : [borderClasses.value, roundedClasses.value, elevationClasses.value, colorClasses.value])];
32951
+ return createVNode(KeyComponent, {
32952
+ "key": keyIndex,
32953
+ "class": normalizeClass(keyClasses),
32954
+ "style": normalizeStyle(isContained ? undefined : colorStyles.value),
32955
+ "aria-hidden": "true",
32956
+ "title": getKeyTooltip(key)
32957
+ }, {
32958
+ default: () => [key[0] === 'icon' ? createVNode(VIcon, {
32959
+ "icon": key[1],
32960
+ "aria-hidden": "true"
32961
+ }, null) : translateKey(key[1])]
32962
+ });
32963
+ }
32964
+ function renderDivider(key, keyIndex) {
32965
+ return createElementVNode("span", {
32966
+ "key": keyIndex,
32967
+ "class": "v-hotkey__divider",
32968
+ "aria-hidden": "true"
32969
+ }, [AND_DELINEATOR.isEqual(key) ? '+' : t('$vuetify.hotkey.then')]);
32970
+ }
32971
+ useRender(() => createElementVNode("div", {
32972
+ "class": normalizeClass(['v-hotkey', {
32973
+ 'v-hotkey--disabled': props.disabled,
32974
+ 'v-hotkey--inline': props.inline,
32975
+ 'v-hotkey--contained': isContainedVariant.value
32976
+ }, themeClasses.value, rtlClasses.value, variantClasses.value, props.class]),
32977
+ "style": normalizeStyle(props.style),
32978
+ "role": "img",
32979
+ "aria-label": accessibleLabel.value
32980
+ }, [isContainedVariant.value ? createVNode(VKbd, {
32981
+ "key": "contained",
32982
+ "class": normalizeClass(['v-hotkey__contained-wrapper', borderClasses.value, roundedClasses.value, elevationClasses.value, colorClasses.value]),
32983
+ "style": normalizeStyle(colorStyles.value),
32984
+ "aria-hidden": "true"
32985
+ }, {
32986
+ default: () => [props.prefix && createElementVNode("span", {
32987
+ "key": "contained-prefix",
32988
+ "class": "v-hotkey__prefix"
32989
+ }, [props.prefix]), keyCombinations.value.map((combination, comboIndex) => createElementVNode("span", {
32990
+ "class": "v-hotkey__combination",
32991
+ "key": comboIndex
32992
+ }, [combination.map((key, keyIndex) => isDelineator(key) ? renderDivider(key, keyIndex) : renderKey(key, keyIndex, true)), comboIndex < keyCombinations.value.length - 1 && createElementVNode("span", {
32993
+ "aria-hidden": "true"
32994
+ }, [createTextVNode("\xA0")])])), props.suffix && createElementVNode("span", {
32995
+ "key": "contained-suffix",
32996
+ "class": "v-hotkey__suffix"
32997
+ }, [props.suffix])]
32998
+ }) : createElementVNode(Fragment, null, [props.prefix && createElementVNode("span", {
32999
+ "key": "prefix",
33000
+ "class": "v-hotkey__prefix"
33001
+ }, [props.prefix]), keyCombinations.value.map((combination, comboIndex) => createElementVNode("span", {
33002
+ "class": "v-hotkey__combination",
33003
+ "key": comboIndex
33004
+ }, [combination.map((key, keyIndex) => isDelineator(key) ? renderDivider(key, keyIndex) : renderKey(key, keyIndex, false)), comboIndex < keyCombinations.value.length - 1 && createElementVNode("span", {
33005
+ "aria-hidden": "true"
33006
+ }, [createTextVNode("\xA0")])])), props.suffix && createElementVNode("span", {
33007
+ "key": "suffix",
33008
+ "class": "v-hotkey__suffix"
33009
+ }, [props.suffix])])]));
33010
+ }
33011
+ });
33012
+
32280
33013
  var components = /*#__PURE__*/Object.freeze({
32281
33014
  __proto__: null,
32282
33015
  VAlert: VAlert,
@@ -32365,6 +33098,7 @@ var components = /*#__PURE__*/Object.freeze({
32365
33098
  VFileUploadItem: VFileUploadItem,
32366
33099
  VFooter: VFooter,
32367
33100
  VForm: VForm,
33101
+ VHotkey: VHotkey,
32368
33102
  VHover: VHover,
32369
33103
  VIcon: VIcon,
32370
33104
  VIconBtn: VIconBtn,
@@ -32788,7 +33522,7 @@ function createVuetify$1() {
32788
33522
  };
32789
33523
  });
32790
33524
  }
32791
- const version$1 = "3.9.0-beta.0-dev.2025-06-24";
33525
+ const version$1 = "3.9.0-beta.1-dev.2025-06-28";
32792
33526
  createVuetify$1.version = version$1;
32793
33527
 
32794
33528
  // Vue's inject() can only be used in setup
@@ -33086,7 +33820,7 @@ var index = /*#__PURE__*/Object.freeze({
33086
33820
 
33087
33821
  /* eslint-disable local-rules/sort-imports */
33088
33822
 
33089
- const version = "3.9.0-beta.0-dev.2025-06-24";
33823
+ const version = "3.9.0-beta.1-dev.2025-06-28";
33090
33824
 
33091
33825
  /* eslint-disable local-rules/sort-imports */
33092
33826
 
@@ -33099,5 +33833,5 @@ const createVuetify = function () {
33099
33833
  });
33100
33834
  };
33101
33835
 
33102
- export { index as blueprints, components, createVuetify, directives, useDate, useDefaults, useDisplay, useGoTo, useLayout, useLocale, useRtl, useTheme, version };
33836
+ export { index as blueprints, components, createVuetify, directives, useDate, useDefaults, useDisplay, useGoTo, useHotkey, useLayout, useLocale, useRtl, useTheme, version };
33103
33837
  //# sourceMappingURL=vuetify-labs.esm.js.map