@tanstack/lit-hotkeys 0.13.1 → 0.15.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.
- package/README.md +3 -0
- package/dist/controllers/_app-hotkeys.js +11 -0
- package/dist/controllers/app-hotkeys.d.ts +48 -0
- package/dist/controllers/app-hotkeys.js +84 -0
- package/dist/controllers/hotkey-hint.d.ts +2 -2
- package/dist/controllers/hotkey-hint.js +13 -5
- package/dist/controllers/hotkey-recorder.d.ts +22 -9
- package/dist/controllers/hotkey-recorder.js +28 -15
- package/dist/controllers/hotkey-registrations.d.ts +11 -18
- package/dist/controllers/hotkey-registrations.js +19 -37
- package/dist/controllers/hotkey.d.ts +44 -18
- package/dist/controllers/hotkey.js +44 -35
- package/dist/controllers/index.d.ts +3 -4
- package/dist/controllers/key-hold.d.ts +2 -2
- package/dist/controllers/key-hold.js +2 -2
- package/dist/decorators/hotkey.d.ts +11 -7
- package/dist/decorators/hotkey.js +1 -21
- package/dist/decorators/index.d.ts +1 -2
- package/dist/index.d.ts +3 -5
- package/dist/index.js +2 -4
- package/package.json +2 -2
- package/dist/constants.js +0 -24
- package/dist/controllers/hotkey-sequence-recorder.d.ts +0 -80
- package/dist/controllers/hotkey-sequence-recorder.js +0 -125
- package/dist/controllers/hotkey-sequence.d.ts +0 -42
- package/dist/controllers/hotkey-sequence.js +0 -63
- package/dist/decorators/hotkey-sequence.d.ts +0 -25
- package/dist/decorators/hotkey-sequence.js +0 -44
package/README.md
CHANGED
|
@@ -67,6 +67,9 @@ Type-safe keyboard shortcuts for the web. Template-string bindings, parsed objec
|
|
|
67
67
|
> [!NOTE]
|
|
68
68
|
> You may know **TanStack Hotkeys** by our adapter names, too!
|
|
69
69
|
>
|
|
70
|
+
> - [**Alpine Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/alpine/quick-start)
|
|
71
|
+
> - [**Ember Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/ember/quick-start)
|
|
72
|
+
> - [**Octane Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/octane/quick-start)
|
|
70
73
|
> - [**React Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/react/react-hotkeys)
|
|
71
74
|
> - [**Preact Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/preact/preact-hotkeys)
|
|
72
75
|
> - [**Solid Hotkeys**](https://tanstack.com/hotkeys/latest/docs/framework/solid/reference)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getHotkeyManager } from "@tanstack/hotkeys";
|
|
2
|
+
import { subscribePublishedAppHotkeys as subscribeAppHotkeys } from "@tanstack/hotkeys/adapter";
|
|
3
|
+
|
|
4
|
+
//#region src/controllers/_app-hotkeys.ts
|
|
5
|
+
/** The app hotkeys store published by `provideAppHotkeys`, if any. */
|
|
6
|
+
function getAppHotkeysStore() {
|
|
7
|
+
return getHotkeyManager().appHotkeys.state;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { getAppHotkeysStore, subscribeAppHotkeys };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { AppHotkey, AppHotkeyListItem, CustomHotkeys, Hotkey, RegisteredAppHotkeys } from "@tanstack/hotkeys";
|
|
2
|
+
import { ReactiveController, ReactiveControllerHost } from "lit";
|
|
3
|
+
//#region src/controllers/app-hotkeys.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A Lit ReactiveController for app hotkeys provided with `provideAppHotkeys`:
|
|
6
|
+
* the effective app hotkeys, a cheat sheet list with live status, and the
|
|
7
|
+
* user's custom hotkeys. Requests an update when any of them change.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* class CheatSheet extends LitElement {
|
|
12
|
+
* private app = new AppHotkeysController(this)
|
|
13
|
+
*
|
|
14
|
+
* render() {
|
|
15
|
+
* return html`<ul>
|
|
16
|
+
* ${this.app.list.map(
|
|
17
|
+
* ({ appHotkey, status }) => html`<li>${appHotkey.meta?.name}: ${status}</li>`,
|
|
18
|
+
* )}
|
|
19
|
+
* </ul>`
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare class AppHotkeysController implements ReactiveController {
|
|
25
|
+
private _host;
|
|
26
|
+
private _unsubscribe;
|
|
27
|
+
constructor(_host: ReactiveControllerHost);
|
|
28
|
+
/** Effective app hotkeys, typed by `Register`. */
|
|
29
|
+
get appHotkeys(): RegisteredAppHotkeys;
|
|
30
|
+
/** Every app hotkey with its live status, in declaration order. */
|
|
31
|
+
get list(): Array<AppHotkeyListItem<RegisteredAppHotkeys[keyof RegisteredAppHotkeys]>>;
|
|
32
|
+
/** The user's hotkeys that differ from the defaults. */
|
|
33
|
+
get customHotkeys(): CustomHotkeys;
|
|
34
|
+
/**
|
|
35
|
+
* Sets the user's hotkey for an app hotkey. `null` unbinds it.
|
|
36
|
+
* Returns conflicting app hotkeys; when any exist, nothing changes.
|
|
37
|
+
*/
|
|
38
|
+
setCustomHotkey(id: keyof RegisteredAppHotkeys & string, hotkey: Hotkey | null): Array<AppHotkey>;
|
|
39
|
+
/** Restores the default hotkey for an app hotkey. */
|
|
40
|
+
resetCustomHotkey(id: keyof RegisteredAppHotkeys & string): void;
|
|
41
|
+
/** Restores every default hotkey. */
|
|
42
|
+
resetCustomHotkeys(): void;
|
|
43
|
+
/** Other app hotkeys that would collide if `id` used `hotkey`. */
|
|
44
|
+
findConflicts(id: keyof RegisteredAppHotkeys & string, hotkey: Hotkey): Array<AppHotkey>;
|
|
45
|
+
hostConnected(): void;
|
|
46
|
+
hostDisconnected(): void;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { getAppHotkeysStore, subscribeAppHotkeys } from "./_app-hotkeys.js";
|
|
2
|
+
import { getHotkeyManager, toHotkeyRegistrationView } from "@tanstack/hotkeys";
|
|
3
|
+
|
|
4
|
+
//#region src/controllers/app-hotkeys.ts
|
|
5
|
+
function requireStore() {
|
|
6
|
+
const store = getAppHotkeysStore();
|
|
7
|
+
if (!store) throw new Error("AppHotkeysController requires provideAppHotkeys()");
|
|
8
|
+
return store;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A Lit ReactiveController for app hotkeys provided with `provideAppHotkeys`:
|
|
12
|
+
* the effective app hotkeys, a cheat sheet list with live status, and the
|
|
13
|
+
* user's custom hotkeys. Requests an update when any of them change.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* class CheatSheet extends LitElement {
|
|
18
|
+
* private app = new AppHotkeysController(this)
|
|
19
|
+
*
|
|
20
|
+
* render() {
|
|
21
|
+
* return html`<ul>
|
|
22
|
+
* ${this.app.list.map(
|
|
23
|
+
* ({ appHotkey, status }) => html`<li>${appHotkey.meta?.name}: ${status}</li>`,
|
|
24
|
+
* )}
|
|
25
|
+
* </ul>`
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
var AppHotkeysController = class {
|
|
31
|
+
_host;
|
|
32
|
+
_unsubscribe;
|
|
33
|
+
constructor(_host) {
|
|
34
|
+
this._host = _host;
|
|
35
|
+
this._host.addController(this);
|
|
36
|
+
}
|
|
37
|
+
/** Effective app hotkeys, typed by `Register`. */
|
|
38
|
+
get appHotkeys() {
|
|
39
|
+
return requireStore().appHotkeys;
|
|
40
|
+
}
|
|
41
|
+
/** Every app hotkey with its live status, in declaration order. */
|
|
42
|
+
get list() {
|
|
43
|
+
return requireStore().getList(Array.from(getHotkeyManager().registrations.state.values()).map(toHotkeyRegistrationView));
|
|
44
|
+
}
|
|
45
|
+
/** The user's hotkeys that differ from the defaults. */
|
|
46
|
+
get customHotkeys() {
|
|
47
|
+
return requireStore().customHotkeys;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Sets the user's hotkey for an app hotkey. `null` unbinds it.
|
|
51
|
+
* Returns conflicting app hotkeys; when any exist, nothing changes.
|
|
52
|
+
*/
|
|
53
|
+
setCustomHotkey(id, hotkey) {
|
|
54
|
+
return requireStore().setCustomHotkey(id, hotkey);
|
|
55
|
+
}
|
|
56
|
+
/** Restores the default hotkey for an app hotkey. */
|
|
57
|
+
resetCustomHotkey(id) {
|
|
58
|
+
requireStore().resetCustomHotkey(id);
|
|
59
|
+
}
|
|
60
|
+
/** Restores every default hotkey. */
|
|
61
|
+
resetCustomHotkeys() {
|
|
62
|
+
requireStore().resetCustomHotkeys();
|
|
63
|
+
}
|
|
64
|
+
/** Other app hotkeys that would collide if `id` used `hotkey`. */
|
|
65
|
+
findConflicts(id, hotkey) {
|
|
66
|
+
return requireStore().findConflicts(id, hotkey);
|
|
67
|
+
}
|
|
68
|
+
hostConnected() {
|
|
69
|
+
const update = () => this._host.requestUpdate();
|
|
70
|
+
const unsubscribeAppHotkeys = subscribeAppHotkeys(update);
|
|
71
|
+
const registrations = getHotkeyManager().registrations.subscribe(update);
|
|
72
|
+
this._unsubscribe = () => {
|
|
73
|
+
unsubscribeAppHotkeys();
|
|
74
|
+
registrations.unsubscribe();
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
hostDisconnected() {
|
|
78
|
+
this._unsubscribe?.();
|
|
79
|
+
this._unsubscribe = void 0;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
export { AppHotkeysController };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HeldModifierOptions, RegisterableHotkey } from "@tanstack/hotkeys";
|
|
1
|
+
import { AppHotkey, HeldModifierOptions, RegisterableHotkey } from "@tanstack/hotkeys";
|
|
2
2
|
import { ReactiveController, ReactiveControllerHost } from "lit";
|
|
3
3
|
//#region src/controllers/hotkey-hint.d.ts
|
|
4
4
|
/** Modifier hint controller. Getter arguments can read reactive host properties. */
|
|
@@ -9,7 +9,7 @@ export declare class HotkeyHintController implements ReactiveController {
|
|
|
9
9
|
private unsubscribe?;
|
|
10
10
|
private visible;
|
|
11
11
|
/** Attaches to the host; getter arguments can read changing reactive properties. */
|
|
12
|
-
constructor(host: ReactiveControllerHost, hotkey: RegisterableHotkey | (() => RegisterableHotkey), options?: HeldModifierOptions | (() => HeldModifierOptions));
|
|
12
|
+
constructor(host: ReactiveControllerHost, hotkey: RegisterableHotkey | AppHotkey | (() => RegisterableHotkey | AppHotkey), options?: HeldModifierOptions | (() => HeldModifierOptions));
|
|
13
13
|
/** Current visibility; combine with the action’s enabled state when rendering. */
|
|
14
14
|
get value(): boolean;
|
|
15
15
|
/** Subscribes on connection and requests renders only when hint visibility changes. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getAppHotkeysStore, subscribeAppHotkeys } from "./_app-hotkeys.js";
|
|
2
|
+
import { getKeyStateTracker, isAppHotkey, matchesHeldModifiers, resolveAppHotkey } from "@tanstack/hotkeys";
|
|
2
3
|
|
|
3
4
|
//#region src/controllers/hotkey-hint.ts
|
|
4
5
|
/** Modifier hint controller. Getter arguments can read reactive host properties. */
|
|
@@ -22,10 +23,15 @@ var HotkeyHintController = class {
|
|
|
22
23
|
/** Subscribes on connection and requests renders only when hint visibility changes. */
|
|
23
24
|
hostConnected() {
|
|
24
25
|
this.update();
|
|
25
|
-
const
|
|
26
|
+
const refresh = () => {
|
|
26
27
|
if (this.update()) this.host.requestUpdate();
|
|
27
|
-
}
|
|
28
|
-
|
|
28
|
+
};
|
|
29
|
+
const subscription = getKeyStateTracker().store.subscribe(refresh);
|
|
30
|
+
const unsubscribeAppHotkeys = subscribeAppHotkeys(refresh);
|
|
31
|
+
this.unsubscribe = () => {
|
|
32
|
+
subscription.unsubscribe();
|
|
33
|
+
unsubscribeAppHotkeys();
|
|
34
|
+
};
|
|
29
35
|
}
|
|
30
36
|
/** Re-evaluates getter arguments when host properties trigger an update. */
|
|
31
37
|
hostUpdate() {
|
|
@@ -39,7 +45,9 @@ var HotkeyHintController = class {
|
|
|
39
45
|
}
|
|
40
46
|
/** Recomputes visibility and reports whether the host needs another render. */
|
|
41
47
|
update() {
|
|
42
|
-
const
|
|
48
|
+
const value = typeof this.hotkey === "function" ? this.hotkey() : this.hotkey;
|
|
49
|
+
const hotkey = isAppHotkey(value) ? resolveAppHotkey(value, getAppHotkeysStore()).hotkey : value;
|
|
50
|
+
const next = hotkey !== null && matchesHeldModifiers(hotkey, getKeyStateTracker().store.state.heldKeys, typeof this.options === "function" ? this.options() : this.options);
|
|
43
51
|
const changed = next !== this.visible;
|
|
44
52
|
this.visible = next;
|
|
45
53
|
return changed;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { Hotkey, HotkeyRecorderOptions } from "@tanstack/hotkeys";
|
|
1
|
+
import { Hotkey, HotkeyChordRecorderOptions, HotkeyRecorderOptions, HotkeySequence, HotkeySequenceRecorderOptions } from "@tanstack/hotkeys";
|
|
2
2
|
import { ReactiveController, ReactiveControllerHost } from "lit";
|
|
3
3
|
//#region src/controllers/hotkey-recorder.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* A Lit ReactiveController that records keyboard shortcuts.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* With the default `maxSteps: 1`, the first valid chord is recorded. With a
|
|
8
|
+
* larger `maxSteps`, each chord adds a step; the recording commits on Enter
|
|
9
|
+
* (unless `commitKeys: 'none'`), after `idleTimeoutMs`, or at `maxSteps`, and
|
|
10
|
+
* `onRecord` receives a chord (one step) or a sequence. Escape cancels;
|
|
11
|
+
* Backspace/Delete removes the last step or clears.
|
|
10
12
|
*
|
|
11
13
|
* @example
|
|
12
14
|
* ```ts
|
|
@@ -41,21 +43,30 @@ export declare class HotkeyRecorderController implements ReactiveController {
|
|
|
41
43
|
private _options;
|
|
42
44
|
/** The recorder instance. */
|
|
43
45
|
private _recorder;
|
|
46
|
+
private _optionOverrides;
|
|
44
47
|
/** The unsubscribe function to unsubscribe from the recorder store. */
|
|
45
48
|
private _unsubscribe;
|
|
46
49
|
/** Whether recording is currently active. */
|
|
47
50
|
private _isRecording;
|
|
48
|
-
/** The
|
|
51
|
+
/** The last committed hotkey. */
|
|
49
52
|
private _recordedHotkey;
|
|
53
|
+
/** Chords recorded so far in a multi-step recording. */
|
|
54
|
+
private _steps;
|
|
50
55
|
/** Whether recording is currently active. */
|
|
51
56
|
get isRecording(): boolean;
|
|
52
|
-
/** The
|
|
57
|
+
/** The last committed hotkey: a chord, or a sequence of two or more steps. */
|
|
53
58
|
get recordedHotkey(): Hotkey | null;
|
|
59
|
+
/** Chords recorded so far in a multi-step recording (for live preview). */
|
|
60
|
+
get steps(): HotkeySequence;
|
|
54
61
|
/**
|
|
55
|
-
* @param
|
|
56
|
-
* @param
|
|
62
|
+
* @param host - The Lit component that owns this controller.
|
|
63
|
+
* @param options - Options or a getter, read during recording.
|
|
57
64
|
*/
|
|
58
|
-
constructor(
|
|
65
|
+
constructor(host: ReactiveControllerHost, options: HotkeyChordRecorderOptions);
|
|
66
|
+
constructor(host: ReactiveControllerHost, options: HotkeySequenceRecorderOptions);
|
|
67
|
+
constructor(host: ReactiveControllerHost, options: () => HotkeySequenceRecorderOptions);
|
|
68
|
+
constructor(host: ReactiveControllerHost, options: () => HotkeyChordRecorderOptions);
|
|
69
|
+
constructor(host: ReactiveControllerHost, options: () => HotkeyRecorderOptions);
|
|
59
70
|
/** Subscribes to the recorder store and updates the internal state when changes occur. */
|
|
60
71
|
hostConnected(): void;
|
|
61
72
|
/** Unsubscribes from the recorder store and destroys the recorder instance to prevent memory leaks. */
|
|
@@ -68,5 +79,7 @@ export declare class HotkeyRecorderController implements ReactiveController {
|
|
|
68
79
|
stopRecording(): void;
|
|
69
80
|
/** Cancel recording without saving. */
|
|
70
81
|
cancelRecording(): void;
|
|
82
|
+
/** Commit the recorded steps now (multi-step recordings). */
|
|
83
|
+
commitRecording(): void;
|
|
71
84
|
}
|
|
72
85
|
//#endregion
|
|
@@ -4,9 +4,11 @@ import { HotkeyRecorder } from "@tanstack/hotkeys";
|
|
|
4
4
|
/**
|
|
5
5
|
* A Lit ReactiveController that records keyboard shortcuts.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* With the default `maxSteps: 1`, the first valid chord is recorded. With a
|
|
8
|
+
* larger `maxSteps`, each chord adds a step; the recording commits on Enter
|
|
9
|
+
* (unless `commitKeys: 'none'`), after `idleTimeoutMs`, or at `maxSteps`, and
|
|
10
|
+
* `onRecord` receives a chord (one step) or a sequence. Escape cancels;
|
|
11
|
+
* Backspace/Delete removes the last step or clears.
|
|
10
12
|
*
|
|
11
13
|
* @example
|
|
12
14
|
* ```ts
|
|
@@ -41,37 +43,44 @@ var HotkeyRecorderController = class {
|
|
|
41
43
|
_options;
|
|
42
44
|
/** The recorder instance. */
|
|
43
45
|
_recorder;
|
|
46
|
+
_optionOverrides = {};
|
|
44
47
|
/** The unsubscribe function to unsubscribe from the recorder store. */
|
|
45
48
|
_unsubscribe;
|
|
46
49
|
/** Whether recording is currently active. */
|
|
47
50
|
_isRecording = false;
|
|
48
|
-
/** The
|
|
51
|
+
/** The last committed hotkey. */
|
|
49
52
|
_recordedHotkey = null;
|
|
53
|
+
/** Chords recorded so far in a multi-step recording. */
|
|
54
|
+
_steps = [];
|
|
50
55
|
/** Whether recording is currently active. */
|
|
51
56
|
get isRecording() {
|
|
52
57
|
return this._isRecording;
|
|
53
58
|
}
|
|
54
|
-
/** The
|
|
59
|
+
/** The last committed hotkey: a chord, or a sequence of two or more steps. */
|
|
55
60
|
get recordedHotkey() {
|
|
56
61
|
return this._recordedHotkey;
|
|
57
62
|
}
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
/** Chords recorded so far in a multi-step recording (for live preview). */
|
|
64
|
+
get steps() {
|
|
65
|
+
return this._steps;
|
|
66
|
+
}
|
|
62
67
|
constructor(_host, _options) {
|
|
63
68
|
this._host = _host;
|
|
64
69
|
this._options = _options;
|
|
65
|
-
this._recorder = new HotkeyRecorder(
|
|
70
|
+
this._recorder = new HotkeyRecorder(() => ({
|
|
71
|
+
...typeof this._options === "function" ? this._options() : this._options,
|
|
72
|
+
...this._optionOverrides
|
|
73
|
+
}));
|
|
66
74
|
this._host.addController(this);
|
|
67
75
|
}
|
|
68
76
|
/** Subscribes to the recorder store and updates the internal state when changes occur. */
|
|
69
77
|
hostConnected() {
|
|
70
78
|
const subscription = this._recorder.store.subscribe(() => {
|
|
71
|
-
const { isRecording, recordedHotkey } = this._recorder.store.state;
|
|
72
|
-
if (isRecording !== this._isRecording || recordedHotkey !== this._recordedHotkey) {
|
|
79
|
+
const { isRecording, recordedHotkey, steps } = this._recorder.store.state;
|
|
80
|
+
if (isRecording !== this._isRecording || recordedHotkey !== this._recordedHotkey || steps !== this._steps) {
|
|
73
81
|
this._isRecording = isRecording;
|
|
74
82
|
this._recordedHotkey = recordedHotkey;
|
|
83
|
+
this._steps = steps;
|
|
75
84
|
this._host.requestUpdate();
|
|
76
85
|
}
|
|
77
86
|
});
|
|
@@ -84,14 +93,14 @@ var HotkeyRecorderController = class {
|
|
|
84
93
|
this._recorder.stop();
|
|
85
94
|
this._isRecording = false;
|
|
86
95
|
this._recordedHotkey = null;
|
|
96
|
+
this._steps = [];
|
|
87
97
|
}
|
|
88
98
|
/** Updates the recorder options (e.g. callbacks). */
|
|
89
99
|
setOptions(options) {
|
|
90
|
-
this.
|
|
91
|
-
...this.
|
|
100
|
+
this._optionOverrides = {
|
|
101
|
+
...this._optionOverrides,
|
|
92
102
|
...options
|
|
93
103
|
};
|
|
94
|
-
this._recorder.setOptions(this._options);
|
|
95
104
|
}
|
|
96
105
|
/** Start recording a new hotkey. */
|
|
97
106
|
startRecording() {
|
|
@@ -105,6 +114,10 @@ var HotkeyRecorderController = class {
|
|
|
105
114
|
cancelRecording() {
|
|
106
115
|
this._recorder.cancel();
|
|
107
116
|
}
|
|
117
|
+
/** Commit the recorded steps now (multi-step recordings). */
|
|
118
|
+
commitRecording() {
|
|
119
|
+
this._recorder.commit();
|
|
120
|
+
}
|
|
108
121
|
};
|
|
109
122
|
|
|
110
123
|
//#endregion
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { HotkeyRegistrationView
|
|
1
|
+
import { HotkeyRegistrationView } from "@tanstack/hotkeys";
|
|
2
2
|
import { ReactiveController, ReactiveControllerHost } from "lit";
|
|
3
3
|
//#region src/controllers/hotkey-registrations.d.ts
|
|
4
4
|
/**
|
|
5
|
-
* A Lit ReactiveController that
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* triggers host updates whenever registrations change.
|
|
5
|
+
* A Lit ReactiveController that reads every hotkey registration, chords and
|
|
6
|
+
* sequences, from the singleton HotkeyManager and requests an update when
|
|
7
|
+
* they change. Narrow each view with `kind`.
|
|
9
8
|
*
|
|
10
9
|
* @example
|
|
11
10
|
* ```ts
|
|
@@ -13,27 +12,21 @@ import { ReactiveController, ReactiveControllerHost } from "lit";
|
|
|
13
12
|
* private registrations = new HotkeyRegistrationsController(this)
|
|
14
13
|
*
|
|
15
14
|
* render() {
|
|
16
|
-
* return html
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* </ul>
|
|
22
|
-
* `
|
|
15
|
+
* return html`<ul>
|
|
16
|
+
* ${this.registrations.hotkeys.map(
|
|
17
|
+
* (reg) => html`<li>${reg.options.meta?.name}: ${formatForDisplay(reg.hotkey)}</li>`,
|
|
18
|
+
* )}
|
|
19
|
+
* </ul>`
|
|
23
20
|
* }
|
|
24
21
|
* }
|
|
25
22
|
* ```
|
|
26
23
|
*/
|
|
27
24
|
export declare class HotkeyRegistrationsController implements ReactiveController {
|
|
28
25
|
private _host;
|
|
29
|
-
private
|
|
30
|
-
private _unsubscribeSequences;
|
|
26
|
+
private _unsubscribe;
|
|
31
27
|
private _hotkeys;
|
|
32
|
-
|
|
33
|
-
/** All registered hotkeys (public view, no callbacks). */
|
|
28
|
+
/** Every registration, chords and sequences (public view, no callbacks). */
|
|
34
29
|
get hotkeys(): Array<HotkeyRegistrationView>;
|
|
35
|
-
/** All registered sequences. */
|
|
36
|
-
get sequences(): Array<SequenceRegistrationView>;
|
|
37
30
|
constructor(_host: ReactiveControllerHost);
|
|
38
31
|
hostConnected(): void;
|
|
39
32
|
hostDisconnected(): void;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { getHotkeyManager,
|
|
1
|
+
import { getHotkeyManager, toHotkeyRegistrationView } from "@tanstack/hotkeys";
|
|
2
2
|
|
|
3
3
|
//#region src/controllers/hotkey-registrations.ts
|
|
4
4
|
/**
|
|
5
|
-
* A Lit ReactiveController that
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* triggers host updates whenever registrations change.
|
|
5
|
+
* A Lit ReactiveController that reads every hotkey registration, chords and
|
|
6
|
+
* sequences, from the singleton HotkeyManager and requests an update when
|
|
7
|
+
* they change. Narrow each view with `kind`.
|
|
9
8
|
*
|
|
10
9
|
* @example
|
|
11
10
|
* ```ts
|
|
@@ -13,58 +12,41 @@ import { getHotkeyManager, getSequenceManager, toHotkeyRegistrationView } from "
|
|
|
13
12
|
* private registrations = new HotkeyRegistrationsController(this)
|
|
14
13
|
*
|
|
15
14
|
* render() {
|
|
16
|
-
* return html
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* </ul>
|
|
22
|
-
* `
|
|
15
|
+
* return html`<ul>
|
|
16
|
+
* ${this.registrations.hotkeys.map(
|
|
17
|
+
* (reg) => html`<li>${reg.options.meta?.name}: ${formatForDisplay(reg.hotkey)}</li>`,
|
|
18
|
+
* )}
|
|
19
|
+
* </ul>`
|
|
23
20
|
* }
|
|
24
21
|
* }
|
|
25
22
|
* ```
|
|
26
23
|
*/
|
|
27
24
|
var HotkeyRegistrationsController = class {
|
|
28
25
|
_host;
|
|
29
|
-
|
|
30
|
-
_unsubscribeSequences;
|
|
26
|
+
_unsubscribe;
|
|
31
27
|
_hotkeys = [];
|
|
32
|
-
|
|
33
|
-
/** All registered hotkeys (public view, no callbacks). */
|
|
28
|
+
/** Every registration, chords and sequences (public view, no callbacks). */
|
|
34
29
|
get hotkeys() {
|
|
35
30
|
return this._hotkeys;
|
|
36
31
|
}
|
|
37
|
-
/** All registered sequences. */
|
|
38
|
-
get sequences() {
|
|
39
|
-
return this._sequences;
|
|
40
|
-
}
|
|
41
32
|
constructor(_host) {
|
|
42
33
|
this._host = _host;
|
|
43
34
|
this._host.addController(this);
|
|
44
35
|
}
|
|
45
36
|
hostConnected() {
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
this._hotkeys =
|
|
50
|
-
this._host.requestUpdate();
|
|
51
|
-
});
|
|
52
|
-
const sequencesSub = sequenceManager.registrations.subscribe(() => {
|
|
53
|
-
this._sequences = Array.from(sequenceManager.registrations.state.values());
|
|
37
|
+
const manager = getHotkeyManager();
|
|
38
|
+
const read = () => Array.from(manager.registrations.state.values()).map(toHotkeyRegistrationView);
|
|
39
|
+
const subscription = manager.registrations.subscribe(() => {
|
|
40
|
+
this._hotkeys = read();
|
|
54
41
|
this._host.requestUpdate();
|
|
55
42
|
});
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
58
|
-
this._hotkeys = Array.from(hotkeyManager.registrations.state.values()).map(toHotkeyRegistrationView);
|
|
59
|
-
this._sequences = Array.from(sequenceManager.registrations.state.values());
|
|
43
|
+
this._unsubscribe = () => subscription.unsubscribe();
|
|
44
|
+
this._hotkeys = read();
|
|
60
45
|
}
|
|
61
46
|
hostDisconnected() {
|
|
62
|
-
this.
|
|
63
|
-
this.
|
|
64
|
-
this._unsubscribeHotkeys = void 0;
|
|
65
|
-
this._unsubscribeSequences = void 0;
|
|
47
|
+
this._unsubscribe?.();
|
|
48
|
+
this._unsubscribe = void 0;
|
|
66
49
|
this._hotkeys = [];
|
|
67
|
-
this._sequences = [];
|
|
68
50
|
}
|
|
69
51
|
};
|
|
70
52
|
|
|
@@ -1,18 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AppHotkey, HotkeyCallback, RegisterableHotkey, Target } from "@tanstack/hotkeys";
|
|
2
|
+
import { AdapterAppHotkeyOptions, AdapterChordOptions, AdapterCommonOptions, AdapterHotkeyOptions, AdapterOptionsFor, AdapterSequenceOptions } from "@tanstack/hotkeys/adapter";
|
|
2
3
|
import { ReactiveController, ReactiveControllerHost } from "lit";
|
|
3
4
|
//#region src/controllers/hotkey.d.ts
|
|
5
|
+
/** The element to listen on. A `null` target skips registration until it is set. */
|
|
6
|
+
export type HotkeyControllerTarget = Target | null;
|
|
7
|
+
/** Options shared by chords and sequences. */
|
|
8
|
+
export type HotkeyControllerOptions = AdapterHotkeyOptions<HotkeyControllerTarget>;
|
|
9
|
+
/** Options for a chord such as `'Mod+S'`. */
|
|
10
|
+
export type HotkeyControllerChordOptions = AdapterChordOptions<HotkeyControllerTarget>;
|
|
11
|
+
/** Options for a sequence such as `['G', 'G']`. */
|
|
12
|
+
export type HotkeyControllerSequenceOptions = AdapterSequenceOptions<HotkeyControllerTarget>;
|
|
13
|
+
/** Options for every kind; each applies to the kinds that support it. */
|
|
14
|
+
export type HotkeyControllerCommonOptions = AdapterCommonOptions<HotkeyControllerTarget>;
|
|
15
|
+
/** The options type for a hotkey: chord options for chords, sequence options for sequences. */
|
|
16
|
+
export type HotkeyControllerOptionsFor<T extends RegisterableHotkey> = AdapterOptionsFor<T, HotkeyControllerTarget>;
|
|
17
|
+
/** Call-site options for an app hotkey, typed by its declared default kind. */
|
|
18
|
+
export type AppHotkeyControllerOptions<T extends AppHotkey = AppHotkey> = AdapterAppHotkeyOptions<T, HotkeyControllerTarget>;
|
|
19
|
+
type MaybeGetter<T> = T | (() => T);
|
|
4
20
|
/**
|
|
5
|
-
* A Lit ReactiveController that registers a
|
|
6
|
-
*
|
|
21
|
+
* A Lit ReactiveController that registers a hotkey when the host element is
|
|
22
|
+
* connected and unregisters it when the host is disconnected. The hotkey can
|
|
23
|
+
* be a chord such as `'Mod+S'`, a sequence such as `['G', 'G']`, or an app
|
|
24
|
+
* hotkey from `defineAppHotkeys`, which uses its custom hotkey from
|
|
25
|
+
* `provideAppHotkeys`.
|
|
26
|
+
*
|
|
27
|
+
* Chords accept `requireReset`; sequences accept `timeout`. Pass a getter for
|
|
28
|
+
* the hotkey or options to re-read them after each host update.
|
|
7
29
|
*
|
|
8
30
|
* @example
|
|
9
31
|
* ```ts
|
|
10
32
|
* class MyElement extends LitElement {
|
|
11
|
-
* private
|
|
33
|
+
* private save = new HotkeyController(this, 'Mod+S', () => this.doSave())
|
|
34
|
+
* private top = new HotkeyController(this, ['G', 'G'], () => this.scrollToTop())
|
|
12
35
|
*
|
|
13
36
|
* constructor() {
|
|
14
37
|
* super()
|
|
15
|
-
* this.addController(this.
|
|
38
|
+
* this.addController(this.save)
|
|
39
|
+
* this.addController(this.top)
|
|
16
40
|
* }
|
|
17
41
|
* }
|
|
18
42
|
* ```
|
|
@@ -20,23 +44,25 @@ import { ReactiveController, ReactiveControllerHost } from "lit";
|
|
|
20
44
|
export declare class HotkeyController implements ReactiveController {
|
|
21
45
|
private _host;
|
|
22
46
|
private _hotkey;
|
|
23
|
-
private _callback;
|
|
24
47
|
private _options;
|
|
25
|
-
|
|
26
|
-
private
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* @param _hotkey - The key or key combo to listen for (e.g. `'Mod+S'` or a raw hotkey object).
|
|
30
|
-
* @param _callback - Function to run when the hotkey is pressed; called with the host as `this`.
|
|
31
|
-
* @param _options - Optional registration options (target, platform, enabled, etc.).
|
|
32
|
-
*/
|
|
33
|
-
constructor(_host: ReactiveControllerHost, _hotkey: RegisterableHotkey, _callback: HotkeyCallback, _options?: HotkeyOptions);
|
|
48
|
+
private _bindings;
|
|
49
|
+
private _connected;
|
|
50
|
+
private _boundCallback;
|
|
51
|
+
private _unsubscribe;
|
|
34
52
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
53
|
+
* @param host - The Lit component that owns this controller. Add the controller with `addController()`.
|
|
54
|
+
* @param hotkey - The chord, sequence, or app hotkey to register, or a getter. A getter is read on connection and after host updates.
|
|
55
|
+
* @param callback - Called with the host as `this`.
|
|
56
|
+
* @param options - Options or a getter. Property getters are read on connection and after host updates.
|
|
37
57
|
*/
|
|
58
|
+
constructor(host: ReactiveControllerHost, hotkey: MaybeGetter<AppHotkey>, callback: HotkeyCallback, options?: MaybeGetter<AppHotkeyControllerOptions>);
|
|
59
|
+
constructor(host: ReactiveControllerHost, hotkey: MaybeGetter<RegisterableHotkey>, callback: HotkeyCallback, options?: MaybeGetter<HotkeyControllerCommonOptions>);
|
|
60
|
+
/** Registers when connected and a target is available. */
|
|
38
61
|
hostConnected(): void;
|
|
39
|
-
/**
|
|
62
|
+
/** Refreshes options after rendering, when scoped targets are available. */
|
|
63
|
+
hostUpdated(): void;
|
|
64
|
+
private _sync;
|
|
65
|
+
/** Releases registrations when the host disconnects. */
|
|
40
66
|
hostDisconnected(): void;
|
|
41
67
|
}
|
|
42
68
|
//#endregion
|