Use second param instead of augmenting system event

This commit is contained in:
rijkvanzanten
2020-09-29 18:26:30 -04:00
parent 72fc6aee9c
commit b7ab31b33d
2 changed files with 56 additions and 51 deletions

View File

@@ -33,10 +33,10 @@ export default defineComponent({
},
setup(props, { emit }) {
const dialog = ref<HTMLElement | null>(null);
useShortcut('escape', (event) => {
useShortcut('escape', (event, cancelNext) => {
if (_active.value) {
emitToggle();
event.cancelNext();
cancelNext();
}
});

View File

@@ -1,11 +1,7 @@
import { onMounted, onUnmounted, Ref, ref } from '@vue/composition-api';
import Vue from 'vue';
type ShortcutHandler = (event: CancelableKeyboardEvent) => void | any | boolean;
interface CancelableKeyboardEvent extends KeyboardEvent {
cancelNext: () => void;
}
type ShortcutHandler = (event: KeyboardEvent, cancelNext: () => void) => void | any | boolean;
const keysdown: Set<string> = new Set([]);
const handlers: Record<string, ShortcutHandler[]> = {};
@@ -23,11 +19,56 @@ document.body.addEventListener('keyup', (event: KeyboardEvent) => {
keysdown.delete(key.toUpperCase());
});
export default function useShortcut(
shortcuts: string | string[],
handler: ShortcutHandler,
reference: Ref<HTMLElement | undefined> | Ref<Vue | undefined> = ref(document.body)
) {
const callback: ShortcutHandler = (event, cancelNext) => {
if (!reference.value) return;
const ref = reference.value instanceof HTMLElement ? reference.value : (reference.value.$el as HTMLElement);
if (
document.activeElement === ref ||
ref.contains(document.activeElement) ||
document.activeElement === document.body
) {
event.preventDefault();
return handler(event, cancelNext);
}
return false;
};
onMounted(() => {
[shortcuts].flat().forEach((shortcut) => {
if (handlers.hasOwnProperty(shortcut)) {
handlers[shortcut].unshift(callback);
} else {
handlers[shortcut] = [callback];
}
});
});
onUnmounted(() => {
[shortcuts].flat().forEach((shortcut) => {
if (handlers.hasOwnProperty(shortcut)) {
handlers[shortcut] = handlers[shortcut].filter((f) => f !== callback);
if (handlers[shortcut].length === 0) {
delete handlers[shortcut];
}
}
});
});
}
function mapKeys(key: string) {
const map: Record<string, string> = {
Control: 'meta',
Command: 'meta',
};
key = map.hasOwnProperty(key) ? map[key] : key;
if (key.match(/^[a-z]$/) !== null) {
@@ -44,56 +85,20 @@ function mapKeys(key: string) {
function callHandlers(event: KeyboardEvent) {
Object.entries(handlers).forEach(([key, value]) => {
const rest = key.split('+').filter((keySegment) => keysdown.has(keySegment) === false);
if (rest.length > 0) return;
for (let i = 0; i < value.length; i++) {
let cancel = false;
(event as CancelableKeyboardEvent).cancelNext = () => {
cancel = true;
};
value[i](event as CancelableKeyboardEvent);
value[i](event, cancelNext);
// if cancelNext is called, discontinue going through the queue.
if (typeof cancel === 'boolean' && cancel) break;
function cancelNext() {
cancel = true;
}
}
});
}
export default function useShortcut(
shortcuts: string | string[],
handler: ShortcutHandler,
reference: Ref<HTMLElement | undefined> | Ref<Vue | undefined> = ref(document.body)
) {
const callback: ShortcutHandler = (event) => {
if (!reference.value) return;
const ref = reference.value instanceof HTMLElement ? reference.value : (reference.value.$el as HTMLElement);
if (
document.activeElement === ref ||
ref.contains(document.activeElement) ||
document.activeElement === document.body
) {
event.preventDefault();
return handler(event);
}
return false;
};
onMounted(() => {
[shortcuts].flat().forEach((shortcut) => {
if (handlers.hasOwnProperty(shortcut)) {
handlers[shortcut].unshift(callback);
} else {
handlers[shortcut] = [callback];
}
});
});
onUnmounted(() => {
[shortcuts].flat().forEach((shortcut) => {
if (handlers.hasOwnProperty(shortcut)) {
handlers[shortcut] = handlers[shortcut].filter((f) => f !== callback);
if (handlers[shortcut].length === 0) {
delete handlers[shortcut];
}
}
});
});
}