@witchcraft/spellcraft 0.0.1
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/README.md +579 -0
- package/dist/core/EmulatedEvent.d.ts +10 -0
- package/dist/core/EmulatedEvent.js +19 -0
- package/dist/core/Emulator.d.ts +74 -0
- package/dist/core/Emulator.js +153 -0
- package/dist/core/ShortcutManagerManager.d.ts +103 -0
- package/dist/core/ShortcutManagerManager.js +267 -0
- package/dist/core/addCommand.d.ts +7 -0
- package/dist/core/addCommand.js +7 -0
- package/dist/core/addKey.d.ts +7 -0
- package/dist/core/addKey.js +7 -0
- package/dist/core/addShortcut.d.ts +7 -0
- package/dist/core/addShortcut.js +7 -0
- package/dist/core/attach.d.ts +10 -0
- package/dist/core/attach.js +13 -0
- package/dist/core/createCommand.d.ts +4 -0
- package/dist/core/createCommand.js +11 -0
- package/dist/core/createCommands.d.ts +11 -0
- package/dist/core/createCommands.js +20 -0
- package/dist/core/createCondition.d.ts +7 -0
- package/dist/core/createCondition.js +11 -0
- package/dist/core/createContext.d.ts +2 -0
- package/dist/core/createContext.js +8 -0
- package/dist/core/createKey.d.ts +10 -0
- package/dist/core/createKey.js +35 -0
- package/dist/core/createKeys.d.ts +5 -0
- package/dist/core/createKeys.js +36 -0
- package/dist/core/createManager.d.ts +81 -0
- package/dist/core/createManager.js +83 -0
- package/dist/core/createManagerEventListeners.d.ts +4 -0
- package/dist/core/createManagerEventListeners.js +130 -0
- package/dist/core/createManagerOptions.d.ts +8 -0
- package/dist/core/createManagerOptions.js +17 -0
- package/dist/core/createShortcut.d.ts +8 -0
- package/dist/core/createShortcut.js +24 -0
- package/dist/core/createShortcuts.d.ts +13 -0
- package/dist/core/createShortcuts.js +20 -0
- package/dist/core/detach.d.ts +10 -0
- package/dist/core/detach.js +6 -0
- package/dist/core/index.d.ts +32 -0
- package/dist/core/index.js +32 -0
- package/dist/core/removeCommand.d.ts +7 -0
- package/dist/core/removeCommand.js +7 -0
- package/dist/core/removeKey.d.ts +7 -0
- package/dist/core/removeKey.js +7 -0
- package/dist/core/removeShortcut.d.ts +7 -0
- package/dist/core/removeShortcut.js +7 -0
- package/dist/core/setCommandProp.d.ts +17 -0
- package/dist/core/setCommandProp.js +96 -0
- package/dist/core/setCommandsProp.d.ts +15 -0
- package/dist/core/setCommandsProp.js +94 -0
- package/dist/core/setKeyProp.d.ts +16 -0
- package/dist/core/setKeyProp.js +47 -0
- package/dist/core/setKeysProp.d.ts +10 -0
- package/dist/core/setKeysProp.js +166 -0
- package/dist/core/setManagerProp.d.ts +34 -0
- package/dist/core/setManagerProp.js +54 -0
- package/dist/core/setShortcutProp.d.ts +9 -0
- package/dist/core/setShortcutProp.js +50 -0
- package/dist/core/setShortcutsProp.d.ts +12 -0
- package/dist/core/setShortcutsProp.js +93 -0
- package/dist/defaults/KeysSorter.d.ts +35 -0
- package/dist/defaults/KeysSorter.js +20 -0
- package/dist/defaults/Stringifier.d.ts +66 -0
- package/dist/defaults/Stringifier.js +119 -0
- package/dist/defaults/defaultConditionEquals.d.ts +19 -0
- package/dist/defaults/defaultConditionEquals.js +5 -0
- package/dist/defaults/defaultManagerCallback.d.ts +7 -0
- package/dist/defaults/defaultManagerCallback.js +5 -0
- package/dist/helpers/KnownError.d.ts +8 -0
- package/dist/helpers/KnownError.js +3 -0
- package/dist/helpers/calculateAndSetPositionAndWidth.d.ts +13 -0
- package/dist/helpers/calculateAndSetPositionAndWidth.js +18 -0
- package/dist/helpers/calculateLayoutSize.d.ts +9 -0
- package/dist/helpers/calculateLayoutSize.js +13 -0
- package/dist/helpers/doesShortcutConflict.d.ts +18 -0
- package/dist/helpers/doesShortcutConflict.js +42 -0
- package/dist/helpers/equalsCommand.d.ts +7 -0
- package/dist/helpers/equalsCommand.js +4 -0
- package/dist/helpers/equalsContext.d.ts +7 -0
- package/dist/helpers/equalsContext.js +19 -0
- package/dist/helpers/equalsShortcut.d.ts +9 -0
- package/dist/helpers/equalsShortcut.js +7 -0
- package/dist/helpers/forceClear.d.ts +12 -0
- package/dist/helpers/forceClear.js +16 -0
- package/dist/helpers/forceUpdateNativeKeysState.d.ts +5 -0
- package/dist/helpers/forceUpdateNativeKeysState.js +4 -0
- package/dist/helpers/generateKeyShortcutMap.d.ts +23 -0
- package/dist/helpers/generateKeyShortcutMap.js +64 -0
- package/dist/helpers/getKeyFromEventCode.d.ts +15 -0
- package/dist/helpers/getKeyFromEventCode.js +36 -0
- package/dist/helpers/getKeyFromIdOrVariant.d.ts +4 -0
- package/dist/helpers/getKeyFromIdOrVariant.js +26 -0
- package/dist/helpers/getKeyboardLayoutMap.d.ts +5 -0
- package/dist/helpers/getKeyboardLayoutMap.js +7 -0
- package/dist/helpers/getLabel.d.ts +9 -0
- package/dist/helpers/getLabel.js +6 -0
- package/dist/helpers/getTriggerableShortcut.d.ts +6 -0
- package/dist/helpers/getTriggerableShortcut.js +25 -0
- package/dist/helpers/index.d.ts +28 -0
- package/dist/helpers/index.js +28 -0
- package/dist/helpers/isValidManager.d.ts +3 -0
- package/dist/helpers/isValidManager.js +20 -0
- package/dist/helpers/isValidShortcut.d.ts +3 -0
- package/dist/helpers/isValidShortcut.js +10 -0
- package/dist/helpers/labelWithEvent.d.ts +13 -0
- package/dist/helpers/labelWithEvent.js +20 -0
- package/dist/helpers/labelWithKeyboardMap.d.ts +15 -0
- package/dist/helpers/labelWithKeyboardMap.js +17 -0
- package/dist/helpers/managerToStorableClone.d.ts +12 -0
- package/dist/helpers/managerToStorableClone.js +13 -0
- package/dist/helpers/onKeyboardLayoutChange.d.ts +10 -0
- package/dist/helpers/onKeyboardLayoutChange.js +7 -0
- package/dist/helpers/safeSetManagerChain.d.ts +20 -0
- package/dist/helpers/safeSetManagerChain.js +37 -0
- package/dist/helpers/shortcutCanExecuteIn.d.ts +4 -0
- package/dist/helpers/shortcutCanExecuteIn.js +9 -0
- package/dist/helpers/shortcutIsTriggerableBy.d.ts +2 -0
- package/dist/helpers/shortcutIsTriggerableBy.js +5 -0
- package/dist/helpers/shortcutSwapChords.d.ts +75 -0
- package/dist/helpers/shortcutSwapChords.js +118 -0
- package/dist/helpers/virtualPress.d.ts +13 -0
- package/dist/helpers/virtualPress.js +15 -0
- package/dist/helpers/virtualRelease.d.ts +5 -0
- package/dist/helpers/virtualRelease.js +15 -0
- package/dist/helpers/virtualToggle.d.ts +7 -0
- package/dist/helpers/virtualToggle.js +16 -0
- package/dist/internal/addToChain.d.ts +3 -0
- package/dist/internal/addToChain.js +27 -0
- package/dist/internal/areValidKeys.d.ts +7 -0
- package/dist/internal/areValidKeys.js +28 -0
- package/dist/internal/areValidVariants.d.ts +4 -0
- package/dist/internal/areValidVariants.js +45 -0
- package/dist/internal/checkTrigger.d.ts +2 -0
- package/dist/internal/checkTrigger.js +47 -0
- package/dist/internal/checkUntrigger.d.ts +2 -0
- package/dist/internal/checkUntrigger.js +18 -0
- package/dist/internal/cloneLastChord.d.ts +4 -0
- package/dist/internal/cloneLastChord.js +5 -0
- package/dist/internal/containsPossibleToggleChords.d.ts +13 -0
- package/dist/internal/containsPossibleToggleChords.js +65 -0
- package/dist/internal/errorTextAdd.d.ts +1 -0
- package/dist/internal/errorTextAdd.js +11 -0
- package/dist/internal/errorTextInUse.d.ts +1 -0
- package/dist/internal/errorTextInUse.js +8 -0
- package/dist/internal/errorTextRemove.d.ts +1 -0
- package/dist/internal/errorTextRemove.js +8 -0
- package/dist/internal/getModifierState.d.ts +2 -0
- package/dist/internal/getModifierState.js +7 -0
- package/dist/internal/getPressedKeys.d.ts +7 -0
- package/dist/internal/getPressedKeys.js +18 -0
- package/dist/internal/getPressedModifierKeys.d.ts +2 -0
- package/dist/internal/getPressedModifierKeys.js +10 -0
- package/dist/internal/getPressedNonModifierKeys.d.ts +7 -0
- package/dist/internal/getPressedNonModifierKeys.js +11 -0
- package/dist/internal/inChain.d.ts +5 -0
- package/dist/internal/inChain.js +14 -0
- package/dist/internal/isValidChain.d.ts +10 -0
- package/dist/internal/isValidChain.js +22 -0
- package/dist/internal/isValidChord.d.ts +11 -0
- package/dist/internal/isValidChord.js +59 -0
- package/dist/internal/isValidCommand.d.ts +12 -0
- package/dist/internal/isValidCommand.js +20 -0
- package/dist/internal/keyOrder.d.ts +6 -0
- package/dist/internal/keyOrder.js +14 -0
- package/dist/internal/removeFromChain.d.ts +3 -0
- package/dist/internal/removeFromChain.js +32 -0
- package/dist/internal/safeSetEmulatedToggleState.d.ts +4 -0
- package/dist/internal/safeSetEmulatedToggleState.js +13 -0
- package/dist/internal/setKeysState.d.ts +8 -0
- package/dist/internal/setKeysState.js +42 -0
- package/dist/internal/updateNativeKeysState.d.ts +14 -0
- package/dist/internal/updateNativeKeysState.js +58 -0
- package/dist/layouts/createLayout.d.ts +25 -0
- package/dist/layouts/createLayout.js +221 -0
- package/dist/module.d.mts +13 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +40 -0
- package/dist/runtime/composables/useLabeledByKeyboardLayoutMap.d.ts +9 -0
- package/dist/runtime/composables/useLabeledByKeyboardLayoutMap.js +19 -0
- package/dist/runtime/composables/usePointerCoords.d.ts +32 -0
- package/dist/runtime/composables/usePointerCoords.js +17 -0
- package/dist/runtime/composables/useShortcutManagerContextCount.d.ts +14 -0
- package/dist/runtime/composables/useShortcutManagerContextCount.js +61 -0
- package/dist/runtime/composables/useShortcutManagerKeysLayout.d.ts +18 -0
- package/dist/runtime/composables/useShortcutManagerKeysLayout.js +22 -0
- package/dist/runtime/composables/useShortcutManagerVirtualPress.d.ts +6 -0
- package/dist/runtime/composables/useShortcutManagerVirtualPress.js +24 -0
- package/dist/runtime/types.d.ts +10 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime/utils/shortcutToId.d.ts +5 -0
- package/dist/runtime/utils/shortcutToId.js +6 -0
- package/dist/types/commands.d.ts +113 -0
- package/dist/types/commands.js +0 -0
- package/dist/types/condition.d.ts +29 -0
- package/dist/types/condition.js +0 -0
- package/dist/types/context.d.ts +18 -0
- package/dist/types/context.js +0 -0
- package/dist/types/enums.d.ts +186 -0
- package/dist/types/enums.js +70 -0
- package/dist/types/general.d.ts +92 -0
- package/dist/types/general.js +0 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.js +8 -0
- package/dist/types/keys.d.ts +332 -0
- package/dist/types/keys.js +0 -0
- package/dist/types/manager.d.ts +249 -0
- package/dist/types/manager.js +0 -0
- package/dist/types/plugins.d.ts +1 -0
- package/dist/types/plugins.js +0 -0
- package/dist/types/shortcuts.d.ts +144 -0
- package/dist/types/shortcuts.js +0 -0
- package/dist/types/utils.d.ts +1 -0
- package/dist/types/utils.js +0 -0
- package/dist/types.d.mts +3 -0
- package/dist/utils/chainContainsSubset.d.ts +27 -0
- package/dist/utils/chainContainsSubset.js +45 -0
- package/dist/utils/cloneChain.d.ts +2 -0
- package/dist/utils/cloneChain.js +11 -0
- package/dist/utils/cloneKey.d.ts +3 -0
- package/dist/utils/cloneKey.js +26 -0
- package/dist/utils/containsKey.d.ts +7 -0
- package/dist/utils/containsKey.js +4 -0
- package/dist/utils/dedupeKeys.d.ts +9 -0
- package/dist/utils/dedupeKeys.js +9 -0
- package/dist/utils/equalsKey.d.ts +12 -0
- package/dist/utils/equalsKey.js +13 -0
- package/dist/utils/equalsKeys.d.ts +24 -0
- package/dist/utils/equalsKeys.js +15 -0
- package/dist/utils/index.d.ts +14 -0
- package/dist/utils/index.js +14 -0
- package/dist/utils/isAnyKey.d.ts +5 -0
- package/dist/utils/isAnyKey.js +5 -0
- package/dist/utils/isMouseKey.d.ts +5 -0
- package/dist/utils/isMouseKey.js +20 -0
- package/dist/utils/isNormalKey.d.ts +5 -0
- package/dist/utils/isNormalKey.js +5 -0
- package/dist/utils/isTriggerKey.d.ts +5 -0
- package/dist/utils/isTriggerKey.js +3 -0
- package/dist/utils/isWheelKey.d.ts +5 -0
- package/dist/utils/isWheelKey.js +11 -0
- package/dist/utils/mapKeys.d.ts +8 -0
- package/dist/utils/mapKeys.js +5 -0
- package/dist/utils/removeKeys.d.ts +7 -0
- package/dist/utils/removeKeys.js +4 -0
- package/package.json +156 -0
- package/src/core/EmulatedEvent.ts +29 -0
- package/src/core/Emulator.ts +185 -0
- package/src/core/ShortcutManagerManager.ts +380 -0
- package/src/core/addCommand.ts +24 -0
- package/src/core/addKey.ts +25 -0
- package/src/core/addShortcut.ts +24 -0
- package/src/core/attach.ts +27 -0
- package/src/core/createCommand.ts +24 -0
- package/src/core/createCommands.ts +45 -0
- package/src/core/createCondition.ts +21 -0
- package/src/core/createContext.ts +14 -0
- package/src/core/createKey.ts +59 -0
- package/src/core/createKeys.ts +68 -0
- package/src/core/createManager.ts +209 -0
- package/src/core/createManagerEventListeners.ts +139 -0
- package/src/core/createManagerOptions.ts +29 -0
- package/src/core/createShortcut.ts +49 -0
- package/src/core/createShortcuts.ts +51 -0
- package/src/core/detach.ts +21 -0
- package/src/core/index.ts +35 -0
- package/src/core/removeCommand.ts +25 -0
- package/src/core/removeKey.ts +25 -0
- package/src/core/removeShortcut.ts +24 -0
- package/src/core/setCommandProp.ts +140 -0
- package/src/core/setCommandsProp.ts +128 -0
- package/src/core/setKeyProp.ts +80 -0
- package/src/core/setKeysProp.ts +205 -0
- package/src/core/setManagerProp.ts +111 -0
- package/src/core/setShortcutProp.ts +89 -0
- package/src/core/setShortcutsProp.ts +124 -0
- package/src/defaults/KeysSorter.ts +55 -0
- package/src/defaults/Stringifier.ts +234 -0
- package/src/defaults/defaultConditionEquals.ts +29 -0
- package/src/defaults/defaultManagerCallback.ts +14 -0
- package/src/helpers/KnownError.ts +13 -0
- package/src/helpers/calculateAndSetPositionAndWidth.ts +30 -0
- package/src/helpers/calculateLayoutSize.ts +22 -0
- package/src/helpers/doesShortcutConflict.ts +72 -0
- package/src/helpers/equalsCommand.ts +18 -0
- package/src/helpers/equalsContext.ts +29 -0
- package/src/helpers/equalsShortcut.ts +34 -0
- package/src/helpers/forceClear.ts +31 -0
- package/src/helpers/forceUpdateNativeKeysState.ts +9 -0
- package/src/helpers/generateKeyShortcutMap.ts +113 -0
- package/src/helpers/getKeyFromEventCode.ts +67 -0
- package/src/helpers/getKeyFromIdOrVariant.ts +33 -0
- package/src/helpers/getKeyboardLayoutMap.ts +13 -0
- package/src/helpers/getLabel.ts +15 -0
- package/src/helpers/getTriggerableShortcut.ts +37 -0
- package/src/helpers/index.ts +30 -0
- package/src/helpers/isValidManager.ts +29 -0
- package/src/helpers/isValidShortcut.ts +20 -0
- package/src/helpers/labelWithEvent.ts +41 -0
- package/src/helpers/labelWithKeyboardMap.ts +37 -0
- package/src/helpers/managerToStorableClone.ts +26 -0
- package/src/helpers/onKeyboardLayoutChange.ts +17 -0
- package/src/helpers/safeSetManagerChain.ts +66 -0
- package/src/helpers/shortcutCanExecuteIn.ts +24 -0
- package/src/helpers/shortcutIsTriggerableBy.ts +15 -0
- package/src/helpers/shortcutSwapChords.ts +240 -0
- package/src/helpers/virtualPress.ts +34 -0
- package/src/helpers/virtualRelease.ts +25 -0
- package/src/helpers/virtualToggle.ts +28 -0
- package/src/internal/addToChain.ts +40 -0
- package/src/internal/areValidKeys.ts +40 -0
- package/src/internal/areValidVariants.ts +59 -0
- package/src/internal/checkTrigger.ts +55 -0
- package/src/internal/checkUntrigger.ts +26 -0
- package/src/internal/cloneLastChord.ts +10 -0
- package/src/internal/containsPossibleToggleChords.ts +91 -0
- package/src/internal/errorTextAdd.ts +18 -0
- package/src/internal/errorTextInUse.ts +10 -0
- package/src/internal/errorTextRemove.ts +10 -0
- package/src/internal/getModifierState.ts +15 -0
- package/src/internal/getPressedKeys.ts +26 -0
- package/src/internal/getPressedModifierKeys.ts +14 -0
- package/src/internal/getPressedNonModifierKeys.ts +19 -0
- package/src/internal/inChain.ts +25 -0
- package/src/internal/isValidChain.ts +42 -0
- package/src/internal/isValidChord.ts +87 -0
- package/src/internal/isValidCommand.ts +35 -0
- package/src/internal/keyOrder.ts +24 -0
- package/src/internal/removeFromChain.ts +46 -0
- package/src/internal/safeSetEmulatedToggleState.ts +23 -0
- package/src/internal/setKeysState.ts +71 -0
- package/src/internal/updateNativeKeysState.ts +84 -0
- package/src/layouts/createLayout.ts +328 -0
- package/src/module.ts +62 -0
- package/src/runtime/composables/useLabeledByKeyboardLayoutMap.ts +28 -0
- package/src/runtime/composables/usePointerCoords.ts +40 -0
- package/src/runtime/composables/useShortcutManagerContextCount.ts +81 -0
- package/src/runtime/composables/useShortcutManagerKeysLayout.ts +42 -0
- package/src/runtime/composables/useShortcutManagerVirtualPress.ts +30 -0
- package/src/runtime/types.ts +10 -0
- package/src/runtime/utils/shortcutToId.ts +14 -0
- package/src/types/commands.ts +148 -0
- package/src/types/condition.ts +35 -0
- package/src/types/context.ts +19 -0
- package/src/types/enums.ts +236 -0
- package/src/types/general.ts +117 -0
- package/src/types/index.ts +10 -0
- package/src/types/keys.ts +385 -0
- package/src/types/manager.ts +374 -0
- package/src/types/plugins.ts +32 -0
- package/src/types/shortcuts.ts +204 -0
- package/src/types/utils.ts +40 -0
- package/src/utils/chainContainsSubset.ts +97 -0
- package/src/utils/cloneChain.ts +13 -0
- package/src/utils/cloneKey.ts +33 -0
- package/src/utils/containsKey.ts +17 -0
- package/src/utils/dedupeKeys.ts +23 -0
- package/src/utils/equalsKey.ts +32 -0
- package/src/utils/equalsKeys.ts +50 -0
- package/src/utils/index.ts +16 -0
- package/src/utils/isAnyKey.ts +12 -0
- package/src/utils/isMouseKey.ts +27 -0
- package/src/utils/isNormalKey.ts +15 -0
- package/src/utils/isTriggerKey.ts +7 -0
- package/src/utils/isWheelKey.ts +18 -0
- package/src/utils/mapKeys.ts +21 -0
- package/src/utils/removeKeys.ts +16 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Ok, type Result } from "@alanscodelog/utils/Result"
|
|
2
|
+
|
|
3
|
+
import { addKey } from "./addKey.js"
|
|
4
|
+
|
|
5
|
+
import { defaultStringifier } from "../defaults/Stringifier.js"
|
|
6
|
+
import { calculateLayoutSize } from "../helpers/calculateLayoutSize.js"
|
|
7
|
+
import type { Key, Keys, MultipleErrors, PickManager, SHORTCUT_ERROR } from "../types/index.js"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export function createKeys<
|
|
11
|
+
TKey extends
|
|
12
|
+
Key = Key,
|
|
13
|
+
TKeys extends
|
|
14
|
+
(TKey)[] = (TKey)[],
|
|
15
|
+
TEntries extends
|
|
16
|
+
Record<TKeys[number]["id"], Key> = Record<TKeys[number]["id"], Key>,
|
|
17
|
+
// causing issues
|
|
18
|
+
// RecordFromArray<TKeys, "id", Key> =
|
|
19
|
+
// RecordFromArray<TKeys, "id", Key>,
|
|
20
|
+
TCheck extends boolean | "only" = true
|
|
21
|
+
>(
|
|
22
|
+
entries: TKeys,
|
|
23
|
+
manager: PickManager<"options", "stringifier"> = {
|
|
24
|
+
options: { stringifier: defaultStringifier }
|
|
25
|
+
},
|
|
26
|
+
rawKeys: Partial<Pick<Keys, "autoManageLayout" | "layout">> = {} as any,
|
|
27
|
+
{
|
|
28
|
+
check = true as TCheck
|
|
29
|
+
}: { check?: TCheck } = {}
|
|
30
|
+
): Result<
|
|
31
|
+
TCheck extends "only" ? true : Keys<TEntries>,
|
|
32
|
+
MultipleErrors<
|
|
33
|
+
typeof SHORTCUT_ERROR.DUPLICATE_KEY
|
|
34
|
+
>
|
|
35
|
+
> {
|
|
36
|
+
const keysList = entries
|
|
37
|
+
const keys: Keys = {
|
|
38
|
+
type: "keys",
|
|
39
|
+
// prevent multiple calculations when initially adding keys
|
|
40
|
+
autoManageLayout: false,
|
|
41
|
+
...rawKeys,
|
|
42
|
+
layout: { y: 0, x: 0, ...(rawKeys.layout ?? {}) },
|
|
43
|
+
entries: {},
|
|
44
|
+
nativeToggleKeys: [],
|
|
45
|
+
nativeModifierKeys: [],
|
|
46
|
+
variants: {},
|
|
47
|
+
toggles: {}
|
|
48
|
+
}
|
|
49
|
+
// clone anything addKey might touch, see below
|
|
50
|
+
const managerClone = { ...manager, keys }
|
|
51
|
+
if (check) {
|
|
52
|
+
for (const key of keysList) {
|
|
53
|
+
// this one is a bit weird
|
|
54
|
+
// we don't use check = "only" because we actually want keys.entries to be modified to error on duplicate keys
|
|
55
|
+
// the entire keys object isn't the user's rawKey copy anymore anyways
|
|
56
|
+
const res = addKey(key, managerClone)
|
|
57
|
+
if (res.isError) return res as any
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (check === "only") return Ok(true) satisfies Result<true, never> as any
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if (rawKeys?.autoManageLayout) {
|
|
64
|
+
keys.autoManageLayout = true
|
|
65
|
+
keys.layout = calculateLayoutSize(keys)
|
|
66
|
+
}
|
|
67
|
+
return Ok(keys) satisfies Result<Keys, never> as any
|
|
68
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { castType } from "@alanscodelog/utils/castType"
|
|
2
|
+
import { isArray } from "@alanscodelog/utils/isArray"
|
|
3
|
+
import { Ok, type Result } from "@alanscodelog/utils/Result"
|
|
4
|
+
import type { RecordFromArray } from "@alanscodelog/utils/types"
|
|
5
|
+
|
|
6
|
+
import { createCommand } from "./createCommand.js"
|
|
7
|
+
import { createCommands } from "./createCommands.js"
|
|
8
|
+
import { createKey } from "./createKey.js"
|
|
9
|
+
import { createKeys } from "./createKeys.js"
|
|
10
|
+
import { createManagerOptions } from "./createManagerOptions.js"
|
|
11
|
+
import { createShortcut } from "./createShortcut.js"
|
|
12
|
+
import { createShortcuts } from "./createShortcuts.js"
|
|
13
|
+
|
|
14
|
+
import type { CanHookErrors, CanHooks, Command, Commands, CommandsSetEntries, Context, Hooks, Key, Keys, KeysSetEntries, Manager, ManagerListener, MultipleErrors, RawCommand, RawKey, RawShortcut, Shortcut, SHORTCUT_ERROR, Shortcuts, ShortcutsSetEntries } from "../types/index.js"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a manager which can track key states, layouts, and trigger shortcuts. Basically the brains of the operation.
|
|
18
|
+
*
|
|
19
|
+
* First, all the elements of a manager need to be created.
|
|
20
|
+
* Then you can create the listeners for the manager with {@link createManagerEventListeners}.
|
|
21
|
+
*
|
|
22
|
+
* Then these listeners can be attached/removed from elements (or the {@link Emulator})
|
|
23
|
+
*
|
|
24
|
+
* You could make several managers for different areas of your application or use single manager and different contexts to differ between them.
|
|
25
|
+
*
|
|
26
|
+
* It is easiest to build a manager like so, but the manager also takes in full {@link Keys}/{@link Commands}/{@link Shortcuts} instances, though it's a bit harder to build those first then pass to the manager:
|
|
27
|
+
* ```ts
|
|
28
|
+
*
|
|
29
|
+
* const manager = createManager(
|
|
30
|
+
* {
|
|
31
|
+
* keys: [
|
|
32
|
+
* createKey("a", ),
|
|
33
|
+
* // or using a raw key
|
|
34
|
+
* {id: "b"}
|
|
35
|
+
* ],
|
|
36
|
+
* commands: [
|
|
37
|
+
* createCommand("a"),
|
|
38
|
+
* {name: "b", execute() {....}}
|
|
39
|
+
* ],
|
|
40
|
+
* shortcuts: [
|
|
41
|
+
* { chain: [["a"]], command: "a" }
|
|
42
|
+
* ]
|
|
43
|
+
* context: createContext({...}),
|
|
44
|
+
* options: {
|
|
45
|
+
* // required
|
|
46
|
+
* evaluateCondition() {
|
|
47
|
+
* ...
|
|
48
|
+
* }
|
|
49
|
+
* }
|
|
50
|
+
* }, {
|
|
51
|
+
* // if constructing from raw entries like above, createKeys/Shortcuts can take additional options
|
|
52
|
+
* ...,
|
|
53
|
+
* keys: {...},
|
|
54
|
+
* shortcuts:{...}
|
|
55
|
+
* }).unwrap()
|
|
56
|
+
*
|
|
57
|
+
* const listeners = createManagerEventListeners(manager)
|
|
58
|
+
* attach(document, listeners)
|
|
59
|
+
* // to remove:
|
|
60
|
+
* dettach(document, listeners)
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* You will then not need to do much else. It will take care of setting the pressed state of keys, the state of the current chord chain (see {@link Manager._chain}), finding a matching shortcut if it exists, and triggering it's command.
|
|
64
|
+
*
|
|
65
|
+
* The way this works is that when a key is pressed it's added to the current chord in the chain. If the chain matches a shortcut's chain that can be triggered (it must be enabled, it must have a command and a function to execute, and it's condition and it's command's condition must evaluate to true), the command's execute function is triggered with `isKeydown = true`, see {@link Command.execute}.
|
|
66
|
+
*
|
|
67
|
+
* If there are no shortcuts to trigger but there are "potential shortcuts" that start with the current chain and could trigger and current chord contains any non-modifier keys (see {@link Manager.pressedNonModifierKeys}), an empty chord will be added to the chain on the next key pressed and the process repeats.
|
|
68
|
+
*
|
|
69
|
+
* If there are no shortcuts and no potential shortcuts, the callback will be called with {@link SHORTCUT_ERROR.NO_MATCHING_SHORTCUT} and you will probably want to clear the chain. When the chain is cleared (see {@link Manager._chain}), the manager will not add/remove keys from the chain until all non-modifier keys are unpressed. Pressed state is still set/tracked though.
|
|
70
|
+
*
|
|
71
|
+
* The moment a key is released after a shortcut is triggered, the command's execute function is fired again with `isKeydown = false`.
|
|
72
|
+
*
|
|
73
|
+
* If {@link Manager.options.updateStateOnAllEvents} is not disabled and a mouseeneter listener was created, the manager is able to keep the most accurate state of the modifier keys. See {@link Manager.options.updateStateOnAllEvents} for more info.
|
|
74
|
+
*
|
|
75
|
+
* For a detailed usage example, see the demo.
|
|
76
|
+
*
|
|
77
|
+
* ### Other
|
|
78
|
+
*
|
|
79
|
+
* - If you need to emulate keypresses for testing see {@link Emulator}.
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
export function createManager<
|
|
84
|
+
THooks extends Hooks,
|
|
85
|
+
TKeys extends Keys | RawKey[],
|
|
86
|
+
TShortcuts extends Shortcuts | RawShortcut[],
|
|
87
|
+
TCommands extends Commands | RawCommand[],
|
|
88
|
+
TContext extends Context,
|
|
89
|
+
TListener extends ManagerListener
|
|
90
|
+
>(
|
|
91
|
+
rawManager: {
|
|
92
|
+
name?: string
|
|
93
|
+
options: Partial<Omit<Manager["options"], "evaluateCondition">>
|
|
94
|
+
& Pick<Manager<any, any, any, any, TContext>["options"], "evaluateCondition">
|
|
95
|
+
context?: TContext
|
|
96
|
+
keys?: TKeys
|
|
97
|
+
shortcuts?: TShortcuts
|
|
98
|
+
commands?: TCommands
|
|
99
|
+
hooks?: Partial<THooks>
|
|
100
|
+
listener?: TListener
|
|
101
|
+
},
|
|
102
|
+
additionalOpts: Partial<{
|
|
103
|
+
keys?: Partial<Pick<Keys, "autoManageLayout" | "layout">>
|
|
104
|
+
shortcuts?: Partial<Pick<Shortcuts, "ignoreModifierConflicts" | "ignoreChainConflicts">>
|
|
105
|
+
}
|
|
106
|
+
> = {}
|
|
107
|
+
): Result<
|
|
108
|
+
Manager<
|
|
109
|
+
THooks,
|
|
110
|
+
TKeys extends Keys
|
|
111
|
+
? Extract<TKeys, Keys>
|
|
112
|
+
: TKeys extends RawKey[]
|
|
113
|
+
? Keys<RecordFromArray<TKeys, "id", Key>>
|
|
114
|
+
: never,
|
|
115
|
+
Shortcuts,
|
|
116
|
+
TCommands extends Commands
|
|
117
|
+
? Extract<TCommands, Commands>
|
|
118
|
+
: TCommands extends RawCommand[]
|
|
119
|
+
? Commands<RecordFromArray<TCommands, "name", Command>>
|
|
120
|
+
: never,
|
|
121
|
+
TContext
|
|
122
|
+
>,
|
|
123
|
+
MultipleErrors<
|
|
124
|
+
| CommandsSetEntries["entries@add"]["error"]
|
|
125
|
+
| KeysSetEntries["entries@add"]["error"]
|
|
126
|
+
| ShortcutsSetEntries["entries@add"]["error"]
|
|
127
|
+
| typeof SHORTCUT_ERROR.INVALID_VARIANT
|
|
128
|
+
> | CanHookErrors<THooks extends never ? never : THooks, keyof CanHooks>
|
|
129
|
+
> {
|
|
130
|
+
const options = createManagerOptions(rawManager.options as any)
|
|
131
|
+
const m = { options }
|
|
132
|
+
const state = {
|
|
133
|
+
chain: [],
|
|
134
|
+
isAwaitingKeyup: false,
|
|
135
|
+
isRecording: false,
|
|
136
|
+
untrigger: false,
|
|
137
|
+
nextIsChord: false
|
|
138
|
+
} satisfies Manager["state"]
|
|
139
|
+
|
|
140
|
+
let keys = rawManager.keys
|
|
141
|
+
|
|
142
|
+
if (!keys || isArray(keys)) {
|
|
143
|
+
castType<RawKey[]>(keys)
|
|
144
|
+
const keysList: Key[] = []
|
|
145
|
+
if (keys) {
|
|
146
|
+
for (const key of keys) {
|
|
147
|
+
const res = createKey(key.id, key)
|
|
148
|
+
if (res.isError) return res
|
|
149
|
+
keysList.push(res.value)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const res = createKeys(keysList, m, additionalOpts?.keys)
|
|
153
|
+
if (res.isError) return res
|
|
154
|
+
keys = res.value satisfies Keys as any
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let commands = rawManager.commands
|
|
158
|
+
|
|
159
|
+
if (!commands || isArray(commands)) {
|
|
160
|
+
castType<RawCommand[]>(commands)
|
|
161
|
+
const commandsList: Command[] = []
|
|
162
|
+
if (commands) {
|
|
163
|
+
for (const command of commands) {
|
|
164
|
+
const res = createCommand(command.name, command)
|
|
165
|
+
commandsList.push(res)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const res = createCommands(commandsList, { options })
|
|
170
|
+
if (res.isError) return res as any
|
|
171
|
+
commands = res.value satisfies Commands as any
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let shortcuts = rawManager.shortcuts
|
|
175
|
+
if (!shortcuts || isArray(shortcuts)) {
|
|
176
|
+
castType<RawShortcut[]>(shortcuts)
|
|
177
|
+
const shortcutsList: Shortcut[] = []
|
|
178
|
+
const m2 = { ...m, commands: commands as Commands, keys: keys as Keys }
|
|
179
|
+
if (shortcuts) {
|
|
180
|
+
for (const shortcut of shortcuts) {
|
|
181
|
+
const res = createShortcut(shortcut, m2)
|
|
182
|
+
if (res.isError) return res
|
|
183
|
+
shortcutsList.push(res.value)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const res = createShortcuts(shortcutsList, {
|
|
188
|
+
keys: keys! as Keys,
|
|
189
|
+
commands: commands! as Commands,
|
|
190
|
+
options
|
|
191
|
+
}, additionalOpts?.shortcuts)
|
|
192
|
+
if (res.isError) return res as any
|
|
193
|
+
shortcuts = res.value satisfies Shortcuts as any
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const manager: Manager = {
|
|
197
|
+
...rawManager,
|
|
198
|
+
name: rawManager.name ?? "manager",
|
|
199
|
+
type: "manager",
|
|
200
|
+
keys: keys! as Keys,
|
|
201
|
+
shortcuts: shortcuts! as Shortcuts,
|
|
202
|
+
commands: commands! as Commands,
|
|
203
|
+
options,
|
|
204
|
+
state,
|
|
205
|
+
context: rawManager.context!,
|
|
206
|
+
hooks: rawManager?.hooks as any as THooks
|
|
207
|
+
}
|
|
208
|
+
return Ok(manager) as any
|
|
209
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { getKeyFromEventCode } from "../helpers/getKeyFromEventCode.js"
|
|
2
|
+
import { addToChain } from "../internal/addToChain.js"
|
|
3
|
+
import { removeFromChain } from "../internal/removeFromChain.js"
|
|
4
|
+
import { setKeysState } from "../internal/setKeysState.js"
|
|
5
|
+
import { updateNativeKeysState } from "../internal/updateNativeKeysState.js"
|
|
6
|
+
import type { EventListenerTypes, EventTypes, Manager } from "../types/index.js"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export function createManagerEventListeners<T extends EventTypes, TTypes extends T[]>(
|
|
10
|
+
manager: Manager,
|
|
11
|
+
types: TTypes = ["keydown", "keyup", "keypress", "wheel", "mousedown", "mouseup", "mouseenter"] as TTypes,
|
|
12
|
+
{ debug }: { debug?: true | ((type: EventTypes, e: KeyboardEvent | MouseEvent) => void) } = {}
|
|
13
|
+
): EventListenerTypes<TTypes[number]> {
|
|
14
|
+
// eslint-disable-next-line no-console
|
|
15
|
+
const debugFn = debug === true ? console.log : undefined
|
|
16
|
+
const listeners: Partial<EventListenerTypes<EventTypes>> = {}
|
|
17
|
+
for (const type of types) {
|
|
18
|
+
switch (type) {
|
|
19
|
+
case "keydown": {
|
|
20
|
+
listeners.keydown = (e: KeyboardEvent): void => {
|
|
21
|
+
debugFn?.("keydown", e)
|
|
22
|
+
if (!manager.options.enableListeners) return
|
|
23
|
+
const keyIds = getKeyFromEventCode(e.code, e, manager.keys.entries)
|
|
24
|
+
if (keyIds.isError) {
|
|
25
|
+
manager.options.cb(manager, keyIds.error, e)
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const ids = keyIds.value
|
|
30
|
+
manager.listener?.({ event: e, isKeydown: true, keys: ids, manager })
|
|
31
|
+
setKeysState(ids, manager, true)
|
|
32
|
+
updateNativeKeysState(manager, e, ids)
|
|
33
|
+
const res = addToChain(manager, ids, e)
|
|
34
|
+
if (res.isError) { manager.options.cb(manager, res.error, e) }
|
|
35
|
+
}
|
|
36
|
+
break
|
|
37
|
+
}
|
|
38
|
+
case "keyup": {
|
|
39
|
+
listeners.keyup = (e: KeyboardEvent): void => {
|
|
40
|
+
debugFn?.("keyup", e)
|
|
41
|
+
if (!manager.options.enableListeners) return
|
|
42
|
+
const keyIds = getKeyFromEventCode(e.code, e, manager.keys.entries)
|
|
43
|
+
|
|
44
|
+
if (keyIds.isError) {
|
|
45
|
+
manager.options.cb(manager, keyIds.error, e)
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const ids = keyIds.value
|
|
50
|
+
manager.listener?.({ event: e, isKeydown: false, keys: ids, manager })
|
|
51
|
+
setKeysState(ids, manager, false)
|
|
52
|
+
updateNativeKeysState(manager, e, ids)
|
|
53
|
+
const res = removeFromChain(manager, ids, e)
|
|
54
|
+
if (res.isError) { manager.options.cb(manager, res.error, e) }
|
|
55
|
+
}
|
|
56
|
+
break
|
|
57
|
+
}
|
|
58
|
+
case "wheel": {
|
|
59
|
+
listeners.wheel = (e: WheelEvent): void => {
|
|
60
|
+
debugFn?.("wheel", e)
|
|
61
|
+
if (!manager.options.enableListeners) return
|
|
62
|
+
const dir = e.deltaY < 0 ? "Up" : "Down"
|
|
63
|
+
const code = `Wheel${dir}`
|
|
64
|
+
const keyIds = getKeyFromEventCode(code, e, manager.keys.entries, { pressedState: false })
|
|
65
|
+
|
|
66
|
+
if (keyIds.isError) {
|
|
67
|
+
manager.options.cb(manager, keyIds.error, e)
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
const ids = keyIds.value
|
|
71
|
+
manager.listener?.({ event: e, isKeydown: true, keys: ids, manager })
|
|
72
|
+
setKeysState(ids, manager, true)
|
|
73
|
+
updateNativeKeysState(manager, e, ids)
|
|
74
|
+
addToChain(manager, ids, e)
|
|
75
|
+
manager.listener?.({ event: e, isKeydown: false, keys: ids, manager })
|
|
76
|
+
setKeysState(ids, manager, false)
|
|
77
|
+
const res = removeFromChain(manager, ids, e)
|
|
78
|
+
if (res.isError) { manager.options.cb(manager, res.error, e) }
|
|
79
|
+
}
|
|
80
|
+
break
|
|
81
|
+
}
|
|
82
|
+
case "mousedown": {
|
|
83
|
+
listeners.mousedown = (e: MouseEvent): void => {
|
|
84
|
+
debugFn?.("mousedown", e)
|
|
85
|
+
if (!manager.options.enableListeners) return
|
|
86
|
+
const button = e.button.toString()
|
|
87
|
+
|
|
88
|
+
const keyIds = getKeyFromEventCode(button, e, manager.keys.entries, { pressedState: false })
|
|
89
|
+
if (keyIds.isError) {
|
|
90
|
+
manager.options.cb(manager, keyIds.error, e)
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
const ids = keyIds.value
|
|
94
|
+
manager.listener?.({ event: e, isKeydown: true, keys: ids, manager })
|
|
95
|
+
setKeysState(ids, manager, true)
|
|
96
|
+
|
|
97
|
+
updateNativeKeysState(manager, e, ids)
|
|
98
|
+
const res = addToChain(manager, ids, e)
|
|
99
|
+
if (res.isError) { manager.options.cb(manager, res.error, e) }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
break
|
|
103
|
+
}
|
|
104
|
+
case "mouseup": {
|
|
105
|
+
listeners.mouseup = (e: MouseEvent): void => {
|
|
106
|
+
debugFn?.("mouseup", e)
|
|
107
|
+
if (!manager.options.enableListeners) return
|
|
108
|
+
const button = e.button.toString()
|
|
109
|
+
const keyIds = getKeyFromEventCode(button, e, manager.keys.entries, { pressedState: true })
|
|
110
|
+
|
|
111
|
+
if (keyIds.isError) {
|
|
112
|
+
manager.options.cb(manager, keyIds.error, e)
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
const ids = keyIds.value
|
|
116
|
+
manager.listener?.({ event: e, isKeydown: false, keys: ids, manager })
|
|
117
|
+
setKeysState(ids, manager, false)
|
|
118
|
+
updateNativeKeysState(manager, e, ids)
|
|
119
|
+
const res = removeFromChain(manager, ids, e)
|
|
120
|
+
if (res.isError) { manager.options.cb(manager, res.error, e) }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
break
|
|
124
|
+
}
|
|
125
|
+
case "mouseenter": {
|
|
126
|
+
listeners.mouseenter = (e: MouseEvent): void => {
|
|
127
|
+
debugFn?.("mouseenter", e)
|
|
128
|
+
if (!manager.options.enableListeners) return
|
|
129
|
+
manager.listener?.({ event: e, isKeydown: true, keys: [], manager })
|
|
130
|
+
updateNativeKeysState(manager, e, [])
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
break
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return listeners as EventListenerTypes<EventTypes>
|
|
138
|
+
}
|
|
139
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { createManager } from "./createManager.js"
|
|
2
|
+
|
|
3
|
+
import { defaultConditionEquals } from "../defaults/defaultConditionEquals.js"
|
|
4
|
+
import { defaultManagerCallback } from "../defaults/defaultManagerCallback.js"
|
|
5
|
+
import { defaultSorter } from "../defaults/KeysSorter.js"
|
|
6
|
+
import { defaultStringifier } from "../defaults/Stringifier.js"
|
|
7
|
+
import type { Manager } from "../types/index.js"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Many methods require some of the manager's options, but not the entire manager. Also it's easier to create a manager from scratch by first creating it's options
|
|
12
|
+
*
|
|
13
|
+
* This can be used to create the base manager options.
|
|
14
|
+
*/
|
|
15
|
+
export function createManagerOptions(
|
|
16
|
+
rawOpts: Parameters<typeof createManager>[0]["options"]
|
|
17
|
+
): Manager["options"] {
|
|
18
|
+
const options: Manager["options"] = {
|
|
19
|
+
sorter: defaultSorter,
|
|
20
|
+
stringifier: defaultStringifier,
|
|
21
|
+
conditionEquals: defaultConditionEquals,
|
|
22
|
+
cb: defaultManagerCallback,
|
|
23
|
+
enableShortcuts: true,
|
|
24
|
+
enableListeners: true,
|
|
25
|
+
updateStateOnAllEvents: true,
|
|
26
|
+
...rawOpts
|
|
27
|
+
}
|
|
28
|
+
return options
|
|
29
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Ok, type Result } from "@alanscodelog/utils/Result"
|
|
2
|
+
|
|
3
|
+
import { isValidShortcut } from "../helpers/isValidShortcut.js"
|
|
4
|
+
import type { ChainError, Command, Condition, Manager, MultipleErrors, PickManager, RawShortcut, Shortcut, SHORTCUT_ERROR } from "../types/index.js"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a {@link Shortcut} object from a {@link RawShortcut}.
|
|
9
|
+
*
|
|
10
|
+
* If the raw shortcut has no condition, a new blank empty condition is created. If you will be following the suggestion of not having any conditions equal eachother (see {@link ConditionComparer}), you can fallback to passing the same instance of an empty condition without issues.
|
|
11
|
+
*/
|
|
12
|
+
export function createShortcut<
|
|
13
|
+
TRawCommand extends Command["name"] | Command = Command["name"] | Command,
|
|
14
|
+
TCommand extends TRawCommand extends string ? Command<TRawCommand> : TRawCommand = TRawCommand extends string ? Command<TRawCommand> : TRawCommand,
|
|
15
|
+
TCondition extends Condition = Condition
|
|
16
|
+
|
|
17
|
+
>(
|
|
18
|
+
rawShortcut: RawShortcut<TRawCommand, TCommand, TCondition>,
|
|
19
|
+
manager: Pick<Manager, "keys" | "commands">
|
|
20
|
+
& PickManager<"options", "stringifier" | "sorter">
|
|
21
|
+
): Result<Shortcut<TCommand["name"], TCondition>, MultipleErrors<
|
|
22
|
+
| ChainError
|
|
23
|
+
| typeof SHORTCUT_ERROR.UNKNOWN_COMMAND
|
|
24
|
+
>> {
|
|
25
|
+
const sorter = manager.options.sorter
|
|
26
|
+
|
|
27
|
+
const finalChain = []
|
|
28
|
+
for (const chord of rawShortcut.chain) {
|
|
29
|
+
const stringChord = chord.map(key => typeof key === "object" ? key.id : key)
|
|
30
|
+
sorter.sort(stringChord, manager.keys)
|
|
31
|
+
finalChain.push(stringChord)
|
|
32
|
+
}
|
|
33
|
+
const command = typeof rawShortcut.command === "string" ? rawShortcut.command : rawShortcut.command?.name
|
|
34
|
+
|
|
35
|
+
const shortcut: Shortcut = {
|
|
36
|
+
...rawShortcut as any,
|
|
37
|
+
type: "shortcut",
|
|
38
|
+
enabled: rawShortcut.enabled ?? true,
|
|
39
|
+
command,
|
|
40
|
+
chain: finalChain,
|
|
41
|
+
condition: rawShortcut.condition ?? { type: "condition", text: "" },
|
|
42
|
+
forceUnequal: false
|
|
43
|
+
}
|
|
44
|
+
const res = isValidShortcut(shortcut, manager)
|
|
45
|
+
if (res.isError) return res
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
return Ok(shortcut satisfies Shortcut as any)
|
|
49
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Ok, type Result } from "@alanscodelog/utils/Result"
|
|
2
|
+
|
|
3
|
+
import { addShortcut } from "./addShortcut.js"
|
|
4
|
+
|
|
5
|
+
import type { CanHookErrors, Manager, MultipleErrors, PickManager, Shortcut, Shortcuts, ShortcutsSetEntries } from "../types/index.js"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* # Shortcut
|
|
9
|
+
*
|
|
10
|
+
* Creates a set of shortcuts.
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
export function createShortcuts<
|
|
14
|
+
THooks extends Manager["hooks"],
|
|
15
|
+
TRawShortcuts extends Shortcut[],
|
|
16
|
+
TCheck extends boolean | "only" = true
|
|
17
|
+
>(
|
|
18
|
+
shortcutsList: TRawShortcuts,
|
|
19
|
+
manager: Pick<Manager, "keys" | "commands">
|
|
20
|
+
& PickManager<"options", | "evaluateCondition" | "conditionEquals" | "stringifier" | "sorter">
|
|
21
|
+
& { hooks?: THooks },
|
|
22
|
+
opts?: Partial<Pick<Shortcuts, "ignoreModifierConflicts" | "ignoreChainConflicts">>,
|
|
23
|
+
{
|
|
24
|
+
check = true as TCheck
|
|
25
|
+
}: { check?: boolean | "only" } = {}
|
|
26
|
+
): Result<
|
|
27
|
+
TCheck extends "only" ? true : Shortcuts,
|
|
28
|
+
MultipleErrors<
|
|
29
|
+
ShortcutsSetEntries["entries@add"]["error"]
|
|
30
|
+
> | CanHookErrors<THooks extends never ? never : THooks, "canSetShortcutsProp">
|
|
31
|
+
> {
|
|
32
|
+
const shortcuts: Shortcuts = {
|
|
33
|
+
entries: [],
|
|
34
|
+
ignoreModifierConflicts: opts?.ignoreModifierConflicts ?? false,
|
|
35
|
+
ignoreChainConflicts: opts?.ignoreChainConflicts ?? false
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
const managerClone = { ...manager, shortcuts }
|
|
39
|
+
if (check) {
|
|
40
|
+
for (const shortcut of shortcutsList) {
|
|
41
|
+
// we check all first to avoid erroring mid-way through
|
|
42
|
+
const res = addShortcut(shortcut, managerClone)
|
|
43
|
+
if (res.isError) return res
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (check === "only") return Ok(true) satisfies Result<true, never> as any
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
return Ok(shortcuts) satisfies Result<Shortcuts, never> as any
|
|
50
|
+
}
|
|
51
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { keys } from "@alanscodelog/utils/keys"
|
|
2
|
+
import type { AnyFunction } from "@alanscodelog/utils/types"
|
|
3
|
+
|
|
4
|
+
import type { AttachTarget, EventTypes } from "../types/index.js"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Detach the listeners from an element.
|
|
8
|
+
*
|
|
9
|
+
* Or you can just use the abort controller returned by {@link attach}.
|
|
10
|
+
*/
|
|
11
|
+
export function detach(
|
|
12
|
+
el: AttachTarget,
|
|
13
|
+
listeners: Record<EventTypes, AnyFunction>,
|
|
14
|
+
/** Listeners need ot be detached with the same options they were attached with. */
|
|
15
|
+
opts: Partial<Record<EventTypes, AddEventListenerOptions>> = { wheel: { passive: true } }
|
|
16
|
+
): void {
|
|
17
|
+
for (const name of keys(listeners)) {
|
|
18
|
+
el.removeEventListener(name, listeners[name], opts[name])
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export * from "../types/index.js"
|
|
2
|
+
export * as helpers from "../helpers/index.js"
|
|
3
|
+
export * as utils from "../helpers/index.js"
|
|
4
|
+
|
|
5
|
+
/* Autogenerated Index */
|
|
6
|
+
|
|
7
|
+
export { addCommand } from "./addCommand.js"
|
|
8
|
+
export { addKey } from "./addKey.js"
|
|
9
|
+
export { addShortcut } from "./addShortcut.js"
|
|
10
|
+
export { attach } from "./attach.js"
|
|
11
|
+
export { createCommand } from "./createCommand.js"
|
|
12
|
+
export { createCommands } from "./createCommands.js"
|
|
13
|
+
export { createCondition } from "./createCondition.js"
|
|
14
|
+
export { createContext } from "./createContext.js"
|
|
15
|
+
export { createKey } from "./createKey.js"
|
|
16
|
+
export { createKeys } from "./createKeys.js"
|
|
17
|
+
export { createManager } from "./createManager.js"
|
|
18
|
+
export { createManagerEventListeners } from "./createManagerEventListeners.js"
|
|
19
|
+
export { createManagerOptions } from "./createManagerOptions.js"
|
|
20
|
+
export { createShortcut } from "./createShortcut.js"
|
|
21
|
+
export { createShortcuts } from "./createShortcuts.js"
|
|
22
|
+
export { detach } from "./detach.js"
|
|
23
|
+
export { EmulatedEvent } from "./EmulatedEvent.js"
|
|
24
|
+
export { Emulator } from "./Emulator.js"
|
|
25
|
+
export { removeCommand } from "./removeCommand.js"
|
|
26
|
+
export { removeKey } from "./removeKey.js"
|
|
27
|
+
export { removeShortcut } from "./removeShortcut.js"
|
|
28
|
+
export { setCommandProp } from "./setCommandProp.js"
|
|
29
|
+
export { setCommandsProp } from "./setCommandsProp.js"
|
|
30
|
+
export { setKeyProp } from "./setKeyProp.js"
|
|
31
|
+
export { setKeysProp } from "./setKeysProp.js"
|
|
32
|
+
export { setManagerProp } from "./setManagerProp.js"
|
|
33
|
+
export { setShortcutProp } from "./setShortcutProp.js"
|
|
34
|
+
export { setShortcutsProp } from "./setShortcutsProp.js"
|
|
35
|
+
export { ShortcutManagerManager } from "./ShortcutManagerManager.js"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Ok, type Result } from "@alanscodelog/utils/Result"
|
|
2
|
+
|
|
3
|
+
import { setCommandsProp } from "./setCommandsProp.js"
|
|
4
|
+
|
|
5
|
+
import type { CanHookErrors, Command, CommandsSetEntries, Manager, MultipleErrors } from "../types/index.js"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export function removeCommand<
|
|
9
|
+
THooks extends Manager["hooks"],
|
|
10
|
+
TCheck extends boolean | "only" = true
|
|
11
|
+
>(
|
|
12
|
+
command: Command,
|
|
13
|
+
manager: CommandsSetEntries["entries@remove"]["manager"] & { hooks?: THooks },
|
|
14
|
+
opts: { check?: TCheck } = {}
|
|
15
|
+
): Result<
|
|
16
|
+
TCheck extends "only" ? true : Command,
|
|
17
|
+
MultipleErrors<
|
|
18
|
+
CommandsSetEntries["entries@remove"]["error"]
|
|
19
|
+
> | CanHookErrors<THooks extends never ? never : THooks, "canSetCommandsProp">
|
|
20
|
+
> {
|
|
21
|
+
const res = setCommandsProp("entries@remove", command, manager, opts)
|
|
22
|
+
if (res.isError) return res
|
|
23
|
+
|
|
24
|
+
return Ok(command) satisfies Result<Command, never> as any
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Ok, type Result } from "@alanscodelog/utils/Result"
|
|
2
|
+
|
|
3
|
+
import { setKeysProp } from "./setKeysProp.js"
|
|
4
|
+
|
|
5
|
+
import type { CanHookErrors, Key, KeysSetEntries, Manager, MultipleErrors } from "../types/index.js"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export function removeKey<
|
|
9
|
+
THooks extends Manager["hooks"],
|
|
10
|
+
TCheck extends boolean | "only" = true
|
|
11
|
+
>(
|
|
12
|
+
key: Key,
|
|
13
|
+
manager: KeysSetEntries["entries@remove"]["manager"] & { hooks?: THooks },
|
|
14
|
+
opts: { check?: TCheck } = {}
|
|
15
|
+
): Result<
|
|
16
|
+
TCheck extends "only" ? true : Key,
|
|
17
|
+
MultipleErrors<
|
|
18
|
+
KeysSetEntries["entries@remove"]["error"]
|
|
19
|
+
> | CanHookErrors<THooks extends never ? never : THooks, "canSetKeysProp">
|
|
20
|
+
> {
|
|
21
|
+
const res = setKeysProp("entries@remove", key, manager, opts)
|
|
22
|
+
if (res.isError) return res
|
|
23
|
+
return Ok(key) satisfies Result<Key, never> as any
|
|
24
|
+
}
|
|
25
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Ok, type Result } from "@alanscodelog/utils/Result"
|
|
2
|
+
|
|
3
|
+
import { setShortcutsProp } from "./setShortcutsProp.js"
|
|
4
|
+
|
|
5
|
+
import type { CanHookErrors, Manager, MultipleErrors, Shortcut, ShortcutsSetEntries } from "../types/index.js"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export function removeShortcut<
|
|
9
|
+
THooks extends Manager["hooks"],
|
|
10
|
+
TCheck extends boolean | "only" = true
|
|
11
|
+
>(
|
|
12
|
+
shortcut: Shortcut,
|
|
13
|
+
manager: ShortcutsSetEntries["entries@remove"]["manager"] & { hooks?: THooks },
|
|
14
|
+
opts: { check?: TCheck } = {}
|
|
15
|
+
): Result<
|
|
16
|
+
TCheck extends "only" ? true : Shortcut,
|
|
17
|
+
MultipleErrors<
|
|
18
|
+
ShortcutsSetEntries["entries@remove"]["error"]
|
|
19
|
+
> | CanHookErrors<THooks extends never ? never : THooks, "canSetShortcutsProp">
|
|
20
|
+
> {
|
|
21
|
+
const res = setShortcutsProp("entries@remove", shortcut, manager, opts)
|
|
22
|
+
if (res.isError) return res
|
|
23
|
+
return Ok(shortcut) satisfies Result<Shortcut, never> as any
|
|
24
|
+
}
|