@tanstack/solid-hotkeys 0.1.3 → 0.3.0

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.
@@ -37,19 +37,37 @@ let solid_js = require("solid-js");
37
37
  */
38
38
  function createHotkeySequence(sequence, callback, options = {}) {
39
39
  const defaultOptions = require_HotkeysProvider.useDefaultHotkeysOptions();
40
+ const manager = (0, _tanstack_hotkeys.getSequenceManager)();
41
+ let registration = null;
40
42
  (0, solid_js.createEffect)(() => {
41
43
  const resolvedSequence = typeof sequence === "function" ? sequence() : sequence;
42
44
  const resolvedOptions = typeof options === "function" ? options() : options;
43
- const { enabled = true, ...sequenceOptions } = {
45
+ const mergedOptions = {
44
46
  ...defaultOptions.hotkeySequence,
45
47
  ...resolvedOptions
46
48
  };
47
- if (!enabled || resolvedSequence.length === 0) return;
48
- const manager = (0, _tanstack_hotkeys.getSequenceManager)();
49
- const registerOptions = { enabled: true };
50
- if (sequenceOptions.timeout !== void 0) registerOptions.timeout = sequenceOptions.timeout;
51
- if (sequenceOptions.platform !== void 0) registerOptions.platform = sequenceOptions.platform;
52
- (0, solid_js.onCleanup)(manager.register(resolvedSequence, callback, registerOptions));
49
+ const { target: _target, ...optionsWithoutTarget } = mergedOptions;
50
+ if (resolvedSequence.length === 0) return;
51
+ const resolvedTarget = "target" in mergedOptions ? mergedOptions.target ?? null : typeof document !== "undefined" ? document : null;
52
+ if (!resolvedTarget) return;
53
+ if (registration?.isActive) {
54
+ registration.unregister();
55
+ registration = null;
56
+ }
57
+ registration = manager.register(resolvedSequence, callback, {
58
+ ...mergedOptions,
59
+ target: resolvedTarget
60
+ });
61
+ if (registration.isActive) {
62
+ registration.callback = callback;
63
+ registration.setOptions(optionsWithoutTarget);
64
+ }
65
+ (0, solid_js.onCleanup)(() => {
66
+ if (registration?.isActive) {
67
+ registration.unregister();
68
+ registration = null;
69
+ }
70
+ });
53
71
  });
54
72
  }
55
73
 
@@ -1 +1 @@
1
- {"version":3,"file":"createHotkeySequence.cjs","names":["useDefaultHotkeysOptions"],"sources":["../src/createHotkeySequence.ts"],"sourcesContent":["import { createEffect, onCleanup } from 'solid-js'\nimport { getSequenceManager } from '@tanstack/hotkeys'\nimport { useDefaultHotkeysOptions } from './HotkeysProvider'\nimport type {\n HotkeyCallback,\n HotkeySequence,\n SequenceOptions,\n} from '@tanstack/hotkeys'\n\nexport interface CreateHotkeySequenceOptions extends Omit<\n SequenceOptions,\n 'enabled'\n> {\n /** Whether the sequence is enabled. Defaults to true. */\n enabled?: boolean\n}\n\n/**\n * SolidJS primitive for registering a keyboard shortcut sequence (Vim-style).\n *\n * This primitive allows you to register multi-key sequences like 'g g' or 'd d'\n * that trigger when the full sequence is pressed within a timeout.\n *\n * @param sequence - Array of hotkey strings that form the sequence (or accessor function)\n * @param callback - Function to call when the sequence is completed\n * @param options - Options for the sequence behavior (or accessor function)\n *\n * @example\n * ```tsx\n * function VimEditor() {\n * // 'g g' to go to top\n * createHotkeySequence(['G', 'G'], () => {\n * scrollToTop()\n * })\n *\n * // 'd d' to delete line\n * createHotkeySequence(['D', 'D'], () => {\n * deleteLine()\n * })\n *\n * // 'd i w' to delete inner word\n * createHotkeySequence(['D', 'I', 'W'], () => {\n * deleteInnerWord()\n * }, { timeout: 500 })\n *\n * return <div>...</div>\n * }\n * ```\n */\nexport function createHotkeySequence(\n sequence: HotkeySequence | (() => HotkeySequence),\n callback: HotkeyCallback,\n options:\n | CreateHotkeySequenceOptions\n | (() => CreateHotkeySequenceOptions) = {},\n): void {\n const defaultOptions = useDefaultHotkeysOptions()\n\n createEffect(() => {\n // Resolve reactive values\n const resolvedSequence =\n typeof sequence === 'function' ? sequence() : sequence\n const resolvedOptions = typeof options === 'function' ? options() : options\n\n const mergedOptions = {\n ...defaultOptions.hotkeySequence,\n ...resolvedOptions,\n } as CreateHotkeySequenceOptions\n\n const { enabled = true, ...sequenceOptions } = mergedOptions\n\n if (!enabled || resolvedSequence.length === 0) {\n return\n }\n\n const manager = getSequenceManager()\n\n // Build options object conditionally to avoid overwriting manager defaults with undefined\n const registerOptions: SequenceOptions = { enabled: true }\n if (sequenceOptions.timeout !== undefined)\n registerOptions.timeout = sequenceOptions.timeout\n if (sequenceOptions.platform !== undefined)\n registerOptions.platform = sequenceOptions.platform\n\n const unregister = manager.register(\n resolvedSequence,\n callback,\n registerOptions,\n )\n\n onCleanup(unregister)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,SAAgB,qBACd,UACA,UACA,UAE0C,EAAE,EACtC;CACN,MAAM,iBAAiBA,kDAA0B;AAEjD,kCAAmB;EAEjB,MAAM,mBACJ,OAAO,aAAa,aAAa,UAAU,GAAG;EAChD,MAAM,kBAAkB,OAAO,YAAY,aAAa,SAAS,GAAG;EAOpE,MAAM,EAAE,UAAU,MAAM,GAAG,oBALL;GACpB,GAAG,eAAe;GAClB,GAAG;GACJ;AAID,MAAI,CAAC,WAAW,iBAAiB,WAAW,EAC1C;EAGF,MAAM,qDAA8B;EAGpC,MAAM,kBAAmC,EAAE,SAAS,MAAM;AAC1D,MAAI,gBAAgB,YAAY,OAC9B,iBAAgB,UAAU,gBAAgB;AAC5C,MAAI,gBAAgB,aAAa,OAC/B,iBAAgB,WAAW,gBAAgB;AAQ7C,0BANmB,QAAQ,SACzB,kBACA,UACA,gBACD,CAEoB;GACrB"}
1
+ {"version":3,"file":"createHotkeySequence.cjs","names":["useDefaultHotkeysOptions"],"sources":["../src/createHotkeySequence.ts"],"sourcesContent":["import { createEffect, onCleanup } from 'solid-js'\nimport { getSequenceManager } from '@tanstack/hotkeys'\nimport { useDefaultHotkeysOptions } from './HotkeysProvider'\nimport type {\n HotkeyCallback,\n HotkeySequence,\n SequenceOptions,\n SequenceRegistrationHandle,\n} from '@tanstack/hotkeys'\n\nexport interface CreateHotkeySequenceOptions extends Omit<\n SequenceOptions,\n 'target'\n> {\n /**\n * The DOM element to attach the event listener to.\n * Can be a direct DOM element, an accessor, or null. Defaults to document.\n */\n target?: HTMLElement | Document | Window | null\n}\n\n/**\n * SolidJS primitive for registering a keyboard shortcut sequence (Vim-style).\n *\n * This primitive allows you to register multi-key sequences like 'g g' or 'd d'\n * that trigger when the full sequence is pressed within a timeout.\n *\n * @param sequence - Array of hotkey strings that form the sequence (or accessor function)\n * @param callback - Function to call when the sequence is completed\n * @param options - Options for the sequence behavior (or accessor function)\n *\n * @example\n * ```tsx\n * function VimEditor() {\n * // 'g g' to go to top\n * createHotkeySequence(['G', 'G'], () => {\n * scrollToTop()\n * })\n *\n * // 'd d' to delete line\n * createHotkeySequence(['D', 'D'], () => {\n * deleteLine()\n * })\n *\n * // 'd i w' to delete inner word\n * createHotkeySequence(['D', 'I', 'W'], () => {\n * deleteInnerWord()\n * }, { timeout: 500 })\n *\n * return <div>...</div>\n * }\n * ```\n */\nexport function createHotkeySequence(\n sequence: HotkeySequence | (() => HotkeySequence),\n callback: HotkeyCallback,\n options:\n | CreateHotkeySequenceOptions\n | (() => CreateHotkeySequenceOptions) = {},\n): void {\n const defaultOptions = useDefaultHotkeysOptions()\n const manager = getSequenceManager()\n\n let registration: SequenceRegistrationHandle | null = null\n\n createEffect(() => {\n // Resolve reactive values\n const resolvedSequence =\n typeof sequence === 'function' ? sequence() : sequence\n const resolvedOptions = typeof options === 'function' ? options() : options\n\n const mergedOptions = {\n ...defaultOptions.hotkeySequence,\n ...resolvedOptions,\n } as CreateHotkeySequenceOptions\n\n // Extract options without target (target is handled separately)\n const { target: _target, ...optionsWithoutTarget } = mergedOptions\n\n if (resolvedSequence.length === 0) {\n return\n }\n\n // Resolve target: when explicitly provided (even as null), use it and skip if null.\n // When not provided, default to document. Matches createHotkey.\n const resolvedTarget =\n 'target' in mergedOptions\n ? (mergedOptions.target ?? null)\n : typeof document !== 'undefined'\n ? document\n : null\n\n if (!resolvedTarget) {\n return\n }\n\n // Unregister previous registration if it exists\n if (registration?.isActive) {\n registration.unregister()\n registration = null\n }\n\n // Register the sequence\n registration = manager.register(resolvedSequence, callback, {\n ...mergedOptions,\n target: resolvedTarget,\n })\n\n // Sync callback and options on every effect run\n if (registration.isActive) {\n registration.callback = callback\n registration.setOptions(optionsWithoutTarget)\n }\n\n // Cleanup on disposal\n onCleanup(() => {\n if (registration?.isActive) {\n registration.unregister()\n registration = null\n }\n })\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,SAAgB,qBACd,UACA,UACA,UAE0C,EAAE,EACtC;CACN,MAAM,iBAAiBA,kDAA0B;CACjD,MAAM,qDAA8B;CAEpC,IAAI,eAAkD;AAEtD,kCAAmB;EAEjB,MAAM,mBACJ,OAAO,aAAa,aAAa,UAAU,GAAG;EAChD,MAAM,kBAAkB,OAAO,YAAY,aAAa,SAAS,GAAG;EAEpE,MAAM,gBAAgB;GACpB,GAAG,eAAe;GAClB,GAAG;GACJ;EAGD,MAAM,EAAE,QAAQ,SAAS,GAAG,yBAAyB;AAErD,MAAI,iBAAiB,WAAW,EAC9B;EAKF,MAAM,iBACJ,YAAY,gBACP,cAAc,UAAU,OACzB,OAAO,aAAa,cAClB,WACA;AAER,MAAI,CAAC,eACH;AAIF,MAAI,cAAc,UAAU;AAC1B,gBAAa,YAAY;AACzB,kBAAe;;AAIjB,iBAAe,QAAQ,SAAS,kBAAkB,UAAU;GAC1D,GAAG;GACH,QAAQ;GACT,CAAC;AAGF,MAAI,aAAa,UAAU;AACzB,gBAAa,WAAW;AACxB,gBAAa,WAAW,qBAAqB;;AAI/C,gCAAgB;AACd,OAAI,cAAc,UAAU;AAC1B,iBAAa,YAAY;AACzB,mBAAe;;IAEjB;GACF"}
@@ -1,9 +1,12 @@
1
1
  import { HotkeyCallback, HotkeySequence, SequenceOptions } from "@tanstack/hotkeys";
2
2
 
3
3
  //#region src/createHotkeySequence.d.ts
4
- interface CreateHotkeySequenceOptions extends Omit<SequenceOptions, 'enabled'> {
5
- /** Whether the sequence is enabled. Defaults to true. */
6
- enabled?: boolean;
4
+ interface CreateHotkeySequenceOptions extends Omit<SequenceOptions, 'target'> {
5
+ /**
6
+ * The DOM element to attach the event listener to.
7
+ * Can be a direct DOM element, an accessor, or null. Defaults to document.
8
+ */
9
+ target?: HTMLElement | Document | Window | null;
7
10
  }
8
11
  /**
9
12
  * SolidJS primitive for registering a keyboard shortcut sequence (Vim-style).
@@ -1,9 +1,12 @@
1
1
  import { HotkeyCallback, HotkeySequence, SequenceOptions } from "@tanstack/hotkeys";
2
2
 
3
3
  //#region src/createHotkeySequence.d.ts
4
- interface CreateHotkeySequenceOptions extends Omit<SequenceOptions, 'enabled'> {
5
- /** Whether the sequence is enabled. Defaults to true. */
6
- enabled?: boolean;
4
+ interface CreateHotkeySequenceOptions extends Omit<SequenceOptions, 'target'> {
5
+ /**
6
+ * The DOM element to attach the event listener to.
7
+ * Can be a direct DOM element, an accessor, or null. Defaults to document.
8
+ */
9
+ target?: HTMLElement | Document | Window | null;
7
10
  }
8
11
  /**
9
12
  * SolidJS primitive for registering a keyboard shortcut sequence (Vim-style).
@@ -37,19 +37,37 @@ import { createEffect, onCleanup } from "solid-js";
37
37
  */
38
38
  function createHotkeySequence(sequence, callback, options = {}) {
39
39
  const defaultOptions = useDefaultHotkeysOptions();
40
+ const manager = getSequenceManager();
41
+ let registration = null;
40
42
  createEffect(() => {
41
43
  const resolvedSequence = typeof sequence === "function" ? sequence() : sequence;
42
44
  const resolvedOptions = typeof options === "function" ? options() : options;
43
- const { enabled = true, ...sequenceOptions } = {
45
+ const mergedOptions = {
44
46
  ...defaultOptions.hotkeySequence,
45
47
  ...resolvedOptions
46
48
  };
47
- if (!enabled || resolvedSequence.length === 0) return;
48
- const manager = getSequenceManager();
49
- const registerOptions = { enabled: true };
50
- if (sequenceOptions.timeout !== void 0) registerOptions.timeout = sequenceOptions.timeout;
51
- if (sequenceOptions.platform !== void 0) registerOptions.platform = sequenceOptions.platform;
52
- onCleanup(manager.register(resolvedSequence, callback, registerOptions));
49
+ const { target: _target, ...optionsWithoutTarget } = mergedOptions;
50
+ if (resolvedSequence.length === 0) return;
51
+ const resolvedTarget = "target" in mergedOptions ? mergedOptions.target ?? null : typeof document !== "undefined" ? document : null;
52
+ if (!resolvedTarget) return;
53
+ if (registration?.isActive) {
54
+ registration.unregister();
55
+ registration = null;
56
+ }
57
+ registration = manager.register(resolvedSequence, callback, {
58
+ ...mergedOptions,
59
+ target: resolvedTarget
60
+ });
61
+ if (registration.isActive) {
62
+ registration.callback = callback;
63
+ registration.setOptions(optionsWithoutTarget);
64
+ }
65
+ onCleanup(() => {
66
+ if (registration?.isActive) {
67
+ registration.unregister();
68
+ registration = null;
69
+ }
70
+ });
53
71
  });
54
72
  }
55
73
 
@@ -1 +1 @@
1
- {"version":3,"file":"createHotkeySequence.js","names":[],"sources":["../src/createHotkeySequence.ts"],"sourcesContent":["import { createEffect, onCleanup } from 'solid-js'\nimport { getSequenceManager } from '@tanstack/hotkeys'\nimport { useDefaultHotkeysOptions } from './HotkeysProvider'\nimport type {\n HotkeyCallback,\n HotkeySequence,\n SequenceOptions,\n} from '@tanstack/hotkeys'\n\nexport interface CreateHotkeySequenceOptions extends Omit<\n SequenceOptions,\n 'enabled'\n> {\n /** Whether the sequence is enabled. Defaults to true. */\n enabled?: boolean\n}\n\n/**\n * SolidJS primitive for registering a keyboard shortcut sequence (Vim-style).\n *\n * This primitive allows you to register multi-key sequences like 'g g' or 'd d'\n * that trigger when the full sequence is pressed within a timeout.\n *\n * @param sequence - Array of hotkey strings that form the sequence (or accessor function)\n * @param callback - Function to call when the sequence is completed\n * @param options - Options for the sequence behavior (or accessor function)\n *\n * @example\n * ```tsx\n * function VimEditor() {\n * // 'g g' to go to top\n * createHotkeySequence(['G', 'G'], () => {\n * scrollToTop()\n * })\n *\n * // 'd d' to delete line\n * createHotkeySequence(['D', 'D'], () => {\n * deleteLine()\n * })\n *\n * // 'd i w' to delete inner word\n * createHotkeySequence(['D', 'I', 'W'], () => {\n * deleteInnerWord()\n * }, { timeout: 500 })\n *\n * return <div>...</div>\n * }\n * ```\n */\nexport function createHotkeySequence(\n sequence: HotkeySequence | (() => HotkeySequence),\n callback: HotkeyCallback,\n options:\n | CreateHotkeySequenceOptions\n | (() => CreateHotkeySequenceOptions) = {},\n): void {\n const defaultOptions = useDefaultHotkeysOptions()\n\n createEffect(() => {\n // Resolve reactive values\n const resolvedSequence =\n typeof sequence === 'function' ? sequence() : sequence\n const resolvedOptions = typeof options === 'function' ? options() : options\n\n const mergedOptions = {\n ...defaultOptions.hotkeySequence,\n ...resolvedOptions,\n } as CreateHotkeySequenceOptions\n\n const { enabled = true, ...sequenceOptions } = mergedOptions\n\n if (!enabled || resolvedSequence.length === 0) {\n return\n }\n\n const manager = getSequenceManager()\n\n // Build options object conditionally to avoid overwriting manager defaults with undefined\n const registerOptions: SequenceOptions = { enabled: true }\n if (sequenceOptions.timeout !== undefined)\n registerOptions.timeout = sequenceOptions.timeout\n if (sequenceOptions.platform !== undefined)\n registerOptions.platform = sequenceOptions.platform\n\n const unregister = manager.register(\n resolvedSequence,\n callback,\n registerOptions,\n )\n\n onCleanup(unregister)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,SAAgB,qBACd,UACA,UACA,UAE0C,EAAE,EACtC;CACN,MAAM,iBAAiB,0BAA0B;AAEjD,oBAAmB;EAEjB,MAAM,mBACJ,OAAO,aAAa,aAAa,UAAU,GAAG;EAChD,MAAM,kBAAkB,OAAO,YAAY,aAAa,SAAS,GAAG;EAOpE,MAAM,EAAE,UAAU,MAAM,GAAG,oBALL;GACpB,GAAG,eAAe;GAClB,GAAG;GACJ;AAID,MAAI,CAAC,WAAW,iBAAiB,WAAW,EAC1C;EAGF,MAAM,UAAU,oBAAoB;EAGpC,MAAM,kBAAmC,EAAE,SAAS,MAAM;AAC1D,MAAI,gBAAgB,YAAY,OAC9B,iBAAgB,UAAU,gBAAgB;AAC5C,MAAI,gBAAgB,aAAa,OAC/B,iBAAgB,WAAW,gBAAgB;AAQ7C,YANmB,QAAQ,SACzB,kBACA,UACA,gBACD,CAEoB;GACrB"}
1
+ {"version":3,"file":"createHotkeySequence.js","names":[],"sources":["../src/createHotkeySequence.ts"],"sourcesContent":["import { createEffect, onCleanup } from 'solid-js'\nimport { getSequenceManager } from '@tanstack/hotkeys'\nimport { useDefaultHotkeysOptions } from './HotkeysProvider'\nimport type {\n HotkeyCallback,\n HotkeySequence,\n SequenceOptions,\n SequenceRegistrationHandle,\n} from '@tanstack/hotkeys'\n\nexport interface CreateHotkeySequenceOptions extends Omit<\n SequenceOptions,\n 'target'\n> {\n /**\n * The DOM element to attach the event listener to.\n * Can be a direct DOM element, an accessor, or null. Defaults to document.\n */\n target?: HTMLElement | Document | Window | null\n}\n\n/**\n * SolidJS primitive for registering a keyboard shortcut sequence (Vim-style).\n *\n * This primitive allows you to register multi-key sequences like 'g g' or 'd d'\n * that trigger when the full sequence is pressed within a timeout.\n *\n * @param sequence - Array of hotkey strings that form the sequence (or accessor function)\n * @param callback - Function to call when the sequence is completed\n * @param options - Options for the sequence behavior (or accessor function)\n *\n * @example\n * ```tsx\n * function VimEditor() {\n * // 'g g' to go to top\n * createHotkeySequence(['G', 'G'], () => {\n * scrollToTop()\n * })\n *\n * // 'd d' to delete line\n * createHotkeySequence(['D', 'D'], () => {\n * deleteLine()\n * })\n *\n * // 'd i w' to delete inner word\n * createHotkeySequence(['D', 'I', 'W'], () => {\n * deleteInnerWord()\n * }, { timeout: 500 })\n *\n * return <div>...</div>\n * }\n * ```\n */\nexport function createHotkeySequence(\n sequence: HotkeySequence | (() => HotkeySequence),\n callback: HotkeyCallback,\n options:\n | CreateHotkeySequenceOptions\n | (() => CreateHotkeySequenceOptions) = {},\n): void {\n const defaultOptions = useDefaultHotkeysOptions()\n const manager = getSequenceManager()\n\n let registration: SequenceRegistrationHandle | null = null\n\n createEffect(() => {\n // Resolve reactive values\n const resolvedSequence =\n typeof sequence === 'function' ? sequence() : sequence\n const resolvedOptions = typeof options === 'function' ? options() : options\n\n const mergedOptions = {\n ...defaultOptions.hotkeySequence,\n ...resolvedOptions,\n } as CreateHotkeySequenceOptions\n\n // Extract options without target (target is handled separately)\n const { target: _target, ...optionsWithoutTarget } = mergedOptions\n\n if (resolvedSequence.length === 0) {\n return\n }\n\n // Resolve target: when explicitly provided (even as null), use it and skip if null.\n // When not provided, default to document. Matches createHotkey.\n const resolvedTarget =\n 'target' in mergedOptions\n ? (mergedOptions.target ?? null)\n : typeof document !== 'undefined'\n ? document\n : null\n\n if (!resolvedTarget) {\n return\n }\n\n // Unregister previous registration if it exists\n if (registration?.isActive) {\n registration.unregister()\n registration = null\n }\n\n // Register the sequence\n registration = manager.register(resolvedSequence, callback, {\n ...mergedOptions,\n target: resolvedTarget,\n })\n\n // Sync callback and options on every effect run\n if (registration.isActive) {\n registration.callback = callback\n registration.setOptions(optionsWithoutTarget)\n }\n\n // Cleanup on disposal\n onCleanup(() => {\n if (registration?.isActive) {\n registration.unregister()\n registration = null\n }\n })\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDA,SAAgB,qBACd,UACA,UACA,UAE0C,EAAE,EACtC;CACN,MAAM,iBAAiB,0BAA0B;CACjD,MAAM,UAAU,oBAAoB;CAEpC,IAAI,eAAkD;AAEtD,oBAAmB;EAEjB,MAAM,mBACJ,OAAO,aAAa,aAAa,UAAU,GAAG;EAChD,MAAM,kBAAkB,OAAO,YAAY,aAAa,SAAS,GAAG;EAEpE,MAAM,gBAAgB;GACpB,GAAG,eAAe;GAClB,GAAG;GACJ;EAGD,MAAM,EAAE,QAAQ,SAAS,GAAG,yBAAyB;AAErD,MAAI,iBAAiB,WAAW,EAC9B;EAKF,MAAM,iBACJ,YAAY,gBACP,cAAc,UAAU,OACzB,OAAO,aAAa,cAClB,WACA;AAER,MAAI,CAAC,eACH;AAIF,MAAI,cAAc,UAAU;AAC1B,gBAAa,YAAY;AACzB,kBAAe;;AAIjB,iBAAe,QAAQ,SAAS,kBAAkB,UAAU;GAC1D,GAAG;GACH,QAAQ;GACT,CAAC;AAGF,MAAI,aAAa,UAAU;AACzB,gBAAa,WAAW;AACxB,gBAAa,WAAW,qBAAqB;;AAI/C,kBAAgB;AACd,OAAI,cAAc,UAAU;AAC1B,iBAAa,YAAY;AACzB,mBAAe;;IAEjB;GACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/solid-hotkeys",
3
- "version": "0.1.3",
3
+ "version": "0.3.0",
4
4
  "description": "SolidJS adapter for TanStack Hotkeys",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -42,8 +42,8 @@
42
42
  "src"
43
43
  ],
44
44
  "dependencies": {
45
- "@tanstack/solid-store": "^0.8.0",
46
- "@tanstack/hotkeys": "0.1.3"
45
+ "@tanstack/solid-store": "^0.9.1",
46
+ "@tanstack/hotkeys": "0.3.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@solidjs/testing-library": "^0.8.10",
@@ -5,14 +5,18 @@ import type {
5
5
  HotkeyCallback,
6
6
  HotkeySequence,
7
7
  SequenceOptions,
8
+ SequenceRegistrationHandle,
8
9
  } from '@tanstack/hotkeys'
9
10
 
10
11
  export interface CreateHotkeySequenceOptions extends Omit<
11
12
  SequenceOptions,
12
- 'enabled'
13
+ 'target'
13
14
  > {
14
- /** Whether the sequence is enabled. Defaults to true. */
15
- enabled?: boolean
15
+ /**
16
+ * The DOM element to attach the event listener to.
17
+ * Can be a direct DOM element, an accessor, or null. Defaults to document.
18
+ */
19
+ target?: HTMLElement | Document | Window | null
16
20
  }
17
21
 
18
22
  /**
@@ -55,6 +59,9 @@ export function createHotkeySequence(
55
59
  | (() => CreateHotkeySequenceOptions) = {},
56
60
  ): void {
57
61
  const defaultOptions = useDefaultHotkeysOptions()
62
+ const manager = getSequenceManager()
63
+
64
+ let registration: SequenceRegistrationHandle | null = null
58
65
 
59
66
  createEffect(() => {
60
67
  // Resolve reactive values
@@ -67,27 +74,50 @@ export function createHotkeySequence(
67
74
  ...resolvedOptions,
68
75
  } as CreateHotkeySequenceOptions
69
76
 
70
- const { enabled = true, ...sequenceOptions } = mergedOptions
77
+ // Extract options without target (target is handled separately)
78
+ const { target: _target, ...optionsWithoutTarget } = mergedOptions
71
79
 
72
- if (!enabled || resolvedSequence.length === 0) {
80
+ if (resolvedSequence.length === 0) {
73
81
  return
74
82
  }
75
83
 
76
- const manager = getSequenceManager()
84
+ // Resolve target: when explicitly provided (even as null), use it and skip if null.
85
+ // When not provided, default to document. Matches createHotkey.
86
+ const resolvedTarget =
87
+ 'target' in mergedOptions
88
+ ? (mergedOptions.target ?? null)
89
+ : typeof document !== 'undefined'
90
+ ? document
91
+ : null
77
92
 
78
- // Build options object conditionally to avoid overwriting manager defaults with undefined
79
- const registerOptions: SequenceOptions = { enabled: true }
80
- if (sequenceOptions.timeout !== undefined)
81
- registerOptions.timeout = sequenceOptions.timeout
82
- if (sequenceOptions.platform !== undefined)
83
- registerOptions.platform = sequenceOptions.platform
93
+ if (!resolvedTarget) {
94
+ return
95
+ }
84
96
 
85
- const unregister = manager.register(
86
- resolvedSequence,
87
- callback,
88
- registerOptions,
89
- )
97
+ // Unregister previous registration if it exists
98
+ if (registration?.isActive) {
99
+ registration.unregister()
100
+ registration = null
101
+ }
102
+
103
+ // Register the sequence
104
+ registration = manager.register(resolvedSequence, callback, {
105
+ ...mergedOptions,
106
+ target: resolvedTarget,
107
+ })
108
+
109
+ // Sync callback and options on every effect run
110
+ if (registration.isActive) {
111
+ registration.callback = callback
112
+ registration.setOptions(optionsWithoutTarget)
113
+ }
90
114
 
91
- onCleanup(unregister)
115
+ // Cleanup on disposal
116
+ onCleanup(() => {
117
+ if (registration?.isActive) {
118
+ registration.unregister()
119
+ registration = null
120
+ }
121
+ })
92
122
  })
93
123
  }