sequence-controller 1.0.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/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 egorkk1211@gmail.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,185 @@
1
+ # SequenceController
2
+
3
+ Small engine for handling **step combinations and sequences**.
4
+
5
+ Supports:
6
+
7
+ - step combos (`A + B`)
8
+ - combo sequences (`A+B → C`)
9
+ - scoped actions (same combos in different contexts)
10
+ - sequence timeouts
11
+
12
+ ---
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install sequence-controller
18
+ ```
19
+
20
+ ---
21
+
22
+ ## Basic usage
23
+
24
+ ```ts
25
+ const controller = new SequenceController<string>();
26
+
27
+ controller.register(["Ctrl", "S"], {
28
+ handler: () => console.log("Save"),
29
+ });
30
+
31
+ controller.emitStep("Ctrl");
32
+ controller.emitStep("S");
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Keyboard example
38
+
39
+ ```ts
40
+ const controller = new SequenceController<string>();
41
+ controller.register(["Ctrl", "S"], {
42
+ handler: () => console.log("Save"),
43
+ });
44
+
45
+ window.addEventListener("keydown", (e) => {
46
+ const fired = controller.emitStep(e.key);
47
+
48
+ for (const [event, handler] of fired) {
49
+ handler(event);
50
+ }
51
+ });
52
+
53
+ window.addEventListener("keyup", (e) => {
54
+ controller.removeStep(e.key);
55
+ });
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Combos
61
+
62
+ ```ts
63
+ controller.register(["Ctrl", "S"], {
64
+ handler: () => console.log("Save"),
65
+ });
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Sequences
71
+
72
+ ```ts
73
+ controller.register(
74
+ [
75
+ ["Ctrl", "K"],
76
+ ["Ctrl", "C"],
77
+ ],
78
+ {
79
+ handler: () => console.log("Comment"),
80
+ },
81
+ );
82
+ ```
83
+
84
+ Execution order:
85
+
86
+ Ctrl+K → Ctrl+C
87
+
88
+ ---
89
+
90
+ ## Scope
91
+
92
+ Scopes isolate actions so the same combos can exist in different
93
+ contexts.
94
+
95
+ ```ts
96
+ controller.register(["Enter"], { handler: submitForm }, "modal");
97
+
98
+ controller.emitStep("Enter", "modal");
99
+ ```
100
+
101
+ Default scope:
102
+
103
+ $global
104
+
105
+ ---
106
+
107
+ ## Sequence timeout
108
+
109
+ Default: **3 seconds**
110
+
111
+ ```ts
112
+ controller.register([["A"], ["B"]], {
113
+ clearDuration: 5,
114
+ handler: () => console.log("Triggered"),
115
+ });
116
+ ```
117
+
118
+ ---
119
+
120
+ ## API
121
+
122
+ ### register(sequence, setup, scope?)
123
+
124
+ Registers an action.
125
+
126
+ ```ts
127
+ register(
128
+ Combo | Sequence,
129
+ {
130
+ handler: (event) => void
131
+ clearDuration?: number
132
+ },
133
+ scope?: string
134
+ ): ActionId
135
+ ```
136
+
137
+ ---
138
+
139
+ ### emitStep(step, scope?)
140
+
141
+ Processes a step.
142
+
143
+ Returns actions to execute.
144
+
145
+ ```ts
146
+ const fired = controller.emitStep(step);
147
+
148
+ for (const [event, handler] of fired) {
149
+ handler(event);
150
+ }
151
+ ```
152
+
153
+ ---
154
+
155
+ ### removeStep(step)
156
+
157
+ Removes step from active steps.
158
+
159
+ Used for events like `keyup`.
160
+
161
+ ---
162
+
163
+ ### unregister(id)
164
+
165
+ Removes registered action.
166
+
167
+ ---
168
+
169
+ ## Event
170
+
171
+ Handler receives:
172
+
173
+ ```ts
174
+ {
175
+ sequence: Sequence;
176
+ activeSteps: Set;
177
+ timestamp: number;
178
+ }
179
+ ```
180
+
181
+ ---
182
+
183
+ ## License
184
+
185
+ MIT
@@ -0,0 +1,95 @@
1
+ import type { ActionId, Combo, Fired, Scope, SequenceAction, Step, ToString } from "./types";
2
+ /**
3
+ * SequenceController manages step combinations and sequences.
4
+ *
5
+ * It allows registering actions that should fire when specific
6
+ * combinations or ordered sequences of combinations occur.
7
+ *
8
+ * Steps represent currently active inputs (e.g. pressed keys).
9
+ * Actions are grouped by scopes so the same combinations can
10
+ * be reused in different contexts (e.g. editor, modal, global).
11
+ */
12
+ export declare class SequenceController<T extends ToString> {
13
+ /** Currently active steps (global state). */
14
+ private activeSteps;
15
+ /**
16
+ * Index of actions grouped by scope.
17
+ *
18
+ * Structure:
19
+ * scope -> comboKey -> ComboIndexEntry[]
20
+ */
21
+ private scopedIndexes;
22
+ /**
23
+ * Current candidates for sequence progression.
24
+ *
25
+ * Stores partial progress of sequences that already matched
26
+ * one or more combos but haven't finished yet.
27
+ *
28
+ * Structure:
29
+ * scope -> actionId -> candidateState
30
+ */
31
+ private scopedCandidates;
32
+ /**
33
+ * Registers a new sequence action.
34
+ *
35
+ * @param sequence A single combo or an ordered sequence of combos.
36
+ * @param setup Action configuration (handler, clearDuration, etc.).
37
+ * @param scope Logical context where this action is active.
38
+ *
39
+ * @returns ActionId that can be used later to unregister the action.
40
+ */
41
+ register(sequence: Combo<T> | Combo<T>[], setup: Omit<SequenceAction<T>, "id" | "sequence">, scope?: Scope): ActionId;
42
+ /**
43
+ * Removes previously registered action.
44
+ *
45
+ * Also clears any pending sequence candidates associated
46
+ * with the removed action.
47
+ * @param id ID of the action to be deleted
48
+ */
49
+ unregister(id: ActionId): void;
50
+ /**
51
+ * Emits a new step.
52
+ *
53
+ * This method should be called whenever an input step occurs
54
+ * (e.g. keydown event).
55
+ *
56
+ * It checks whether the current active steps match any
57
+ * registered combos or progress any sequence.
58
+ *
59
+ * @param step Current step
60
+ * @param scope Current execution context
61
+ *
62
+ * @returns Array of [event, handler] tuples to be executed.
63
+ */
64
+ emitStep(step: Step<T>, scope?: Scope): Fired<T>;
65
+ /**
66
+ * Removes step from active steps set.
67
+ *
68
+ * Should be called when input step ends
69
+ * (e.g. keyup event).
70
+ * @param step Step to be deleted
71
+ */
72
+ removeStep(step: Step<T>): void;
73
+ /**
74
+ * Creates event object passed to action handlers.
75
+ */
76
+ private buildEvent;
77
+ /**
78
+ * Generates a unique key for a combo.
79
+ *
80
+ * Steps are sorted so combo order doesn't matter.
81
+ */
82
+ private comboKey;
83
+ /**
84
+ * Generates key representing currently active steps.
85
+ */
86
+ private activeKey;
87
+ /**
88
+ * Removes expired sequence candidates.
89
+ *
90
+ * Candidates expire if they are not continued within
91
+ * `clearDuration` seconds.
92
+ */
93
+ private cleanupCandidates;
94
+ }
95
+ //# sourceMappingURL=SequenceController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SequenceController.d.ts","sourceRoot":"","sources":["../src/SequenceController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAGR,KAAK,EACL,KAAK,EACL,KAAK,EAEL,cAAc,EAEd,IAAI,EACJ,QAAQ,EACT,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;GASG;AACH,qBAAa,kBAAkB,CAAC,CAAC,SAAS,QAAQ;IAChD,6CAA6C;IAC7C,OAAO,CAAC,WAAW,CAAgB;IACnC;;;;;OAKG;IACH,OAAO,CAAC,aAAa,CAAoC;IACzD;;;;;;;;OAQG;IACH,OAAO,CAAC,gBAAgB,CAAuC;IAE/D;;;;;;;;OAQG;IACH,QAAQ,CACN,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,EAC/B,KAAK,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,IAAI,GAAG,UAAU,CAAC,EACjD,KAAK,GAAE,KAAiB,GACvB,QAAQ;IAiCX;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,EAAE,QAAQ;IAYvB;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,GAAE,KAAiB,GAAG,KAAK,CAAC,CAAC,CAAC;IAiD3D;;;;;;OAMG;IACH,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAIxB;;OAEG;IACH,OAAO,CAAC,UAAU;IAQlB;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAKhB;;OAEG;IACH,OAAO,CAAC,SAAS;IAKjB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;CAW1B"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * SequenceController manages step combinations and sequences.
3
+ *
4
+ * It allows registering actions that should fire when specific
5
+ * combinations or ordered sequences of combinations occur.
6
+ *
7
+ * Steps represent currently active inputs (e.g. pressed keys).
8
+ * Actions are grouped by scopes so the same combinations can
9
+ * be reused in different contexts (e.g. editor, modal, global).
10
+ */
11
+ export class SequenceController {
12
+ /** Currently active steps (global state). */
13
+ activeSteps = new Set();
14
+ /**
15
+ * Index of actions grouped by scope.
16
+ *
17
+ * Structure:
18
+ * scope -> comboKey -> ComboIndexEntry[]
19
+ */
20
+ scopedIndexes = new Map();
21
+ /**
22
+ * Current candidates for sequence progression.
23
+ *
24
+ * Stores partial progress of sequences that already matched
25
+ * one or more combos but haven't finished yet.
26
+ *
27
+ * Structure:
28
+ * scope -> actionId -> candidateState
29
+ */
30
+ scopedCandidates = new Map();
31
+ /**
32
+ * Registers a new sequence action.
33
+ *
34
+ * @param sequence A single combo or an ordered sequence of combos.
35
+ * @param setup Action configuration (handler, clearDuration, etc.).
36
+ * @param scope Logical context where this action is active.
37
+ *
38
+ * @returns ActionId that can be used later to unregister the action.
39
+ */
40
+ register(sequence, setup, scope = "$global") {
41
+ const id = crypto.randomUUID();
42
+ const normalized = Array.isArray(sequence[0])
43
+ ? sequence
44
+ : [sequence];
45
+ if (!normalized[0] || normalized[0].length === 0)
46
+ throw Error("Empty sequence.");
47
+ const action = {
48
+ id,
49
+ sequence: normalized,
50
+ ...setup,
51
+ };
52
+ const actionIndex = this.scopedIndexes.get(scope) ?? new Map();
53
+ normalized.forEach((combo, index) => {
54
+ const key = this.comboKey(combo);
55
+ const list = actionIndex.get(key) ?? [];
56
+ list.push({
57
+ action,
58
+ index,
59
+ });
60
+ actionIndex.set(key, list);
61
+ });
62
+ this.scopedIndexes.set(scope, actionIndex);
63
+ return id;
64
+ }
65
+ /**
66
+ * Removes previously registered action.
67
+ *
68
+ * Also clears any pending sequence candidates associated
69
+ * with the removed action.
70
+ * @param id ID of the action to be deleted
71
+ */
72
+ unregister(id) {
73
+ for (const [scope, actionIndex] of this.scopedIndexes.entries()) {
74
+ actionIndex.delete(id);
75
+ this.scopedIndexes.set(scope, actionIndex);
76
+ }
77
+ for (const [scope, actionsCandidates] of this.scopedCandidates.entries()) {
78
+ actionsCandidates.delete(id);
79
+ this.scopedCandidates.set(scope, actionsCandidates);
80
+ }
81
+ }
82
+ /**
83
+ * Emits a new step.
84
+ *
85
+ * This method should be called whenever an input step occurs
86
+ * (e.g. keydown event).
87
+ *
88
+ * It checks whether the current active steps match any
89
+ * registered combos or progress any sequence.
90
+ *
91
+ * @param step Current step
92
+ * @param scope Current execution context
93
+ *
94
+ * @returns Array of [event, handler] tuples to be executed.
95
+ */
96
+ emitStep(step, scope = "$global") {
97
+ this.cleanupCandidates(scope);
98
+ const firedToNextStep = new Set();
99
+ const actionIndex = this.scopedIndexes.get(scope);
100
+ if (!actionIndex)
101
+ return [];
102
+ this.activeSteps.add(step);
103
+ const key = this.activeKey();
104
+ const actions = actionIndex.get(key);
105
+ if (!actions)
106
+ return [];
107
+ const actionsCandidates = this.scopedCandidates.get(scope) ?? new Map();
108
+ const emitActions = actions.filter(({ action, index }) => {
109
+ const comboIndex = actionsCandidates.get(action.id)?.index ?? 0;
110
+ const combo = action.sequence[comboIndex];
111
+ if (!combo || index !== comboIndex || firedToNextStep.has(action.id))
112
+ return false;
113
+ firedToNextStep.add(action.id);
114
+ if (comboIndex === action.sequence.length - 1) {
115
+ actionsCandidates.delete(action.id);
116
+ this.scopedCandidates.set(scope, actionsCandidates);
117
+ return true;
118
+ }
119
+ actionsCandidates.set(action.id, {
120
+ index: comboIndex + 1,
121
+ timestamp: Date.now(),
122
+ clearDuration: action.clearDuration,
123
+ });
124
+ this.scopedCandidates.set(scope, actionsCandidates);
125
+ return false;
126
+ });
127
+ const fired = [];
128
+ for (const { action } of emitActions) {
129
+ fired.push([this.buildEvent(action), action.handler]);
130
+ }
131
+ return fired;
132
+ }
133
+ /**
134
+ * Removes step from active steps set.
135
+ *
136
+ * Should be called when input step ends
137
+ * (e.g. keyup event).
138
+ * @param step Step to be deleted
139
+ */
140
+ removeStep(step) {
141
+ this.activeSteps.delete(step);
142
+ }
143
+ /**
144
+ * Creates event object passed to action handlers.
145
+ */
146
+ buildEvent(action) {
147
+ return {
148
+ sequence: action.sequence,
149
+ activeSteps: new Set(this.activeSteps),
150
+ timestamp: Date.now(),
151
+ };
152
+ }
153
+ /**
154
+ * Generates a unique key for a combo.
155
+ *
156
+ * Steps are sorted so combo order doesn't matter.
157
+ */
158
+ comboKey(combo) {
159
+ const strings = combo.map((step) => step.toString()).sort();
160
+ return JSON.stringify(strings);
161
+ }
162
+ /**
163
+ * Generates key representing currently active steps.
164
+ */
165
+ activeKey() {
166
+ const strings = [...this.activeSteps].map((step) => step.toString()).sort();
167
+ return JSON.stringify(strings);
168
+ }
169
+ /**
170
+ * Removes expired sequence candidates.
171
+ *
172
+ * Candidates expire if they are not continued within
173
+ * `clearDuration` seconds.
174
+ */
175
+ cleanupCandidates(scope) {
176
+ const now = Date.now();
177
+ const actionsCandidates = this.scopedCandidates.get(scope);
178
+ if (!actionsCandidates)
179
+ return;
180
+ for (const [id, { timestamp, clearDuration }] of actionsCandidates) {
181
+ const clearMs = (clearDuration ?? 3) * 1000;
182
+ if (now - timestamp > clearMs) {
183
+ actionsCandidates.delete(id);
184
+ }
185
+ }
186
+ }
187
+ }
188
+ //# sourceMappingURL=SequenceController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SequenceController.js","sourceRoot":"","sources":["../src/SequenceController.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from "./SequenceController";
2
+ export type { Step, Combo, Sequence, ToString, ActionId, SequenceEvent, Fired, SequenceActionHandler, SequenceAction, } from "./types";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,YAAY,EACV,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,KAAK,EACL,qBAAqB,EACrB,cAAc,GACf,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./SequenceController";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,36 @@
1
+ export type ToString = {
2
+ toString: () => string;
3
+ };
4
+ export type ActionId = string;
5
+ export type Scope = string;
6
+ export type Step<T extends ToString> = T;
7
+ export type Combo<T extends ToString> = Step<T>[];
8
+ export type Sequence<T extends ToString> = Combo<T>[];
9
+ export type SequenceEvent<T extends ToString> = {
10
+ sequence: Sequence<T>;
11
+ activeSteps: Set<T>;
12
+ timestamp: number;
13
+ };
14
+ export type Fired<T extends ToString> = [
15
+ SequenceEvent<T>,
16
+ SequenceActionHandler<T>
17
+ ][];
18
+ export type SequenceActionHandler<T extends ToString, K extends SequenceEvent<T> = SequenceEvent<T>> = (e: K) => void;
19
+ export type SequenceAction<T extends ToString> = {
20
+ id: ActionId;
21
+ sequence: Sequence<T>;
22
+ handler: SequenceActionHandler<T>;
23
+ clearDuration?: number;
24
+ };
25
+ export type ComboIndexEntry<T extends ToString> = {
26
+ action: SequenceAction<T>;
27
+ index: number;
28
+ };
29
+ export type ActionIndex<T extends ToString> = Map<ActionId, ComboIndexEntry<T>[]>;
30
+ export type ActionCandidate = {
31
+ index: number;
32
+ timestamp: number;
33
+ clearDuration: number | undefined;
34
+ };
35
+ export type ActionsCandidates = Map<ActionId, ActionCandidate>;
36
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC;AAE3B,MAAM,MAAM,IAAI,CAAC,CAAC,SAAS,QAAQ,IAAI,CAAC,CAAC;AAEzC,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AAElD,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAEtD,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,QAAQ,IAAI;IAC9C,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtB,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,QAAQ,IAAI;IACtC,aAAa,CAAC,CAAC,CAAC;IAChB,qBAAqB,CAAC,CAAC,CAAC;CACzB,EAAE,CAAC;AAEJ,MAAM,MAAM,qBAAqB,CAC/B,CAAC,SAAS,QAAQ,EAClB,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,IAC3C,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;AAEnB,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,QAAQ,IAAI;IAC/C,EAAE,EAAE,QAAQ,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtB,OAAO,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,QAAQ,IAAI;IAChD,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,QAAQ,IAAI,GAAG,CAC/C,QAAQ,EACR,eAAe,CAAC,CAAC,CAAC,EAAE,CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,GAAG,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "sequence-controller",
3
+ "version": "1.0.0",
4
+ "description": "A small engine for handling step combos and sequences with scoped actions.",
5
+ "author": "egorkk1211@gmail.com",
6
+ "license": "MIT",
7
+ "main": "dist/index.cjs.js",
8
+ "module": "dist/index.esm.js",
9
+ "types": "dist/index.d.ts",
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc -p tsconfig.json"
15
+ },
16
+ "keywords": [
17
+ "sequence",
18
+ "combo",
19
+ "hotkeys",
20
+ "typescript"
21
+ ],
22
+ "homepage": "https://github.com/Egor-source/sequence_builder/tree/main/packages/sequenceController",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/egorkrotov/sequence_builder.git",
26
+ "directory": "packages/sequenceController"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/Egor-source/sequence_builder/issues"
30
+ },
31
+ "devDependencies": {
32
+ "typescript": "^5.1.6"
33
+ },
34
+ "exports": {
35
+ ".": {
36
+ "import": "./dist/index.esm.js",
37
+ "require": "./dist/index.cjs.js",
38
+ "types": "./dist/index.d.ts"
39
+ }
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ }
44
+ }