secret-sequence-react 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/README.md ADDED
@@ -0,0 +1,249 @@
1
+ <div align="center">
2
+
3
+ # Secret Sequence React
4
+
5
+ [![en](https://img.shields.io/badge/lang-en-red.svg)](./README.md)
6
+ [![es](https://img.shields.io/badge/lang-es-yellow.svg)](./README_ES.md)
7
+
8
+ ![GitHub stars](https://img.shields.io/github/stars/Diego0Alonso/secret-sequence)
9
+ ![GitHub forks](https://img.shields.io/github/forks/Diego0Alonso/secret-sequence)
10
+ ![GitHub issues](https://img.shields.io/github/issues/Diego0Alonso/secret-sequence)
11
+ [![GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub-pink?logo=github)](https://github.com/sponsors/Diego0Alonso)
12
+
13
+ ![React](https://img.shields.io/badge/React-≥17-61DAFB?style=for-the-badge&logo=react)
14
+ ![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue?style=for-the-badge&logo=typescript)
15
+
16
+ > React hook & component for detecting directional sequences, key combos, and touch gestures — powered by [secret-sequence-core](../core/README.md).
17
+
18
+ This package provides **React bindings** for the [Secret Sequence](../../README.md) monorepo.
19
+ It wraps the core engine in a hook and a declarative component with full lifecycle management.
20
+
21
+ </div>
22
+
23
+ ---
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ npm install secret-sequence-react secret-sequence-core
29
+ ````
30
+
31
+ > `secret-sequence-core` is a peer dependency.
32
+
33
+ ---
34
+
35
+ ## Quick Start
36
+
37
+ ### Hook — `useSecretSequence`
38
+
39
+ ```tsx
40
+ import { useSecretSequence } from "secret-sequence-react"
41
+
42
+ function App() {
43
+ const { progress } = useSecretSequence({
44
+ sequences: [
45
+ {
46
+ id: "konami",
47
+ sequence: ["up", "up", "down", "down", "left", "right", "left", "right"],
48
+ onSuccess: () => alert("🎉 Konami Code activated!"),
49
+ },
50
+ ],
51
+ enableTouch: true,
52
+ touchOptions: { minDistance: 50, maxTime: 400 },
53
+ })
54
+
55
+ return <pre>{JSON.stringify(progress, null, 2)}</pre>
56
+ }
57
+ ```
58
+
59
+ ---
60
+
61
+ ### Component — `<SecretSequence />`
62
+
63
+ #### Invisible Mode (effect only)
64
+
65
+ ```tsx
66
+ import { SecretSequence } from "secret-sequence-react"
67
+
68
+ function App() {
69
+ return (
70
+ <SecretSequence
71
+ sequences={[
72
+ {
73
+ id: "konami",
74
+ sequence: ["up", "up", "down", "down", "left", "right", "left", "right"],
75
+ onSuccess: () => console.log("🎉"),
76
+ },
77
+ ]}
78
+ enableTouch={true}
79
+ touchOptions={{ minDistance: 40 }}
80
+ />
81
+ )
82
+ }
83
+ ```
84
+
85
+ #### With render prop
86
+
87
+ ```tsx
88
+ <SecretSequence
89
+ sequences={[{ id: "code", sequence: ["up", "down"], onSuccess: fn }]}
90
+ >
91
+ {({ progress, reset }) => (
92
+ <div>
93
+ <p>Progress: {JSON.stringify(progress)}</p>
94
+ <button onClick={reset}>Reset</button>
95
+ </div>
96
+ )}
97
+ </SecretSequence>
98
+ ```
99
+
100
+ ---
101
+
102
+ ### Stratagem-Style Input
103
+
104
+ ```tsx
105
+ const { progress } = useSecretSequence({
106
+ sequences: [
107
+ {
108
+ id: "orbitalStrike",
109
+ sequence: ["right", "right", "up"],
110
+ onSuccess: () => deployStrike(),
111
+ },
112
+ ],
113
+ timeout: 2000,
114
+ })
115
+ ```
116
+
117
+ ---
118
+
119
+ ### Key Combo Shortcut
120
+
121
+ ```tsx
122
+ const { progress } = useSecretSequence({
123
+ sequences: [
124
+ {
125
+ id: "shortcut",
126
+ sequence: [{ key: "k", ctrl: true }],
127
+ onSuccess: () => console.log("Shortcut triggered"),
128
+ },
129
+ ],
130
+ })
131
+ ```
132
+
133
+ ---
134
+
135
+ ### Touch Gesture Support
136
+
137
+ Swipe gestures on touch devices are automatically mapped to directional steps.
138
+
139
+ ```tsx
140
+ const { progress } = useSecretSequence({
141
+ sequences: [
142
+ {
143
+ id: "swipe-pattern",
144
+ sequence: ["up", "down", "left", "right"],
145
+ onSuccess: () => alert("Swipe pattern detected!"),
146
+ },
147
+ ],
148
+ enableTouch: true,
149
+ touchOptions: {
150
+ minDistance: 30,
151
+ maxTime: 300,
152
+ threshold: 1.5,
153
+ },
154
+ })
155
+ ```
156
+
157
+ ---
158
+
159
+ ## API
160
+
161
+ ### `useSecretSequence(options)`
162
+
163
+ React hook that manages the engine lifecycle automatically.
164
+
165
+ **Returns:** `{ progress, reset }`
166
+
167
+ | Return | Type | Description |
168
+ | ---------- | -------------------------- | ----------------------------- |
169
+ | `progress` | `Record<string, number>` | Current progress per sequence |
170
+ | `reset` | `() => void` | Reset all sequence progress |
171
+
172
+ ---
173
+
174
+ ### `<SecretSequence />` Component
175
+
176
+ Declarative JSX wrapper over the `useSecretSequence` hook.
177
+
178
+ | Prop | Type | Description |
179
+ | ------------------ | ----------------------------------------------------------------------- | ---------------------------------------- |
180
+ | `onProgressChange` | `(progress: Record<string, number>) => void` | Callback fired on progress changes |
181
+ | `children` | `(state: { progress: Record<string, number>; reset: () => void }) => …` | Optional render prop for progress/reset |
182
+ | *...hookOptions* | `UseSecretSequenceOptions` | All hook options (see below) |
183
+
184
+ ---
185
+
186
+ ### Options (shared by hook & component)
187
+
188
+ | Option | Type | Default | Description |
189
+ | -------------- | ------------------------ | ------- | ------------------------------------------------------ |
190
+ | `sequences` | `SecretSequenceConfig[]` | — | Array of sequences to detect simultaneously |
191
+ | `timeout` | `number` | `2000` | Milliseconds of inactivity before resetting progress |
192
+ | `enabled` | `boolean` | `true` | Globally enable or disable detection |
193
+ | `enableTouch` | `boolean` | `true` | Enable swipe gesture detection |
194
+ | `ignoreInputs` | `boolean` | `true` | Ignore key events when focus is on input-like elements |
195
+ | `touchOptions` | `TouchConfig` | — | Advanced touch configuration |
196
+
197
+ ---
198
+
199
+ ## Configuration Types
200
+
201
+ ### `SecretSequenceConfig`
202
+
203
+ | Property | Type | Description |
204
+ | ----------- | --------------------- | ------------------------------------------- |
205
+ | `id` | `string` *(optional)* | Unique identifier (defaults to array index) |
206
+ | `sequence` | `SequenceStep[]` | Ordered steps to detect |
207
+ | `onSuccess` | `() => void` | Fired when the sequence completes |
208
+
209
+ ---
210
+
211
+ ### Core Types
212
+
213
+ ```ts
214
+ type Direction = "up" | "down" | "left" | "right"
215
+
216
+ type KeyCombo = {
217
+ key: string
218
+ ctrl?: boolean
219
+ shift?: boolean
220
+ alt?: boolean
221
+ meta?: boolean
222
+ }
223
+
224
+ type SequenceStep = Direction | KeyCombo
225
+ ```
226
+
227
+ ---
228
+
229
+ ### `TouchConfig`
230
+
231
+ | Property | Type | Default | Description |
232
+ | ------------- | -------- | ------- | ---------------------------------------------- |
233
+ | `minDistance` | `number` | `30` | Minimum swipe distance (px) |
234
+ | `maxTime` | `number` | `300` | Maximum swipe duration (ms) |
235
+ | `threshold` | `number` | `1.5` | Axis dominance ratio to reject diagonal swipes |
236
+
237
+ ---
238
+
239
+ ## SSR Compatibility
240
+
241
+ This package is safe to use in SSR environments such as Next.js or Remix.
242
+
243
+ The underlying engine guards against accessing `window` during server rendering and only attaches event listeners in the browser.
244
+
245
+ ---
246
+
247
+ ## License
248
+
249
+ MIT © Diego Alonso
@@ -0,0 +1,137 @@
1
+ import { SecretSequenceConfig, TouchConfig } from 'secret-sequence-core';
2
+ export { Direction, KeyCombo, SecretSequenceConfig, SecretSequenceEngineOptions, SequenceStep, SwipeDirection, TouchConfig, TouchPoint } from 'secret-sequence-core';
3
+
4
+ /**
5
+ * Opciones para el hook useSecretSequence.
6
+ * Refleja las opciones del engine del core.
7
+ */
8
+ interface UseSecretSequenceOptions {
9
+ /** Lista de secuencias a detectar */
10
+ sequences: SecretSequenceConfig[];
11
+ /** Tiempo máximo entre pasos antes de resetear (ms). Default: 2000 */
12
+ timeout?: number;
13
+ /** Habilitar/deshabilitar la detección. Default: true */
14
+ enabled?: boolean;
15
+ /** Habilitar detección de gestos táctiles (swipes). Default: true */
16
+ enableTouch?: boolean;
17
+ /** Ignorar eventos cuando el foco está en inputs/textareas. Default: true */
18
+ ignoreInputs?: boolean;
19
+ /** Configuración de sensibilidad para gestos táctiles */
20
+ touchOptions?: TouchConfig;
21
+ }
22
+ /**
23
+ * Valor retornado por el hook useSecretSequence.
24
+ */
25
+ interface UseSecretSequenceReturn {
26
+ /** Mapa de progreso actual: { [sequenceId]: stepsCompleted } */
27
+ progress: Record<string, number>;
28
+ /** Resetea el progreso de todas las secuencias */
29
+ reset: () => void;
30
+ }
31
+ /**
32
+ * Hook de React para detectar secuencias de teclado (Konami codes, combos de teclas)
33
+ * y gestos táctiles (swipes) usando el engine de secret-sequence-core.
34
+ *
35
+ * Gestiona automáticamente el ciclo de vida del engine:
36
+ * - Se inicia al montar el componente
37
+ * - Se actualiza reactivamente cuando cambian las opciones
38
+ * - Se destruye al desmontar el componente
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * function App() {
43
+ * const { progress } = useSecretSequence({
44
+ * sequences: [
45
+ * {
46
+ * id: "konami",
47
+ * sequence: ["up", "up", "down", "down", "left", "right", "left", "right"],
48
+ * onSuccess: () => console.log("🎉 Konami activado!"),
49
+ * },
50
+ * ],
51
+ * enableTouch: true,
52
+ * touchOptions: { minDistance: 50, maxTime: 400 },
53
+ * })
54
+ *
55
+ * return <pre>{JSON.stringify(progress, null, 2)}</pre>
56
+ * }
57
+ * ```
58
+ *
59
+ * @example Touch-only (sin teclado)
60
+ * ```tsx
61
+ * const { progress } = useSecretSequence({
62
+ * sequences: [
63
+ * {
64
+ * id: "swipe-pattern",
65
+ * sequence: ["up", "down", "left", "right"],
66
+ * onSuccess: () => alert("Patrón de swipe detectado!"),
67
+ * },
68
+ * ],
69
+ * enableTouch: true,
70
+ * touchOptions: {
71
+ * minDistance: 30,
72
+ * maxTime: 300,
73
+ * threshold: 1.5,
74
+ * },
75
+ * })
76
+ * ```
77
+ */
78
+ declare function useSecretSequence(options: UseSecretSequenceOptions): UseSecretSequenceReturn;
79
+
80
+ /**
81
+ * Props del componente SecretSequence.
82
+ * Idénticas a UseSecretSequenceOptions, con callbacks y render prop opcionales.
83
+ */
84
+ interface SecretSequenceProps extends UseSecretSequenceOptions {
85
+ /** Callback invocado cuando cambia el progreso de alguna secuencia */
86
+ onProgressChange?: (progress: Record<string, number>) => void;
87
+ /** Render prop opcional para acceder al progreso y reset */
88
+ children?: (state: {
89
+ progress: Record<string, number>;
90
+ reset: () => void;
91
+ }) => React.ReactNode;
92
+ }
93
+ /**
94
+ * Componente declarativo para detectar secuencias secretas.
95
+ * Wrapper JSX sobre el hook `useSecretSequence`.
96
+ *
97
+ * Si no se pasa `children`, no renderiza nada.
98
+ * Si se pasa `children` como render prop, recibe `{ progress, reset }`.
99
+ *
100
+ * Soporta todas las funcionalidades del core:
101
+ * - Secuencias de teclado (direcciones y combos de teclas)
102
+ * - Gestos táctiles (swipes) con configuración personalizable
103
+ * - Timeout entre pasos
104
+ * - Ignorar inputs/textareas
105
+ *
106
+ * @example Modo invisible (solo efecto)
107
+ * ```tsx
108
+ * <SecretSequence
109
+ * sequences={[
110
+ * {
111
+ * id: "konami",
112
+ * sequence: ["up", "up", "down", "down", "left", "right", "left", "right"],
113
+ * onSuccess: () => console.log("🎉"),
114
+ * },
115
+ * ]}
116
+ * enableTouch={true}
117
+ * touchOptions={{ minDistance: 40 }}
118
+ * />
119
+ * ```
120
+ *
121
+ * @example Con render prop para mostrar progreso
122
+ * ```tsx
123
+ * <SecretSequence
124
+ * sequences={[{ id: "code", sequence: ["up", "down"], onSuccess: fn }]}
125
+ * >
126
+ * {({ progress, reset }) => (
127
+ * <div>
128
+ * <p>Progreso: {JSON.stringify(progress)}</p>
129
+ * <button onClick={reset}>Reset</button>
130
+ * </div>
131
+ * )}
132
+ * </SecretSequence>
133
+ * ```
134
+ */
135
+ declare function SecretSequence(props: SecretSequenceProps): React.ReactNode;
136
+
137
+ export { SecretSequence, type SecretSequenceProps, type UseSecretSequenceOptions, type UseSecretSequenceReturn, useSecretSequence };
@@ -0,0 +1,137 @@
1
+ import { SecretSequenceConfig, TouchConfig } from 'secret-sequence-core';
2
+ export { Direction, KeyCombo, SecretSequenceConfig, SecretSequenceEngineOptions, SequenceStep, SwipeDirection, TouchConfig, TouchPoint } from 'secret-sequence-core';
3
+
4
+ /**
5
+ * Opciones para el hook useSecretSequence.
6
+ * Refleja las opciones del engine del core.
7
+ */
8
+ interface UseSecretSequenceOptions {
9
+ /** Lista de secuencias a detectar */
10
+ sequences: SecretSequenceConfig[];
11
+ /** Tiempo máximo entre pasos antes de resetear (ms). Default: 2000 */
12
+ timeout?: number;
13
+ /** Habilitar/deshabilitar la detección. Default: true */
14
+ enabled?: boolean;
15
+ /** Habilitar detección de gestos táctiles (swipes). Default: true */
16
+ enableTouch?: boolean;
17
+ /** Ignorar eventos cuando el foco está en inputs/textareas. Default: true */
18
+ ignoreInputs?: boolean;
19
+ /** Configuración de sensibilidad para gestos táctiles */
20
+ touchOptions?: TouchConfig;
21
+ }
22
+ /**
23
+ * Valor retornado por el hook useSecretSequence.
24
+ */
25
+ interface UseSecretSequenceReturn {
26
+ /** Mapa de progreso actual: { [sequenceId]: stepsCompleted } */
27
+ progress: Record<string, number>;
28
+ /** Resetea el progreso de todas las secuencias */
29
+ reset: () => void;
30
+ }
31
+ /**
32
+ * Hook de React para detectar secuencias de teclado (Konami codes, combos de teclas)
33
+ * y gestos táctiles (swipes) usando el engine de secret-sequence-core.
34
+ *
35
+ * Gestiona automáticamente el ciclo de vida del engine:
36
+ * - Se inicia al montar el componente
37
+ * - Se actualiza reactivamente cuando cambian las opciones
38
+ * - Se destruye al desmontar el componente
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * function App() {
43
+ * const { progress } = useSecretSequence({
44
+ * sequences: [
45
+ * {
46
+ * id: "konami",
47
+ * sequence: ["up", "up", "down", "down", "left", "right", "left", "right"],
48
+ * onSuccess: () => console.log("🎉 Konami activado!"),
49
+ * },
50
+ * ],
51
+ * enableTouch: true,
52
+ * touchOptions: { minDistance: 50, maxTime: 400 },
53
+ * })
54
+ *
55
+ * return <pre>{JSON.stringify(progress, null, 2)}</pre>
56
+ * }
57
+ * ```
58
+ *
59
+ * @example Touch-only (sin teclado)
60
+ * ```tsx
61
+ * const { progress } = useSecretSequence({
62
+ * sequences: [
63
+ * {
64
+ * id: "swipe-pattern",
65
+ * sequence: ["up", "down", "left", "right"],
66
+ * onSuccess: () => alert("Patrón de swipe detectado!"),
67
+ * },
68
+ * ],
69
+ * enableTouch: true,
70
+ * touchOptions: {
71
+ * minDistance: 30,
72
+ * maxTime: 300,
73
+ * threshold: 1.5,
74
+ * },
75
+ * })
76
+ * ```
77
+ */
78
+ declare function useSecretSequence(options: UseSecretSequenceOptions): UseSecretSequenceReturn;
79
+
80
+ /**
81
+ * Props del componente SecretSequence.
82
+ * Idénticas a UseSecretSequenceOptions, con callbacks y render prop opcionales.
83
+ */
84
+ interface SecretSequenceProps extends UseSecretSequenceOptions {
85
+ /** Callback invocado cuando cambia el progreso de alguna secuencia */
86
+ onProgressChange?: (progress: Record<string, number>) => void;
87
+ /** Render prop opcional para acceder al progreso y reset */
88
+ children?: (state: {
89
+ progress: Record<string, number>;
90
+ reset: () => void;
91
+ }) => React.ReactNode;
92
+ }
93
+ /**
94
+ * Componente declarativo para detectar secuencias secretas.
95
+ * Wrapper JSX sobre el hook `useSecretSequence`.
96
+ *
97
+ * Si no se pasa `children`, no renderiza nada.
98
+ * Si se pasa `children` como render prop, recibe `{ progress, reset }`.
99
+ *
100
+ * Soporta todas las funcionalidades del core:
101
+ * - Secuencias de teclado (direcciones y combos de teclas)
102
+ * - Gestos táctiles (swipes) con configuración personalizable
103
+ * - Timeout entre pasos
104
+ * - Ignorar inputs/textareas
105
+ *
106
+ * @example Modo invisible (solo efecto)
107
+ * ```tsx
108
+ * <SecretSequence
109
+ * sequences={[
110
+ * {
111
+ * id: "konami",
112
+ * sequence: ["up", "up", "down", "down", "left", "right", "left", "right"],
113
+ * onSuccess: () => console.log("🎉"),
114
+ * },
115
+ * ]}
116
+ * enableTouch={true}
117
+ * touchOptions={{ minDistance: 40 }}
118
+ * />
119
+ * ```
120
+ *
121
+ * @example Con render prop para mostrar progreso
122
+ * ```tsx
123
+ * <SecretSequence
124
+ * sequences={[{ id: "code", sequence: ["up", "down"], onSuccess: fn }]}
125
+ * >
126
+ * {({ progress, reset }) => (
127
+ * <div>
128
+ * <p>Progreso: {JSON.stringify(progress)}</p>
129
+ * <button onClick={reset}>Reset</button>
130
+ * </div>
131
+ * )}
132
+ * </SecretSequence>
133
+ * ```
134
+ */
135
+ declare function SecretSequence(props: SecretSequenceProps): React.ReactNode;
136
+
137
+ export { SecretSequence, type SecretSequenceProps, type UseSecretSequenceOptions, type UseSecretSequenceReturn, useSecretSequence };
package/dist/index.js ADDED
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ SecretSequence: () => SecretSequence,
24
+ useSecretSequence: () => useSecretSequence
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/useSecretSequence.ts
29
+ var import_react = require("react");
30
+ var import_secret_sequence_core = require("secret-sequence-core");
31
+ function useSecretSequence(options) {
32
+ const {
33
+ sequences,
34
+ timeout,
35
+ enabled = true,
36
+ enableTouch = true,
37
+ ignoreInputs = true,
38
+ touchOptions
39
+ } = options;
40
+ const [progress, setProgress] = (0, import_react.useState)({});
41
+ const engineRef = (0, import_react.useRef)(null);
42
+ const sequencesRef = (0, import_react.useRef)(sequences);
43
+ sequencesRef.current = sequences;
44
+ const touchOptionsRef = (0, import_react.useRef)(touchOptions);
45
+ touchOptionsRef.current = touchOptions;
46
+ const sequencesKey = JSON.stringify(
47
+ sequences.map(({ onSuccess, ...rest }) => rest)
48
+ );
49
+ const touchOptionsKey = JSON.stringify(touchOptions);
50
+ (0, import_react.useEffect)(() => {
51
+ const engineOptions = {
52
+ sequences: sequencesRef.current,
53
+ timeout,
54
+ enabled,
55
+ enableTouch,
56
+ ignoreInputs,
57
+ touchOptions: touchOptionsRef.current,
58
+ onProgress: (_id, _step) => {
59
+ if (engineRef.current) {
60
+ setProgress(engineRef.current.getProgressMap());
61
+ }
62
+ }
63
+ };
64
+ const engine = new import_secret_sequence_core.SecretSequenceEngine(engineOptions);
65
+ engineRef.current = engine;
66
+ setProgress(engine.getProgressMap());
67
+ engine.start();
68
+ return () => {
69
+ engine.destroy();
70
+ engineRef.current = null;
71
+ };
72
+ }, [timeout, enabled, enableTouch, ignoreInputs]);
73
+ (0, import_react.useEffect)(() => {
74
+ if (!engineRef.current) return;
75
+ engineRef.current.setOptions({
76
+ sequences: sequencesRef.current,
77
+ touchOptions: touchOptionsRef.current,
78
+ onProgress: () => {
79
+ if (engineRef.current) {
80
+ setProgress(engineRef.current.getProgressMap());
81
+ }
82
+ }
83
+ });
84
+ setProgress(engineRef.current.getProgressMap());
85
+ }, [sequencesKey, touchOptionsKey]);
86
+ const reset = (0, import_react.useCallback)(() => {
87
+ if (engineRef.current) {
88
+ engineRef.current.reset();
89
+ setProgress(engineRef.current.getProgressMap());
90
+ }
91
+ }, []);
92
+ return { progress, reset };
93
+ }
94
+
95
+ // src/SecretSequence.tsx
96
+ var import_react2 = require("react");
97
+ function SecretSequence(props) {
98
+ const {
99
+ onProgressChange,
100
+ children,
101
+ ...hookOptions
102
+ } = props;
103
+ const { progress, reset } = useSecretSequence(hookOptions);
104
+ (0, import_react2.useEffect)(() => {
105
+ if (onProgressChange) {
106
+ onProgressChange(progress);
107
+ }
108
+ }, [progress, onProgressChange]);
109
+ if (typeof children === "function") {
110
+ return children({ progress, reset });
111
+ }
112
+ return null;
113
+ }
114
+ // Annotate the CommonJS export names for ESM import in node:
115
+ 0 && (module.exports = {
116
+ SecretSequence,
117
+ useSecretSequence
118
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,92 @@
1
+ // src/useSecretSequence.ts
2
+ import { useEffect, useRef, useState, useCallback } from "react";
3
+ import {
4
+ SecretSequenceEngine
5
+ } from "secret-sequence-core";
6
+ function useSecretSequence(options) {
7
+ const {
8
+ sequences,
9
+ timeout,
10
+ enabled = true,
11
+ enableTouch = true,
12
+ ignoreInputs = true,
13
+ touchOptions
14
+ } = options;
15
+ const [progress, setProgress] = useState({});
16
+ const engineRef = useRef(null);
17
+ const sequencesRef = useRef(sequences);
18
+ sequencesRef.current = sequences;
19
+ const touchOptionsRef = useRef(touchOptions);
20
+ touchOptionsRef.current = touchOptions;
21
+ const sequencesKey = JSON.stringify(
22
+ sequences.map(({ onSuccess, ...rest }) => rest)
23
+ );
24
+ const touchOptionsKey = JSON.stringify(touchOptions);
25
+ useEffect(() => {
26
+ const engineOptions = {
27
+ sequences: sequencesRef.current,
28
+ timeout,
29
+ enabled,
30
+ enableTouch,
31
+ ignoreInputs,
32
+ touchOptions: touchOptionsRef.current,
33
+ onProgress: (_id, _step) => {
34
+ if (engineRef.current) {
35
+ setProgress(engineRef.current.getProgressMap());
36
+ }
37
+ }
38
+ };
39
+ const engine = new SecretSequenceEngine(engineOptions);
40
+ engineRef.current = engine;
41
+ setProgress(engine.getProgressMap());
42
+ engine.start();
43
+ return () => {
44
+ engine.destroy();
45
+ engineRef.current = null;
46
+ };
47
+ }, [timeout, enabled, enableTouch, ignoreInputs]);
48
+ useEffect(() => {
49
+ if (!engineRef.current) return;
50
+ engineRef.current.setOptions({
51
+ sequences: sequencesRef.current,
52
+ touchOptions: touchOptionsRef.current,
53
+ onProgress: () => {
54
+ if (engineRef.current) {
55
+ setProgress(engineRef.current.getProgressMap());
56
+ }
57
+ }
58
+ });
59
+ setProgress(engineRef.current.getProgressMap());
60
+ }, [sequencesKey, touchOptionsKey]);
61
+ const reset = useCallback(() => {
62
+ if (engineRef.current) {
63
+ engineRef.current.reset();
64
+ setProgress(engineRef.current.getProgressMap());
65
+ }
66
+ }, []);
67
+ return { progress, reset };
68
+ }
69
+
70
+ // src/SecretSequence.tsx
71
+ import { useEffect as useEffect2 } from "react";
72
+ function SecretSequence(props) {
73
+ const {
74
+ onProgressChange,
75
+ children,
76
+ ...hookOptions
77
+ } = props;
78
+ const { progress, reset } = useSecretSequence(hookOptions);
79
+ useEffect2(() => {
80
+ if (onProgressChange) {
81
+ onProgressChange(progress);
82
+ }
83
+ }, [progress, onProgressChange]);
84
+ if (typeof children === "function") {
85
+ return children({ progress, reset });
86
+ }
87
+ return null;
88
+ }
89
+ export {
90
+ SecretSequence,
91
+ useSecretSequence
92
+ };
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "secret-sequence-react",
3
+ "version": "1.0.0",
4
+ "description": "React hook & component wrapper for secret-sequence-core — detect directional sequences, key combos, and touch gestures",
5
+ "keywords": [
6
+ "react",
7
+ "hook",
8
+ "keyboard",
9
+ "stratagem",
10
+ "konami",
11
+ "sequence",
12
+ "shortcut",
13
+ "input-engine",
14
+ "helldivers",
15
+ "key-combo",
16
+ "easter-egg",
17
+ "typescript",
18
+ "touch",
19
+ "gesture"
20
+ ],
21
+ "author": "diego0alonso",
22
+ "license": "MIT",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/diego0alonso/secret-sequence.git",
26
+ "directory": "packages/react"
27
+ },
28
+ "main": "dist/index.js",
29
+ "module": "dist/index.mjs",
30
+ "types": "dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.mjs",
35
+ "require": "./dist/index.js"
36
+ }
37
+ },
38
+ "sideEffects": false,
39
+ "files": [
40
+ "dist"
41
+ ],
42
+ "scripts": {
43
+ "build": "tsup",
44
+ "prepublishOnly": "npm run build"
45
+ },
46
+ "peerDependencies": {
47
+ "react": ">=17.0.0",
48
+ "secret-sequence-core": "^2.0.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/react": "^19.0.0",
52
+ "react": "^19.0.0",
53
+ "secret-sequence-core": "^2.0.0",
54
+ "tsup": "^8.0.0",
55
+ "typescript": "^5.0.0"
56
+ }
57
+ }