@remcostoeten/use-shortcut 2.0.1 → 2.2.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 +100 -34
- package/dist/constants.d.ts +36 -0
- package/dist/constants.js +1 -0
- package/dist/constants.mjs +1 -0
- package/dist/formatter.d.ts +30 -0
- package/dist/formatter.js +1 -0
- package/dist/formatter.mjs +1 -0
- package/dist/index.d.ts +5 -415
- package/dist/index.js +1 -946
- package/dist/index.mjs +1 -928
- package/dist/parser.d.ts +47 -0
- package/dist/parser.js +1 -0
- package/dist/parser.mjs +1 -0
- package/dist/react.d.ts +79 -0
- package/dist/react.js +1 -0
- package/dist/react.mjs +1 -0
- package/dist/{index.d.mts → types-Cg7uyv1m.d.ts} +65 -166
- package/package.json +49 -9
- package/CHANGELOG.md +0 -66
- package/dist/cli/index.mjs +0 -455
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,46 +1,78 @@
|
|
|
1
1
|
# @remcostoeten/use-shortcut
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Tiny, chainable keyboard shortcuts for React and Next.js.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The package keeps the fluent `useShortcut()` API, but it is now documented as explicit entrypoints so consumers can choose the narrowest surface that fits their use case.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- Documentation scope: feature/status overview only (full API docs will be expanded later)
|
|
7
|
+
## Entrypoints
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
- `@remcostoeten/use-shortcut`
|
|
10
|
+
Full compatibility barrel.
|
|
11
|
+
- `@remcostoeten/use-shortcut/react`
|
|
12
|
+
Recommended React entrypoint.
|
|
13
|
+
- `@remcostoeten/use-shortcut/parser`
|
|
14
|
+
Parser and matcher utilities.
|
|
15
|
+
- `@remcostoeten/use-shortcut/formatter`
|
|
16
|
+
Display formatting utilities such as `formatShortcut()` and `getModifierSymbols()`.
|
|
17
|
+
- `@remcostoeten/use-shortcut/constants`
|
|
18
|
+
Platform and normalization constants.
|
|
11
19
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- Register with `.in("editor")`
|
|
18
|
-
- Runtime controls: `setScopes`, `enableScope`, `disableScope`, `getScopes`, `isScopeActive`
|
|
19
|
-
- Exception predicates/presets with `.except(...)`
|
|
20
|
-
- Recording mode: `$.record({ timeoutMs })`
|
|
21
|
-
- Conflict detection (`exact`, `sequence-prefix`)
|
|
22
|
-
- Priority ordering and `stopOnMatch`
|
|
23
|
-
- Global guard/filter support via `eventFilter`
|
|
24
|
-
- React entry point:
|
|
25
|
-
- `useShortcut`
|
|
26
|
-
- `useShortcutMap`
|
|
27
|
-
- `useShortcutGroup`
|
|
20
|
+
This package is for React and Next.js apps. If you are building on that stack, prefer `@remcostoeten/use-shortcut/react`.
|
|
21
|
+
|
|
22
|
+
## Size
|
|
23
|
+
|
|
24
|
+
Measured in this package on March 12, 2026:
|
|
28
25
|
|
|
29
|
-
|
|
26
|
+
- root published ESM build: about `16.5 kB` minified
|
|
27
|
+
- app bundle for `useShortcut` only: about `13.8 kB` minified
|
|
28
|
+
- gzip for the React hook path: about `5.3 kB`
|
|
29
|
+
|
|
30
|
+
That means the runtime is already small in practice. The entrypoint split mainly prevents accidental convenience-barrel imports and makes the architecture explicit.
|
|
31
|
+
|
|
32
|
+
## React API
|
|
33
|
+
|
|
34
|
+
The public runtime API is React-only. Parser, formatter, and constants exports are supporting utilities inside the same React/Next.js package, not a separate framework-agnostic runtime.
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { useShortcut } from "@remcostoeten/use-shortcut/react"
|
|
38
|
+
|
|
39
|
+
function App() {
|
|
40
|
+
const $ = useShortcut()
|
|
41
|
+
|
|
42
|
+
$.mod.key("k").on(() => openPalette(), { preventDefault: true })
|
|
43
|
+
$.key("escape").on(() => closePalette())
|
|
44
|
+
|
|
45
|
+
return <div>Press Cmd/Ctrl+K</div>
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Main React exports:
|
|
30
50
|
|
|
31
51
|
- `useShortcut(options?)`
|
|
32
|
-
- Main React hook. Use this for the chainable API (`$.mod.key("s").on(...)`).
|
|
33
52
|
- `useShortcutMap(shortcutMap, options?)`
|
|
34
|
-
- React-safe bulk registration for render paths where a declarative object is cleaner than multiple `.on()` calls.
|
|
35
53
|
- `registerShortcutMap(builder, shortcutMap)`
|
|
36
|
-
|
|
54
|
+
- `createShortcutGroup()`
|
|
55
|
+
- `useShortcutGroup()`
|
|
56
|
+
|
|
57
|
+
## Features
|
|
37
58
|
|
|
38
|
-
|
|
59
|
+
- Chainable shortcut builder: `$.mod.key("k").on(handler)`
|
|
60
|
+
- Bulk shortcut maps: `useShortcutMap()` and `registerShortcutMap()`
|
|
61
|
+
- Modifier support: `ctrl`, `shift`, `alt`, `cmd`, `mod`
|
|
62
|
+
- Sequence support: `$.key("g").then("d")`
|
|
63
|
+
- Scope-aware shortcuts with `.in(...)`, `setScopes`, `enableScope`, `disableScope`
|
|
64
|
+
- Exception predicates and presets with `.except(...)`
|
|
65
|
+
- Recording mode with `$.record({ timeoutMs })`
|
|
66
|
+
- Structured debug stream with `$.onDebug(...)`
|
|
67
|
+
- Per-shortcut attempt inspection with `result.onAttempt(...)`
|
|
68
|
+
- Conflict detection for exact and sequence-prefix overlaps
|
|
69
|
+
- Priority ordering and `stopOnMatch`
|
|
70
|
+
- Global guard/filter support via `eventFilter`
|
|
39
71
|
|
|
40
72
|
## Shortcut Map Example
|
|
41
73
|
|
|
42
74
|
```tsx
|
|
43
|
-
import { useShortcutMap } from "@remcostoeten/use-shortcut"
|
|
75
|
+
import { useShortcutMap } from "@remcostoeten/use-shortcut/react"
|
|
44
76
|
|
|
45
77
|
function App() {
|
|
46
78
|
useShortcutMap(
|
|
@@ -66,15 +98,49 @@ function App() {
|
|
|
66
98
|
}
|
|
67
99
|
```
|
|
68
100
|
|
|
69
|
-
|
|
101
|
+
## Debug Example
|
|
70
102
|
|
|
71
|
-
|
|
103
|
+
```tsx
|
|
104
|
+
import { useShortcut } from "@remcostoeten/use-shortcut/react"
|
|
105
|
+
|
|
106
|
+
const $ = useShortcut({
|
|
107
|
+
debug: {
|
|
108
|
+
console: true,
|
|
109
|
+
includeCode: true,
|
|
110
|
+
includeLocation: true,
|
|
111
|
+
includeKeyCode: true,
|
|
112
|
+
},
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
const removeDebug = $.onDebug((event) => {
|
|
116
|
+
console.log("key", event.input.combo, event.attempts)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
const result = $.shift.key("e").then("e").on(runProbe, {
|
|
120
|
+
description: "sequence probe",
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
const removeAttempt = result.onAttempt?.((matched, _event, details) => {
|
|
124
|
+
console.log(matched ? "matched" : details?.status, details?.steps)
|
|
125
|
+
})
|
|
126
|
+
```
|
|
72
127
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
-
|
|
76
|
-
|
|
77
|
-
-
|
|
128
|
+
## Architecture
|
|
129
|
+
|
|
130
|
+
- `src/builder.ts`
|
|
131
|
+
Chainable builder runtime and registration plumbing.
|
|
132
|
+
- `src/runtime/*`
|
|
133
|
+
Listener attachment, matching, conflicts, guards, recording, and debug internals.
|
|
134
|
+
- `src/hook.ts`
|
|
135
|
+
React integration and bulk registration helpers.
|
|
136
|
+
- `src/react.ts`
|
|
137
|
+
Narrow React entrypoint for hook consumers.
|
|
138
|
+
- `src/parser.ts`, `src/formatter.ts`, `src/constants.ts`
|
|
139
|
+
Standalone utility entrypoints.
|
|
140
|
+
- `src/index.ts`
|
|
141
|
+
Full compatibility barrel.
|
|
142
|
+
|
|
143
|
+
The API design keeps the fluent React path front-and-center while still exposing low-level parser and formatter utilities when needed.
|
|
78
144
|
|
|
79
145
|
## Development
|
|
80
146
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Supported runtime OS identifiers used by formatter and parser normalization. */
|
|
2
|
+
declare const OS: {
|
|
3
|
+
readonly MAC: "mac";
|
|
4
|
+
readonly WINDOWS: "windows";
|
|
5
|
+
readonly LINUX: "linux";
|
|
6
|
+
};
|
|
7
|
+
type PlatformType = (typeof OS)[keyof typeof OS];
|
|
8
|
+
/** Public platform constant alias (`Platform.MAC`, `Platform.WINDOWS`, `Platform.LINUX`). */
|
|
9
|
+
declare const Platform: {
|
|
10
|
+
readonly MAC: "mac";
|
|
11
|
+
readonly WINDOWS: "windows";
|
|
12
|
+
readonly LINUX: "linux";
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Detect the current OS platform for modifier normalization and display formatting.
|
|
16
|
+
* Result is memoized for the page lifecycle.
|
|
17
|
+
*/
|
|
18
|
+
declare function detectPlatform(): PlatformType;
|
|
19
|
+
/** Canonical modifier token names used internally across parsing/formatting. */
|
|
20
|
+
declare const ModifierKey: {
|
|
21
|
+
readonly META: "meta";
|
|
22
|
+
readonly CTRL: "ctrl";
|
|
23
|
+
readonly ALT: "alt";
|
|
24
|
+
readonly SHIFT: "shift";
|
|
25
|
+
};
|
|
26
|
+
type ModifierKeyType = (typeof ModifierKey)[keyof typeof ModifierKey];
|
|
27
|
+
/** Alias map from user-facing modifier tokens to canonical modifier keys. */
|
|
28
|
+
declare const ModifierAliases: Record<string, ModifierKeyType>;
|
|
29
|
+
/** Alias map from human shortcut key tokens to `KeyboardEvent.key`-compatible values. */
|
|
30
|
+
declare const SpecialKeyMap: Record<string, string>;
|
|
31
|
+
/** Platform-specific display labels/symbols for modifier keys. */
|
|
32
|
+
declare const ModifierDisplaySymbols: Record<PlatformType, Record<ModifierKeyType, string>>;
|
|
33
|
+
/** Platform-specific canonical order for modifier rendering and combo normalization. */
|
|
34
|
+
declare const ModifierDisplayOrder: Record<PlatformType, ModifierKeyType[]>;
|
|
35
|
+
|
|
36
|
+
export { ModifierAliases, ModifierDisplayOrder, ModifierDisplaySymbols, ModifierKey, type ModifierKeyType, OS, Platform, type PlatformType, SpecialKeyMap, detectPlatform };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var o={MAC:"mac",WINDOWS:"windows",LINUX:"linux"},n=o,t=null;function i(){if(t)return t;if(typeof navigator>"u")return t=o.WINDOWS,t;let r=(navigator.userAgentData?.platform?.toLowerCase()??navigator.platform??navigator.userAgent??"").toLowerCase();return r.includes("mac")||r.includes("iphone")||r.includes("ipad")||r.includes("ipod")?(t=o.MAC,t):r.includes("linux")||r.includes("android")?(t=o.LINUX,t):(r.includes("win"),t=o.WINDOWS,t)}var e={META:"meta",CTRL:"ctrl",ALT:"alt",SHIFT:"shift"},s={command:e.META,cmd:e.META,"\u2318":e.META,meta:e.META,win:e.META,windows:e.META,super:e.META,mod:e.META,control:e.CTRL,ctrl:e.CTRL,"\u2303":e.CTRL,ctl:e.CTRL,alt:e.ALT,option:e.ALT,opt:e.ALT,"\u2325":e.ALT,shift:e.SHIFT,"\u21E7":e.SHIFT,shft:e.SHIFT},f={up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",enter:"Enter",return:"Enter",space:" ",spacebar:" ",tab:"Tab",backspace:"Backspace",delete:"Delete",del:"Delete",escape:"Escape",esc:"Escape",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",plus:"+",minus:"-",comma:",",period:".",slash:"/",backslash:"\\",bracket:"[",closebracket:"]"},T={[o.MAC]:{[e.META]:"\u2318",[e.CTRL]:"\u2303",[e.ALT]:"\u2325",[e.SHIFT]:"\u21E7"},[o.WINDOWS]:{[e.META]:"Ctrl",[e.CTRL]:"Ctrl",[e.ALT]:"Alt",[e.SHIFT]:"Shift"},[o.LINUX]:{[e.META]:"Super",[e.CTRL]:"Ctrl",[e.ALT]:"Alt",[e.SHIFT]:"Shift"}},p={[o.MAC]:[e.CTRL,e.ALT,e.SHIFT,e.META],[o.WINDOWS]:[e.META,e.ALT,e.SHIFT,e.CTRL],[o.LINUX]:[e.META,e.ALT,e.SHIFT,e.CTRL]};exports.ModifierAliases=s;exports.ModifierDisplayOrder=p;exports.ModifierDisplaySymbols=T;exports.ModifierKey=e;exports.OS=o;exports.Platform=n;exports.SpecialKeyMap=f;exports.detectPlatform=i;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var o={MAC:"mac",WINDOWS:"windows",LINUX:"linux"},n=o,t=null;function i(){if(t)return t;if(typeof navigator>"u")return t=o.WINDOWS,t;let r=(navigator.userAgentData?.platform?.toLowerCase()??navigator.platform??navigator.userAgent??"").toLowerCase();return r.includes("mac")||r.includes("iphone")||r.includes("ipad")||r.includes("ipod")?(t=o.MAC,t):r.includes("linux")||r.includes("android")?(t=o.LINUX,t):(r.includes("win"),t=o.WINDOWS,t)}var e={META:"meta",CTRL:"ctrl",ALT:"alt",SHIFT:"shift"},s={command:e.META,cmd:e.META,"\u2318":e.META,meta:e.META,win:e.META,windows:e.META,super:e.META,mod:e.META,control:e.CTRL,ctrl:e.CTRL,"\u2303":e.CTRL,ctl:e.CTRL,alt:e.ALT,option:e.ALT,opt:e.ALT,"\u2325":e.ALT,shift:e.SHIFT,"\u21E7":e.SHIFT,shft:e.SHIFT},f={up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",enter:"Enter",return:"Enter",space:" ",spacebar:" ",tab:"Tab",backspace:"Backspace",delete:"Delete",del:"Delete",escape:"Escape",esc:"Escape",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",plus:"+",minus:"-",comma:",",period:".",slash:"/",backslash:"\\",bracket:"[",closebracket:"]"},T={[o.MAC]:{[e.META]:"\u2318",[e.CTRL]:"\u2303",[e.ALT]:"\u2325",[e.SHIFT]:"\u21E7"},[o.WINDOWS]:{[e.META]:"Ctrl",[e.CTRL]:"Ctrl",[e.ALT]:"Alt",[e.SHIFT]:"Shift"},[o.LINUX]:{[e.META]:"Super",[e.CTRL]:"Ctrl",[e.ALT]:"Alt",[e.SHIFT]:"Shift"}},p={[o.MAC]:[e.CTRL,e.ALT,e.SHIFT,e.META],[o.WINDOWS]:[e.META,e.ALT,e.SHIFT,e.CTRL],[o.LINUX]:[e.META,e.ALT,e.SHIFT,e.CTRL]};export{s as ModifierAliases,p as ModifierDisplayOrder,T as ModifierDisplaySymbols,e as ModifierKey,o as OS,n as Platform,f as SpecialKeyMap,i as detectPlatform};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { PlatformType, ModifierKeyType } from './constants.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Format a shortcut string for display with platform-aware symbols
|
|
5
|
+
*
|
|
6
|
+
* @param shortcut - Shortcut string (e.g., "cmd+s")
|
|
7
|
+
* @param platform - Optional platform override (default: auto-detect)
|
|
8
|
+
* @returns Formatted display string (e.g., "⌘S" on Mac, "Ctrl+S" on Windows)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* formatShortcut("cmd+s") // "⌘S" on Mac, "Ctrl+S" on Windows
|
|
13
|
+
* formatShortcut("ctrl+shift+p", "mac") // "⌃⇧P"
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare function formatShortcut(shortcut: string, platform?: PlatformType): string;
|
|
17
|
+
/**
|
|
18
|
+
* Get the modifier key symbols for a platform
|
|
19
|
+
*
|
|
20
|
+
* @param platform - Optional platform override (default: auto-detect)
|
|
21
|
+
* @returns Object mapping modifier keys to display symbols
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* getModifierSymbols("mac") // { meta: "⌘", ctrl: "⌃", alt: "⌥", shift: "⇧" }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
declare function getModifierSymbols(platform?: PlatformType): Record<ModifierKeyType, string>;
|
|
29
|
+
|
|
30
|
+
export { formatShortcut, getModifierSymbols };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var r={MAC:"mac",WINDOWS:"windows",LINUX:"linux"},T=r,o=null;function p(){if(o)return o;if(typeof navigator>"u")return o=r.WINDOWS,o;let t=(navigator.userAgentData?.platform?.toLowerCase()??navigator.platform??navigator.userAgent??"").toLowerCase();return t.includes("mac")||t.includes("iphone")||t.includes("ipad")||t.includes("ipod")?(o=r.MAC,o):t.includes("linux")||t.includes("android")?(o=r.LINUX,o):(t.includes("win"),o=r.WINDOWS,o)}var e={META:"meta",CTRL:"ctrl",ALT:"alt",SHIFT:"shift"},u={command:e.META,cmd:e.META,"\u2318":e.META,meta:e.META,win:e.META,windows:e.META,super:e.META,mod:e.META,control:e.CTRL,ctrl:e.CTRL,"\u2303":e.CTRL,ctl:e.CTRL,alt:e.ALT,option:e.ALT,opt:e.ALT,"\u2325":e.ALT,shift:e.SHIFT,"\u21E7":e.SHIFT,shft:e.SHIFT},A={up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",enter:"Enter",return:"Enter",space:" ",spacebar:" ",tab:"Tab",backspace:"Backspace",delete:"Delete",del:"Delete",escape:"Escape",esc:"Escape",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",plus:"+",minus:"-",comma:",",period:".",slash:"/",backslash:"\\",bracket:"[",closebracket:"]"},m={[r.MAC]:{[e.META]:"\u2318",[e.CTRL]:"\u2303",[e.ALT]:"\u2325",[e.SHIFT]:"\u21E7"},[r.WINDOWS]:{[e.META]:"Ctrl",[e.CTRL]:"Ctrl",[e.ALT]:"Alt",[e.SHIFT]:"Shift"},[r.LINUX]:{[e.META]:"Super",[e.CTRL]:"Ctrl",[e.ALT]:"Alt",[e.SHIFT]:"Shift"}},M={[r.MAC]:[e.CTRL,e.ALT,e.SHIFT,e.META],[r.WINDOWS]:[e.META,e.ALT,e.SHIFT,e.CTRL],[r.LINUX]:[e.META,e.ALT,e.SHIFT,e.CTRL]};function S(a){let t=p(),n=a.toLowerCase().trim().split(/[\s+-]+/).filter(Boolean);if(n.length===0)throw new Error(`Invalid shortcut: "${a}"`);let c={meta:false,ctrl:false,alt:false,shift:false},f=n.pop();for(let l of n){let d=u[l];d?l==="mod"?t===T.MAC?c.meta=true:c.ctrl=true:c[d]=true:f=l+f;}let s=A[f]||f;return {modifiers:c,key:s.length===1?s.toLowerCase():s,original:a}}var g={ArrowUp:"\u2191",ArrowDown:"\u2193",ArrowLeft:"\u2190",ArrowRight:"\u2192",Home:"Home",End:"End",PageUp:"PgUp",PageDown:"PgDn"},h={...g,Enter:"\u21A9",Tab:"\u21E5",Escape:"\u238B",Backspace:"\u232B",Delete:"\u2326"," ":"\u2423"},E={...g,Enter:"Enter",Tab:"Tab",Escape:"Esc",Backspace:"Backspace",Delete:"Del"," ":"Space"};function K(a,t){let i=t??p(),n=S(a),c=m[i],f=M[i],s=[];for(let y of f)n.modifiers[y]&&s.push(c[y]);let l=L(n.key,i);s.push(l);let d=i===r.MAC?"":"+";return s.join(d)}function L(a,t){return (t===r.MAC?h:E)[a]||a.toUpperCase()}function F(a){let t=a??p();return m[t]}exports.formatShortcut=K;exports.getModifierSymbols=F;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var r={MAC:"mac",WINDOWS:"windows",LINUX:"linux"},T=r,o=null;function p(){if(o)return o;if(typeof navigator>"u")return o=r.WINDOWS,o;let t=(navigator.userAgentData?.platform?.toLowerCase()??navigator.platform??navigator.userAgent??"").toLowerCase();return t.includes("mac")||t.includes("iphone")||t.includes("ipad")||t.includes("ipod")?(o=r.MAC,o):t.includes("linux")||t.includes("android")?(o=r.LINUX,o):(t.includes("win"),o=r.WINDOWS,o)}var e={META:"meta",CTRL:"ctrl",ALT:"alt",SHIFT:"shift"},u={command:e.META,cmd:e.META,"\u2318":e.META,meta:e.META,win:e.META,windows:e.META,super:e.META,mod:e.META,control:e.CTRL,ctrl:e.CTRL,"\u2303":e.CTRL,ctl:e.CTRL,alt:e.ALT,option:e.ALT,opt:e.ALT,"\u2325":e.ALT,shift:e.SHIFT,"\u21E7":e.SHIFT,shft:e.SHIFT},A={up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",enter:"Enter",return:"Enter",space:" ",spacebar:" ",tab:"Tab",backspace:"Backspace",delete:"Delete",del:"Delete",escape:"Escape",esc:"Escape",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",plus:"+",minus:"-",comma:",",period:".",slash:"/",backslash:"\\",bracket:"[",closebracket:"]"},m={[r.MAC]:{[e.META]:"\u2318",[e.CTRL]:"\u2303",[e.ALT]:"\u2325",[e.SHIFT]:"\u21E7"},[r.WINDOWS]:{[e.META]:"Ctrl",[e.CTRL]:"Ctrl",[e.ALT]:"Alt",[e.SHIFT]:"Shift"},[r.LINUX]:{[e.META]:"Super",[e.CTRL]:"Ctrl",[e.ALT]:"Alt",[e.SHIFT]:"Shift"}},M={[r.MAC]:[e.CTRL,e.ALT,e.SHIFT,e.META],[r.WINDOWS]:[e.META,e.ALT,e.SHIFT,e.CTRL],[r.LINUX]:[e.META,e.ALT,e.SHIFT,e.CTRL]};function S(a){let t=p(),n=a.toLowerCase().trim().split(/[\s+-]+/).filter(Boolean);if(n.length===0)throw new Error(`Invalid shortcut: "${a}"`);let c={meta:false,ctrl:false,alt:false,shift:false},f=n.pop();for(let l of n){let d=u[l];d?l==="mod"?t===T.MAC?c.meta=true:c.ctrl=true:c[d]=true:f=l+f;}let s=A[f]||f;return {modifiers:c,key:s.length===1?s.toLowerCase():s,original:a}}var g={ArrowUp:"\u2191",ArrowDown:"\u2193",ArrowLeft:"\u2190",ArrowRight:"\u2192",Home:"Home",End:"End",PageUp:"PgUp",PageDown:"PgDn"},h={...g,Enter:"\u21A9",Tab:"\u21E5",Escape:"\u238B",Backspace:"\u232B",Delete:"\u2326"," ":"\u2423"},E={...g,Enter:"Enter",Tab:"Tab",Escape:"Esc",Backspace:"Backspace",Delete:"Del"," ":"Space"};function K(a,t){let i=t??p(),n=S(a),c=m[i],f=M[i],s=[];for(let y of f)n.modifiers[y]&&s.push(c[y]);let l=L(n.key,i);s.push(l);let d=i===r.MAC?"":"+";return s.join(d)}function L(a,t){return (t===r.MAC?h:E)[a]||a.toUpperCase()}function F(a){let t=a??p();return m[t]}export{K as formatShortcut,F as getModifierSymbols};
|