@keybindy/react 1.1.1 → 1.1.3
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/dist/Keybindy.js +80 -0
- package/dist/ShortcutLabel.js +69 -0
- package/dist/index.d.ts +188 -0
- package/dist/index.js +3 -0
- package/dist/useKeybindy.js +163 -0
- package/package.json +4 -4
- package/dist/index.cjs +0 -232
- package/dist/index.mjs +0 -232
package/dist/Keybindy.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useKeybindy } from './useKeybindy.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `<Keybindy />` is a React component that registers keyboard shortcuts within a given scope. It allows
|
|
7
|
+
* users to define custom shortcuts and their associated handlers, while managing scope-based shortcut behavior.
|
|
8
|
+
* The component listens for keyboard events and triggers the registered handler when the corresponding keys are pressed.
|
|
9
|
+
* It also provides an optional callback (`onShortcutFired`) to notify users when a shortcut is triggered.
|
|
10
|
+
*
|
|
11
|
+
* @component
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // Basic usage
|
|
15
|
+
* <Keybindy scope="global" shortcuts={[{ keys: ['ctrl', 's'], handler: saveDocument }]} >
|
|
16
|
+
* <div>Content with shortcuts</div>
|
|
17
|
+
* </Keybindy>
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // With custom callback for onShortcutFired
|
|
21
|
+
* <Keybindy
|
|
22
|
+
* scope="editor"
|
|
23
|
+
* shortcuts={[{ keys: ['ctrl', 'e'], handler: editDocument }]}
|
|
24
|
+
* onShortcutFired={(info) => console.log('Shortcut fired:', info)}
|
|
25
|
+
* >
|
|
26
|
+
* <div>Editor with shortcuts</div>
|
|
27
|
+
* </Keybindy>
|
|
28
|
+
*
|
|
29
|
+
* @param {ShortcutProps} props - Props for the Shortcut component.
|
|
30
|
+
* @param {string} props.scope - The scope under which the shortcuts should be active.
|
|
31
|
+
* @param {ShortcutDefinition[]} [props.shortcuts] - An array of shortcut definitions, each containing keys, handler, and options.
|
|
32
|
+
* @param {boolean} [props.disabled=false] - Whether the shortcuts should be disabled for this scope.
|
|
33
|
+
* @param {(info: Shortcut) => void} [props.onShortcutFired] - Optional callback triggered when a shortcut is fired, providing the shortcut info.
|
|
34
|
+
* @param {React.ReactNode} props.children - The children to be rendered inside the component, which can contain any JSX elements.
|
|
35
|
+
*
|
|
36
|
+
* @returns {JSX.Element} The rendered component with registered shortcuts within the provided scope.
|
|
37
|
+
*/
|
|
38
|
+
const Keybindy = ({ scope = 'global', shortcuts = [], children, disabled, onShortcutFired, logs = false, }) => {
|
|
39
|
+
const { register, unregister, manager, pushScope, popScope, getScopes, setScope } = useKeybindy({
|
|
40
|
+
onShortcutFired,
|
|
41
|
+
logs,
|
|
42
|
+
});
|
|
43
|
+
const prevScope = React.useRef(null);
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
if (!manager) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
prevScope.current = manager.getActiveScope() ?? 'global';
|
|
49
|
+
// Add scope if doesn't exist
|
|
50
|
+
if (!getScopes()?.includes(scope)) {
|
|
51
|
+
pushScope(scope);
|
|
52
|
+
}
|
|
53
|
+
// Set this scope as active
|
|
54
|
+
setScope(scope);
|
|
55
|
+
// Register all shortcuts for this scope
|
|
56
|
+
shortcuts.forEach(({ keys, handler, options }) => {
|
|
57
|
+
register(keys, handler, { ...options, scope });
|
|
58
|
+
});
|
|
59
|
+
if (disabled) {
|
|
60
|
+
manager.disableAll(scope);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
manager.enableAll(scope);
|
|
64
|
+
}
|
|
65
|
+
return () => {
|
|
66
|
+
shortcuts.forEach(({ keys }) => {
|
|
67
|
+
if (Array.isArray(keys[0])) {
|
|
68
|
+
keys.forEach(key => unregister(key, scope));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
unregister(keys, scope);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
popScope();
|
|
75
|
+
};
|
|
76
|
+
}, [scope, shortcuts, manager, disabled]);
|
|
77
|
+
return jsx(Fragment, { children: children });
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export { Keybindy };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `<ShortcutLabel />` is a utility React component that visually renders a keyboard shortcut label.
|
|
6
|
+
*
|
|
7
|
+
* It accepts an array of keys (e.g. `["Ctrl", "S"]`) and renders a styled label using platform-aware
|
|
8
|
+
* symbols (⌘ for Mac, Ctrl for others). Users can also provide a custom render function to override
|
|
9
|
+
* the default display logic for advanced layouts or custom themes.
|
|
10
|
+
*
|
|
11
|
+
* @component
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // Default usage
|
|
15
|
+
* <ShortcutLabel keys={['ctrl', 's']} />
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // With custom renderKey
|
|
19
|
+
* <ShortcutLabel
|
|
20
|
+
* keys={['ctrl', 'alt', 'delete']}
|
|
21
|
+
* renderKey={(key, i, all) => (
|
|
22
|
+
* <>
|
|
23
|
+
* <span style={{ color: '#00eaff' }}>{key.toUpperCase()}</span>
|
|
24
|
+
* {i < all.length - 1 && <span style={{ opacity: 0.5 }}> + </span>}
|
|
25
|
+
* </>
|
|
26
|
+
* )}
|
|
27
|
+
* />
|
|
28
|
+
*
|
|
29
|
+
* @param {ShortcutLabelProps} props - Props for the ShortcutLabel component
|
|
30
|
+
* @param {string[]} props.keys - The list of keys to display.
|
|
31
|
+
* @param {Function} [props.renderKey] - Optional custom render function for full control over how each key appears.
|
|
32
|
+
*
|
|
33
|
+
* @returns {JSX.Element} Rendered shortcut label
|
|
34
|
+
*/
|
|
35
|
+
const ShortcutLabel = ({ keys, renderKey, style, ...props }) => {
|
|
36
|
+
const isMac = typeof navigator !== 'undefined' && /Mac/.test(navigator.userAgent);
|
|
37
|
+
const defaultRenderKey = (key) => {
|
|
38
|
+
switch (key.toLowerCase()) {
|
|
39
|
+
case 'meta':
|
|
40
|
+
return isMac ? '⌘' : 'Ctrl';
|
|
41
|
+
case 'ctrl':
|
|
42
|
+
return 'Ctrl';
|
|
43
|
+
case 'shift':
|
|
44
|
+
return '⇧';
|
|
45
|
+
case 'alt':
|
|
46
|
+
return isMac ? '⌥' : 'Alt';
|
|
47
|
+
case 'enter':
|
|
48
|
+
return '↵';
|
|
49
|
+
default:
|
|
50
|
+
return key.toUpperCase();
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const rendered = renderKey
|
|
54
|
+
? keys.map((key, i) => (jsx(React.Fragment, { children: renderKey(key, i, keys) }, i)))
|
|
55
|
+
: defaultRenderKey
|
|
56
|
+
? [keys.map(key => defaultRenderKey(key)).join(' + ')]
|
|
57
|
+
: [];
|
|
58
|
+
return (jsx("kbd", { style: {
|
|
59
|
+
fontFamily: 'monospace',
|
|
60
|
+
padding: '2.5px 5px',
|
|
61
|
+
border: '1px solid #cccccc2f',
|
|
62
|
+
backgroundColor: '#2e2e2e',
|
|
63
|
+
borderRadius: '4px',
|
|
64
|
+
userSelect: 'none',
|
|
65
|
+
...style,
|
|
66
|
+
}, ...props, children: rendered }));
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export { ShortcutLabel };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ShortcutManager, { Keys, ShortcutHandler, HoldShortcutHandler, ShortcutOptions, Shortcut } from '@keybindy/core';
|
|
3
|
+
export { KeyBinding, Keys, Shortcut, ShortcutHandler, ShortcutOptions } from '@keybindy/core';
|
|
4
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Represents a keyboard shortcut definition.
|
|
8
|
+
*/
|
|
9
|
+
type ShortcutDefinition = {
|
|
10
|
+
/**
|
|
11
|
+
* The key combination(s) to listen for.
|
|
12
|
+
* Can be a single array of keys or an array of key combinations.
|
|
13
|
+
*/
|
|
14
|
+
keys: Keys[] | Keys[][];
|
|
15
|
+
/**
|
|
16
|
+
* Callback function to invoke when the shortcut is triggered.
|
|
17
|
+
*/
|
|
18
|
+
handler: ShortcutHandler | HoldShortcutHandler;
|
|
19
|
+
/**
|
|
20
|
+
* Optional configuration, including scope and other metadata.
|
|
21
|
+
*/
|
|
22
|
+
options?: Omit<ShortcutOptions, 'scope'>;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Props for the `<Keybindy />` component.
|
|
26
|
+
*/
|
|
27
|
+
type KeybindyProps = {
|
|
28
|
+
/**
|
|
29
|
+
* The scope under which the shortcuts should be active.
|
|
30
|
+
* This allows managing different contexts for shortcuts.
|
|
31
|
+
*/
|
|
32
|
+
scope?: 'global' | string;
|
|
33
|
+
/**
|
|
34
|
+
* Array of shortcut definitions to register for this scope.
|
|
35
|
+
*/
|
|
36
|
+
shortcuts?: ShortcutDefinition[];
|
|
37
|
+
/**
|
|
38
|
+
* Whether the shortcuts should be disabled for this scope.
|
|
39
|
+
* Defaults to `false`.
|
|
40
|
+
*/
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Callback function that will be called when a shortcut is fired.
|
|
44
|
+
* Receives the fired shortcut info as an argument.
|
|
45
|
+
*/
|
|
46
|
+
onShortcutFired?: (info: Shortcut) => void;
|
|
47
|
+
/**
|
|
48
|
+
* Whether to enable debug logs in the console.
|
|
49
|
+
*/
|
|
50
|
+
logs?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* The content that will be rendered inside the Shortcut component.
|
|
53
|
+
*/
|
|
54
|
+
children?: React.ReactNode;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* `<Keybindy />` is a React component that registers keyboard shortcuts within a given scope. It allows
|
|
58
|
+
* users to define custom shortcuts and their associated handlers, while managing scope-based shortcut behavior.
|
|
59
|
+
* The component listens for keyboard events and triggers the registered handler when the corresponding keys are pressed.
|
|
60
|
+
* It also provides an optional callback (`onShortcutFired`) to notify users when a shortcut is triggered.
|
|
61
|
+
*
|
|
62
|
+
* @component
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* // Basic usage
|
|
66
|
+
* <Keybindy scope="global" shortcuts={[{ keys: ['ctrl', 's'], handler: saveDocument }]} >
|
|
67
|
+
* <div>Content with shortcuts</div>
|
|
68
|
+
* </Keybindy>
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* // With custom callback for onShortcutFired
|
|
72
|
+
* <Keybindy
|
|
73
|
+
* scope="editor"
|
|
74
|
+
* shortcuts={[{ keys: ['ctrl', 'e'], handler: editDocument }]}
|
|
75
|
+
* onShortcutFired={(info) => console.log('Shortcut fired:', info)}
|
|
76
|
+
* >
|
|
77
|
+
* <div>Editor with shortcuts</div>
|
|
78
|
+
* </Keybindy>
|
|
79
|
+
*
|
|
80
|
+
* @param {ShortcutProps} props - Props for the Shortcut component.
|
|
81
|
+
* @param {string} props.scope - The scope under which the shortcuts should be active.
|
|
82
|
+
* @param {ShortcutDefinition[]} [props.shortcuts] - An array of shortcut definitions, each containing keys, handler, and options.
|
|
83
|
+
* @param {boolean} [props.disabled=false] - Whether the shortcuts should be disabled for this scope.
|
|
84
|
+
* @param {(info: Shortcut) => void} [props.onShortcutFired] - Optional callback triggered when a shortcut is fired, providing the shortcut info.
|
|
85
|
+
* @param {React.ReactNode} props.children - The children to be rendered inside the component, which can contain any JSX elements.
|
|
86
|
+
*
|
|
87
|
+
* @returns {JSX.Element} The rendered component with registered shortcuts within the provided scope.
|
|
88
|
+
*/
|
|
89
|
+
declare const Keybindy: React.FC<KeybindyProps>;
|
|
90
|
+
|
|
91
|
+
interface ShortcutLabelProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> {
|
|
92
|
+
/**
|
|
93
|
+
* Array of keys to display
|
|
94
|
+
*/
|
|
95
|
+
keys: Omit<Keys, 'Ctrl (Left)' | 'Ctrl (Right)' | 'Shift (Left)' | 'Shift (Right)' | 'Alt (Left)' | 'Alt (Right)' | 'Meta (Left)' | 'Meta (Right)'>[];
|
|
96
|
+
/**
|
|
97
|
+
* Custom render function for each key
|
|
98
|
+
*/
|
|
99
|
+
renderKey?: (
|
|
100
|
+
/**
|
|
101
|
+
* The key to render
|
|
102
|
+
*/
|
|
103
|
+
key: string,
|
|
104
|
+
/**
|
|
105
|
+
* The index of the key in the array
|
|
106
|
+
*/
|
|
107
|
+
index: number,
|
|
108
|
+
/**
|
|
109
|
+
* All keys in the array
|
|
110
|
+
*/
|
|
111
|
+
allKeys: string[]) => React.ReactNode;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* `<ShortcutLabel />` is a utility React component that visually renders a keyboard shortcut label.
|
|
115
|
+
*
|
|
116
|
+
* It accepts an array of keys (e.g. `["Ctrl", "S"]`) and renders a styled label using platform-aware
|
|
117
|
+
* symbols (⌘ for Mac, Ctrl for others). Users can also provide a custom render function to override
|
|
118
|
+
* the default display logic for advanced layouts or custom themes.
|
|
119
|
+
*
|
|
120
|
+
* @component
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* // Default usage
|
|
124
|
+
* <ShortcutLabel keys={['ctrl', 's']} />
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* // With custom renderKey
|
|
128
|
+
* <ShortcutLabel
|
|
129
|
+
* keys={['ctrl', 'alt', 'delete']}
|
|
130
|
+
* renderKey={(key, i, all) => (
|
|
131
|
+
* <>
|
|
132
|
+
* <span style={{ color: '#00eaff' }}>{key.toUpperCase()}</span>
|
|
133
|
+
* {i < all.length - 1 && <span style={{ opacity: 0.5 }}> + </span>}
|
|
134
|
+
* </>
|
|
135
|
+
* )}
|
|
136
|
+
* />
|
|
137
|
+
*
|
|
138
|
+
* @param {ShortcutLabelProps} props - Props for the ShortcutLabel component
|
|
139
|
+
* @param {string[]} props.keys - The list of keys to display.
|
|
140
|
+
* @param {Function} [props.renderKey] - Optional custom render function for full control over how each key appears.
|
|
141
|
+
*
|
|
142
|
+
* @returns {JSX.Element} Rendered shortcut label
|
|
143
|
+
*/
|
|
144
|
+
declare const ShortcutLabel: ({ keys, renderKey, style, ...props }: ShortcutLabelProps) => react_jsx_runtime.JSX.Element;
|
|
145
|
+
|
|
146
|
+
type UseKeybindyReturn = {
|
|
147
|
+
register: (keys: Keys[] | Keys[][], handler: ShortcutHandler | HoldShortcutHandler, options?: ShortcutOptions) => void;
|
|
148
|
+
unregister: (keys: Keys[], scope?: string) => void;
|
|
149
|
+
enable: (keys: Keys[], scope?: string) => void;
|
|
150
|
+
disable: (keys: Keys[], scope?: string) => void;
|
|
151
|
+
toggle: (keys: Keys[], scope?: string) => void;
|
|
152
|
+
setScope: (scope: string) => void;
|
|
153
|
+
getCheatSheet: (scope?: string) => {
|
|
154
|
+
keys: string[];
|
|
155
|
+
}[] | undefined;
|
|
156
|
+
destroy: () => void;
|
|
157
|
+
getScopeInfo: (scope?: string) => any;
|
|
158
|
+
getActiveScope: () => string | undefined;
|
|
159
|
+
popScope: () => void;
|
|
160
|
+
pushScope: (scope: string) => void;
|
|
161
|
+
resetScope: () => void;
|
|
162
|
+
getScopes: () => string[] | undefined;
|
|
163
|
+
isScopeActive: (scope: string) => boolean | undefined;
|
|
164
|
+
onTyping: (callback: (payload: {
|
|
165
|
+
key: string;
|
|
166
|
+
event: KeyboardEvent;
|
|
167
|
+
}) => void) => void;
|
|
168
|
+
enableAll: (scope?: string) => void;
|
|
169
|
+
clear: () => void;
|
|
170
|
+
disableAll: (scope?: string) => void;
|
|
171
|
+
manager: ShortcutManager | null;
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* React hook to manage keyboard shortcuts using a shared instance of `ShortcutManager`.
|
|
175
|
+
* This hook is safe for server-side rendering (SSR) and will only initialize the manager on the client.
|
|
176
|
+
*
|
|
177
|
+
* @param {Object} config - Configuration object.
|
|
178
|
+
* @param {boolean} [config.logs=false] - Whether to enable debug logs in the console.
|
|
179
|
+
* @param {(info: Shortcut) => void} [config.onShortcutFired] - Callback for when a shortcut is fired.
|
|
180
|
+
*
|
|
181
|
+
* @returns {Object} Object containing shortcut management methods and the manager instance (null on server).
|
|
182
|
+
*/
|
|
183
|
+
declare const useKeybindy: ({ logs, onShortcutFired, }?: {
|
|
184
|
+
logs?: boolean;
|
|
185
|
+
onShortcutFired?: (info: Shortcut) => void;
|
|
186
|
+
}) => UseKeybindyReturn;
|
|
187
|
+
|
|
188
|
+
export { Keybindy, ShortcutLabel, useKeybindy };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ShortcutManager from '@keybindy/core';
|
|
3
|
+
|
|
4
|
+
let sharedInstance = null;
|
|
5
|
+
const getSharedInstance = (options) => {
|
|
6
|
+
if (typeof window === 'undefined') {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
if (!sharedInstance) {
|
|
10
|
+
sharedInstance = new ShortcutManager(options);
|
|
11
|
+
}
|
|
12
|
+
return sharedInstance;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* React hook to manage keyboard shortcuts using a shared instance of `ShortcutManager`.
|
|
16
|
+
* This hook is safe for server-side rendering (SSR) and will only initialize the manager on the client.
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} config - Configuration object.
|
|
19
|
+
* @param {boolean} [config.logs=false] - Whether to enable debug logs in the console.
|
|
20
|
+
* @param {(info: Shortcut) => void} [config.onShortcutFired] - Callback for when a shortcut is fired.
|
|
21
|
+
*
|
|
22
|
+
* @returns {Object} Object containing shortcut management methods and the manager instance (null on server).
|
|
23
|
+
*/
|
|
24
|
+
const useKeybindy = ({ logs = false, onShortcutFired, } = {}) => {
|
|
25
|
+
const [manager, setManager] = React.useState(null);
|
|
26
|
+
React.useEffect(() => {
|
|
27
|
+
if (!manager) {
|
|
28
|
+
const instance = getSharedInstance({ onShortcutFired, silent: !logs });
|
|
29
|
+
setManager(instance);
|
|
30
|
+
}
|
|
31
|
+
}, []);
|
|
32
|
+
const log = (...args) => {
|
|
33
|
+
if (logs)
|
|
34
|
+
console.log('[Keybindy]', ...args);
|
|
35
|
+
};
|
|
36
|
+
const warn = (...args) => {
|
|
37
|
+
if (logs)
|
|
38
|
+
console.warn('[Keybindy]', ...args);
|
|
39
|
+
};
|
|
40
|
+
const register = React.useCallback((keys, handler, options) => {
|
|
41
|
+
if (!manager)
|
|
42
|
+
return;
|
|
43
|
+
if (keys.length === 0) {
|
|
44
|
+
warn('No keys provided to register');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const id = options?.data?.id;
|
|
48
|
+
log('Registered:', id ?? keys);
|
|
49
|
+
manager.register(keys, handler, options);
|
|
50
|
+
}, [manager]);
|
|
51
|
+
const unregister = React.useCallback((keys, scope) => {
|
|
52
|
+
if (!manager)
|
|
53
|
+
return;
|
|
54
|
+
if (keys.length === 0) {
|
|
55
|
+
warn('No keys provided to unregister');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
manager.unregister(keys, scope);
|
|
59
|
+
log('Unregistered:', keys);
|
|
60
|
+
}, [manager]);
|
|
61
|
+
const enable = React.useCallback((keys, scope) => {
|
|
62
|
+
if (!manager)
|
|
63
|
+
return;
|
|
64
|
+
if (keys.length === 0) {
|
|
65
|
+
warn('No keys provided to enable');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
manager.enable(keys, scope);
|
|
69
|
+
log('Enabled:', keys);
|
|
70
|
+
}, [manager]);
|
|
71
|
+
const disable = React.useCallback((keys, scope) => {
|
|
72
|
+
if (!manager)
|
|
73
|
+
return;
|
|
74
|
+
if (keys.length === 0) {
|
|
75
|
+
warn('No keys provided to disable');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
manager.disable(keys, scope);
|
|
79
|
+
log('Disabled:', keys);
|
|
80
|
+
}, [manager]);
|
|
81
|
+
const toggle = React.useCallback((keys, scope) => {
|
|
82
|
+
if (!manager)
|
|
83
|
+
return;
|
|
84
|
+
if (keys.length === 0) {
|
|
85
|
+
warn('No keys provided to toggle');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
manager.toggle(keys, scope);
|
|
89
|
+
log('Toggled:', keys);
|
|
90
|
+
}, [manager]);
|
|
91
|
+
const getCheatSheet = React.useCallback((scope) => {
|
|
92
|
+
return manager?.getCheatSheet(scope);
|
|
93
|
+
}, [manager]);
|
|
94
|
+
const getActiveScope = React.useCallback(() => {
|
|
95
|
+
return manager?.getActiveScope();
|
|
96
|
+
}, [manager]);
|
|
97
|
+
const disableAll = React.useCallback((scope) => {
|
|
98
|
+
manager?.disableAll(scope);
|
|
99
|
+
log(`Disabled all shortcuts${scope ? ` in scope "${scope}"` : ''}`);
|
|
100
|
+
}, [manager]);
|
|
101
|
+
const enableAll = React.useCallback((scope) => {
|
|
102
|
+
manager?.enableAll(scope);
|
|
103
|
+
log(`Enabled all shortcuts${scope ? ` in scope "${scope}"` : ''}`);
|
|
104
|
+
}, [manager]);
|
|
105
|
+
const setScope = React.useCallback((scope) => {
|
|
106
|
+
manager?.setActiveScope(scope);
|
|
107
|
+
log('Scope set to:', scope);
|
|
108
|
+
}, [manager]);
|
|
109
|
+
const resetScope = React.useCallback(() => {
|
|
110
|
+
manager?.resetScope();
|
|
111
|
+
log('Reset scope');
|
|
112
|
+
}, [manager]);
|
|
113
|
+
const getScopes = React.useCallback(() => {
|
|
114
|
+
return manager?.getScopes();
|
|
115
|
+
}, [manager]);
|
|
116
|
+
const isScopeActive = React.useCallback((scope) => {
|
|
117
|
+
return manager?.isScopeActive(scope);
|
|
118
|
+
}, [manager]);
|
|
119
|
+
const onTyping = React.useCallback((callback) => {
|
|
120
|
+
manager?.onTyping(callback);
|
|
121
|
+
}, [manager]);
|
|
122
|
+
const popScope = React.useCallback(() => {
|
|
123
|
+
manager?.popScope();
|
|
124
|
+
log('Popped scope, active scope is:', manager?.getActiveScope());
|
|
125
|
+
}, [manager]);
|
|
126
|
+
const pushScope = React.useCallback((scope) => {
|
|
127
|
+
manager?.pushScope(scope);
|
|
128
|
+
log('Pushed scope:', scope);
|
|
129
|
+
}, [manager]);
|
|
130
|
+
const getScopeInfo = React.useCallback((scope) => {
|
|
131
|
+
return manager?.getScopesInfo(scope);
|
|
132
|
+
}, [manager]);
|
|
133
|
+
const destroy = () => {
|
|
134
|
+
manager?.destroy();
|
|
135
|
+
};
|
|
136
|
+
const clear = () => {
|
|
137
|
+
manager?.clear();
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
register,
|
|
141
|
+
unregister,
|
|
142
|
+
enable,
|
|
143
|
+
disable,
|
|
144
|
+
toggle,
|
|
145
|
+
setScope,
|
|
146
|
+
getCheatSheet,
|
|
147
|
+
destroy,
|
|
148
|
+
getScopeInfo,
|
|
149
|
+
getActiveScope,
|
|
150
|
+
popScope,
|
|
151
|
+
pushScope,
|
|
152
|
+
resetScope,
|
|
153
|
+
getScopes,
|
|
154
|
+
isScopeActive,
|
|
155
|
+
onTyping,
|
|
156
|
+
enableAll,
|
|
157
|
+
clear,
|
|
158
|
+
disableAll,
|
|
159
|
+
manager,
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
export { useKeybindy };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keybindy/react",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "Keybindy for React: Simple, scoped keyboard shortcuts that require little setup. designed to smoothly blend in with your React applications, allowing for robust keybinding functionality without the overhead.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "PRASSamin",
|
|
@@ -51,13 +51,13 @@
|
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"react": "^19.1.0",
|
|
54
|
-
"@keybindy/core": "1.1.
|
|
54
|
+
"@keybindy/core": "1.1.3"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
58
58
|
"prebuild": "rm -rf dist",
|
|
59
|
-
"build": "
|
|
60
|
-
"dev": "
|
|
59
|
+
"build": "rollup -c",
|
|
60
|
+
"dev": "rollup -c -w",
|
|
61
61
|
"test": "vitest"
|
|
62
62
|
}
|
|
63
63
|
}
|
package/dist/index.cjs
DELETED
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }'use client';
|
|
2
|
-
|
|
3
|
-
// src/Keybindy.tsx
|
|
4
|
-
var _react = require('react'); var _react2 = _interopRequireDefault(_react);
|
|
5
|
-
|
|
6
|
-
// src/useKeybindy.tsx
|
|
7
|
-
|
|
8
|
-
var _core = require('@keybindy/core'); var _core2 = _interopRequireDefault(_core);
|
|
9
|
-
var sharedInstance = null;
|
|
10
|
-
var useKeybindy = ({
|
|
11
|
-
logs = false,
|
|
12
|
-
onShortcutFired
|
|
13
|
-
} = {}) => {
|
|
14
|
-
const managerRef = _react2.default.useRef(null);
|
|
15
|
-
const registeredIds = _react2.default.useRef(/* @__PURE__ */ new Set());
|
|
16
|
-
if (!sharedInstance) {
|
|
17
|
-
sharedInstance = new (0, _core2.default)({ onShortcutFired, silent: !logs });
|
|
18
|
-
}
|
|
19
|
-
if (!managerRef.current) {
|
|
20
|
-
managerRef.current = sharedInstance;
|
|
21
|
-
}
|
|
22
|
-
const log = (...args) => {
|
|
23
|
-
if (logs) console.log("[Keybindy]", ...args);
|
|
24
|
-
};
|
|
25
|
-
const warn = (...args) => {
|
|
26
|
-
if (logs) console.warn("[Keybindy]", ...args);
|
|
27
|
-
};
|
|
28
|
-
const register = _react2.default.useCallback(
|
|
29
|
-
(keys, handler, options) => {
|
|
30
|
-
if (keys.length === 0) {
|
|
31
|
-
warn("No keys provided to register");
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const id = _optionalChain([options, 'optionalAccess', _ => _.data, 'optionalAccess', _2 => _2.id]);
|
|
35
|
-
if (id) registeredIds.current.add(id);
|
|
36
|
-
log("Registered:", _nullishCoalesce(id, () => ( keys)));
|
|
37
|
-
_optionalChain([managerRef, 'access', _3 => _3.current, 'optionalAccess', _4 => _4.register, 'call', _5 => _5(keys, handler, options)]);
|
|
38
|
-
},
|
|
39
|
-
[]
|
|
40
|
-
);
|
|
41
|
-
const unregister = _react2.default.useCallback((keys, scope) => {
|
|
42
|
-
if (keys.length === 0) {
|
|
43
|
-
warn("No keys provided to unregister");
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
_optionalChain([managerRef, 'access', _6 => _6.current, 'optionalAccess', _7 => _7.unregister, 'call', _8 => _8(keys, scope)]);
|
|
47
|
-
log("Unregistered:", keys);
|
|
48
|
-
}, []);
|
|
49
|
-
const enable = _react2.default.useCallback((keys, scope) => {
|
|
50
|
-
if (keys.length === 0) {
|
|
51
|
-
warn("No keys provided to enable");
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
_optionalChain([managerRef, 'access', _9 => _9.current, 'optionalAccess', _10 => _10.enable, 'call', _11 => _11(keys, scope)]);
|
|
55
|
-
log("Enabled:", keys);
|
|
56
|
-
}, []);
|
|
57
|
-
const disable = _react2.default.useCallback((keys, scope) => {
|
|
58
|
-
if (keys.length === 0) {
|
|
59
|
-
warn("No keys provided to disable");
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
_optionalChain([managerRef, 'access', _12 => _12.current, 'optionalAccess', _13 => _13.disable, 'call', _14 => _14(keys, scope)]);
|
|
63
|
-
log("Disabled:", keys);
|
|
64
|
-
}, []);
|
|
65
|
-
const toggle = _react2.default.useCallback((keys, scope) => {
|
|
66
|
-
if (keys.length === 0) {
|
|
67
|
-
warn("No keys provided to toggle");
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
_optionalChain([managerRef, 'access', _15 => _15.current, 'optionalAccess', _16 => _16.toggle, 'call', _17 => _17(keys, scope)]);
|
|
71
|
-
log("Toggled:", keys);
|
|
72
|
-
}, []);
|
|
73
|
-
const getCheatSheet = _react2.default.useCallback((scope) => {
|
|
74
|
-
return _optionalChain([managerRef, 'access', _18 => _18.current, 'optionalAccess', _19 => _19.getCheatSheet, 'call', _20 => _20(scope)]);
|
|
75
|
-
}, []);
|
|
76
|
-
const getActiveScope = _react2.default.useCallback(() => {
|
|
77
|
-
return _nullishCoalesce(_optionalChain([managerRef, 'access', _21 => _21.current, 'optionalAccess', _22 => _22.getActiveScope, 'call', _23 => _23()]), () => ( ""));
|
|
78
|
-
}, []);
|
|
79
|
-
const disableAll = _react2.default.useCallback((scope) => {
|
|
80
|
-
_optionalChain([managerRef, 'access', _24 => _24.current, 'optionalAccess', _25 => _25.disableAll, 'call', _26 => _26(scope)]);
|
|
81
|
-
log(`Disabled all shortcuts${scope ? ` in scope "${scope}"` : ""}`);
|
|
82
|
-
}, []);
|
|
83
|
-
const enableAll = _react2.default.useCallback((scope) => {
|
|
84
|
-
_optionalChain([managerRef, 'access', _27 => _27.current, 'optionalAccess', _28 => _28.enableAll, 'call', _29 => _29(scope)]);
|
|
85
|
-
log(`Enabled all shortcuts${scope ? ` in scope "${scope}"` : ""}`);
|
|
86
|
-
}, []);
|
|
87
|
-
const setScope = _react2.default.useCallback((scope) => {
|
|
88
|
-
_optionalChain([managerRef, 'access', _30 => _30.current, 'optionalAccess', _31 => _31.setActiveScope, 'call', _32 => _32(scope)]);
|
|
89
|
-
log("Scope set to:", scope);
|
|
90
|
-
}, []);
|
|
91
|
-
const resetScope = _react2.default.useCallback(() => {
|
|
92
|
-
_optionalChain([managerRef, 'access', _33 => _33.current, 'optionalAccess', _34 => _34.resetScope, 'call', _35 => _35()]);
|
|
93
|
-
log("Reset scope");
|
|
94
|
-
}, []);
|
|
95
|
-
const getScopes = _react2.default.useCallback(() => {
|
|
96
|
-
return _nullishCoalesce(_optionalChain([managerRef, 'access', _36 => _36.current, 'optionalAccess', _37 => _37.getScopes, 'call', _38 => _38()]), () => ( []));
|
|
97
|
-
}, []);
|
|
98
|
-
const isScopeActive = _react2.default.useCallback((scope) => {
|
|
99
|
-
return _optionalChain([managerRef, 'access', _39 => _39.current, 'optionalAccess', _40 => _40.isScopeActive, 'call', _41 => _41(scope)]);
|
|
100
|
-
}, []);
|
|
101
|
-
const onTyping = _react2.default.useCallback(
|
|
102
|
-
(callback) => {
|
|
103
|
-
_optionalChain([managerRef, 'access', _42 => _42.current, 'optionalAccess', _43 => _43.onTyping, 'call', _44 => _44(callback)]);
|
|
104
|
-
},
|
|
105
|
-
[]
|
|
106
|
-
);
|
|
107
|
-
const popScope = _react2.default.useCallback(() => {
|
|
108
|
-
_optionalChain([managerRef, 'access', _45 => _45.current, 'optionalAccess', _46 => _46.popScope, 'call', _47 => _47()]);
|
|
109
|
-
log("Popped scope, active scope is:", _optionalChain([managerRef, 'access', _48 => _48.current, 'optionalAccess', _49 => _49.getActiveScope, 'call', _50 => _50()]));
|
|
110
|
-
}, []);
|
|
111
|
-
const pushScope = _react2.default.useCallback((scope) => {
|
|
112
|
-
_optionalChain([managerRef, 'access', _51 => _51.current, 'optionalAccess', _52 => _52.pushScope, 'call', _53 => _53(scope)]);
|
|
113
|
-
log("Pushed scope:", scope);
|
|
114
|
-
}, []);
|
|
115
|
-
const getScopeInfo = _react2.default.useCallback((scope) => {
|
|
116
|
-
return _optionalChain([managerRef, 'access', _54 => _54.current, 'optionalAccess', _55 => _55.getScopesInfo, 'call', _56 => _56(scope)]);
|
|
117
|
-
}, []);
|
|
118
|
-
const destroy = () => {
|
|
119
|
-
_optionalChain([managerRef, 'access', _57 => _57.current, 'optionalAccess', _58 => _58.destroy, 'call', _59 => _59()]);
|
|
120
|
-
};
|
|
121
|
-
const clear = () => {
|
|
122
|
-
_optionalChain([managerRef, 'access', _60 => _60.current, 'optionalAccess', _61 => _61.clear, 'call', _62 => _62()]);
|
|
123
|
-
};
|
|
124
|
-
return {
|
|
125
|
-
register,
|
|
126
|
-
unregister,
|
|
127
|
-
enable,
|
|
128
|
-
disable,
|
|
129
|
-
toggle,
|
|
130
|
-
setScope,
|
|
131
|
-
getCheatSheet,
|
|
132
|
-
destroy,
|
|
133
|
-
getScopeInfo,
|
|
134
|
-
getActiveScope,
|
|
135
|
-
popScope,
|
|
136
|
-
pushScope,
|
|
137
|
-
resetScope,
|
|
138
|
-
getScopes,
|
|
139
|
-
isScopeActive,
|
|
140
|
-
onTyping,
|
|
141
|
-
enableAll,
|
|
142
|
-
clear,
|
|
143
|
-
disableAll,
|
|
144
|
-
manager: managerRef.current
|
|
145
|
-
};
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
// src/Keybindy.tsx
|
|
149
|
-
var _jsxruntime = require('react/jsx-runtime');
|
|
150
|
-
var Keybindy = ({
|
|
151
|
-
scope = "global",
|
|
152
|
-
shortcuts = [],
|
|
153
|
-
children,
|
|
154
|
-
disabled,
|
|
155
|
-
onShortcutFired,
|
|
156
|
-
logs = false
|
|
157
|
-
}) => {
|
|
158
|
-
const { register, unregister, manager, pushScope, popScope, getScopes, setScope } = useKeybindy({
|
|
159
|
-
onShortcutFired,
|
|
160
|
-
logs
|
|
161
|
-
});
|
|
162
|
-
const prevScope = _react2.default.useRef(null);
|
|
163
|
-
_react2.default.useEffect(() => {
|
|
164
|
-
prevScope.current = manager.getActiveScope();
|
|
165
|
-
if (!_optionalChain([getScopes, 'call', _63 => _63(), 'optionalAccess', _64 => _64.includes, 'call', _65 => _65(scope)])) {
|
|
166
|
-
pushScope(scope);
|
|
167
|
-
}
|
|
168
|
-
setScope(scope);
|
|
169
|
-
shortcuts.forEach(({ keys, handler, options }) => {
|
|
170
|
-
register(keys, handler, { ...options, scope });
|
|
171
|
-
});
|
|
172
|
-
if (disabled) {
|
|
173
|
-
manager.disableAll(scope);
|
|
174
|
-
}
|
|
175
|
-
return () => {
|
|
176
|
-
shortcuts.forEach(({ keys }) => {
|
|
177
|
-
if (Array.isArray(keys[0])) {
|
|
178
|
-
keys.forEach((key) => unregister(key, scope));
|
|
179
|
-
} else {
|
|
180
|
-
unregister(keys, scope);
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
popScope();
|
|
184
|
-
};
|
|
185
|
-
}, [scope, JSON.stringify(shortcuts)]);
|
|
186
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children });
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
// src/ShortcutLabel.tsx
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
var ShortcutLabel = ({ keys, renderKey, style, ...props }) => {
|
|
193
|
-
const isMac = typeof navigator !== "undefined" && /Mac/.test(navigator.userAgent);
|
|
194
|
-
const defaultRenderKey = (key) => {
|
|
195
|
-
switch (key.toLowerCase()) {
|
|
196
|
-
case "meta":
|
|
197
|
-
return isMac ? "\u2318" : "Ctrl";
|
|
198
|
-
case "ctrl":
|
|
199
|
-
return "Ctrl";
|
|
200
|
-
case "shift":
|
|
201
|
-
return "\u21E7";
|
|
202
|
-
case "alt":
|
|
203
|
-
return isMac ? "\u2325" : "Alt";
|
|
204
|
-
case "enter":
|
|
205
|
-
return "\u21B5";
|
|
206
|
-
default:
|
|
207
|
-
return key.toUpperCase();
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
const rendered = renderKey ? keys.map((key, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react2.default.Fragment, { children: renderKey(key, i, keys) }, i)) : defaultRenderKey ? [keys.map((key) => defaultRenderKey(key)).join(" + ")] : [];
|
|
211
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
212
|
-
"kbd",
|
|
213
|
-
{
|
|
214
|
-
style: {
|
|
215
|
-
fontFamily: "monospace",
|
|
216
|
-
padding: "2.5px 5px",
|
|
217
|
-
border: "1px solid #cccccc2f",
|
|
218
|
-
backgroundColor: "#2e2e2e",
|
|
219
|
-
borderRadius: "4px",
|
|
220
|
-
userSelect: "none",
|
|
221
|
-
...style
|
|
222
|
-
},
|
|
223
|
-
...props,
|
|
224
|
-
children: rendered
|
|
225
|
-
}
|
|
226
|
-
);
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
exports.Keybindy = Keybindy; exports.ShortcutLabel = ShortcutLabel; exports.useKeybindy = useKeybindy;
|
package/dist/index.mjs
DELETED
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
// src/Keybindy.tsx
|
|
4
|
-
import React2 from "react";
|
|
5
|
-
|
|
6
|
-
// src/useKeybindy.tsx
|
|
7
|
-
import React from "react";
|
|
8
|
-
import ShortcutManager from "@keybindy/core";
|
|
9
|
-
var sharedInstance = null;
|
|
10
|
-
var useKeybindy = ({
|
|
11
|
-
logs = false,
|
|
12
|
-
onShortcutFired
|
|
13
|
-
} = {}) => {
|
|
14
|
-
const managerRef = React.useRef(null);
|
|
15
|
-
const registeredIds = React.useRef(/* @__PURE__ */ new Set());
|
|
16
|
-
if (!sharedInstance) {
|
|
17
|
-
sharedInstance = new ShortcutManager({ onShortcutFired, silent: !logs });
|
|
18
|
-
}
|
|
19
|
-
if (!managerRef.current) {
|
|
20
|
-
managerRef.current = sharedInstance;
|
|
21
|
-
}
|
|
22
|
-
const log = (...args) => {
|
|
23
|
-
if (logs) console.log("[Keybindy]", ...args);
|
|
24
|
-
};
|
|
25
|
-
const warn = (...args) => {
|
|
26
|
-
if (logs) console.warn("[Keybindy]", ...args);
|
|
27
|
-
};
|
|
28
|
-
const register = React.useCallback(
|
|
29
|
-
(keys, handler, options) => {
|
|
30
|
-
if (keys.length === 0) {
|
|
31
|
-
warn("No keys provided to register");
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const id = options?.data?.id;
|
|
35
|
-
if (id) registeredIds.current.add(id);
|
|
36
|
-
log("Registered:", id ?? keys);
|
|
37
|
-
managerRef.current?.register(keys, handler, options);
|
|
38
|
-
},
|
|
39
|
-
[]
|
|
40
|
-
);
|
|
41
|
-
const unregister = React.useCallback((keys, scope) => {
|
|
42
|
-
if (keys.length === 0) {
|
|
43
|
-
warn("No keys provided to unregister");
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
managerRef.current?.unregister(keys, scope);
|
|
47
|
-
log("Unregistered:", keys);
|
|
48
|
-
}, []);
|
|
49
|
-
const enable = React.useCallback((keys, scope) => {
|
|
50
|
-
if (keys.length === 0) {
|
|
51
|
-
warn("No keys provided to enable");
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
managerRef.current?.enable(keys, scope);
|
|
55
|
-
log("Enabled:", keys);
|
|
56
|
-
}, []);
|
|
57
|
-
const disable = React.useCallback((keys, scope) => {
|
|
58
|
-
if (keys.length === 0) {
|
|
59
|
-
warn("No keys provided to disable");
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
managerRef.current?.disable(keys, scope);
|
|
63
|
-
log("Disabled:", keys);
|
|
64
|
-
}, []);
|
|
65
|
-
const toggle = React.useCallback((keys, scope) => {
|
|
66
|
-
if (keys.length === 0) {
|
|
67
|
-
warn("No keys provided to toggle");
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
managerRef.current?.toggle(keys, scope);
|
|
71
|
-
log("Toggled:", keys);
|
|
72
|
-
}, []);
|
|
73
|
-
const getCheatSheet = React.useCallback((scope) => {
|
|
74
|
-
return managerRef.current?.getCheatSheet(scope);
|
|
75
|
-
}, []);
|
|
76
|
-
const getActiveScope = React.useCallback(() => {
|
|
77
|
-
return managerRef.current?.getActiveScope() ?? "";
|
|
78
|
-
}, []);
|
|
79
|
-
const disableAll = React.useCallback((scope) => {
|
|
80
|
-
managerRef.current?.disableAll(scope);
|
|
81
|
-
log(`Disabled all shortcuts${scope ? ` in scope "${scope}"` : ""}`);
|
|
82
|
-
}, []);
|
|
83
|
-
const enableAll = React.useCallback((scope) => {
|
|
84
|
-
managerRef.current?.enableAll(scope);
|
|
85
|
-
log(`Enabled all shortcuts${scope ? ` in scope "${scope}"` : ""}`);
|
|
86
|
-
}, []);
|
|
87
|
-
const setScope = React.useCallback((scope) => {
|
|
88
|
-
managerRef.current?.setActiveScope(scope);
|
|
89
|
-
log("Scope set to:", scope);
|
|
90
|
-
}, []);
|
|
91
|
-
const resetScope = React.useCallback(() => {
|
|
92
|
-
managerRef.current?.resetScope();
|
|
93
|
-
log("Reset scope");
|
|
94
|
-
}, []);
|
|
95
|
-
const getScopes = React.useCallback(() => {
|
|
96
|
-
return managerRef.current?.getScopes() ?? [];
|
|
97
|
-
}, []);
|
|
98
|
-
const isScopeActive = React.useCallback((scope) => {
|
|
99
|
-
return managerRef.current?.isScopeActive(scope);
|
|
100
|
-
}, []);
|
|
101
|
-
const onTyping = React.useCallback(
|
|
102
|
-
(callback) => {
|
|
103
|
-
managerRef.current?.onTyping(callback);
|
|
104
|
-
},
|
|
105
|
-
[]
|
|
106
|
-
);
|
|
107
|
-
const popScope = React.useCallback(() => {
|
|
108
|
-
managerRef.current?.popScope();
|
|
109
|
-
log("Popped scope, active scope is:", managerRef.current?.getActiveScope());
|
|
110
|
-
}, []);
|
|
111
|
-
const pushScope = React.useCallback((scope) => {
|
|
112
|
-
managerRef.current?.pushScope(scope);
|
|
113
|
-
log("Pushed scope:", scope);
|
|
114
|
-
}, []);
|
|
115
|
-
const getScopeInfo = React.useCallback((scope) => {
|
|
116
|
-
return managerRef.current?.getScopesInfo(scope);
|
|
117
|
-
}, []);
|
|
118
|
-
const destroy = () => {
|
|
119
|
-
managerRef.current?.destroy();
|
|
120
|
-
};
|
|
121
|
-
const clear = () => {
|
|
122
|
-
managerRef.current?.clear();
|
|
123
|
-
};
|
|
124
|
-
return {
|
|
125
|
-
register,
|
|
126
|
-
unregister,
|
|
127
|
-
enable,
|
|
128
|
-
disable,
|
|
129
|
-
toggle,
|
|
130
|
-
setScope,
|
|
131
|
-
getCheatSheet,
|
|
132
|
-
destroy,
|
|
133
|
-
getScopeInfo,
|
|
134
|
-
getActiveScope,
|
|
135
|
-
popScope,
|
|
136
|
-
pushScope,
|
|
137
|
-
resetScope,
|
|
138
|
-
getScopes,
|
|
139
|
-
isScopeActive,
|
|
140
|
-
onTyping,
|
|
141
|
-
enableAll,
|
|
142
|
-
clear,
|
|
143
|
-
disableAll,
|
|
144
|
-
manager: managerRef.current
|
|
145
|
-
};
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
// src/Keybindy.tsx
|
|
149
|
-
import { Fragment, jsx } from "react/jsx-runtime";
|
|
150
|
-
var Keybindy = ({
|
|
151
|
-
scope = "global",
|
|
152
|
-
shortcuts = [],
|
|
153
|
-
children,
|
|
154
|
-
disabled,
|
|
155
|
-
onShortcutFired,
|
|
156
|
-
logs = false
|
|
157
|
-
}) => {
|
|
158
|
-
const { register, unregister, manager, pushScope, popScope, getScopes, setScope } = useKeybindy({
|
|
159
|
-
onShortcutFired,
|
|
160
|
-
logs
|
|
161
|
-
});
|
|
162
|
-
const prevScope = React2.useRef(null);
|
|
163
|
-
React2.useEffect(() => {
|
|
164
|
-
prevScope.current = manager.getActiveScope();
|
|
165
|
-
if (!getScopes()?.includes(scope)) {
|
|
166
|
-
pushScope(scope);
|
|
167
|
-
}
|
|
168
|
-
setScope(scope);
|
|
169
|
-
shortcuts.forEach(({ keys, handler, options }) => {
|
|
170
|
-
register(keys, handler, { ...options, scope });
|
|
171
|
-
});
|
|
172
|
-
if (disabled) {
|
|
173
|
-
manager.disableAll(scope);
|
|
174
|
-
}
|
|
175
|
-
return () => {
|
|
176
|
-
shortcuts.forEach(({ keys }) => {
|
|
177
|
-
if (Array.isArray(keys[0])) {
|
|
178
|
-
keys.forEach((key) => unregister(key, scope));
|
|
179
|
-
} else {
|
|
180
|
-
unregister(keys, scope);
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
popScope();
|
|
184
|
-
};
|
|
185
|
-
}, [scope, JSON.stringify(shortcuts)]);
|
|
186
|
-
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
// src/ShortcutLabel.tsx
|
|
190
|
-
import React3 from "react";
|
|
191
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
192
|
-
var ShortcutLabel = ({ keys, renderKey, style, ...props }) => {
|
|
193
|
-
const isMac = typeof navigator !== "undefined" && /Mac/.test(navigator.userAgent);
|
|
194
|
-
const defaultRenderKey = (key) => {
|
|
195
|
-
switch (key.toLowerCase()) {
|
|
196
|
-
case "meta":
|
|
197
|
-
return isMac ? "\u2318" : "Ctrl";
|
|
198
|
-
case "ctrl":
|
|
199
|
-
return "Ctrl";
|
|
200
|
-
case "shift":
|
|
201
|
-
return "\u21E7";
|
|
202
|
-
case "alt":
|
|
203
|
-
return isMac ? "\u2325" : "Alt";
|
|
204
|
-
case "enter":
|
|
205
|
-
return "\u21B5";
|
|
206
|
-
default:
|
|
207
|
-
return key.toUpperCase();
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
const rendered = renderKey ? keys.map((key, i) => /* @__PURE__ */ jsx2(React3.Fragment, { children: renderKey(key, i, keys) }, i)) : defaultRenderKey ? [keys.map((key) => defaultRenderKey(key)).join(" + ")] : [];
|
|
211
|
-
return /* @__PURE__ */ jsx2(
|
|
212
|
-
"kbd",
|
|
213
|
-
{
|
|
214
|
-
style: {
|
|
215
|
-
fontFamily: "monospace",
|
|
216
|
-
padding: "2.5px 5px",
|
|
217
|
-
border: "1px solid #cccccc2f",
|
|
218
|
-
backgroundColor: "#2e2e2e",
|
|
219
|
-
borderRadius: "4px",
|
|
220
|
-
userSelect: "none",
|
|
221
|
-
...style
|
|
222
|
-
},
|
|
223
|
-
...props,
|
|
224
|
-
children: rendered
|
|
225
|
-
}
|
|
226
|
-
);
|
|
227
|
-
};
|
|
228
|
-
export {
|
|
229
|
-
Keybindy,
|
|
230
|
-
ShortcutLabel,
|
|
231
|
-
useKeybindy
|
|
232
|
-
};
|