@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,140 @@
|
|
|
1
|
+
import { castType } from "@alanscodelog/utils/castType"
|
|
2
|
+
import { crop } from "@alanscodelog/utils/crop"
|
|
3
|
+
import { indent } from "@alanscodelog/utils/indent"
|
|
4
|
+
import { Err, Ok, type Result } from "@alanscodelog/utils/Result"
|
|
5
|
+
|
|
6
|
+
import { setCommandsProp } from "./setCommandsProp.js"
|
|
7
|
+
import { setShortcutProp } from "./setShortcutProp.js"
|
|
8
|
+
|
|
9
|
+
import { KnownError } from "../helpers/KnownError.js"
|
|
10
|
+
import { errorTextAdd } from "../internal/errorTextAdd.js"
|
|
11
|
+
import { type CanHookCommandProps, type CanHookErrors, type Command, type CommandSetEntries, type Manager, type MultipleErrors, SHORTCUT_ERROR } from "../types/index.js"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
const canHookable: CanHookCommandProps[] = ["condition", "execute"]
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Sets a settable command property.
|
|
18
|
+
*
|
|
19
|
+
* You should not use this to set key state the manager manages (those tagged with @Managed in the docs) unless you've forgone using the manager.
|
|
20
|
+
*
|
|
21
|
+
* Note that while the manager argument is always required, for unmanaged properties you can pass {} and for most others you can pass a partial manager if needed. This is because it's very difficult to keep the heavy per prop types and allow the manager to be optional in these cases.
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
export function setCommandProp<
|
|
25
|
+
TEntries extends CommandSetEntries,
|
|
26
|
+
TProp extends keyof CommandSetEntries,
|
|
27
|
+
TEntry extends TEntries[TProp],
|
|
28
|
+
THooks extends Manager["hooks"],
|
|
29
|
+
TCheck extends boolean | "only" = true
|
|
30
|
+
>(
|
|
31
|
+
/** Command is mutated if check is not "only". */
|
|
32
|
+
command: Command,
|
|
33
|
+
prop: TProp,
|
|
34
|
+
val: TEntry["val"],
|
|
35
|
+
manager: (TEntry["manager"] extends never ? unknown : TEntry["manager"]) & { hooks?: THooks },
|
|
36
|
+
{
|
|
37
|
+
check = true as TCheck
|
|
38
|
+
}: { check?: TCheck } = {}
|
|
39
|
+
): Result<
|
|
40
|
+
TCheck extends "only" ? true : Command,
|
|
41
|
+
MultipleErrors<TEntry["error"]>
|
|
42
|
+
| CanHookErrors<Manager["hooks"] extends never ? never : THooks, "canSetCommandProp">
|
|
43
|
+
> {
|
|
44
|
+
if (check) {
|
|
45
|
+
switch (prop) {
|
|
46
|
+
case "name": {
|
|
47
|
+
castType<TEntries["name"]["manager"]>(manager)
|
|
48
|
+
castType<TEntries["name"]["val"]>(val)
|
|
49
|
+
const s = manager.options.stringifier
|
|
50
|
+
const existing = manager.commands.entries[val as string]
|
|
51
|
+
if (existing) {
|
|
52
|
+
return Err(new KnownError(
|
|
53
|
+
SHORTCUT_ERROR.DUPLICATE_COMMAND,
|
|
54
|
+
errorTextAdd(
|
|
55
|
+
"Command",
|
|
56
|
+
val as string,
|
|
57
|
+
s.stringify(existing),
|
|
58
|
+
s.stringify(command)
|
|
59
|
+
),
|
|
60
|
+
{ existing, self: manager.commands }
|
|
61
|
+
))
|
|
62
|
+
}
|
|
63
|
+
// note that the old command being missing is NOT an error, see Command.name
|
|
64
|
+
|
|
65
|
+
// we artificially add the command so we don't get errors that it's unknown
|
|
66
|
+
const managerClone = {
|
|
67
|
+
...manager,
|
|
68
|
+
commands: {
|
|
69
|
+
...manager.commands,
|
|
70
|
+
entries: {
|
|
71
|
+
...manager.commands.entries,
|
|
72
|
+
[val]: { ...command, name: val }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const shortcutErrors = []
|
|
78
|
+
for (const shortcut of manager.shortcuts.entries) {
|
|
79
|
+
if (shortcut.command === command.name) {
|
|
80
|
+
// we should only receive hook errors
|
|
81
|
+
const res = setShortcutProp(shortcut, "command", val, managerClone, { check: "only" })
|
|
82
|
+
if (res.isError) shortcutErrors.push(res.error)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (shortcutErrors.length > 0) {
|
|
86
|
+
return Err(new KnownError(
|
|
87
|
+
SHORTCUT_ERROR.MULTIPLE_ERRORS,
|
|
88
|
+
crop`
|
|
89
|
+
Received multiple errors attempting to change command name from ${command.name} to ${val}:
|
|
90
|
+
${indent(shortcutErrors.map(_ => _.message).join("\n"), 7)}
|
|
91
|
+
`,
|
|
92
|
+
{ errors: shortcutErrors }
|
|
93
|
+
))
|
|
94
|
+
}
|
|
95
|
+
break
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
default: break
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (manager?.hooks && "canSetCommandProp" in manager.hooks && canHookable.includes(prop as any)) {
|
|
102
|
+
const canHook = manager.hooks.canSetCommandProp?.(command, prop as any, val)
|
|
103
|
+
if (canHook instanceof Error) {
|
|
104
|
+
return Err(canHook) as any
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (check === "only") {
|
|
110
|
+
return Ok(true) satisfies Result<true, never> as any
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if (prop === "name") {
|
|
115
|
+
castType<TEntries["name"]["manager"]>(manager)
|
|
116
|
+
castType<TEntries["name"]["val"]>(val)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
setCommandsProp("entries@add", { ...command, name: val }, manager).unwrap()
|
|
120
|
+
const old = command.name
|
|
121
|
+
const oldCommand = manager.commands.entries[old]
|
|
122
|
+
for (const shortcut of manager.shortcuts.entries) {
|
|
123
|
+
if (shortcut.command === old) {
|
|
124
|
+
setShortcutProp(shortcut, "command", val, manager).unwrap()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// only remove if it existed
|
|
128
|
+
if (manager.commands.entries[old]) {
|
|
129
|
+
setCommandsProp("entries@remove", oldCommand, manager).unwrap()
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
(command as any)[prop] = val
|
|
133
|
+
}
|
|
134
|
+
if (manager?.hooks && "onSetCommandProp" in manager.hooks!) {
|
|
135
|
+
manager?.hooks?.onSetCommandProp?.(command, prop as any, val)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return Ok(command) satisfies Result<Command, never> as any
|
|
139
|
+
}
|
|
140
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { castType } from "@alanscodelog/utils/castType"
|
|
2
|
+
import { Err, Ok, type Result } from "@alanscodelog/utils/Result"
|
|
3
|
+
|
|
4
|
+
import { KnownError } from "../helpers/KnownError.js"
|
|
5
|
+
import { errorTextAdd } from "../internal/errorTextAdd.js"
|
|
6
|
+
import { errorTextInUse } from "../internal/errorTextInUse.js"
|
|
7
|
+
import { errorTextRemove } from "../internal/errorTextRemove.js"
|
|
8
|
+
import { type CanHookCommandsProps, type CanHookErrors, type Command, type Commands, type CommandsSetEntries, type Manager, type MultipleErrors, SHORTCUT_ERROR } from "../types/index.js"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const canHookable: CanHookCommandsProps[] = ["entries@add", "entries@remove"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Sets a settable command property.
|
|
16
|
+
*
|
|
17
|
+
* You should not use this to set command state the manager manages (those tagged with @Managed in the docs) unless you've forgone using the manager.
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
export function setCommandsProp<
|
|
21
|
+
TEntries extends CommandsSetEntries,
|
|
22
|
+
TProp extends keyof CommandsSetEntries,
|
|
23
|
+
TEntry extends TEntries[TProp],
|
|
24
|
+
THooks extends Manager["hooks"],
|
|
25
|
+
TCheck extends boolean | "only" = true
|
|
26
|
+
>(
|
|
27
|
+
prop: TProp,
|
|
28
|
+
val: TEntry["val"],
|
|
29
|
+
/** Commands is mutated if check is not "only". */
|
|
30
|
+
manager: TEntry["manager"] & { hooks?: THooks },
|
|
31
|
+
{
|
|
32
|
+
check = true as TCheck
|
|
33
|
+
}: { check?: TCheck } = {}
|
|
34
|
+
): Result<
|
|
35
|
+
TCheck extends "only" ? true : Command,
|
|
36
|
+
MultipleErrors<TEntry["error"]>
|
|
37
|
+
| CanHookErrors<Manager["hooks"] extends never ? never : THooks, "canSetCommandsProp">
|
|
38
|
+
> {
|
|
39
|
+
const commands = manager.commands
|
|
40
|
+
const s = manager.options.stringifier
|
|
41
|
+
if (check) {
|
|
42
|
+
switch (prop) {
|
|
43
|
+
case "entries@add": {
|
|
44
|
+
castType<TEntries["entries@add"]["val"]>(val)
|
|
45
|
+
castType<TEntries["entries@add"]["manager"]>(manager)
|
|
46
|
+
const command = val
|
|
47
|
+
const existing = commands.entries[command.name]
|
|
48
|
+
|
|
49
|
+
if (existing) {
|
|
50
|
+
return Err(new KnownError(
|
|
51
|
+
SHORTCUT_ERROR.DUPLICATE_COMMAND,
|
|
52
|
+
errorTextAdd(
|
|
53
|
+
"Command",
|
|
54
|
+
s.stringifyCommand(existing.name, manager),
|
|
55
|
+
s.stringifyCommand(existing.name, manager),
|
|
56
|
+
s.stringifyCommand(command.name, manager)
|
|
57
|
+
),
|
|
58
|
+
{ existing, self: commands }
|
|
59
|
+
))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
break
|
|
63
|
+
}
|
|
64
|
+
case "entries@remove": {
|
|
65
|
+
castType<TEntries["entries@remove"]["val"]>(val)
|
|
66
|
+
castType<TEntries["entries@remove"]["manager"]>(manager)
|
|
67
|
+
|
|
68
|
+
const command = val
|
|
69
|
+
if (!commands.entries[command.name]) {
|
|
70
|
+
return Err(new KnownError(
|
|
71
|
+
SHORTCUT_ERROR.MISSING,
|
|
72
|
+
errorTextRemove(
|
|
73
|
+
"Command",
|
|
74
|
+
s.stringify(command),
|
|
75
|
+
s.stringifyList("commands", Object.values(commands.entries))
|
|
76
|
+
),
|
|
77
|
+
{ entry: command.name, self: commands }
|
|
78
|
+
))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const inUseShortcuts = manager.shortcuts.entries.filter(shortcut => shortcut.command === command.name)
|
|
82
|
+
if (inUseShortcuts.length > 0) {
|
|
83
|
+
return Err(new KnownError(
|
|
84
|
+
SHORTCUT_ERROR.COMMAND_IN_USE,
|
|
85
|
+
errorTextInUse(
|
|
86
|
+
"command",
|
|
87
|
+
s.stringify(command),
|
|
88
|
+
s.stringifyList("shortcuts", inUseShortcuts, manager)
|
|
89
|
+
),
|
|
90
|
+
{ inUseShortcuts }))
|
|
91
|
+
}
|
|
92
|
+
break
|
|
93
|
+
}
|
|
94
|
+
default: break
|
|
95
|
+
}
|
|
96
|
+
if (manager?.hooks && "canSetCommandsProp" in manager.hooks && canHookable.includes(prop as any)) {
|
|
97
|
+
const canHook = manager.hooks?.canSetCommandsProp?.(commands, prop as any, val as any)
|
|
98
|
+
if (canHook instanceof Error) {
|
|
99
|
+
return Err(canHook) as any
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (check === "only") {
|
|
105
|
+
return Ok(true) satisfies Result<true, never> as any
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
switch (prop) {
|
|
109
|
+
case "entries@add": {
|
|
110
|
+
const command = val as any as Command
|
|
111
|
+
commands.entries[command.name] = command
|
|
112
|
+
break
|
|
113
|
+
}
|
|
114
|
+
case "entries@remove": {
|
|
115
|
+
const command = val as any as Command
|
|
116
|
+
delete commands.entries[command.name]
|
|
117
|
+
break
|
|
118
|
+
}
|
|
119
|
+
default:
|
|
120
|
+
(commands as any)[prop] = val
|
|
121
|
+
break
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
manager.hooks?.onSetCommandsProp?.(commands, prop as any, val as any)
|
|
125
|
+
|
|
126
|
+
return Ok(commands) satisfies Result<Commands, never> as any
|
|
127
|
+
}
|
|
128
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { castType } from "@alanscodelog/utils/castType"
|
|
2
|
+
import { crop } from "@alanscodelog/utils/crop"
|
|
3
|
+
import { Err, Ok, type Result } from "@alanscodelog/utils/Result"
|
|
4
|
+
import { set } from "@alanscodelog/utils/set"
|
|
5
|
+
|
|
6
|
+
import { KnownError } from "../helpers/KnownError.js"
|
|
7
|
+
import type { CanHookErrors, Key, KeySetEntries, Manager, MultipleErrors, OnHookKeyProps } from "../types/index.js"
|
|
8
|
+
import { SHORTCUT_ERROR } from "../types/index.js"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const canHookable: OnHookKeyProps[] = ["x", "y", "width", "height", "label", "enabled", "render", "classes"]
|
|
12
|
+
/**
|
|
13
|
+
* Sets a settable key property.
|
|
14
|
+
*
|
|
15
|
+
* You should not use this to set key state the manager manages (those tagged with @Managed in the docs) unless you've forgone using the manager.
|
|
16
|
+
*
|
|
17
|
+
* Note that while the manager argument is always required, for unmanaged properties you can pass {} and for most others you can pass a partial manager if needed. This is because it's very difficult to keep the heavy per prop types and allow the manager to be optional in these cases.
|
|
18
|
+
*/
|
|
19
|
+
export function setKeyProp<
|
|
20
|
+
TEntries extends KeySetEntries,
|
|
21
|
+
TProp extends keyof KeySetEntries,
|
|
22
|
+
TEntry extends TEntries[TProp],
|
|
23
|
+
THooks extends Manager["hooks"],
|
|
24
|
+
TCheck extends boolean | "only" = true
|
|
25
|
+
>(
|
|
26
|
+
/** Key is mutated if check is not "only". */
|
|
27
|
+
key: Key,
|
|
28
|
+
prop: TProp,
|
|
29
|
+
val: TEntry["val"],
|
|
30
|
+
manager: (TEntry["manager"] extends never ? unknown : TEntry["manager"]) & { hooks?: THooks },
|
|
31
|
+
{
|
|
32
|
+
check = true as TCheck
|
|
33
|
+
}: { check?: TCheck } = {}
|
|
34
|
+
): Result<
|
|
35
|
+
TCheck extends "only" ? true : Key,
|
|
36
|
+
MultipleErrors<TEntry["error"]>
|
|
37
|
+
| CanHookErrors<THooks extends never ? never : THooks, "canSetKeyProp">
|
|
38
|
+
> {
|
|
39
|
+
if (check) {
|
|
40
|
+
switch (prop) {
|
|
41
|
+
case "toggleOnPressed":
|
|
42
|
+
case "toggleOffPressed":
|
|
43
|
+
case "pressed": {
|
|
44
|
+
castType<TEntries["pressed"]["manager"]>(manager)
|
|
45
|
+
const s = manager.options.stringifier
|
|
46
|
+
if (!key.enabled && val === true) {
|
|
47
|
+
return Err(
|
|
48
|
+
new KnownError(SHORTCUT_ERROR.CANNOT_SET_WHILE_DISABLED, crop`
|
|
49
|
+
The "${prop}" property cannot be set to true while a key is disabled. (Key: ${s.stringify(key, manager)})
|
|
50
|
+
`, { key })
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
break
|
|
54
|
+
}
|
|
55
|
+
default: break
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (manager?.hooks && "canSetKeyProp" in manager.hooks && canHookable.includes(prop as any)) {
|
|
59
|
+
const canHook = manager.hooks.canSetKeyProp?.(key, prop as any, val as any)
|
|
60
|
+
if (canHook instanceof Error) {
|
|
61
|
+
return Err(canHook) as any
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (check === "only") {
|
|
67
|
+
return Ok(true) satisfies Result<true, never> as any
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (prop.includes(".")) {
|
|
71
|
+
set(key, prop.split("."), val)
|
|
72
|
+
} else {
|
|
73
|
+
(key as any)[prop] = val
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
manager?.hooks?.onSetKeyProp?.(key, prop, val)
|
|
77
|
+
|
|
78
|
+
return Ok(key) satisfies Result<Key, never> as any
|
|
79
|
+
}
|
|
80
|
+
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { castType } from "@alanscodelog/utils/castType"
|
|
2
|
+
import { Err, Ok, type Result } from "@alanscodelog/utils/Result"
|
|
3
|
+
|
|
4
|
+
import { calculateLayoutSize } from "../helpers/calculateLayoutSize.js"
|
|
5
|
+
import { KnownError } from "../helpers/KnownError.js"
|
|
6
|
+
import { areValidVariants } from "../internal/areValidVariants.js"
|
|
7
|
+
import { errorTextAdd } from "../internal/errorTextAdd.js"
|
|
8
|
+
import { errorTextInUse } from "../internal/errorTextInUse.js"
|
|
9
|
+
import { errorTextRemove } from "../internal/errorTextRemove.js"
|
|
10
|
+
import { type CanHookErrors, type CanHookKeysProps, type Key, type Keys, type KeysSetEntries, type Manager, type MultipleErrors, SHORTCUT_ERROR } from "../types/index.js"
|
|
11
|
+
import { containsKey } from "../utils/containsKey.js"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
const canHookable: CanHookKeysProps[] = ["entries@add", "entries@remove"]
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Sets a settable {@link Keys} property.
|
|
18
|
+
*/
|
|
19
|
+
export function setKeysProp<
|
|
20
|
+
TEntries extends KeysSetEntries,
|
|
21
|
+
TProp extends keyof KeysSetEntries,
|
|
22
|
+
TEntry extends TEntries[TProp],
|
|
23
|
+
THooks extends Manager["hooks"],
|
|
24
|
+
TCheck extends boolean | "only" = true
|
|
25
|
+
>(
|
|
26
|
+
prop: TProp,
|
|
27
|
+
val: TEntry["val"],
|
|
28
|
+
manager: TEntry["manager"] & { hooks?: THooks },
|
|
29
|
+
{
|
|
30
|
+
check = true as TCheck
|
|
31
|
+
}: { check?: TCheck } = {}
|
|
32
|
+
): Result<
|
|
33
|
+
TCheck extends "only" ? true : Key,
|
|
34
|
+
MultipleErrors<TEntry["error"]>
|
|
35
|
+
| CanHookErrors<Manager["hooks"] extends never ? never : THooks, "canSetKeysProp">
|
|
36
|
+
> {
|
|
37
|
+
const keys = manager.keys
|
|
38
|
+
if (check) {
|
|
39
|
+
switch (prop) {
|
|
40
|
+
case "entries@add": {
|
|
41
|
+
castType<TEntries["entries@add"]["val"]>(val)
|
|
42
|
+
castType<TEntries["entries@add"]["manager"]>(manager)
|
|
43
|
+
|
|
44
|
+
const s = manager.options.stringifier
|
|
45
|
+
const key = val
|
|
46
|
+
// we only need to check .entries at this point
|
|
47
|
+
const existing = keys.entries[key.id]
|
|
48
|
+
|
|
49
|
+
if (existing) {
|
|
50
|
+
return Err(new KnownError(
|
|
51
|
+
SHORTCUT_ERROR.DUPLICATE_KEY,
|
|
52
|
+
errorTextAdd(
|
|
53
|
+
"Key",
|
|
54
|
+
s.stringify(existing, manager),
|
|
55
|
+
s.stringify(existing, manager),
|
|
56
|
+
s.stringify(key, manager)
|
|
57
|
+
),
|
|
58
|
+
{ existing, self: keys }
|
|
59
|
+
))
|
|
60
|
+
}
|
|
61
|
+
const areValidVariantsRes = areValidVariants(key, manager)
|
|
62
|
+
if (areValidVariantsRes.isError) return areValidVariantsRes
|
|
63
|
+
|
|
64
|
+
break
|
|
65
|
+
}
|
|
66
|
+
case "entries@remove": {
|
|
67
|
+
castType<TEntries["entries@remove"]["val"]>(val)
|
|
68
|
+
castType<TEntries["entries@remove"]["manager"]>(manager)
|
|
69
|
+
const s = manager.options.stringifier
|
|
70
|
+
|
|
71
|
+
const key = val
|
|
72
|
+
if (!keys.entries[key.id]) {
|
|
73
|
+
return Err(new KnownError(
|
|
74
|
+
SHORTCUT_ERROR.MISSING,
|
|
75
|
+
errorTextRemove(
|
|
76
|
+
"Key",
|
|
77
|
+
s.stringify(key),
|
|
78
|
+
s.stringifyList("keys", Object.values(keys.entries))
|
|
79
|
+
),
|
|
80
|
+
{ entry: key.id, self: keys }
|
|
81
|
+
)) as any
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const inUseShortcuts = manager.shortcuts.entries.filter(shortcut => containsKey(shortcut.chain, key.id, keys))
|
|
85
|
+
|
|
86
|
+
if (inUseShortcuts.length > 0) {
|
|
87
|
+
return Err(new KnownError(
|
|
88
|
+
SHORTCUT_ERROR.KEY_IN_USE,
|
|
89
|
+
errorTextInUse(
|
|
90
|
+
"key",
|
|
91
|
+
s.stringify(key),
|
|
92
|
+
s.stringifyList("shortcuts", inUseShortcuts, manager)),
|
|
93
|
+
|
|
94
|
+
{ inUseShortcuts }))
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
break
|
|
98
|
+
}
|
|
99
|
+
default: break
|
|
100
|
+
}
|
|
101
|
+
if (manager.hooks && "canSetKeysProp" in manager.hooks && canHookable.includes(prop as any)) {
|
|
102
|
+
const canHook = manager.hooks.canSetKeysProp?.(keys, prop as any, val as any)
|
|
103
|
+
if (canHook instanceof Error) {
|
|
104
|
+
return Err(canHook) as any
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (check === "only") {
|
|
110
|
+
return Ok(true) satisfies Result<true, never> as any
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
switch (prop) {
|
|
114
|
+
case "entries@add": {
|
|
115
|
+
castType<TEntries["entries@add"]["val"]>(val)
|
|
116
|
+
castType<TEntries["entries@add"]["manager"]>(manager)
|
|
117
|
+
|
|
118
|
+
const key = val
|
|
119
|
+
keys.entries[key.id] = key
|
|
120
|
+
if (key.isToggle === "native") {
|
|
121
|
+
setKeysProp("nativeToggleKeys", [
|
|
122
|
+
...keys.nativeToggleKeys,
|
|
123
|
+
key.id
|
|
124
|
+
], manager).unwrap()
|
|
125
|
+
}
|
|
126
|
+
if (key.isModifier === "native") {
|
|
127
|
+
setKeysProp("nativeModifierKeys", [
|
|
128
|
+
...keys.nativeModifierKeys,
|
|
129
|
+
key.id
|
|
130
|
+
], manager).unwrap()
|
|
131
|
+
}
|
|
132
|
+
if (key.isToggle) {
|
|
133
|
+
setKeysProp(`toggles@add@${key.toggleOnId}`, key, manager).unwrap()
|
|
134
|
+
setKeysProp(`toggles@add@${key.toggleOffId}`, key, manager).unwrap()
|
|
135
|
+
}
|
|
136
|
+
if (key.variants) {
|
|
137
|
+
for (const variant of key.variants) {
|
|
138
|
+
setKeysProp(`variants@add@${variant}`, key.id, manager).unwrap()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (keys.autoManageLayout) {
|
|
142
|
+
setKeysProp("layout", calculateLayoutSize(keys), manager).unwrap()
|
|
143
|
+
}
|
|
144
|
+
break
|
|
145
|
+
}
|
|
146
|
+
case "entries@remove": {
|
|
147
|
+
const key = val as any as Key
|
|
148
|
+
delete keys.entries[key.id]
|
|
149
|
+
if (key.isToggle === "native") {
|
|
150
|
+
setKeysProp("nativeToggleKeys", keys.nativeToggleKeys.filter(k => k !== key.id), manager).unwrap()
|
|
151
|
+
}
|
|
152
|
+
if (key.isModifier === "native") {
|
|
153
|
+
setKeysProp("nativeModifierKeys", keys.nativeToggleKeys.filter(k => k !== key.id), manager).unwrap()
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (key.isToggle) {
|
|
157
|
+
setKeysProp(`toggles@remove@${key.toggleOnId}`, key, manager).unwrap()
|
|
158
|
+
setKeysProp(`toggles@remove@${key.toggleOffId}`, key, manager).unwrap()
|
|
159
|
+
}
|
|
160
|
+
if (key.variants) {
|
|
161
|
+
for (const variant of key.variants) {
|
|
162
|
+
setKeysProp(`variants@remove@${variant}`, key.id, manager).unwrap()
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (keys.autoManageLayout) {
|
|
166
|
+
setKeysProp("layout", calculateLayoutSize(keys), manager).unwrap()
|
|
167
|
+
}
|
|
168
|
+
break
|
|
169
|
+
}
|
|
170
|
+
default:
|
|
171
|
+
if (prop.startsWith("toggles@add@")) {
|
|
172
|
+
const name = prop.slice("toggles@add@".length)
|
|
173
|
+
keys.toggles[name] = val as Key
|
|
174
|
+
} else if (prop.startsWith("toggles@remove@")) {
|
|
175
|
+
const name = prop.slice("toggles@remove@".length)
|
|
176
|
+
delete keys.toggles[name]
|
|
177
|
+
} else if (prop.startsWith("variants@add@")) {
|
|
178
|
+
const variant = prop.slice("variants@add@".length)
|
|
179
|
+
const existing = keys.variants[variant]
|
|
180
|
+
? [...keys.variants[variant]]
|
|
181
|
+
: []
|
|
182
|
+
existing.push(val as string)
|
|
183
|
+
keys.variants[variant] = existing
|
|
184
|
+
} else if (prop.startsWith("variants@remove@")) {
|
|
185
|
+
const variant = prop.slice("variants@remove@".length)
|
|
186
|
+
const existing = keys.variants[variant]
|
|
187
|
+
? [...keys.variants[variant]]
|
|
188
|
+
: []
|
|
189
|
+
existing.splice(existing.indexOf(val as string), 1)
|
|
190
|
+
if (existing.length > 0) {
|
|
191
|
+
keys.variants[variant] = existing
|
|
192
|
+
} else {
|
|
193
|
+
delete keys.variants[variant]
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
(keys as any)[prop] = val
|
|
197
|
+
}
|
|
198
|
+
break
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
manager.hooks?.onSetKeysProp?.(keys, prop as any, val as any)
|
|
202
|
+
|
|
203
|
+
return Ok(keys) satisfies Result<Keys, never> as any
|
|
204
|
+
}
|
|
205
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { castType } from "@alanscodelog/utils/castType"
|
|
2
|
+
import { Err, Ok, type Result } from "@alanscodelog/utils/Result"
|
|
3
|
+
import { set } from "@alanscodelog/utils/set"
|
|
4
|
+
import { unreachable } from "@alanscodelog/utils/unreachable"
|
|
5
|
+
|
|
6
|
+
import { isValidManager } from "../helpers/isValidManager.js"
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
8
|
+
import type { safeSetManagerChain } from "../helpers/safeSetManagerChain.js"
|
|
9
|
+
import { areValidKeys } from "../internal/areValidKeys.js"
|
|
10
|
+
import { type CanHookErrors, type CanHookManagerProps, type ChainError, type Manager, type ManagerSetEntries, type MultipleErrors, SHORTCUT_ERROR } from "../types/index.js"
|
|
11
|
+
import { cloneChain } from "../utils/cloneChain.js"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
const canHookable: CanHookManagerProps[] = ["state.chain", "shortcuts", "commands", "keys"]
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Safely sets a settable manager property.
|
|
18
|
+
*
|
|
19
|
+
* You should not use this to set properties the manager manages (those tagged with @Managed in the docs) unless you've forgone using the manager.
|
|
20
|
+
*
|
|
21
|
+
* If you need to set the chain, use {@link safeSetManagerChain}.
|
|
22
|
+
*
|
|
23
|
+
* If enabling/disabling {@link Manager.state.isRecording} it's suggested you use {@link safeSetManagerChain} just before.
|
|
24
|
+
*
|
|
25
|
+
* # How to set multiple manager properties safely (i.e. batch replace shortcuts/commands/keys)
|
|
26
|
+
*
|
|
27
|
+
* This can be an issue because there isn't a way to tell the manager you want to replace *multiple* properties and it might be impossible to, for example, replace commands with a smaller subset but not have it error even if you're planning to replace the shortcuts so they don't contain missing commands.
|
|
28
|
+
*
|
|
29
|
+
* To achieve this, you can shallow clone the manager, change all the properties you want directly, then validate it's state by using isValidManager which is what this function does internally.
|
|
30
|
+
*
|
|
31
|
+
* Once you know it's valid, detach the old manager and attach the new one.
|
|
32
|
+
* ```ts
|
|
33
|
+
* const clone = {...manager, keys: newKeys, shortcuts: newShortcuts}
|
|
34
|
+
*
|
|
35
|
+
* if (isValidManager(manager)) {
|
|
36
|
+
* detach(manager, ...)
|
|
37
|
+
* attach(clone, ...)
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
export function setManagerProp<
|
|
43
|
+
TEntries extends ManagerSetEntries,
|
|
44
|
+
TProp extends keyof ManagerSetEntries,
|
|
45
|
+
TEntry extends TEntries[TProp],
|
|
46
|
+
THooks extends Manager["hooks"],
|
|
47
|
+
TCheck extends boolean | "only" = true
|
|
48
|
+
|
|
49
|
+
>(
|
|
50
|
+
/** Manager is mutate if check is not "only" */
|
|
51
|
+
manager: TEntry["manager"] & { hooks?: THooks },
|
|
52
|
+
prop: TProp,
|
|
53
|
+
val: TEntry["val"],
|
|
54
|
+
{ check = true as TCheck }: { check?: TCheck } = {}
|
|
55
|
+
): Result<
|
|
56
|
+
TCheck extends "only" ? true : Manager,
|
|
57
|
+
MultipleErrors<TEntry["error"]>
|
|
58
|
+
| CanHookErrors<Manager["hooks"] extends never ? never : THooks, "canSetManagerProp">
|
|
59
|
+
> {
|
|
60
|
+
// castType is used extensively because of https://github.com/microsoft/TypeScript/issues/50652
|
|
61
|
+
if (check) {
|
|
62
|
+
switch (prop) {
|
|
63
|
+
case "state.chain": {
|
|
64
|
+
castType<TEntries["state.chain"]["val"]>(val)
|
|
65
|
+
castType<TEntries["state.chain"]["manager"]>(manager)
|
|
66
|
+
|
|
67
|
+
const resIsValid = areValidKeys(val, manager)
|
|
68
|
+
if (resIsValid.isError) return resIsValid satisfies Result<never, MultipleErrors<TEntries["state.chain"]["error"]>>
|
|
69
|
+
break
|
|
70
|
+
}
|
|
71
|
+
case "commands":
|
|
72
|
+
case "keys":
|
|
73
|
+
case "shortcuts": {
|
|
74
|
+
castType<TEntries["commands" | "shortcuts" | "keys"]["val"]>(val)
|
|
75
|
+
castType<TEntries["commands" | "shortcuts" | "keys"]["manager"]>(manager)
|
|
76
|
+
|
|
77
|
+
const managerClone = { ...manager, [prop as any]: val }
|
|
78
|
+
const res = isValidManager(managerClone)
|
|
79
|
+
if (res.isError && res.error.code === SHORTCUT_ERROR.INVALID_MANAGER) unreachable()
|
|
80
|
+
if (res.isError) return res satisfies Result<any, MultipleErrors<typeof SHORTCUT_ERROR.UNKNOWN_COMMAND | ChainError | typeof SHORTCUT_ERROR.INVALID_MANAGER>> as any
|
|
81
|
+
break
|
|
82
|
+
}
|
|
83
|
+
default:
|
|
84
|
+
break
|
|
85
|
+
}
|
|
86
|
+
if (manager?.hooks && "canSetManagerProp" in manager.hooks && canHookable.includes(prop as any)) {
|
|
87
|
+
const canHook = manager.hooks?.canSetManagerProp?.(manager, prop as any, val as any)
|
|
88
|
+
if (canHook instanceof Error) {
|
|
89
|
+
return Err(canHook) as any
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (check === "only") {
|
|
94
|
+
return Ok(true) satisfies Result<true, never> as any
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
if ((prop as string).includes(".")) {
|
|
99
|
+
if (prop === "state.chain") {
|
|
100
|
+
val = cloneChain(val as any) satisfies Manager["state"]["chain"] as any
|
|
101
|
+
}
|
|
102
|
+
set(manager, (prop as string).split("."), val)
|
|
103
|
+
} else {
|
|
104
|
+
(manager as any)[prop] = val
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
manager.hooks?.onSetManagerProp?.(manager, prop, val)
|
|
108
|
+
|
|
109
|
+
return Ok(manager) satisfies Result<Manager, never> as any
|
|
110
|
+
}
|
|
111
|
+
|