generated from gxc-solutions/gxc-template-repo
Added files
This commit is contained in:
parent
bf0142bd6a
commit
7c351972cc
17 changed files with 966 additions and 8 deletions
|
|
@ -41,7 +41,7 @@ jobs:
|
|||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: gxc-math-${{ github.sha }}
|
||||
name: gxc-hotkeys-${{ github.sha }}
|
||||
path: ./dist/
|
||||
|
||||
deploy:
|
||||
|
|
@ -53,7 +53,7 @@ jobs:
|
|||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: gxc-math-${{ github.sha }}
|
||||
name: gxc-hotkeys-${{ github.sha }}
|
||||
path: ./artifact
|
||||
|
||||
- name: Setup Node.js
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
/** Identifier for global keyboard zone */
|
||||
export const GLOBAL_ZONE_TOKEN = "GLOBAL";
|
||||
205
lib/src/constants/key-labels.ts
Normal file
205
lib/src/constants/key-labels.ts
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
import { IKeyLabel } from "../interfaces";
|
||||
import { Key } from "./key";
|
||||
|
||||
/** Labels for Windows keys */
|
||||
export const WINDOWS_KEYS: IKeyLabel[] = [
|
||||
{ code: Key.Backspace, label: "Backspace" },
|
||||
{ code: Key.Tab, label: "Tab" },
|
||||
{ code: Key.Enter, label: "Enter" },
|
||||
{ code: Key.Shift, label: "Shift" },
|
||||
{ code: Key.Ctrl, label: "Ctrl" },
|
||||
{ code: Key.Alt, label: "Alt" },
|
||||
{ code: Key.PauseBreak, label: "Pause" },
|
||||
{ code: Key.CapsLock, label: "Caps Lock" },
|
||||
{ code: Key.Escape, label: "Esc" },
|
||||
{ code: Key.Space, label: "Space" },
|
||||
{ code: Key.PageUp, label: "PgUp" },
|
||||
{ code: Key.PageDown, label: "PgDn" },
|
||||
{ code: Key.End, label: "End" },
|
||||
{ code: Key.Home, label: "Home" },
|
||||
{ code: Key.LeftArrow, label: "←" },
|
||||
{ code: Key.UpArrow, label: "↑" },
|
||||
{ code: Key.RightArrow, label: "→" },
|
||||
{ code: Key.DownArrow, label: "↓" },
|
||||
{ code: Key.Insert, label: "Insert" },
|
||||
{ code: Key.Delete, label: "Del" },
|
||||
{ code: Key.Zero, label: "0", altLabel: ")" },
|
||||
{ code: Key.One, label: "1", altLabel: "!" },
|
||||
{ code: Key.Two, label: "2", altLabel: "@" },
|
||||
{ code: Key.Three, label: "3", altLabel: "#" },
|
||||
{ code: Key.Four, label: "4", altLabel: "$" },
|
||||
{ code: Key.Five, label: "5", altLabel: "%" },
|
||||
{ code: Key.Six, label: "6", altLabel: "^" },
|
||||
{ code: Key.Seven, label: "7", altLabel: "&" },
|
||||
{ code: Key.Eight, label: "8", altLabel: "*" },
|
||||
{ code: Key.Nine, label: "9", altLabel: "(" },
|
||||
{ code: Key.A, label: "A" },
|
||||
{ code: Key.B, label: "B" },
|
||||
{ code: Key.C, label: "C" },
|
||||
{ code: Key.D, label: "D" },
|
||||
{ code: Key.E, label: "E" },
|
||||
{ code: Key.F, label: "F" },
|
||||
{ code: Key.G, label: "G" },
|
||||
{ code: Key.H, label: "H" },
|
||||
{ code: Key.I, label: "I" },
|
||||
{ code: Key.J, label: "J" },
|
||||
{ code: Key.K, label: "K" },
|
||||
{ code: Key.L, label: "L" },
|
||||
{ code: Key.M, label: "M" },
|
||||
{ code: Key.N, label: "N" },
|
||||
{ code: Key.O, label: "O" },
|
||||
{ code: Key.P, label: "P" },
|
||||
{ code: Key.Q, label: "Q" },
|
||||
{ code: Key.R, label: "R" },
|
||||
{ code: Key.S, label: "S" },
|
||||
{ code: Key.T, label: "T" },
|
||||
{ code: Key.U, label: "U" },
|
||||
{ code: Key.V, label: "V" },
|
||||
{ code: Key.W, label: "W" },
|
||||
{ code: Key.X, label: "X" },
|
||||
{ code: Key.Y, label: "Y" },
|
||||
{ code: Key.Z, label: "Z" },
|
||||
{ code: Key.LeftWindowKey, label: "Win" },
|
||||
{ code: Key.RightWindowKey, label: "Win" },
|
||||
{ code: Key.SelectKey, label: "Menu" },
|
||||
{ code: Key.Numpad0, label: "0" },
|
||||
{ code: Key.Numpad1, label: "1" },
|
||||
{ code: Key.Numpad2, label: "2" },
|
||||
{ code: Key.Numpad3, label: "3" },
|
||||
{ code: Key.Numpad4, label: "4" },
|
||||
{ code: Key.Numpad5, label: "5" },
|
||||
{ code: Key.Numpad6, label: "6" },
|
||||
{ code: Key.Numpad7, label: "7" },
|
||||
{ code: Key.Numpad8, label: "8" },
|
||||
{ code: Key.Numpad9, label: "9" },
|
||||
{ code: Key.Multiply, label: "*" },
|
||||
{ code: Key.Add, label: "+" },
|
||||
{ code: Key.Subtract, label: "-" },
|
||||
{ code: Key.DecimalPoint, label: "." },
|
||||
{ code: Key.Divide, label: "/" },
|
||||
{ code: Key.F1, label: "F1" },
|
||||
{ code: Key.F2, label: "F2" },
|
||||
{ code: Key.F3, label: "F3" },
|
||||
{ code: Key.F4, label: "F4" },
|
||||
{ code: Key.F5, label: "F5" },
|
||||
{ code: Key.F6, label: "F6" },
|
||||
{ code: Key.F7, label: "F7" },
|
||||
{ code: Key.F8, label: "F8" },
|
||||
{ code: Key.F9, label: "F9" },
|
||||
{ code: Key.F10, label: "F10" },
|
||||
{ code: Key.F11, label: "F11" },
|
||||
{ code: Key.F12, label: "F12" },
|
||||
{ code: Key.NumLock, label: "Num Lock" },
|
||||
{ code: Key.ScrollLock, label: "ScrLk" },
|
||||
{ code: Key.SemiColon, label: ";" },
|
||||
{ code: Key.Equals, label: "=", altLabel: "+" },
|
||||
{ code: Key.Comma, label: "," },
|
||||
{ code: Key.Dash, label: "-", altLabel: "_" },
|
||||
{ code: Key.Period, label: "." },
|
||||
{ code: Key.ForwardSlash, label: "/" },
|
||||
{ code: Key.Tilde, label: "~", altLabel: "`" },
|
||||
{ code: Key.OpenBracket, label: "[" },
|
||||
{ code: Key.ClosedBracket, label: "]" },
|
||||
{ code: Key.Quote, label: "'" },
|
||||
];
|
||||
|
||||
/** Labels for Mac OS keys */
|
||||
export const MAC_KEYS: IKeyLabel[] = [
|
||||
{ code: Key.Backspace, label: "Backspace" },
|
||||
{ code: Key.Tab, label: "⇥" },
|
||||
{ code: Key.Enter, label: "Enter" },
|
||||
{ code: Key.Shift, label: "⇧" },
|
||||
{ code: Key.Ctrl, label: "Control" },
|
||||
{ code: Key.Alt, label: "⌥" },
|
||||
{ code: Key.PauseBreak, label: "Pause" },
|
||||
{ code: Key.CapsLock, label: "⇪" },
|
||||
{ code: Key.Escape, label: "Esc" },
|
||||
{ code: Key.Space, label: "Space" },
|
||||
{ code: Key.PageUp, label: "PgUp" },
|
||||
{ code: Key.PageDown, label: "PgDn" },
|
||||
{ code: Key.End, label: "End" },
|
||||
{ code: Key.Home, label: "Home" },
|
||||
{ code: Key.LeftArrow, label: "←" },
|
||||
{ code: Key.UpArrow, label: "↑" },
|
||||
{ code: Key.RightArrow, label: "→" },
|
||||
{ code: Key.DownArrow, label: "↓" },
|
||||
{ code: Key.Insert, label: "Insert" },
|
||||
{ code: Key.Delete, label: "Backspace" },
|
||||
{ code: Key.Zero, label: "0", altLabel: ")" },
|
||||
{ code: Key.One, label: "1", altLabel: "!" },
|
||||
{ code: Key.Two, label: "2", altLabel: "@" },
|
||||
{ code: Key.Three, label: "3", altLabel: "#" },
|
||||
{ code: Key.Four, label: "4", altLabel: "$" },
|
||||
{ code: Key.Five, label: "5", altLabel: "%" },
|
||||
{ code: Key.Six, label: "6", altLabel: "^" },
|
||||
{ code: Key.Seven, label: "7", altLabel: "&" },
|
||||
{ code: Key.Eight, label: "8", altLabel: "*" },
|
||||
{ code: Key.Nine, label: "9", altLabel: "(" },
|
||||
{ code: Key.A, label: "A" },
|
||||
{ code: Key.B, label: "B" },
|
||||
{ code: Key.C, label: "C" },
|
||||
{ code: Key.D, label: "D" },
|
||||
{ code: Key.E, label: "E" },
|
||||
{ code: Key.F, label: "F" },
|
||||
{ code: Key.G, label: "G" },
|
||||
{ code: Key.H, label: "H" },
|
||||
{ code: Key.I, label: "I" },
|
||||
{ code: Key.J, label: "J" },
|
||||
{ code: Key.K, label: "K" },
|
||||
{ code: Key.L, label: "L" },
|
||||
{ code: Key.M, label: "M" },
|
||||
{ code: Key.N, label: "N" },
|
||||
{ code: Key.O, label: "O" },
|
||||
{ code: Key.P, label: "P" },
|
||||
{ code: Key.Q, label: "Q" },
|
||||
{ code: Key.R, label: "R" },
|
||||
{ code: Key.S, label: "S" },
|
||||
{ code: Key.T, label: "T" },
|
||||
{ code: Key.U, label: "U" },
|
||||
{ code: Key.V, label: "V" },
|
||||
{ code: Key.W, label: "W" },
|
||||
{ code: Key.X, label: "X" },
|
||||
{ code: Key.Y, label: "Y" },
|
||||
{ code: Key.Z, label: "Z" },
|
||||
{ code: Key.LeftWindowKey, label: "⌘" },
|
||||
{ code: Key.RightWindowKey, label: "⌘" },
|
||||
{ code: Key.Numpad0, label: "0" },
|
||||
{ code: Key.Numpad1, label: "1" },
|
||||
{ code: Key.Numpad2, label: "2" },
|
||||
{ code: Key.Numpad3, label: "3" },
|
||||
{ code: Key.Numpad4, label: "4" },
|
||||
{ code: Key.Numpad5, label: "5" },
|
||||
{ code: Key.Numpad6, label: "6" },
|
||||
{ code: Key.Numpad7, label: "7" },
|
||||
{ code: Key.Numpad8, label: "8" },
|
||||
{ code: Key.Numpad9, label: "9" },
|
||||
{ code: Key.Multiply, label: "*" },
|
||||
{ code: Key.Add, label: "+" },
|
||||
{ code: Key.Subtract, label: "-" },
|
||||
{ code: Key.DecimalPoint, label: "." },
|
||||
{ code: Key.Divide, label: "/" },
|
||||
{ code: Key.F1, label: "F1" },
|
||||
{ code: Key.F2, label: "F2" },
|
||||
{ code: Key.F3, label: "F3" },
|
||||
{ code: Key.F4, label: "F4" },
|
||||
{ code: Key.F5, label: "F5" },
|
||||
{ code: Key.F6, label: "F6" },
|
||||
{ code: Key.F7, label: "F7" },
|
||||
{ code: Key.F8, label: "F8" },
|
||||
{ code: Key.F9, label: "F9" },
|
||||
{ code: Key.F10, label: "F10" },
|
||||
{ code: Key.F11, label: "F11" },
|
||||
{ code: Key.F12, label: "F12" },
|
||||
{ code: Key.NumLock, label: "Num Lock" },
|
||||
{ code: Key.ScrollLock, label: "ScrLk" },
|
||||
{ code: Key.SemiColon, label: ";" },
|
||||
{ code: Key.Equals, label: "=", altLabel: "+" },
|
||||
{ code: Key.Comma, label: "," },
|
||||
{ code: Key.Dash, label: "-", altLabel: "_" },
|
||||
{ code: Key.Period, label: "." },
|
||||
{ code: Key.ForwardSlash, label: "/" },
|
||||
{ code: Key.Tilde, label: "~", altLabel: "`" },
|
||||
{ code: Key.OpenBracket, label: "[" },
|
||||
{ code: Key.ClosedBracket, label: "]" },
|
||||
{ code: Key.Quote, label: "'" },
|
||||
];
|
||||
127
lib/src/constants/key.ts
Normal file
127
lib/src/constants/key.ts
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
export enum Key {
|
||||
Backspace = 8,
|
||||
Tab = 9,
|
||||
Enter = 13,
|
||||
Shift = 16,
|
||||
Ctrl = 17,
|
||||
Alt = 18,
|
||||
PauseBreak = 19,
|
||||
CapsLock = 20,
|
||||
Escape = 27,
|
||||
Space = 32,
|
||||
PageUp = 33,
|
||||
PageDown = 34,
|
||||
End = 35,
|
||||
Home = 36,
|
||||
|
||||
LeftArrow = 37,
|
||||
UpArrow = 38,
|
||||
RightArrow = 39,
|
||||
DownArrow = 40,
|
||||
|
||||
Insert = 45,
|
||||
Delete = 46,
|
||||
|
||||
Zero = 48,
|
||||
ClosedParen = Zero,
|
||||
One = 49,
|
||||
ExclamationMark = One,
|
||||
Two = 50,
|
||||
AtSign = Two,
|
||||
Three = 51,
|
||||
PoundSign = Three,
|
||||
Hash = PoundSign,
|
||||
Four = 52,
|
||||
DollarSign = Four,
|
||||
Five = 53,
|
||||
PercentSign = Five,
|
||||
Six = 54,
|
||||
Caret = Six,
|
||||
Hat = Caret,
|
||||
Seven = 55,
|
||||
Ampersand = Seven,
|
||||
Eight = 56,
|
||||
Star = Eight,
|
||||
Asterik = Star,
|
||||
Nine = 57,
|
||||
OpenParen = Nine,
|
||||
|
||||
A = 65,
|
||||
B = 66,
|
||||
C = 67,
|
||||
D = 68,
|
||||
E = 69,
|
||||
F = 70,
|
||||
G = 71,
|
||||
H = 72,
|
||||
I = 73,
|
||||
J = 74,
|
||||
K = 75,
|
||||
L = 76,
|
||||
M = 77,
|
||||
N = 78,
|
||||
O = 79,
|
||||
P = 80,
|
||||
Q = 81,
|
||||
R = 82,
|
||||
S = 83,
|
||||
T = 84,
|
||||
U = 85,
|
||||
V = 86,
|
||||
W = 87,
|
||||
X = 88,
|
||||
Y = 89,
|
||||
Z = 90,
|
||||
|
||||
LeftWindowKey = 91,
|
||||
RightWindowKey = 92,
|
||||
SelectKey = 93,
|
||||
|
||||
Numpad0 = 96,
|
||||
Numpad1 = 97,
|
||||
Numpad2 = 98,
|
||||
Numpad3 = 99,
|
||||
Numpad4 = 100,
|
||||
Numpad5 = 101,
|
||||
Numpad6 = 102,
|
||||
Numpad7 = 103,
|
||||
Numpad8 = 104,
|
||||
Numpad9 = 105,
|
||||
|
||||
Multiply = 106,
|
||||
Add = 107,
|
||||
Subtract = 109,
|
||||
DecimalPoint = 110,
|
||||
Divide = 111,
|
||||
|
||||
F1 = 112,
|
||||
F2 = 113,
|
||||
F3 = 114,
|
||||
F4 = 115,
|
||||
F5 = 116,
|
||||
F6 = 117,
|
||||
F7 = 118,
|
||||
F8 = 119,
|
||||
F9 = 120,
|
||||
F10 = 121,
|
||||
F11 = 122,
|
||||
F12 = 123,
|
||||
|
||||
NumLock = 144,
|
||||
ScrollLock = 145,
|
||||
|
||||
SemiColon = 186,
|
||||
Equals = 187,
|
||||
Comma = 188,
|
||||
Dash = 189,
|
||||
Period = 190,
|
||||
UnderScore = Dash,
|
||||
PlusSign = Equals,
|
||||
ForwardSlash = 191,
|
||||
Tilde = 192,
|
||||
GraveAccent = Tilde,
|
||||
|
||||
OpenBracket = 219,
|
||||
ClosedBracket = 221,
|
||||
Quote = 222,
|
||||
}
|
||||
18
lib/src/functions/index.spec.ts
Normal file
18
lib/src/functions/index.spec.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { adaptKeysToPlatform, getOS } from ".";
|
||||
import { Key } from "../constants/key";
|
||||
import { MAC_SPECIAL_KEYS, OPERATING_SYSTEM } from "../interfaces";
|
||||
|
||||
describe("Utils", () => {
|
||||
beforeEach(async () => {});
|
||||
|
||||
it("Adapting keys to platform", () => {
|
||||
const os = getOS();
|
||||
const adapted = adaptKeysToPlatform([[Key.Ctrl]]);
|
||||
if (os === OPERATING_SYSTEM.WINDOWS) {
|
||||
expect(adapted[0][0]).toBe(Key.Ctrl);
|
||||
}
|
||||
if (os === OPERATING_SYSTEM.MAC_OS) {
|
||||
expect(adapted[0][0]).toBe(MAC_SPECIAL_KEYS.CmdLeft as any);
|
||||
}
|
||||
});
|
||||
});
|
||||
70
lib/src/functions/index.ts
Normal file
70
lib/src/functions/index.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import { Key } from "../constants/key";
|
||||
import { MAC_KEYS, WINDOWS_KEYS } from "../constants/key-labels";
|
||||
import { IKeyLabel, IKeyRegistry, OPERATING_SYSTEM } from "../interfaces";
|
||||
import { getMacKeys } from "../utils";
|
||||
|
||||
/**
|
||||
* Create label string for hotkey depending on OS
|
||||
* @param keySet - array describing the hotkey. For example: [Key.Ctrl, Key.A]
|
||||
* @param delimiter - string for joining labels
|
||||
* @returns label string for hotkey. For example "Ctrl + A"
|
||||
*/
|
||||
export const getLabelByKeySet = (keySet: Key[], delimiter?: string): string => {
|
||||
let platformKeySet: IKeyLabel[] = WINDOWS_KEYS;
|
||||
|
||||
if (getOS() === OPERATING_SYSTEM.MAC_OS) {
|
||||
if (delimiter == null) delimiter = "";
|
||||
platformKeySet = MAC_KEYS;
|
||||
} else {
|
||||
if (delimiter == null) delimiter = " + ";
|
||||
}
|
||||
|
||||
if (Array.isArray(keySet)) {
|
||||
return keySet
|
||||
.map((key) => platformKeySet.find((item) => item.code === key)?.label ?? "")
|
||||
.filter((label) => label !== "")
|
||||
.join(delimiter);
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Create label string for hotkey depending on OS using interface `IKeyRegistry`.
|
||||
* For creating label will be use first hotkey from `keys` array
|
||||
*/
|
||||
export const getLabel = (hotkey: IKeyRegistry, delimiter?: string): string => hotkey.label ?? getLabelByKeySet(hotkey.keys[0], delimiter);
|
||||
|
||||
/**
|
||||
* Adapt keyboard keys to platform
|
||||
* @param keySet - array describing the hotkey. For example: [Key.Ctrl, Key.A]
|
||||
* @returns keyboard keys adapted to the platform
|
||||
*/
|
||||
export const adaptKeysToPlatform = (keySet: Key[][]): Key[][] => {
|
||||
switch (getOS()) {
|
||||
case OPERATING_SYSTEM.WINDOWS:
|
||||
case OPERATING_SYSTEM.OTHER:
|
||||
return keySet;
|
||||
case OPERATING_SYSTEM.MAC_OS:
|
||||
return getMacKeys(keySet);
|
||||
default:
|
||||
return keySet;
|
||||
}
|
||||
};
|
||||
|
||||
/** Get current OS */
|
||||
export const getOS = () => {
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
const macosPlatforms = /(macintosh|macintel|macppc|mac68k|macos)/i;
|
||||
const windowsPlatforms = /(win32|win64|windows|wince)/i;
|
||||
const iosPlatforms = /(iphone|ipad|ipod)/i;
|
||||
|
||||
if (macosPlatforms.test(userAgent)) {
|
||||
return OPERATING_SYSTEM.MAC_OS;
|
||||
} else if (windowsPlatforms.test(userAgent)) {
|
||||
return OPERATING_SYSTEM.WINDOWS;
|
||||
} else if (iosPlatforms.test(userAgent)) {
|
||||
return OPERATING_SYSTEM.IOS;
|
||||
}
|
||||
|
||||
return OPERATING_SYSTEM.OTHER;
|
||||
};
|
||||
308
lib/src/hotkey-manager.ts
Normal file
308
lib/src/hotkey-manager.ts
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
import { arraysIsEqual } from "@gxc-solutions/lett-js/algorithms/array";
|
||||
import { Subject, fromEvent, takeWhile } from "rxjs";
|
||||
import { GLOBAL_ZONE_TOKEN } from "./constants";
|
||||
import { Key } from "./constants/key";
|
||||
import { FindKeyCb, IKeyRegistry, IKeyboardEvent, IRegistrationCheckResult, MouseKey } from "./interfaces";
|
||||
import { KeyRegistry } from "./models/key-registry";
|
||||
import { actionExistError, correspondsToKeySet, hotkeyExistError } from "./utils";
|
||||
|
||||
/** A service that registers hotkeys, handles events, and notifies of hotkey events */
|
||||
export class HotkeyManager<A = string> {
|
||||
protected _zonesMap = new Map<string, Map<A, KeyRegistry<A>>>([[GLOBAL_ZONE_TOKEN, new Map()]]);
|
||||
protected _events = new Subject<IKeyboardEvent<A>>();
|
||||
/** Current pressed keyboard key */
|
||||
protected _currentDownKeys: Key[] = [];
|
||||
/** Current pressed mouse buttons */
|
||||
protected _currentMouseDownKeys = new Set<MouseKey>([]);
|
||||
protected _isDestroyed = false;
|
||||
/** Set `true` for ignore events */
|
||||
public ignore = false;
|
||||
|
||||
/** Notify when found hotkeys event */
|
||||
get $keyboardEvents() {
|
||||
return this._events.asObservable();
|
||||
}
|
||||
|
||||
/** @hideconstructor */
|
||||
constructor(
|
||||
private _element: HTMLElement,
|
||||
rootHotkeys: IKeyRegistry<A>[],
|
||||
) {
|
||||
// Keyboard
|
||||
fromEvent(this._element, "keydown")
|
||||
.pipe(takeWhile(() => !this._isDestroyed))
|
||||
.subscribe((e: KeyboardEvent) => this.handleKeyPressing(e));
|
||||
fromEvent(this._element, "keyup")
|
||||
.pipe(takeWhile(() => !this._isDestroyed))
|
||||
.subscribe((e: KeyboardEvent) => this.handleKeyUp(e));
|
||||
// Mouse
|
||||
fromEvent(this._element, "blur")
|
||||
.pipe(takeWhile(() => !this._isDestroyed))
|
||||
.subscribe(() => (this._currentDownKeys = []));
|
||||
fromEvent(this._element, "wheel", { passive: false })
|
||||
.pipe(takeWhile(() => !this._isDestroyed))
|
||||
.subscribe((e: WheelEvent) => this.handleWheel(e));
|
||||
fromEvent(this._element, "click")
|
||||
.pipe(takeWhile(() => !this._isDestroyed))
|
||||
.subscribe((e: MouseEvent) => this.handleClick(e));
|
||||
fromEvent(this._element, "dbclick")
|
||||
.pipe(takeWhile(() => !this._isDestroyed))
|
||||
.subscribe((e: MouseEvent) => this.handleDbClick(e));
|
||||
// fromEvent(window, "mousemove").subscribe((e: MouseEvent) => this._handleMove(e));
|
||||
fromEvent(this._element, "mousedown")
|
||||
.pipe(takeWhile(() => !this._isDestroyed))
|
||||
.subscribe((e: MouseEvent) => this.handleMouseDown(e));
|
||||
fromEvent(this._element, "mouseup")
|
||||
.pipe(takeWhile(() => !this._isDestroyed))
|
||||
.subscribe((e: MouseEvent) => this.handleMouseUp(e));
|
||||
// Registry root hotkeys
|
||||
this.registryKeysSet(rootHotkeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hotkeys to system
|
||||
* @param keyInfo - hotkey registry data
|
||||
* @param provider - handler provider service
|
||||
*/
|
||||
public registryKeys(keyInfo: IKeyRegistry<A>): void {
|
||||
const keyRegistry = new KeyRegistry<A>(keyInfo);
|
||||
const map = this._zonesMap.get(keyRegistry.zone);
|
||||
const result = this._isRegisteredHotkey(keyRegistry);
|
||||
if (result.isRegistered) {
|
||||
throw new Error(result.message);
|
||||
}
|
||||
if (map) {
|
||||
map.set(keyRegistry.action, keyRegistry);
|
||||
} else {
|
||||
const actionMap = new Map<A, KeyRegistry<A>>();
|
||||
this._zonesMap.set(keyRegistry.zone, actionMap);
|
||||
actionMap.set(keyRegistry.action, keyRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister hotkey from system
|
||||
* @param keyInfo - hotkey registry data
|
||||
*/
|
||||
public unregisterKeys(keyInfo: IKeyRegistry<A>): void {
|
||||
this._zonesMap.get(keyInfo.zone || GLOBAL_ZONE_TOKEN)?.delete(keyInfo.action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk hotkeys registration
|
||||
* @param keysSet - array hotkey registry data
|
||||
* @param provider - handler provider service
|
||||
*/
|
||||
public registryKeysSet(keysSet: IKeyRegistry<A>[]): void {
|
||||
keysSet.forEach((item) => this.registryKeys(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk hotkeys unregister
|
||||
* @param keysSet - array hotkey registry data
|
||||
*/
|
||||
public unregisterKeysSet(keysSet: IKeyRegistry<A>[]): void {
|
||||
keysSet.forEach((item) => this.unregisterKeys(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Found hotkey event by current pressed keys and other events
|
||||
* @param zone - zone for find
|
||||
* @returns hotkey event
|
||||
* @hidden
|
||||
*/
|
||||
public getEventByKeys(zone: string, event: Event, cb: FindKeyCb): IKeyboardEvent<A> | undefined {
|
||||
const [action, inZone] = this._findHotkeyAction(zone, cb);
|
||||
if (action) {
|
||||
return {
|
||||
action,
|
||||
keys: [...this._currentDownKeys],
|
||||
zone: inZone,
|
||||
triggeringEvent: event,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle key press event and try found registered hotkey event
|
||||
* @param zone - the zone from which the event came
|
||||
* @returns found hotkeys event (if found)
|
||||
*/
|
||||
public handleKeyPressing(e: KeyboardEvent, zone: string = GLOBAL_ZONE_TOKEN): IKeyboardEvent<A> | undefined {
|
||||
if (this._isPressedKey(e.keyCode)) {
|
||||
return;
|
||||
}
|
||||
this._currentDownKeys.push(Key[Key[e.keyCode]]);
|
||||
const event = this.getEventByKeys(zone, e, (k, m, mouseKeys) => this._isCurrentKeySet(k) && !(mouseKeys && mouseKeys?.length) && !m);
|
||||
this._notify(e, event);
|
||||
return event;
|
||||
}
|
||||
|
||||
private _notify(e: Event, event: IKeyboardEvent<A>): void {
|
||||
if (event && !this.ignore) {
|
||||
e.preventDefault();
|
||||
this._events.next(event);
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove key from list current down keys */
|
||||
public handleKeyUp(e: KeyboardEvent): void {
|
||||
this._currentDownKeys = this._currentDownKeys.filter((key) => key !== Key[Key[e.keyCode]]);
|
||||
if ((e as any).key === "Meta") {
|
||||
this.clearCurrentDownKeys();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle wheel event and try found registered hotkey event
|
||||
* @param zone - the zone from which the event came
|
||||
* @returns found hotkeys event (if found)
|
||||
*/
|
||||
public handleWheel(e: WheelEvent, zone: string = GLOBAL_ZONE_TOKEN): IKeyboardEvent<A> {
|
||||
let event: IKeyboardEvent<A>;
|
||||
if (e.deltaY < 0) {
|
||||
event = this.getEventByKeys(
|
||||
zone,
|
||||
e,
|
||||
(keys, mouseEvents, mouseKeys) => this._isCurrentKeySet(keys) && this._isCurMouseKeySet(mouseKeys) && mouseEvents === "wheelup",
|
||||
);
|
||||
} else {
|
||||
event = this.getEventByKeys(
|
||||
zone,
|
||||
e,
|
||||
(keys, mouseEvents, mouseKeys) => this._isCurrentKeySet(keys) && this._isCurMouseKeySet(mouseKeys) && mouseEvents === "wheeldown",
|
||||
);
|
||||
}
|
||||
this._notify(e, event);
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle click event and try found registered hotkey event
|
||||
* @param zone - the zone from which the event came
|
||||
* @returns found hotkeys event (if found)
|
||||
*/
|
||||
public handleClick(e: MouseEvent, zone: string = GLOBAL_ZONE_TOKEN): IKeyboardEvent<A> {
|
||||
const event = this.getEventByKeys(zone, e, (keys, mouseEvent) => this._isCurrentKeySet(keys) && mouseEvent === "click");
|
||||
this._notify(e, event);
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle double click event and try found registered hotkey event
|
||||
* @param zone - the zone from which the event came
|
||||
* @returns found hotkeys event (if found)
|
||||
*/
|
||||
public handleDbClick(e: MouseEvent, zone: string = GLOBAL_ZONE_TOKEN): IKeyboardEvent<A> {
|
||||
const event = this.getEventByKeys(
|
||||
zone,
|
||||
e,
|
||||
(keys, mouseEvent, mouseKeys) => this._isCurrentKeySet(keys) && this._isCurMouseKeySet(mouseKeys) && mouseEvent === "dbclick",
|
||||
);
|
||||
this._notify(e, event);
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle mouse down event and try found registered hotkey event
|
||||
* @param zone - the zone from which the event came
|
||||
* @returns found hotkeys event (if found)
|
||||
*/
|
||||
public handleMouseDown(e: MouseEvent, zone: string = GLOBAL_ZONE_TOKEN): IKeyboardEvent<A> {
|
||||
this._currentMouseDownKeys = new Set([]);
|
||||
// * See: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
|
||||
[
|
||||
[1, MouseKey.LMB],
|
||||
[2, MouseKey.RMB],
|
||||
[4, MouseKey.MMB],
|
||||
[8, MouseKey.BMB],
|
||||
[16, MouseKey.FMB],
|
||||
].forEach(([v, b]) => {
|
||||
if (e.buttons >= v) {
|
||||
this._currentMouseDownKeys.add(b);
|
||||
}
|
||||
});
|
||||
const event = this.getEventByKeys(
|
||||
zone,
|
||||
e,
|
||||
(keys, mouseEvent, mouseKeys) => this._isCurrentKeySet(keys) && this._isCurMouseKeySet(mouseKeys) && !mouseEvent,
|
||||
);
|
||||
this._notify(e, event);
|
||||
return event;
|
||||
}
|
||||
|
||||
/** Remove key from list current mouse down keys */
|
||||
public handleMouseUp(e: MouseEvent): void {
|
||||
this._currentMouseDownKeys.delete(e.button);
|
||||
}
|
||||
|
||||
private _handleMove(e: MouseEvent, zone: string = GLOBAL_ZONE_TOKEN) {
|
||||
const event = this.getEventByKeys(zone, e, (keys, mouseEvent) => this._isCurrentKeySet(keys) && mouseEvent === "mousemove");
|
||||
this._notify(e, event);
|
||||
}
|
||||
|
||||
private _isPressedKey(keyCode: number): boolean {
|
||||
return this._currentDownKeys.includes(keyCode);
|
||||
}
|
||||
|
||||
private _findHotkeyAction(zone: string, cb: FindKeyCb): [A | undefined, string] {
|
||||
const foundAction = this._findAction(zone, cb);
|
||||
return foundAction ? [foundAction, zone] : [this._findAction(GLOBAL_ZONE_TOKEN, cb), GLOBAL_ZONE_TOKEN];
|
||||
}
|
||||
|
||||
private _isCurrentKeySet(keys: Key[][]): boolean {
|
||||
return correspondsToKeySet(this._currentDownKeys, keys);
|
||||
}
|
||||
|
||||
private _isCurMouseKeySet(mouseKeys: MouseKey[]): boolean {
|
||||
if (!mouseKeys && this._currentMouseDownKeys.size === 0) {
|
||||
return true;
|
||||
}
|
||||
if (!mouseKeys || mouseKeys?.length !== this._currentMouseDownKeys.size) {
|
||||
return false;
|
||||
}
|
||||
return mouseKeys.every((mk) => this._currentMouseDownKeys.has(mk));
|
||||
}
|
||||
|
||||
private _findAction(zone: string, cb: FindKeyCb): A | undefined {
|
||||
let foundAction: A | undefined;
|
||||
this._zonesMap.get(zone).forEach(({ mouseEvents, action, keys, mouseKeys }) => {
|
||||
if (cb(keys, mouseEvents, mouseKeys)) {
|
||||
foundAction = action;
|
||||
}
|
||||
});
|
||||
return foundAction;
|
||||
}
|
||||
|
||||
/** Clear current down keyboard keys */
|
||||
public clearCurrentDownKeys(): void {
|
||||
this._currentDownKeys = [];
|
||||
}
|
||||
|
||||
/** Allows you to check whether a hotkey or action is registered or not */
|
||||
public isRegisteredHotkey(data: IKeyRegistry<A>): boolean {
|
||||
const result = this._isRegisteredHotkey(new KeyRegistry<A>(data));
|
||||
return result.isRegistered;
|
||||
}
|
||||
|
||||
private _isRegisteredHotkey(data: KeyRegistry<A>): IRegistrationCheckResult {
|
||||
const actionsMap = this._zonesMap.get(data.zone);
|
||||
if (actionsMap == null) return { isRegistered: false };
|
||||
if (actionsMap.get(data.action)) {
|
||||
return { isRegistered: true, message: actionExistError(data.action) };
|
||||
}
|
||||
for (const registry of actionsMap.values()) {
|
||||
const someHotkeyEqual = registry.keys.some((existKeySet) => data.keys.some((keySet) => arraysIsEqual(keySet, existKeySet)));
|
||||
const mouseKeysEqual = arraysIsEqual(data.mouseKeys, registry.mouseKeys);
|
||||
const mouseEventEqual = data.mouseEvents === registry.mouseEvents;
|
||||
if (someHotkeyEqual && mouseKeysEqual && mouseEventEqual) {
|
||||
return { isRegistered: true, message: hotkeyExistError(data, registry) };
|
||||
}
|
||||
}
|
||||
return { isRegistered: false };
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
this._isDestroyed = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export * from "./hotkey-manager";
|
||||
export * from "./utils";
|
||||
export * from "./functions";
|
||||
export * from "./interfaces";
|
||||
export * from "./constants";
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import { Key } from "../constants/key";
|
||||
|
||||
/** Describe the mouse events */
|
||||
export type TMouseEvent = "click" | "dbclick" | "mousemove" | "wheelup" | "wheeldown";
|
||||
// "mouseup" | "mousedown"
|
||||
|
||||
/** Interface for describe hotkey */
|
||||
export interface IKeyRegistry<A = string> {
|
||||
/** Type of mouse event */
|
||||
mouseEvents?: TMouseEvent;
|
||||
/** List of mouse keys. */
|
||||
mouseKeys?: MouseKey[];
|
||||
/** Action identifier */
|
||||
action: A;
|
||||
/** Label for hotkey */
|
||||
label?: string;
|
||||
/** List of hotkeys */
|
||||
keys: Key[][];
|
||||
/** Zone where hotkeys works */
|
||||
zone?: string;
|
||||
}
|
||||
|
||||
/** Describe keyboard event */
|
||||
export interface IKeyboardEvent<A = string, P = any> {
|
||||
/** Pressed keys */
|
||||
keys: Key[];
|
||||
/** Action identifier */
|
||||
action: A;
|
||||
/** Keyboard zone */
|
||||
zone: string | "GLOBAL";
|
||||
/** Event which provoked actuation of hotkey event */
|
||||
triggeringEvent: Event;
|
||||
/** Event payload. Can be any data */
|
||||
payload?: P;
|
||||
}
|
||||
|
||||
/** Describe types of mouse keys */
|
||||
export enum MouseKey {
|
||||
LMB = 0,
|
||||
MMB = 1,
|
||||
RMB = 2,
|
||||
FMB = 3,
|
||||
BMB = 4,
|
||||
}
|
||||
|
||||
/** Available types for actions */
|
||||
export type Action = string | number;
|
||||
|
||||
/** Function type for check is the hotkey suitable or not */
|
||||
export type FindKeyCb = (keys: Key[][], mouseEvents: TMouseEvent, mouseKeys: MouseKey[]) => boolean;
|
||||
|
||||
/** Description keyboard key label */
|
||||
export interface IKeyLabel {
|
||||
/** Key code */
|
||||
code: number;
|
||||
/** Label for key */
|
||||
label: string;
|
||||
/** Alternate label for key */
|
||||
altLabel?: string | null;
|
||||
}
|
||||
|
||||
/** Describe OS types */
|
||||
export enum OPERATING_SYSTEM {
|
||||
WINDOWS,
|
||||
MAC_OS,
|
||||
IOS,
|
||||
OTHER,
|
||||
}
|
||||
|
||||
/** Mac OS key codes */
|
||||
export enum MAC_SPECIAL_KEYS {
|
||||
/** 91 - key code for CmdLeft on macOS */
|
||||
CmdLeft = 91,
|
||||
/** 93 - key code for CmdRight on macOS */
|
||||
CmdRight = 93,
|
||||
/** 8 - key code for Backspace on macOS */
|
||||
Backspace = 8,
|
||||
/** 18 - key code for Option on macOS */
|
||||
Option = 18,
|
||||
}
|
||||
|
||||
/** Describes the result of registration checking */
|
||||
export interface IRegistrationCheckResult {
|
||||
/** `true` if action or hotkey is registered */
|
||||
isRegistered: boolean;
|
||||
/** Describes detail of checking */
|
||||
message?: string;
|
||||
}
|
||||
28
lib/src/models/key-registry.ts
Normal file
28
lib/src/models/key-registry.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { GLOBAL_ZONE_TOKEN } from "../constants";
|
||||
import { Key } from "../constants/key";
|
||||
import { IKeyRegistry, MouseKey, TMouseEvent } from "../interfaces";
|
||||
|
||||
/** Describe data of hotkey */
|
||||
export class KeyRegistry<T = string> implements IKeyRegistry<T> {
|
||||
/** Type of mouse event */
|
||||
mouseEvents: TMouseEvent;
|
||||
/** List of mouse keys. */
|
||||
mouseKeys: MouseKey[];
|
||||
/** Action identifier */
|
||||
action: T;
|
||||
/** Label for hotkey */
|
||||
label: string;
|
||||
/** List of hotkeys */
|
||||
keys: Key[][];
|
||||
/** Zone where hotkeys works */
|
||||
zone: string;
|
||||
|
||||
constructor(keyRegistry: IKeyRegistry<T>) {
|
||||
this.mouseEvents = keyRegistry.mouseEvents;
|
||||
this.mouseKeys = keyRegistry.mouseKeys ?? [];
|
||||
this.action = keyRegistry.action;
|
||||
this.keys = keyRegistry.keys;
|
||||
this.label = keyRegistry.label;
|
||||
this.zone = keyRegistry.zone ?? GLOBAL_ZONE_TOKEN;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
{
|
||||
"name": "@gxc-solutions/lib",
|
||||
"version": "0.0.1",
|
||||
"name": "@gxc-solutions/hotkeys",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"author": "GXC Solutions",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.gxc-solutions.ru"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@gxc-solutions/lett-js": "1.0.0",
|
||||
"rxjs": "^7.8.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
3
lib/src/utils/README.MD
Normal file
3
lib/src/utils/README.MD
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Описание
|
||||
|
||||
Эта директория предназначена для **непубличных** функций, т.е функций используемых внутри пакета.
|
||||
31
lib/src/utils/index.spec.ts
Normal file
31
lib/src/utils/index.spec.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { getMacKeys } from ".";
|
||||
import { Key } from "../constants/key";
|
||||
import { MAC_SPECIAL_KEYS } from "../interfaces";
|
||||
|
||||
describe("getMacKeys", () => {
|
||||
it("Correct 'CTRL' key transform", () => {
|
||||
const result = getMacKeys([[Key.Ctrl, Key.A]]);
|
||||
expect(result).toEqual([[MAC_SPECIAL_KEYS.CmdLeft as number, Key.A]]);
|
||||
});
|
||||
|
||||
it("Correct 'DELETE' key transform", () => {
|
||||
const result = getMacKeys([[Key.Delete, Key.A]]);
|
||||
expect(result).toEqual([[MAC_SPECIAL_KEYS.Backspace as number, Key.A]]);
|
||||
});
|
||||
|
||||
it("Correct 'ALT' key transform", () => {
|
||||
const result = getMacKeys([[Key.Alt, Key.A]]);
|
||||
expect(result).toEqual([[MAC_SPECIAL_KEYS.Option as number, Key.A]]);
|
||||
});
|
||||
|
||||
it("Correct transform all key set", () => {
|
||||
const result = getMacKeys([
|
||||
[Key.Alt, Key.A],
|
||||
[Key.Alt, Key.A],
|
||||
]);
|
||||
expect(result).toEqual([
|
||||
[MAC_SPECIAL_KEYS.Option as number, Key.A],
|
||||
[MAC_SPECIAL_KEYS.Option as number, Key.A],
|
||||
]);
|
||||
});
|
||||
});
|
||||
41
lib/src/utils/index.ts
Normal file
41
lib/src/utils/index.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { Key } from "../constants/key";
|
||||
import { IKeyRegistry, MAC_SPECIAL_KEYS } from "../interfaces";
|
||||
|
||||
/**
|
||||
* Adapt keyboard keys for another platform to Mac OS
|
||||
* @param keys - array describing the hotkey. For example: [Key.Ctrl, Key.A]
|
||||
* @returns keyboard keys adapted to the Mac OS
|
||||
*/
|
||||
export const getMacKeys = (keys: Key[][]): Key[][] =>
|
||||
keys.map((keySet) =>
|
||||
keySet.map((key) => {
|
||||
switch (key) {
|
||||
case Key.Delete:
|
||||
return MAC_SPECIAL_KEYS.Backspace as number;
|
||||
case Key.Ctrl:
|
||||
return MAC_SPECIAL_KEYS.CmdLeft as number;
|
||||
case Key.Alt:
|
||||
return MAC_SPECIAL_KEYS.Option as number;
|
||||
default:
|
||||
return key;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
/** Does the key match the given keys set */
|
||||
export const correspondsToKeySet = (keys: Key[], keySet: Key[][]) => keySet.some((set) => set.every((key, idx) => keys[idx] === key));
|
||||
|
||||
/** Add package name to message */
|
||||
const addPackageName = (message: string) => `[@aurigma/ng-hotkeys] ${message}`;
|
||||
|
||||
/** Create message for error */
|
||||
export const actionExistError = <A>(action: A) =>
|
||||
addPackageName(`Attempt to register a hotkey with the action '${action}'. This action already exists. Call unregisterKeys() first.`);
|
||||
|
||||
/** Create message for error */
|
||||
export const hotkeyExistError = <A>(data: IKeyRegistry<A>, exist: IKeyRegistry<A>) =>
|
||||
addPackageName(
|
||||
`Attempt to register a hotkey ${JSON.stringify(data)} in to zone '${data.zone}'. This hotkey already exists as ${JSON.stringify(
|
||||
exist,
|
||||
)}. Call unregisterKeys() first.`,
|
||||
);
|
||||
28
package-lock.json
generated
28
package-lock.json
generated
|
|
@ -1,13 +1,17 @@
|
|||
{
|
||||
"name": "template-of-lib-repo",
|
||||
"name": "gxc-hotkeys",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "template-of-lib-repo",
|
||||
"name": "gxc-hotkeys",
|
||||
"version": "0.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@gxc-solutions/lett-js": "1.0.0",
|
||||
"rxjs": "^7.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.4",
|
||||
"@eslint/js": "^10.0.1",
|
||||
|
|
@ -691,6 +695,11 @@
|
|||
"node": "^20.19.0 || ^22.13.0 || >=24"
|
||||
}
|
||||
},
|
||||
"node_modules/@gxc-solutions/lett-js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://npm.gxc-solutions.ru/@gxc-solutions/lett-js/-/lett-js-1.0.0.tgz",
|
||||
"integrity": "sha512-9qkFVWS6ZRoMBGe4gPC9eR+6ozxIKFqm0nSbPqWywOzUJNpTQByuHHCtejTyIxrxLqyoASI8quiFtf9/UpWmow=="
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||
|
|
@ -2331,6 +2340,15 @@
|
|||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
|
|
@ -2420,6 +2438,12 @@
|
|||
"typescript": ">=4.8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "template-of-lib-repo",
|
||||
"name": "gxc-hotkeys",
|
||||
"version": "0.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
|
@ -29,5 +29,9 @@
|
|||
"rimraf": "^6.0.1",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@gxc-solutions/lett-js": "1.0.0",
|
||||
"rxjs": "^7.8.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,5 +17,5 @@
|
|||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["./lib/src/**/*"],
|
||||
"exclude": ["src/**/*.test.ts"]
|
||||
"exclude": ["./lib/src/**/*.test.ts", "./lib/src/**/*.spec.ts"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue