@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.
- package/CHANGELOG.md +4 -83
- package/dist/_component-variables-labs.sass +1 -0
- package/dist/json/attributes.json +2471 -2411
- package/dist/json/importMap-labs.json +34 -30
- package/dist/json/importMap.json +146 -146
- package/dist/json/tags.json +20 -0
- package/dist/json/web-types.json +4808 -4642
- package/dist/vuetify-labs.cjs +750 -15
- package/dist/vuetify-labs.css +5609 -5358
- package/dist/vuetify-labs.d.ts +300 -54
- package/dist/vuetify-labs.esm.js +750 -16
- package/dist/vuetify-labs.esm.js.map +1 -1
- package/dist/vuetify-labs.js +750 -15
- package/dist/vuetify-labs.min.css +2 -2
- package/dist/vuetify.cjs +357 -15
- package/dist/vuetify.cjs.map +1 -1
- package/dist/vuetify.css +3235 -3226
- package/dist/vuetify.d.ts +73 -53
- package/dist/vuetify.esm.js +357 -16
- package/dist/vuetify.esm.js.map +1 -1
- package/dist/vuetify.js +357 -15
- package/dist/vuetify.js.map +1 -1
- package/dist/vuetify.min.css +2 -2
- package/dist/vuetify.min.js +292 -253
- package/dist/vuetify.min.js.map +1 -1
- package/lib/components/VKbd/VKbd.css +14 -5
- package/lib/components/VKbd/VKbd.js.map +1 -1
- package/lib/components/VKbd/VKbd.scss +26 -0
- package/lib/components/VKbd/_variables.scss +12 -6
- package/lib/components/VKbd/index.js.map +1 -1
- package/lib/components/VTreeview/VTreeviewChildren.d.ts +13 -0
- package/lib/components/VTreeview/VTreeviewChildren.js +2 -1
- package/lib/components/VTreeview/VTreeviewChildren.js.map +1 -1
- package/lib/components/VTreeview/VTreeviewItem.js +3 -3
- package/lib/components/VTreeview/VTreeviewItem.js.map +1 -1
- package/lib/composables/hotkey/hotkey-parsing.d.ts +15 -0
- package/lib/composables/hotkey/hotkey-parsing.js +154 -0
- package/lib/composables/hotkey/hotkey-parsing.js.map +1 -0
- package/lib/composables/hotkey/hotkey.d.ts +9 -0
- package/lib/composables/{hotkey.js → hotkey/hotkey.js} +31 -39
- package/lib/composables/hotkey/hotkey.js.map +1 -0
- package/lib/composables/hotkey/index.d.ts +1 -0
- package/lib/composables/hotkey/index.js +2 -0
- package/lib/composables/hotkey/index.js.map +1 -0
- package/lib/composables/hotkey/key-aliases.d.ts +14 -0
- package/lib/composables/hotkey/key-aliases.js +38 -0
- package/lib/composables/hotkey/key-aliases.js.map +1 -0
- package/lib/composables/icons.d.ts +11 -0
- package/lib/composables/icons.js.map +1 -1
- package/lib/composables/index.d.ts +1 -0
- package/lib/composables/index.js +1 -0
- package/lib/composables/index.js.map +1 -1
- package/lib/composables/nested/nested.js +8 -8
- package/lib/composables/nested/nested.js.map +1 -1
- package/lib/entry-bundler.js +1 -1
- package/lib/framework.d.ts +74 -53
- package/lib/framework.js +1 -1
- package/lib/iconsets/fa.js +12 -1
- package/lib/iconsets/fa.js.map +1 -1
- package/lib/iconsets/fa4.js +12 -1
- package/lib/iconsets/fa4.js.map +1 -1
- package/lib/iconsets/md.js +12 -1
- package/lib/iconsets/md.js.map +1 -1
- package/lib/iconsets/mdi-svg.js +12 -1
- package/lib/iconsets/mdi-svg.js.map +1 -1
- package/lib/iconsets/mdi.js +12 -1
- package/lib/iconsets/mdi.js.map +1 -1
- package/lib/labs/VHotkey/VHotkey.css +242 -0
- package/lib/labs/VHotkey/VHotkey.d.ts +387 -0
- package/lib/labs/VHotkey/VHotkey.js +432 -0
- package/lib/labs/VHotkey/VHotkey.js.map +1 -0
- package/lib/labs/VHotkey/VHotkey.scss +253 -0
- package/lib/labs/VHotkey/_variables.scss +43 -0
- package/lib/labs/VHotkey/index.d.ts +1 -0
- package/lib/labs/VHotkey/index.js +2 -0
- package/lib/labs/VHotkey/index.js.map +1 -0
- package/lib/labs/components.d.ts +1 -0
- package/lib/labs/components.js +1 -0
- package/lib/labs/components.js.map +1 -1
- package/lib/locale/af.d.ts +18 -0
- package/lib/locale/af.js +18 -0
- package/lib/locale/af.js.map +1 -1
- package/lib/locale/ar.d.ts +18 -0
- package/lib/locale/ar.js +18 -0
- package/lib/locale/ar.js.map +1 -1
- package/lib/locale/az.d.ts +18 -0
- package/lib/locale/az.js +18 -0
- package/lib/locale/az.js.map +1 -1
- package/lib/locale/bg.d.ts +18 -0
- package/lib/locale/bg.js +18 -0
- package/lib/locale/bg.js.map +1 -1
- package/lib/locale/ca.d.ts +18 -0
- package/lib/locale/ca.js +18 -0
- package/lib/locale/ca.js.map +1 -1
- package/lib/locale/ckb.d.ts +18 -0
- package/lib/locale/ckb.js +18 -0
- package/lib/locale/ckb.js.map +1 -1
- package/lib/locale/cs.d.ts +18 -0
- package/lib/locale/cs.js +18 -0
- package/lib/locale/cs.js.map +1 -1
- package/lib/locale/da.d.ts +18 -0
- package/lib/locale/da.js +18 -0
- package/lib/locale/da.js.map +1 -1
- package/lib/locale/de.d.ts +18 -0
- package/lib/locale/de.js +18 -0
- package/lib/locale/de.js.map +1 -1
- package/lib/locale/el.d.ts +18 -0
- package/lib/locale/el.js +18 -0
- package/lib/locale/el.js.map +1 -1
- package/lib/locale/en.d.ts +18 -0
- package/lib/locale/en.js +18 -0
- package/lib/locale/en.js.map +1 -1
- package/lib/locale/es.d.ts +18 -0
- package/lib/locale/es.js +18 -0
- package/lib/locale/es.js.map +1 -1
- package/lib/locale/et.d.ts +18 -0
- package/lib/locale/et.js +18 -0
- package/lib/locale/et.js.map +1 -1
- package/lib/locale/fa.d.ts +18 -0
- package/lib/locale/fa.js +18 -0
- package/lib/locale/fa.js.map +1 -1
- package/lib/locale/fi.d.ts +18 -0
- package/lib/locale/fi.js +18 -0
- package/lib/locale/fi.js.map +1 -1
- package/lib/locale/fr.d.ts +18 -0
- package/lib/locale/fr.js +18 -0
- package/lib/locale/fr.js.map +1 -1
- package/lib/locale/he.d.ts +18 -0
- package/lib/locale/he.js +18 -0
- package/lib/locale/he.js.map +1 -1
- package/lib/locale/hr.d.ts +18 -0
- package/lib/locale/hr.js +18 -0
- package/lib/locale/hr.js.map +1 -1
- package/lib/locale/hu.d.ts +18 -0
- package/lib/locale/hu.js +18 -0
- package/lib/locale/hu.js.map +1 -1
- package/lib/locale/id.d.ts +18 -0
- package/lib/locale/id.js +18 -0
- package/lib/locale/id.js.map +1 -1
- package/lib/locale/it.d.ts +18 -0
- package/lib/locale/it.js +18 -0
- package/lib/locale/it.js.map +1 -1
- package/lib/locale/ja.d.ts +18 -0
- package/lib/locale/ja.js +18 -0
- package/lib/locale/ja.js.map +1 -1
- package/lib/locale/km.d.ts +18 -0
- package/lib/locale/km.js +18 -0
- package/lib/locale/km.js.map +1 -1
- package/lib/locale/ko.d.ts +18 -0
- package/lib/locale/ko.js +18 -0
- package/lib/locale/ko.js.map +1 -1
- package/lib/locale/lt.d.ts +18 -0
- package/lib/locale/lt.js +18 -0
- package/lib/locale/lt.js.map +1 -1
- package/lib/locale/lv.d.ts +18 -0
- package/lib/locale/lv.js +18 -0
- package/lib/locale/lv.js.map +1 -1
- package/lib/locale/nl.d.ts +18 -0
- package/lib/locale/nl.js +18 -0
- package/lib/locale/nl.js.map +1 -1
- package/lib/locale/no.d.ts +18 -0
- package/lib/locale/no.js +18 -0
- package/lib/locale/no.js.map +1 -1
- package/lib/locale/pl.d.ts +18 -0
- package/lib/locale/pl.js +18 -0
- package/lib/locale/pl.js.map +1 -1
- package/lib/locale/pt.d.ts +18 -0
- package/lib/locale/pt.js +18 -0
- package/lib/locale/pt.js.map +1 -1
- package/lib/locale/ro.d.ts +18 -0
- package/lib/locale/ro.js +18 -0
- package/lib/locale/ro.js.map +1 -1
- package/lib/locale/ru.d.ts +18 -0
- package/lib/locale/ru.js +18 -0
- package/lib/locale/ru.js.map +1 -1
- package/lib/locale/sk.d.ts +18 -0
- package/lib/locale/sk.js +18 -0
- package/lib/locale/sk.js.map +1 -1
- package/lib/locale/sl.d.ts +18 -0
- package/lib/locale/sl.js +18 -0
- package/lib/locale/sl.js.map +1 -1
- package/lib/locale/sr-Cyrl.d.ts +18 -0
- package/lib/locale/sr-Cyrl.js +18 -0
- package/lib/locale/sr-Cyrl.js.map +1 -1
- package/lib/locale/sr-Latn.d.ts +18 -0
- package/lib/locale/sr-Latn.js +18 -0
- package/lib/locale/sr-Latn.js.map +1 -1
- package/lib/locale/sv.d.ts +18 -0
- package/lib/locale/sv.js +18 -0
- package/lib/locale/sv.js.map +1 -1
- package/lib/locale/th.d.ts +18 -0
- package/lib/locale/th.js +18 -0
- package/lib/locale/th.js.map +1 -1
- package/lib/locale/tr.d.ts +18 -0
- package/lib/locale/tr.js +18 -0
- package/lib/locale/tr.js.map +1 -1
- package/lib/locale/uk.d.ts +18 -0
- package/lib/locale/uk.js +18 -0
- package/lib/locale/uk.js.map +1 -1
- package/lib/locale/vi.d.ts +18 -0
- package/lib/locale/vi.js +18 -0
- package/lib/locale/vi.js.map +1 -1
- package/lib/locale/zh-Hans.d.ts +18 -0
- package/lib/locale/zh-Hans.js +18 -0
- package/lib/locale/zh-Hans.js.map +1 -1
- package/lib/locale/zh-Hant.d.ts +18 -0
- package/lib/locale/zh-Hant.js +18 -0
- package/lib/locale/zh-Hant.js.map +1 -1
- package/package.json +1 -1
- package/lib/components/VKbd/VKbd.sass +0 -15
- package/lib/composables/hotkey.d.ts +0 -9
- package/lib/composables/hotkey.js.map +0 -1
package/dist/vuetify-labs.cjs
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
* Vuetify v3.9.0-beta.
|
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
|
*/
|
@@ -2145,6 +2145,24 @@
|
|
2145
2145
|
exclude: 'The {0} character is not allowed',
|
2146
2146
|
notEmpty: 'Please choose at least one value',
|
2147
2147
|
pattern: 'Invalid format'
|
2148
|
+
},
|
2149
|
+
hotkey: {
|
2150
|
+
then: 'then',
|
2151
|
+
ctrl: 'Ctrl',
|
2152
|
+
command: 'Command',
|
2153
|
+
space: 'Space',
|
2154
|
+
shift: 'Shift',
|
2155
|
+
alt: 'Alt',
|
2156
|
+
enter: 'Enter',
|
2157
|
+
escape: 'Escape',
|
2158
|
+
upArrow: 'Up Arrow',
|
2159
|
+
downArrow: 'Down Arrow',
|
2160
|
+
leftArrow: 'Left Arrow',
|
2161
|
+
rightArrow: 'Right Arrow',
|
2162
|
+
backspace: 'Backspace',
|
2163
|
+
option: 'Option',
|
2164
|
+
plus: 'plus',
|
2165
|
+
shortcut: 'Keyboard shortcut: {0}'
|
2148
2166
|
}
|
2149
2167
|
};
|
2150
2168
|
|
@@ -4655,7 +4673,18 @@
|
|
4655
4673
|
treeviewExpand: 'mdi-menu-right',
|
4656
4674
|
eyeDropper: 'mdi-eyedropper',
|
4657
4675
|
upload: 'mdi-cloud-upload',
|
4658
|
-
color: 'mdi-palette'
|
4676
|
+
color: 'mdi-palette',
|
4677
|
+
command: 'mdi-apple-keyboard-command',
|
4678
|
+
ctrl: 'mdi-apple-keyboard-control',
|
4679
|
+
space: 'mdi-keyboard-space',
|
4680
|
+
shift: 'mdi-apple-keyboard-shift',
|
4681
|
+
alt: 'mdi-apple-keyboard-option',
|
4682
|
+
enter: 'mdi-keyboard-return',
|
4683
|
+
arrowup: 'mdi-arrow-up',
|
4684
|
+
arrowdown: 'mdi-arrow-down',
|
4685
|
+
arrowleft: 'mdi-arrow-left',
|
4686
|
+
arrowright: 'mdi-arrow-right',
|
4687
|
+
backspace: 'mdi-backspace'
|
4659
4688
|
};
|
4660
4689
|
const mdi = {
|
4661
4690
|
// Not using mergeProps here, functional components merge props by default (?)
|
@@ -9021,9 +9050,9 @@
|
|
9021
9050
|
}, 'nested');
|
9022
9051
|
const useNested = props => {
|
9023
9052
|
let isUnmounted = false;
|
9024
|
-
const children = vue.
|
9025
|
-
const parents = vue.
|
9026
|
-
const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(v), v => [...v.values()]);
|
9053
|
+
const children = vue.shallowRef(new Map());
|
9054
|
+
const parents = vue.shallowRef(new Map());
|
9055
|
+
const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(Array.isArray(v) ? v.map(i => vue.toRaw(i)) : v), v => [...v.values()]);
|
9027
9056
|
const activeStrategy = vue.computed(() => {
|
9028
9057
|
if (typeof props.activeStrategy === 'object') return props.activeStrategy;
|
9029
9058
|
if (typeof props.activeStrategy === 'function') return props.activeStrategy(props.mandatory);
|
@@ -9077,7 +9106,7 @@
|
|
9077
9106
|
});
|
9078
9107
|
function getPath(id) {
|
9079
9108
|
const path = [];
|
9080
|
-
let parent = id;
|
9109
|
+
let parent = vue.toRaw(id);
|
9081
9110
|
while (parent != null) {
|
9082
9111
|
path.unshift(parent);
|
9083
9112
|
parent = parents.value.get(parent);
|
@@ -9220,7 +9249,7 @@
|
|
9220
9249
|
const useNestedItem = (id, isGroup) => {
|
9221
9250
|
const parent = vue.inject(VNestedSymbol, emptyNested);
|
9222
9251
|
const uidSymbol = Symbol('nested item');
|
9223
|
-
const computedId = vue.computed(() => vue.toValue(id) ?? uidSymbol);
|
9252
|
+
const computedId = vue.computed(() => vue.toRaw(vue.toValue(id)) ?? uidSymbol);
|
9224
9253
|
const item = {
|
9225
9254
|
...parent,
|
9226
9255
|
id: computedId,
|
@@ -9229,10 +9258,10 @@
|
|
9229
9258
|
isOpen: vue.computed(() => parent.root.opened.value.has(computedId.value)),
|
9230
9259
|
parent: vue.computed(() => parent.root.parents.value.get(computedId.value)),
|
9231
9260
|
activate: (activated, e) => parent.root.activate(computedId.value, activated, e),
|
9232
|
-
isActivated: vue.computed(() => parent.root.activated.value.has(
|
9261
|
+
isActivated: vue.computed(() => parent.root.activated.value.has(computedId.value)),
|
9233
9262
|
select: (selected, e) => parent.root.select(computedId.value, selected, e),
|
9234
|
-
isSelected: vue.computed(() => parent.root.selected.value.get(
|
9235
|
-
isIndeterminate: vue.computed(() => parent.root.selected.value.get(
|
9263
|
+
isSelected: vue.computed(() => parent.root.selected.value.get(computedId.value) === 'on'),
|
9264
|
+
isIndeterminate: vue.computed(() => parent.root.selected.value.get(computedId.value) === 'indeterminate'),
|
9236
9265
|
isLeaf: vue.computed(() => !parent.root.children.value.get(computedId.value)),
|
9237
9266
|
isGroupActivator: parent.isGroupActivator
|
9238
9267
|
};
|
@@ -18077,6 +18106,317 @@
|
|
18077
18106
|
return createInstance(options, locale);
|
18078
18107
|
}
|
18079
18108
|
|
18109
|
+
/**
|
18110
|
+
* Centralized key alias mapping for consistent key normalization across the hotkey system.
|
18111
|
+
*
|
18112
|
+
* This maps various user-friendly aliases to canonical key names that match
|
18113
|
+
* KeyboardEvent.key values (in lowercase) where possible.
|
18114
|
+
*/
|
18115
|
+
const keyAliasMap = {
|
18116
|
+
// Modifier aliases (from vue-use, other libraries, and current implementation)
|
18117
|
+
control: 'ctrl',
|
18118
|
+
command: 'cmd',
|
18119
|
+
option: 'alt',
|
18120
|
+
// Arrow key aliases (common abbreviations)
|
18121
|
+
up: 'arrowup',
|
18122
|
+
down: 'arrowdown',
|
18123
|
+
left: 'arrowleft',
|
18124
|
+
right: 'arrowright',
|
18125
|
+
// Other common key aliases
|
18126
|
+
esc: 'escape',
|
18127
|
+
spacebar: ' ',
|
18128
|
+
space: ' ',
|
18129
|
+
return: 'enter',
|
18130
|
+
del: 'delete',
|
18131
|
+
// Symbol aliases (existing from hotkey-parsing.ts)
|
18132
|
+
minus: '-',
|
18133
|
+
hyphen: '-'
|
18134
|
+
};
|
18135
|
+
|
18136
|
+
/**
|
18137
|
+
* Normalizes a key string to its canonical form using the alias map.
|
18138
|
+
*
|
18139
|
+
* @param key - The key string to normalize
|
18140
|
+
* @returns The canonical key name in lowercase
|
18141
|
+
*/
|
18142
|
+
function normalizeKey(key) {
|
18143
|
+
const lowerKey = key.toLowerCase();
|
18144
|
+
return keyAliasMap[lowerKey] || lowerKey;
|
18145
|
+
}
|
18146
|
+
|
18147
|
+
// Utilities
|
18148
|
+
|
18149
|
+
/**
|
18150
|
+
* Splits a single combination string into individual key parts.
|
18151
|
+
*
|
18152
|
+
* A combination is a set of keys that must be pressed simultaneously.
|
18153
|
+
* e.g. `ctrl+k`, `shift--`
|
18154
|
+
*/
|
18155
|
+
function splitKeyCombination(combination) {
|
18156
|
+
let isInternal = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
18157
|
+
if (!combination) {
|
18158
|
+
if (!isInternal) consoleWarn('Invalid hotkey combination: empty string provided');
|
18159
|
+
return [];
|
18160
|
+
}
|
18161
|
+
|
18162
|
+
// --- VALIDATION ---
|
18163
|
+
const startsWithPlusOrUnderscore = combination.startsWith('+') || combination.startsWith('_');
|
18164
|
+
const hasInvalidLeadingSeparator =
|
18165
|
+
// Starts with a single '+' or '_' followed by a non-separator character (e.g. '+a', '_a')
|
18166
|
+
startsWithPlusOrUnderscore && !(combination.startsWith('++') || combination.startsWith('__'));
|
18167
|
+
const hasInvalidStructure =
|
18168
|
+
// Invalid leading separator patterns
|
18169
|
+
combination.length > 1 && hasInvalidLeadingSeparator ||
|
18170
|
+
// Disallow literal + or _ keys (they require shift)
|
18171
|
+
combination.includes('++') || combination.includes('__') || combination === '+' || combination === '_' ||
|
18172
|
+
// Ends with a separator that is not part of a doubled literal
|
18173
|
+
combination.length > 1 && (combination.endsWith('+') || combination.endsWith('_')) && combination.at(-2) !== combination.at(-1) ||
|
18174
|
+
// Stand-alone doubled separators (dangling)
|
18175
|
+
combination === '++' || combination === '--' || combination === '__';
|
18176
|
+
if (hasInvalidStructure) {
|
18177
|
+
if (!isInternal) consoleWarn(`Invalid hotkey combination: "${combination}" has invalid structure`);
|
18178
|
+
return [];
|
18179
|
+
}
|
18180
|
+
const keys = [];
|
18181
|
+
let buffer = '';
|
18182
|
+
const flushBuffer = () => {
|
18183
|
+
if (buffer) {
|
18184
|
+
keys.push(normalizeKey(buffer));
|
18185
|
+
buffer = '';
|
18186
|
+
}
|
18187
|
+
};
|
18188
|
+
for (let i = 0; i < combination.length; i++) {
|
18189
|
+
const char = combination[i];
|
18190
|
+
const nextChar = combination[i + 1];
|
18191
|
+
if (char === '+' || char === '_' || char === '-') {
|
18192
|
+
if (char === nextChar) {
|
18193
|
+
flushBuffer();
|
18194
|
+
keys.push(char);
|
18195
|
+
i++;
|
18196
|
+
} else if (char === '+' || char === '_') {
|
18197
|
+
flushBuffer();
|
18198
|
+
} else {
|
18199
|
+
buffer += char;
|
18200
|
+
}
|
18201
|
+
} else {
|
18202
|
+
buffer += char;
|
18203
|
+
}
|
18204
|
+
}
|
18205
|
+
flushBuffer();
|
18206
|
+
|
18207
|
+
// Within a combination, `-` is only valid as a literal key (e.g., `ctrl+-`).
|
18208
|
+
// `-` cannot be part of a longer key name within a combination.
|
18209
|
+
const hasInvalidMinus = keys.some(key => key.length > 1 && key.includes('-') && key !== '--');
|
18210
|
+
if (hasInvalidMinus) {
|
18211
|
+
if (!isInternal) consoleWarn(`Invalid hotkey combination: "${combination}" has invalid structure`);
|
18212
|
+
return [];
|
18213
|
+
}
|
18214
|
+
if (keys.length === 0 && combination) {
|
18215
|
+
return [normalizeKey(combination)];
|
18216
|
+
}
|
18217
|
+
return keys;
|
18218
|
+
}
|
18219
|
+
|
18220
|
+
/**
|
18221
|
+
* Splits a hotkey string into its constituent combination groups.
|
18222
|
+
*
|
18223
|
+
* A sequence is a series of combinations that must be pressed in order.
|
18224
|
+
* e.g. `a-b`, `ctrl+k-p`
|
18225
|
+
*/
|
18226
|
+
function splitKeySequence(str) {
|
18227
|
+
if (!str) {
|
18228
|
+
consoleWarn('Invalid hotkey sequence: empty string provided');
|
18229
|
+
return [];
|
18230
|
+
}
|
18231
|
+
|
18232
|
+
// A sequence is invalid if it starts or ends with a separator,
|
18233
|
+
// unless it is part of a combination (e.g., `shift+-`).
|
18234
|
+
const hasInvalidStart = str.startsWith('-') && !['---', '--+'].includes(str);
|
18235
|
+
const hasInvalidEnd = str.endsWith('-') && !str.endsWith('+-') && !str.endsWith('_-') && str !== '-' && str !== '---';
|
18236
|
+
if (hasInvalidStart || hasInvalidEnd) {
|
18237
|
+
consoleWarn(`Invalid hotkey sequence: "${str}" contains invalid combinations`);
|
18238
|
+
return [];
|
18239
|
+
}
|
18240
|
+
const result = [];
|
18241
|
+
let buffer = '';
|
18242
|
+
let i = 0;
|
18243
|
+
while (i < str.length) {
|
18244
|
+
const char = str[i];
|
18245
|
+
if (char === '-') {
|
18246
|
+
// Determine if this hyphen is part of the current combination
|
18247
|
+
const prevChar = str[i - 1];
|
18248
|
+
const prevPrevChar = i > 1 ? str[i - 2] : undefined;
|
18249
|
+
const precededBySinglePlusOrUnderscore = (prevChar === '+' || prevChar === '_') && prevPrevChar !== '+';
|
18250
|
+
if (precededBySinglePlusOrUnderscore) {
|
18251
|
+
// Treat as part of the combination (e.g., 'ctrl+-')
|
18252
|
+
buffer += char;
|
18253
|
+
i++;
|
18254
|
+
} else {
|
18255
|
+
// Treat as sequence separator
|
18256
|
+
if (buffer) {
|
18257
|
+
result.push(buffer);
|
18258
|
+
buffer = '';
|
18259
|
+
} else {
|
18260
|
+
// Empty buffer means we have a literal '-' key
|
18261
|
+
result.push('-');
|
18262
|
+
}
|
18263
|
+
i++;
|
18264
|
+
}
|
18265
|
+
} else {
|
18266
|
+
buffer += char;
|
18267
|
+
i++;
|
18268
|
+
}
|
18269
|
+
}
|
18270
|
+
|
18271
|
+
// Add final buffer if it exists
|
18272
|
+
if (buffer) {
|
18273
|
+
result.push(buffer);
|
18274
|
+
}
|
18275
|
+
|
18276
|
+
// Collapse runs of '-' so that every second '-' is removed
|
18277
|
+
const collapsed = [];
|
18278
|
+
let minusCount = 0;
|
18279
|
+
for (const part of result) {
|
18280
|
+
if (part === '-') {
|
18281
|
+
if (minusCount % 2 === 0) collapsed.push('-');
|
18282
|
+
minusCount++;
|
18283
|
+
} else {
|
18284
|
+
minusCount = 0;
|
18285
|
+
collapsed.push(part);
|
18286
|
+
}
|
18287
|
+
}
|
18288
|
+
|
18289
|
+
// Validate that each part of the sequence is a valid combination
|
18290
|
+
const areAllValid = collapsed.every(s => splitKeyCombination(s, true).length > 0);
|
18291
|
+
if (!areAllValid) {
|
18292
|
+
consoleWarn(`Invalid hotkey sequence: "${str}" contains invalid combinations`);
|
18293
|
+
return [];
|
18294
|
+
}
|
18295
|
+
return collapsed;
|
18296
|
+
}
|
18297
|
+
|
18298
|
+
// Composables
|
18299
|
+
|
18300
|
+
// Types
|
18301
|
+
|
18302
|
+
function useHotkey(keys, callback) {
|
18303
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
18304
|
+
if (!IN_BROWSER) return function () {};
|
18305
|
+
const {
|
18306
|
+
event = 'keydown',
|
18307
|
+
inputs = false,
|
18308
|
+
preventDefault = true,
|
18309
|
+
sequenceTimeout = 1000
|
18310
|
+
} = options;
|
18311
|
+
const isMac = navigator?.userAgent?.includes('Macintosh') ?? false;
|
18312
|
+
let timeout = 0;
|
18313
|
+
let keyGroups;
|
18314
|
+
let isSequence = false;
|
18315
|
+
let groupIndex = 0;
|
18316
|
+
function clearTimer() {
|
18317
|
+
if (!timeout) return;
|
18318
|
+
clearTimeout(timeout);
|
18319
|
+
timeout = 0;
|
18320
|
+
}
|
18321
|
+
function isInputFocused() {
|
18322
|
+
if (vue.toValue(inputs)) return false;
|
18323
|
+
const activeElement = document.activeElement;
|
18324
|
+
return activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA' || activeElement.isContentEditable || activeElement.contentEditable === 'true');
|
18325
|
+
}
|
18326
|
+
function resetSequence() {
|
18327
|
+
groupIndex = 0;
|
18328
|
+
clearTimer();
|
18329
|
+
}
|
18330
|
+
function handler(e) {
|
18331
|
+
const group = keyGroups[groupIndex];
|
18332
|
+
if (!group || isInputFocused()) return;
|
18333
|
+
if (!matchesKeyGroup(e, group)) {
|
18334
|
+
if (isSequence) resetSequence();
|
18335
|
+
return;
|
18336
|
+
}
|
18337
|
+
if (vue.toValue(preventDefault)) e.preventDefault();
|
18338
|
+
if (!isSequence) {
|
18339
|
+
callback(e);
|
18340
|
+
return;
|
18341
|
+
}
|
18342
|
+
clearTimer();
|
18343
|
+
groupIndex++;
|
18344
|
+
if (groupIndex === keyGroups.length) {
|
18345
|
+
callback(e);
|
18346
|
+
resetSequence();
|
18347
|
+
return;
|
18348
|
+
}
|
18349
|
+
timeout = window.setTimeout(resetSequence, vue.toValue(sequenceTimeout));
|
18350
|
+
}
|
18351
|
+
function cleanup() {
|
18352
|
+
window.removeEventListener(vue.toValue(event), handler);
|
18353
|
+
clearTimer();
|
18354
|
+
}
|
18355
|
+
vue.watch(() => vue.toValue(keys), function (unrefKeys) {
|
18356
|
+
cleanup();
|
18357
|
+
if (unrefKeys) {
|
18358
|
+
const groups = splitKeySequence(unrefKeys.toLowerCase());
|
18359
|
+
isSequence = groups.length > 1;
|
18360
|
+
keyGroups = groups;
|
18361
|
+
resetSequence();
|
18362
|
+
window.addEventListener(vue.toValue(event), handler);
|
18363
|
+
}
|
18364
|
+
}, {
|
18365
|
+
immediate: true
|
18366
|
+
});
|
18367
|
+
|
18368
|
+
// Watch for changes in the event type to re-register the listener
|
18369
|
+
vue.watch(() => vue.toValue(event), function (newEvent, oldEvent) {
|
18370
|
+
if (oldEvent && keyGroups && keyGroups.length > 0) {
|
18371
|
+
window.removeEventListener(oldEvent, handler);
|
18372
|
+
window.addEventListener(newEvent, handler);
|
18373
|
+
}
|
18374
|
+
});
|
18375
|
+
try {
|
18376
|
+
getCurrentInstance('useHotkey');
|
18377
|
+
vue.onBeforeUnmount(cleanup);
|
18378
|
+
} catch {
|
18379
|
+
// Not in Vue setup context
|
18380
|
+
}
|
18381
|
+
function parseKeyGroup(group) {
|
18382
|
+
const MODIFIERS = ['ctrl', 'shift', 'alt', 'meta', 'cmd'];
|
18383
|
+
|
18384
|
+
// Use the shared combination splitting logic
|
18385
|
+
const parts = splitKeyCombination(group.toLowerCase());
|
18386
|
+
|
18387
|
+
// If the combination is invalid, return empty result
|
18388
|
+
if (parts.length === 0) {
|
18389
|
+
return {
|
18390
|
+
modifiers: Object.fromEntries(MODIFIERS.map(m => [m, false])),
|
18391
|
+
actualKey: undefined
|
18392
|
+
};
|
18393
|
+
}
|
18394
|
+
const modifiers = Object.fromEntries(MODIFIERS.map(m => [m, false]));
|
18395
|
+
let actualKey;
|
18396
|
+
for (const part of parts) {
|
18397
|
+
if (MODIFIERS.includes(part)) {
|
18398
|
+
modifiers[part] = true;
|
18399
|
+
} else {
|
18400
|
+
actualKey = part;
|
18401
|
+
}
|
18402
|
+
}
|
18403
|
+
return {
|
18404
|
+
modifiers,
|
18405
|
+
actualKey
|
18406
|
+
};
|
18407
|
+
}
|
18408
|
+
function matchesKeyGroup(e, group) {
|
18409
|
+
const {
|
18410
|
+
modifiers,
|
18411
|
+
actualKey
|
18412
|
+
} = parseKeyGroup(group);
|
18413
|
+
const expectCtrl = modifiers.ctrl || !isMac && (modifiers.cmd || modifiers.meta);
|
18414
|
+
const expectMeta = isMac && (modifiers.cmd || modifiers.meta);
|
18415
|
+
return e.ctrlKey === expectCtrl && e.metaKey === expectMeta && e.shiftKey === modifiers.shift && e.altKey === modifiers.alt && e.key.toLowerCase() === actualKey?.toLowerCase();
|
18416
|
+
}
|
18417
|
+
return cleanup;
|
18418
|
+
}
|
18419
|
+
|
18080
18420
|
// Types
|
18081
18421
|
|
18082
18422
|
const makeVColorPickerProps = propsFactory({
|
@@ -29766,7 +30106,7 @@
|
|
29766
30106
|
emit('toggleExpand', e);
|
29767
30107
|
}
|
29768
30108
|
useRender(() => {
|
29769
|
-
const listItemProps =
|
30109
|
+
const listItemProps = VListItem.filterProps(props);
|
29770
30110
|
const hasPrepend = slots.prepend || props.toggleIcon;
|
29771
30111
|
return vue.createVNode(VListItem, vue.mergeProps({
|
29772
30112
|
"ref": vListItemRef
|
@@ -29777,7 +30117,7 @@
|
|
29777
30117
|
'v-treeview-item--filtered': isFiltered.value
|
29778
30118
|
}, props.class],
|
29779
30119
|
"ripple": false,
|
29780
|
-
"onClick":
|
30120
|
+
"onClick": activateGroupActivator
|
29781
30121
|
}), {
|
29782
30122
|
...slots,
|
29783
30123
|
prepend: hasPrepend ? slotProps => {
|
@@ -29828,6 +30168,7 @@
|
|
29828
30168
|
falseIcon: IconValue,
|
29829
30169
|
trueIcon: IconValue,
|
29830
30170
|
returnObject: Boolean,
|
30171
|
+
activatable: Boolean,
|
29831
30172
|
selectable: Boolean,
|
29832
30173
|
selectedColor: String,
|
29833
30174
|
selectStrategy: [String, Function, Object],
|
@@ -29847,7 +30188,7 @@
|
|
29847
30188
|
} = _ref;
|
29848
30189
|
const isLoading = vue.reactive(new Set());
|
29849
30190
|
const activatorItems = vue.ref([]);
|
29850
|
-
const isClickOnOpen = vue.computed(() => !props.disabled && (props.openOnClick != null ? props.openOnClick : props.selectable));
|
30191
|
+
const isClickOnOpen = vue.computed(() => !props.disabled && (props.openOnClick != null ? props.openOnClick : props.selectable && !props.activatable));
|
29851
30192
|
async function checkChildren(item) {
|
29852
30193
|
try {
|
29853
30194
|
if (!props.items?.length || !props.loadChildren) return;
|
@@ -32281,6 +32622,398 @@
|
|
32281
32622
|
}
|
32282
32623
|
});
|
32283
32624
|
|
32625
|
+
// Types
|
32626
|
+
|
32627
|
+
// Display mode types for different visual representations
|
32628
|
+
|
32629
|
+
// Extended variant type that includes our custom 'contained' variant
|
32630
|
+
|
32631
|
+
// Key display tuple: [mode, content] where content is string or IconValue
|
32632
|
+
|
32633
|
+
// Key tuple: [mode, content] where content is string or IconValue
|
32634
|
+
|
32635
|
+
function processKey(config, requestedMode, isMac) {
|
32636
|
+
const keyCfg = isMac && config.mac ? config.mac : config.default;
|
32637
|
+
|
32638
|
+
// 1. Resolve the safest display mode for the current platform
|
32639
|
+
const mode = (() => {
|
32640
|
+
// Non-Mac platforms rarely use icons – prefer text
|
32641
|
+
if (requestedMode === 'icon' && !isMac) return 'text';
|
32642
|
+
|
32643
|
+
// If the requested mode lacks an asset, fall back to text
|
32644
|
+
if (requestedMode === 'icon' && !keyCfg.icon) return 'text';
|
32645
|
+
if (requestedMode === 'symbol' && !keyCfg.symbol) return 'text';
|
32646
|
+
return requestedMode;
|
32647
|
+
})();
|
32648
|
+
|
32649
|
+
// 2. Pick value for the chosen mode, defaulting to text representation
|
32650
|
+
let value = keyCfg[mode] ?? keyCfg.text;
|
32651
|
+
|
32652
|
+
// 3. Guard against icon tokens leaking into text mode (e.g. "$ctrl")
|
32653
|
+
if (mode === 'text' && typeof value === 'string' && value.startsWith('$') && !value.startsWith('$vuetify.')) {
|
32654
|
+
value = value.slice(1).toUpperCase(); // "$ctrl" → "CTRL"
|
32655
|
+
}
|
32656
|
+
return mode === 'icon' ? ['icon', value] : [mode, value];
|
32657
|
+
}
|
32658
|
+
const hotkeyMap = {
|
32659
|
+
ctrl: {
|
32660
|
+
mac: {
|
32661
|
+
symbol: '⌃',
|
32662
|
+
icon: '$ctrl',
|
32663
|
+
text: '$vuetify.hotkey.ctrl'
|
32664
|
+
},
|
32665
|
+
default: {
|
32666
|
+
text: 'Ctrl'
|
32667
|
+
}
|
32668
|
+
},
|
32669
|
+
meta: {
|
32670
|
+
mac: {
|
32671
|
+
symbol: '⌘',
|
32672
|
+
icon: '$command',
|
32673
|
+
text: '$vuetify.hotkey.command'
|
32674
|
+
},
|
32675
|
+
default: {
|
32676
|
+
text: 'Ctrl'
|
32677
|
+
}
|
32678
|
+
},
|
32679
|
+
cmd: {
|
32680
|
+
mac: {
|
32681
|
+
symbol: '⌘',
|
32682
|
+
icon: '$command',
|
32683
|
+
text: '$vuetify.hotkey.command'
|
32684
|
+
},
|
32685
|
+
default: {
|
32686
|
+
text: 'Ctrl'
|
32687
|
+
}
|
32688
|
+
},
|
32689
|
+
shift: {
|
32690
|
+
mac: {
|
32691
|
+
symbol: '⇧',
|
32692
|
+
icon: '$shift',
|
32693
|
+
text: '$vuetify.hotkey.shift'
|
32694
|
+
},
|
32695
|
+
default: {
|
32696
|
+
text: 'Shift'
|
32697
|
+
}
|
32698
|
+
},
|
32699
|
+
alt: {
|
32700
|
+
mac: {
|
32701
|
+
symbol: '⌥',
|
32702
|
+
icon: '$alt',
|
32703
|
+
text: '$vuetify.hotkey.option'
|
32704
|
+
},
|
32705
|
+
default: {
|
32706
|
+
text: 'Alt'
|
32707
|
+
}
|
32708
|
+
},
|
32709
|
+
enter: {
|
32710
|
+
default: {
|
32711
|
+
symbol: '↵',
|
32712
|
+
icon: '$enter',
|
32713
|
+
text: '$vuetify.hotkey.enter'
|
32714
|
+
}
|
32715
|
+
},
|
32716
|
+
arrowup: {
|
32717
|
+
default: {
|
32718
|
+
symbol: '↑',
|
32719
|
+
icon: '$arrowup',
|
32720
|
+
text: '$vuetify.hotkey.upArrow'
|
32721
|
+
}
|
32722
|
+
},
|
32723
|
+
arrowdown: {
|
32724
|
+
default: {
|
32725
|
+
symbol: '↓',
|
32726
|
+
icon: '$arrowdown',
|
32727
|
+
text: '$vuetify.hotkey.downArrow'
|
32728
|
+
}
|
32729
|
+
},
|
32730
|
+
arrowleft: {
|
32731
|
+
default: {
|
32732
|
+
symbol: '←',
|
32733
|
+
icon: '$arrowleft',
|
32734
|
+
text: '$vuetify.hotkey.leftArrow'
|
32735
|
+
}
|
32736
|
+
},
|
32737
|
+
arrowright: {
|
32738
|
+
default: {
|
32739
|
+
symbol: '→',
|
32740
|
+
icon: '$arrowright',
|
32741
|
+
text: '$vuetify.hotkey.rightArrow'
|
32742
|
+
}
|
32743
|
+
},
|
32744
|
+
backspace: {
|
32745
|
+
default: {
|
32746
|
+
symbol: '⌫',
|
32747
|
+
icon: '$backspace',
|
32748
|
+
text: '$vuetify.hotkey.backspace'
|
32749
|
+
}
|
32750
|
+
},
|
32751
|
+
escape: {
|
32752
|
+
default: {
|
32753
|
+
text: '$vuetify.hotkey.escape'
|
32754
|
+
}
|
32755
|
+
},
|
32756
|
+
' ': {
|
32757
|
+
mac: {
|
32758
|
+
symbol: '␣',
|
32759
|
+
icon: '$space',
|
32760
|
+
text: '$vuetify.hotkey.space'
|
32761
|
+
},
|
32762
|
+
default: {
|
32763
|
+
text: '$vuetify.hotkey.space'
|
32764
|
+
}
|
32765
|
+
},
|
32766
|
+
'-': {
|
32767
|
+
default: {
|
32768
|
+
text: '-'
|
32769
|
+
}
|
32770
|
+
}
|
32771
|
+
};
|
32772
|
+
|
32773
|
+
// Create custom variant props that extend the base variant props with our 'contained' option
|
32774
|
+
const makeVHotkeyVariantProps = propsFactory({
|
32775
|
+
variant: {
|
32776
|
+
type: String,
|
32777
|
+
default: 'elevated',
|
32778
|
+
validator: v => ['elevated', 'flat', 'tonal', 'outlined', 'text', 'plain', 'contained'].includes(v)
|
32779
|
+
}
|
32780
|
+
}, 'VHotkeyVariant');
|
32781
|
+
const makeVHotkeyProps = propsFactory({
|
32782
|
+
// String representing keyboard shortcuts (e.g., "ctrl+k", "meta+shift+p")
|
32783
|
+
keys: String,
|
32784
|
+
// How to display keys: 'symbol' uses special characters (⌘, ⌃), 'icon' uses SVG icons, 'text' uses words
|
32785
|
+
displayMode: {
|
32786
|
+
type: String,
|
32787
|
+
default: 'icon'
|
32788
|
+
},
|
32789
|
+
// Custom key mapping configuration. Users can import and modify the exported hotkeyMap as needed
|
32790
|
+
keyMap: {
|
32791
|
+
type: Object,
|
32792
|
+
default: () => hotkeyMap
|
32793
|
+
},
|
32794
|
+
platform: {
|
32795
|
+
type: String,
|
32796
|
+
default: 'auto'
|
32797
|
+
},
|
32798
|
+
inline: Boolean,
|
32799
|
+
disabled: Boolean,
|
32800
|
+
prefix: String,
|
32801
|
+
suffix: String,
|
32802
|
+
...makeComponentProps(),
|
32803
|
+
...makeThemeProps(),
|
32804
|
+
...makeBorderProps(),
|
32805
|
+
...makeRoundedProps(),
|
32806
|
+
...makeElevationProps(),
|
32807
|
+
...makeVHotkeyVariantProps(),
|
32808
|
+
color: String
|
32809
|
+
}, 'VHotkey');
|
32810
|
+
class Delineator {
|
32811
|
+
constructor(delineator) {
|
32812
|
+
if (['and', 'then'].includes(delineator)) this.val = delineator;else {
|
32813
|
+
throw new Error('Not a valid delineator');
|
32814
|
+
}
|
32815
|
+
}
|
32816
|
+
isEqual(d) {
|
32817
|
+
return this.val === d.val;
|
32818
|
+
}
|
32819
|
+
}
|
32820
|
+
function isDelineator(value) {
|
32821
|
+
return value instanceof Delineator;
|
32822
|
+
}
|
32823
|
+
function isString(value) {
|
32824
|
+
return typeof value === 'string';
|
32825
|
+
}
|
32826
|
+
function getKeyText(keyMap, key, isMac) {
|
32827
|
+
const lowerKey = key.toLowerCase();
|
32828
|
+
if (lowerKey in keyMap) {
|
32829
|
+
const result = processKey(keyMap[lowerKey], 'text', isMac);
|
32830
|
+
return typeof result[1] === 'string' ? result[1] : String(result[1]);
|
32831
|
+
}
|
32832
|
+
return key.toUpperCase();
|
32833
|
+
}
|
32834
|
+
function applyDisplayModeToKey(keyMap, mode, key, isMac) {
|
32835
|
+
const lowerKey = key.toLowerCase();
|
32836
|
+
if (lowerKey in keyMap) {
|
32837
|
+
const result = processKey(keyMap[lowerKey], mode, isMac);
|
32838
|
+
if (result[0] === 'text' && typeof result[1] === 'string' && result[1].startsWith('$') && !result[1].startsWith('$vuetify.')) {
|
32839
|
+
return ['text', result[1].replace('$', '').toUpperCase(), key];
|
32840
|
+
}
|
32841
|
+
return [...result, key];
|
32842
|
+
}
|
32843
|
+
return ['text', key.toUpperCase(), key];
|
32844
|
+
}
|
32845
|
+
const VHotkey = genericComponent()({
|
32846
|
+
name: 'VHotkey',
|
32847
|
+
props: makeVHotkeyProps(),
|
32848
|
+
setup(props) {
|
32849
|
+
const {
|
32850
|
+
t
|
32851
|
+
} = useLocale();
|
32852
|
+
const {
|
32853
|
+
themeClasses
|
32854
|
+
} = provideTheme(props);
|
32855
|
+
const {
|
32856
|
+
rtlClasses
|
32857
|
+
} = useRtl();
|
32858
|
+
const {
|
32859
|
+
borderClasses
|
32860
|
+
} = useBorder(props);
|
32861
|
+
const {
|
32862
|
+
roundedClasses
|
32863
|
+
} = useRounded(props);
|
32864
|
+
const {
|
32865
|
+
elevationClasses
|
32866
|
+
} = useElevation(props);
|
32867
|
+
const isContainedVariant = vue.computed(() => props.variant === 'contained');
|
32868
|
+
const effectiveVariantProps = vue.computed(() => ({
|
32869
|
+
...props,
|
32870
|
+
variant: isContainedVariant.value ? 'elevated' : props.variant
|
32871
|
+
}));
|
32872
|
+
const {
|
32873
|
+
colorClasses,
|
32874
|
+
colorStyles,
|
32875
|
+
variantClasses
|
32876
|
+
} = useVariant(effectiveVariantProps);
|
32877
|
+
const isMac = vue.computed(() => props.platform === 'auto' ? typeof navigator !== 'undefined' && /macintosh/i.test(navigator.userAgent) : props.platform === 'mac');
|
32878
|
+
const effectiveDisplayMode = vue.computed(() => props.displayMode);
|
32879
|
+
const AND_DELINEATOR = new Delineator('and'); // For + separators
|
32880
|
+
const THEN_DELINEATOR = new Delineator('then'); // For - separators
|
32881
|
+
|
32882
|
+
const effectiveKeyMap = vue.computed(() => props.keyMap);
|
32883
|
+
const keyCombinations = vue.computed(() => {
|
32884
|
+
if (!props.keys) return [];
|
32885
|
+
|
32886
|
+
// Split by spaces to handle multiple key combinations
|
32887
|
+
// Example: "ctrl+k meta+p" -> ["ctrl+k", "meta+p"]
|
32888
|
+
return props.keys.split(' ').map(combination => {
|
32889
|
+
// Use the shared sequence splitting logic
|
32890
|
+
const sequenceGroups = splitKeySequence(combination);
|
32891
|
+
|
32892
|
+
// Process each sequence group
|
32893
|
+
return sequenceGroups.flatMap((group, groupIndex) => {
|
32894
|
+
// Use the shared key combination splitting logic
|
32895
|
+
const keyParts = splitKeyCombination(group);
|
32896
|
+
const parts = keyParts.reduce((acc, part, index) => {
|
32897
|
+
if (index !== 0) {
|
32898
|
+
// Add AND delineator between keys
|
32899
|
+
return [...acc, AND_DELINEATOR, part];
|
32900
|
+
}
|
32901
|
+
return [...acc, part];
|
32902
|
+
}, []);
|
32903
|
+
|
32904
|
+
// Add THEN delineator between sequence groups
|
32905
|
+
const result = parts.map(key => {
|
32906
|
+
if (isString(key)) {
|
32907
|
+
return applyDisplayModeToKey(effectiveKeyMap.value, effectiveDisplayMode.value, key, isMac.value);
|
32908
|
+
}
|
32909
|
+
return key;
|
32910
|
+
});
|
32911
|
+
|
32912
|
+
// Add sequence separator if not the last group
|
32913
|
+
if (groupIndex < sequenceGroups.length - 1) {
|
32914
|
+
result.push(THEN_DELINEATOR);
|
32915
|
+
}
|
32916
|
+
return result;
|
32917
|
+
});
|
32918
|
+
});
|
32919
|
+
});
|
32920
|
+
const accessibleLabel = vue.computed(() => {
|
32921
|
+
if (!props.keys) return '';
|
32922
|
+
|
32923
|
+
// Convert the parsed key combinations into readable text
|
32924
|
+
const readableShortcuts = keyCombinations.value.map(combination => {
|
32925
|
+
const readableParts = [];
|
32926
|
+
for (const key of combination) {
|
32927
|
+
if (isDelineator(key)) {
|
32928
|
+
if (AND_DELINEATOR.isEqual(key)) {
|
32929
|
+
readableParts.push(t('$vuetify.hotkey.plus'));
|
32930
|
+
} else if (THEN_DELINEATOR.isEqual(key)) {
|
32931
|
+
readableParts.push(t('$vuetify.hotkey.then'));
|
32932
|
+
}
|
32933
|
+
} else {
|
32934
|
+
// Always use text representation for screen readers
|
32935
|
+
const textKey = key[0] === 'icon' || key[0] === 'symbol' ? applyDisplayModeToKey(mergeDeep(hotkeyMap, props.keyMap), 'text', String(key[1]), isMac.value)[1] : key[1];
|
32936
|
+
readableParts.push(translateKey(textKey));
|
32937
|
+
}
|
32938
|
+
}
|
32939
|
+
return readableParts.join(' ');
|
32940
|
+
});
|
32941
|
+
const shortcutText = readableShortcuts.join(', ');
|
32942
|
+
return t('$vuetify.hotkey.shortcut', shortcutText);
|
32943
|
+
});
|
32944
|
+
function translateKey(key) {
|
32945
|
+
return key.startsWith('$vuetify.') ? t(key) : key;
|
32946
|
+
}
|
32947
|
+
function getKeyTooltip(key) {
|
32948
|
+
if (effectiveDisplayMode.value === 'text') return undefined;
|
32949
|
+
const textKey = getKeyText(effectiveKeyMap.value, String(key[2]), isMac.value);
|
32950
|
+
return translateKey(textKey);
|
32951
|
+
}
|
32952
|
+
function renderKey(key, keyIndex, isContained) {
|
32953
|
+
const KeyComponent = isContained ? 'kbd' : VKbd;
|
32954
|
+
const keyClasses = ['v-hotkey__key', `v-hotkey__key-${key[0]}`, ...(isContained ? ['v-hotkey__key--nested'] : [borderClasses.value, roundedClasses.value, elevationClasses.value, colorClasses.value])];
|
32955
|
+
return vue.createVNode(KeyComponent, {
|
32956
|
+
"key": keyIndex,
|
32957
|
+
"class": vue.normalizeClass(keyClasses),
|
32958
|
+
"style": vue.normalizeStyle(isContained ? undefined : colorStyles.value),
|
32959
|
+
"aria-hidden": "true",
|
32960
|
+
"title": getKeyTooltip(key)
|
32961
|
+
}, {
|
32962
|
+
default: () => [key[0] === 'icon' ? vue.createVNode(VIcon, {
|
32963
|
+
"icon": key[1],
|
32964
|
+
"aria-hidden": "true"
|
32965
|
+
}, null) : translateKey(key[1])]
|
32966
|
+
});
|
32967
|
+
}
|
32968
|
+
function renderDivider(key, keyIndex) {
|
32969
|
+
return vue.createElementVNode("span", {
|
32970
|
+
"key": keyIndex,
|
32971
|
+
"class": "v-hotkey__divider",
|
32972
|
+
"aria-hidden": "true"
|
32973
|
+
}, [AND_DELINEATOR.isEqual(key) ? '+' : t('$vuetify.hotkey.then')]);
|
32974
|
+
}
|
32975
|
+
useRender(() => vue.createElementVNode("div", {
|
32976
|
+
"class": vue.normalizeClass(['v-hotkey', {
|
32977
|
+
'v-hotkey--disabled': props.disabled,
|
32978
|
+
'v-hotkey--inline': props.inline,
|
32979
|
+
'v-hotkey--contained': isContainedVariant.value
|
32980
|
+
}, themeClasses.value, rtlClasses.value, variantClasses.value, props.class]),
|
32981
|
+
"style": vue.normalizeStyle(props.style),
|
32982
|
+
"role": "img",
|
32983
|
+
"aria-label": accessibleLabel.value
|
32984
|
+
}, [isContainedVariant.value ? vue.createVNode(VKbd, {
|
32985
|
+
"key": "contained",
|
32986
|
+
"class": vue.normalizeClass(['v-hotkey__contained-wrapper', borderClasses.value, roundedClasses.value, elevationClasses.value, colorClasses.value]),
|
32987
|
+
"style": vue.normalizeStyle(colorStyles.value),
|
32988
|
+
"aria-hidden": "true"
|
32989
|
+
}, {
|
32990
|
+
default: () => [props.prefix && vue.createElementVNode("span", {
|
32991
|
+
"key": "contained-prefix",
|
32992
|
+
"class": "v-hotkey__prefix"
|
32993
|
+
}, [props.prefix]), keyCombinations.value.map((combination, comboIndex) => vue.createElementVNode("span", {
|
32994
|
+
"class": "v-hotkey__combination",
|
32995
|
+
"key": comboIndex
|
32996
|
+
}, [combination.map((key, keyIndex) => isDelineator(key) ? renderDivider(key, keyIndex) : renderKey(key, keyIndex, true)), comboIndex < keyCombinations.value.length - 1 && vue.createElementVNode("span", {
|
32997
|
+
"aria-hidden": "true"
|
32998
|
+
}, [vue.createTextVNode("\xA0")])])), props.suffix && vue.createElementVNode("span", {
|
32999
|
+
"key": "contained-suffix",
|
33000
|
+
"class": "v-hotkey__suffix"
|
33001
|
+
}, [props.suffix])]
|
33002
|
+
}) : vue.createElementVNode(vue.Fragment, null, [props.prefix && vue.createElementVNode("span", {
|
33003
|
+
"key": "prefix",
|
33004
|
+
"class": "v-hotkey__prefix"
|
33005
|
+
}, [props.prefix]), keyCombinations.value.map((combination, comboIndex) => vue.createElementVNode("span", {
|
33006
|
+
"class": "v-hotkey__combination",
|
33007
|
+
"key": comboIndex
|
33008
|
+
}, [combination.map((key, keyIndex) => isDelineator(key) ? renderDivider(key, keyIndex) : renderKey(key, keyIndex, false)), comboIndex < keyCombinations.value.length - 1 && vue.createElementVNode("span", {
|
33009
|
+
"aria-hidden": "true"
|
33010
|
+
}, [vue.createTextVNode("\xA0")])])), props.suffix && vue.createElementVNode("span", {
|
33011
|
+
"key": "suffix",
|
33012
|
+
"class": "v-hotkey__suffix"
|
33013
|
+
}, [props.suffix])])]));
|
33014
|
+
}
|
33015
|
+
});
|
33016
|
+
|
32284
33017
|
var components = /*#__PURE__*/Object.freeze({
|
32285
33018
|
__proto__: null,
|
32286
33019
|
VAlert: VAlert,
|
@@ -32369,6 +33102,7 @@
|
|
32369
33102
|
VFileUploadItem: VFileUploadItem,
|
32370
33103
|
VFooter: VFooter,
|
32371
33104
|
VForm: VForm,
|
33105
|
+
VHotkey: VHotkey,
|
32372
33106
|
VHover: VHover,
|
32373
33107
|
VIcon: VIcon,
|
32374
33108
|
VIconBtn: VIconBtn,
|
@@ -32792,7 +33526,7 @@
|
|
32792
33526
|
};
|
32793
33527
|
});
|
32794
33528
|
}
|
32795
|
-
const version$1 = "3.9.0-beta.
|
33529
|
+
const version$1 = "3.9.0-beta.1-dev.2025-06-28";
|
32796
33530
|
createVuetify$1.version = version$1;
|
32797
33531
|
|
32798
33532
|
// Vue's inject() can only be used in setup
|
@@ -33090,7 +33824,7 @@
|
|
33090
33824
|
|
33091
33825
|
/* eslint-disable local-rules/sort-imports */
|
33092
33826
|
|
33093
|
-
const version = "3.9.0-beta.
|
33827
|
+
const version = "3.9.0-beta.1-dev.2025-06-28";
|
33094
33828
|
|
33095
33829
|
/* eslint-disable local-rules/sort-imports */
|
33096
33830
|
|
@@ -33111,6 +33845,7 @@
|
|
33111
33845
|
exports.useDefaults = useDefaults;
|
33112
33846
|
exports.useDisplay = useDisplay;
|
33113
33847
|
exports.useGoTo = useGoTo;
|
33848
|
+
exports.useHotkey = useHotkey;
|
33114
33849
|
exports.useLayout = useLayout;
|
33115
33850
|
exports.useLocale = useLocale;
|
33116
33851
|
exports.useRtl = useRtl;
|