foundation.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import BaseFoundation, { DefaultAdapter } from '../base/foundation';
  2. import { keyToCode, Keys } from './constants';
  3. export interface HotKeysAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
  4. notifyHotKey: (e: KeyboardEvent) => void;
  5. getListenerTarget: () => HTMLElement
  6. }
  7. export default class HotKeysFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<HotKeysAdapter<P, S>, P, S> {
  8. constructor(adapter: HotKeysAdapter<P, S>) {
  9. super({ ...adapter });
  10. }
  11. init(): void {
  12. // init Listener
  13. const target = this._adapter.getListenerTarget();
  14. target?.addEventListener('keydown', this.handleKeyDown);
  15. const hotKeys = this.getProps().hotKeys;
  16. if (!this.isValidHotKeys(hotKeys)) {
  17. throw new Error('HotKeys must have one common key and 0/some modifier key');
  18. }
  19. }
  20. isValidHotKeys = (hotKeys: string[]): boolean => {
  21. let commonKeyCnt = 0;
  22. const modifierKeys: string[] = [Keys.Meta, Keys.Alt, Keys.Shift, Keys.Control];
  23. hotKeys.forEach(key => {
  24. key = key.toLowerCase();
  25. if (!Object.values(Keys).some((value) => value === key)) {
  26. throw new Error(`${key} is not a valid key`);
  27. }
  28. if (!modifierKeys.includes(key)) {
  29. commonKeyCnt += 1;
  30. }
  31. });
  32. return commonKeyCnt === 1;
  33. }
  34. handleKeyDown = (event: KeyboardEvent): void => {
  35. const { mergeMetaCtrl: merged, hotKeys, preventDefault } = this.getProps();
  36. let allModifier = new Array(4).fill(false); // Meta Shift Alt Ctrl
  37. let clickedModifier = [event.metaKey, event.shiftKey, event.altKey, event.ctrlKey];
  38. const keysPressed = hotKeys?.map((key: KeyboardEvent["key"]) => {
  39. key = key.toLowerCase();
  40. if (key === Keys.Meta) {
  41. allModifier[0] = true;
  42. return event.metaKey;
  43. } else if (key === Keys.Shift) {
  44. allModifier[1] = true;
  45. return event.shiftKey;
  46. } else if (key === Keys.Alt) {
  47. allModifier[2] = true;
  48. return event.altKey;
  49. } else if (key === Keys.Control) {
  50. allModifier[3] = true;
  51. return event.ctrlKey;
  52. }
  53. return event.code === keyToCode(key);
  54. });
  55. if (!allModifier.every((value, index) => value === clickedModifier[index])) {
  56. return;
  57. }
  58. if (keysPressed.every(Boolean)) {
  59. if (preventDefault) {
  60. event.preventDefault();
  61. }
  62. this._adapter.notifyHotKey(event);
  63. return;
  64. }
  65. }
  66. destroy(): void {
  67. // remove Listener
  68. const target = this._adapter.getListenerTarget();
  69. target?.removeEventListener('keydown', this.handleKeyDown);
  70. }
  71. }