@trackunit/react-components 1.15.21 → 1.15.22
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/index.cjs.js +401 -0
- package/index.esm.js +401 -1
- package/package.json +1 -1
- package/src/hooks/useKeyboardShortcut/formatShortcutLabel.d.ts +24 -0
- package/src/hooks/useKeyboardShortcut/platformUtils.d.ts +20 -0
- package/src/hooks/useKeyboardShortcut/reservedShortcutTypes.d.ts +188 -0
- package/src/hooks/useKeyboardShortcut/reservedShortcuts.d.ts +20 -0
- package/src/hooks/useKeyboardShortcut/shortcutMatcher.d.ts +18 -0
- package/src/hooks/useKeyboardShortcut/shortcutUtils.d.ts +6 -0
- package/src/hooks/useKeyboardShortcut/shortcutUtils.testUtils.d.ts +12 -0
- package/src/hooks/useKeyboardShortcut/types.d.ts +97 -0
- package/src/hooks/useKeyboardShortcut/useKeyboardShortcut.d.ts +56 -0
- package/src/hooks/useKeyboardShortcut/useShortcutConflicts.d.ts +41 -0
- package/src/index.d.ts +1 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ReservedShortcutInfo } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Reserved application shortcuts.
|
|
4
|
+
* These are host-level shortcuts that are blocked at the type level.
|
|
5
|
+
* See reservedShortcutTypes.ts for the type-level enforcement.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: When adding a new reserved shortcut here, you must also
|
|
8
|
+
* update the type definitions in reservedShortcutTypes.ts and the
|
|
9
|
+
* isGlobalShortcut() function in apps/iris-app-loader/src/forward-events-to-host.ts.
|
|
10
|
+
*/
|
|
11
|
+
export declare const RESERVED_SHORTCUTS: Record<string, ReservedShortcutInfo>;
|
|
12
|
+
/**
|
|
13
|
+
* Common browser shortcuts that cannot be reliably overridden.
|
|
14
|
+
* Using these shortcuts will trigger a development warning since
|
|
15
|
+
* the browser typically intercepts them before JavaScript can handle them.
|
|
16
|
+
*
|
|
17
|
+
* Note: Some of these can be overridden with preventDefault(), but it's
|
|
18
|
+
* generally a bad UX to override expected browser behavior.
|
|
19
|
+
*/
|
|
20
|
+
export declare const BROWSER_SHORTCUTS: Record<string, string>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ShortcutDefinition } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a keyboard event matches the shortcut definition.
|
|
4
|
+
*
|
|
5
|
+
* This is a pure function that handles:
|
|
6
|
+
* - Case-insensitive key matching
|
|
7
|
+
* - Platform-aware modifier key checking (Cmd on Mac, Ctrl on Windows/Linux)
|
|
8
|
+
* - Space key normalization
|
|
9
|
+
* - Extra modifier rejection (ensures only expected modifiers are pressed)
|
|
10
|
+
*
|
|
11
|
+
* @param event - The keyboard event to check
|
|
12
|
+
* @param shortcut - The shortcut definition to match against
|
|
13
|
+
* @returns {boolean} true if the event matches the shortcut, false otherwise
|
|
14
|
+
* @example
|
|
15
|
+
* // Check if Cmd+K (Mac) or Ctrl+K (Windows) was pressed
|
|
16
|
+
* const isMatch = matchesShortcut(event, { key: "k", modifiers: "mod" });
|
|
17
|
+
*/
|
|
18
|
+
export declare const matchesShortcut: (event: KeyboardEvent, shortcut: ShortcutDefinition) => boolean;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ShortcutDefinition } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Converts a ShortcutDefinition to a normalized string key for lookup.
|
|
4
|
+
* Format: "mod+shift+k" (modifiers sorted alphabetically, then key)
|
|
5
|
+
*/
|
|
6
|
+
export declare const shortcutToString: (shortcut: ShortcutDefinition) => string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ShortcutDefinition } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Parses a string shortcut into a ShortcutDefinition.
|
|
4
|
+
* Useful for debugging and testing.
|
|
5
|
+
*
|
|
6
|
+
* @param shortcutStr - The shortcut string to parse (e.g., "mod+k")
|
|
7
|
+
* @returns {ShortcutDefinition} The parsed shortcut definition
|
|
8
|
+
* @example
|
|
9
|
+
* parseShortcut("mod+k") // { key: "k", modifiers: "mod" }
|
|
10
|
+
* parseShortcut("mod+shift+l") // { key: "l", modifiers: "mod+shift" }
|
|
11
|
+
*/
|
|
12
|
+
export declare const parseShortcut: (shortcutStr: string) => ShortcutDefinition;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { RefObject } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Individual semantic modifier keys (internal use for parsing).
|
|
4
|
+
*
|
|
5
|
+
* - `mod`: Primary action modifier - Cmd on Mac, Ctrl on Windows/Linux
|
|
6
|
+
* - `alt`: Alternative/Option key - Option on Mac, Alt on Windows/Linux
|
|
7
|
+
* - `shift`: Shift key on all platforms
|
|
8
|
+
*
|
|
9
|
+
* Note: Explicit ctrl/meta are intentionally not supported.
|
|
10
|
+
* Use "mod" for cross-platform shortcuts.
|
|
11
|
+
*/
|
|
12
|
+
export type SemanticModifier = "mod" | "alt" | "shift";
|
|
13
|
+
/**
|
|
14
|
+
* Valid modifier combinations as a string.
|
|
15
|
+
* Modifiers are joined with "+" in alphabetical order.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* "mod" // Cmd on Mac, Ctrl on Windows/Linux
|
|
19
|
+
* "mod+shift" // Cmd+Shift on Mac, Ctrl+Shift on Windows/Linux
|
|
20
|
+
* "alt+mod+shift" // Option+Cmd+Shift on Mac, Alt+Ctrl+Shift on Windows/Linux
|
|
21
|
+
*/
|
|
22
|
+
export type ModifierString = "mod" | "alt" | "shift" | "alt+mod" | "alt+shift" | "mod+shift" | "alt+mod+shift";
|
|
23
|
+
/**
|
|
24
|
+
* Supported shortcut keys.
|
|
25
|
+
* These map to the `event.key` values from KeyboardEvent.
|
|
26
|
+
*/
|
|
27
|
+
export type ShortcutKey = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "Enter" | "Escape" | "Tab" | "Space" | "Backspace" | "Delete" | "ArrowUp" | "ArrowDown" | "ArrowLeft" | "ArrowRight" | "F1" | "F2" | "F3" | "F4" | "F5" | "F6" | "F7" | "F8" | "F9" | "F10" | "F11" | "F12" | "/" | "[" | "]" | "," | "." | "-" | "=" | "`" | "\\";
|
|
28
|
+
/**
|
|
29
|
+
* Defines a keyboard shortcut with a key and optional modifiers.
|
|
30
|
+
*/
|
|
31
|
+
export type ShortcutDefinition = {
|
|
32
|
+
/** The primary key for the shortcut */
|
|
33
|
+
readonly key: ShortcutKey;
|
|
34
|
+
/**
|
|
35
|
+
* Optional modifier string. Modifiers are joined with "+" in alphabetical order.
|
|
36
|
+
*
|
|
37
|
+
* @example "mod" | "mod+shift" | "alt+mod+shift"
|
|
38
|
+
*/
|
|
39
|
+
readonly modifiers?: ModifierString;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Controls how the shortcut handles the browser's default behavior.
|
|
43
|
+
*
|
|
44
|
+
* - `"never"` - Never prevent default. Browser handles the event normally.
|
|
45
|
+
* - `"once"` - Prevent default on first trigger. Pressing the same shortcut
|
|
46
|
+
* twice within 400ms passes through to the browser, providing an escape
|
|
47
|
+
* hatch for accessing native browser shortcuts that are overridden.
|
|
48
|
+
* - `"always"` - Always prevent default on every press, including rapid repeats.
|
|
49
|
+
* No browser escape hatch.
|
|
50
|
+
*/
|
|
51
|
+
export type PreventDefaultMode = "never" | "once" | "always";
|
|
52
|
+
/**
|
|
53
|
+
* Options for the useKeyboardShortcut hook.
|
|
54
|
+
*/
|
|
55
|
+
export type UseKeyboardShortcutOptions = {
|
|
56
|
+
/** Called when the shortcut is triggered */
|
|
57
|
+
onTrigger: () => void;
|
|
58
|
+
/**
|
|
59
|
+
* Disable the shortcut conditionally.
|
|
60
|
+
*
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
disabled?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Controls how the shortcut handles the browser's default behavior.
|
|
66
|
+
*
|
|
67
|
+
* - `"never"` - Never prevent default. Browser handles the event normally.
|
|
68
|
+
* - `"once"` - Prevent default on first trigger. Pressing the same shortcut
|
|
69
|
+
* twice within 400ms passes through to the browser, providing an escape
|
|
70
|
+
* hatch for accessing native browser shortcuts that are overridden.
|
|
71
|
+
* - `"always"` - Always prevent default on every press, including rapid repeats.
|
|
72
|
+
* No browser escape hatch.
|
|
73
|
+
*
|
|
74
|
+
* @default "never"
|
|
75
|
+
*/
|
|
76
|
+
preventDefault?: PreventDefaultMode;
|
|
77
|
+
/**
|
|
78
|
+
* Target element for the keyboard listener.
|
|
79
|
+
* Can be a ref to an HTMLElement or "window" for global shortcuts.
|
|
80
|
+
*
|
|
81
|
+
* @default "window"
|
|
82
|
+
*/
|
|
83
|
+
target?: RefObject<HTMLElement | null> | "window";
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Detected platform for keyboard shortcut handling.
|
|
87
|
+
*/
|
|
88
|
+
export type Platform = "mac" | "windows" | "linux";
|
|
89
|
+
/**
|
|
90
|
+
* Information about a reserved shortcut.
|
|
91
|
+
*/
|
|
92
|
+
export type ReservedShortcutInfo = {
|
|
93
|
+
/** Human-readable name of the shortcut */
|
|
94
|
+
name: string;
|
|
95
|
+
/** The module/feature that owns this shortcut */
|
|
96
|
+
owner: string;
|
|
97
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ValidShortcutParam } from "./reservedShortcutTypes";
|
|
2
|
+
import { ShortcutDefinition, UseKeyboardShortcutOptions } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Hook for handling keyboard shortcuts with platform-aware modifiers.
|
|
5
|
+
*
|
|
6
|
+
* Reserved shortcuts are blocked at the type level and will show specific error messages.
|
|
7
|
+
* There are two categories:
|
|
8
|
+
*
|
|
9
|
+
* **App-reserved** (host-level features):
|
|
10
|
+
* - mod+k: Global Search
|
|
11
|
+
* - mod+shift+l: Local Dev Mode Toggle
|
|
12
|
+
*
|
|
13
|
+
* **Browser-reserved** (native browser shortcuts):
|
|
14
|
+
* - Clipboard: mod+c (Copy), mod+v (Paste), mod+x (Cut), mod+a (Select All)
|
|
15
|
+
* - Undo/Redo: mod+z (Undo), mod+shift+z (Redo Mac), mod+y (Redo Win/Linux)
|
|
16
|
+
* - Find: mod+f (Find), mod+g (Find next), mod+shift+g (Find previous)
|
|
17
|
+
* - Navigation: mod+r (Reload), mod+shift+r (Hard reload), mod+t (New tab),
|
|
18
|
+
* mod+w (Close tab), mod+shift+t (Reopen tab), mod+n (New window),
|
|
19
|
+
* mod+shift+n (Incognito), mod+l (Address bar), mod+d (Bookmark)
|
|
20
|
+
* - Zoom: mod+= (Zoom in), mod+- (Zoom out), mod+0 (Reset zoom)
|
|
21
|
+
* - Other: mod+p (Print), mod+s (Save), mod+o (Open), mod+h (History/Hide),
|
|
22
|
+
* mod+j (Downloads), mod+q (Quit Mac)
|
|
23
|
+
*
|
|
24
|
+
* See reservedShortcutTypes.ts for the full list with error messages.
|
|
25
|
+
*
|
|
26
|
+
* @param shortcut - The shortcut definition with key and optional modifiers
|
|
27
|
+
* @param options - Configuration options for the shortcut handler
|
|
28
|
+
* @param options.onTrigger - Callback invoked when the shortcut is triggered
|
|
29
|
+
* @param options.disabled - Disable the shortcut conditionally (default: false)
|
|
30
|
+
* @param options.preventDefault - Controls browser default behavior:
|
|
31
|
+
* - `"never"` (default) - Browser handles the event normally
|
|
32
|
+
* - `"once"` - Prevent default, but rapid repeat (within 400ms) passes to browser
|
|
33
|
+
* - `"always"` - Always prevent default, no browser escape hatch
|
|
34
|
+
* @param options.target - Target element for the listener (default: "window")
|
|
35
|
+
* @returns {{ label: string }} Object containing the formatted shortcut label (e.g., "Cmd + K" on Mac)
|
|
36
|
+
* @example
|
|
37
|
+
* // Simple Escape key handler (no preventDefault)
|
|
38
|
+
* const { label } = useKeyboardShortcut(
|
|
39
|
+
* { key: "Escape" },
|
|
40
|
+
* { onTrigger: () => closeModal() }
|
|
41
|
+
* );
|
|
42
|
+
* // label = "Esc"
|
|
43
|
+
* @example
|
|
44
|
+
* // Always prevent default, allow rapid re-triggering
|
|
45
|
+
* const { label } = useKeyboardShortcut(
|
|
46
|
+
* { key: "m", modifiers: "mod" },
|
|
47
|
+
* {
|
|
48
|
+
* onTrigger: () => createNewItem(),
|
|
49
|
+
* preventDefault: "always",
|
|
50
|
+
* }
|
|
51
|
+
* );
|
|
52
|
+
* // label = "Cmd + M" (Mac) or "Ctrl + M" (Windows/Linux)
|
|
53
|
+
*/
|
|
54
|
+
export declare const useKeyboardShortcut: <const TShortcut extends ShortcutDefinition>(shortcut: TShortcut extends ValidShortcutParam<TShortcut> ? TShortcut : never, { onTrigger, disabled, preventDefault, target }: UseKeyboardShortcutOptions) => {
|
|
55
|
+
label: string;
|
|
56
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ReservedShortcutInfo, ShortcutDefinition } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Information about shortcut conflicts.
|
|
4
|
+
*/
|
|
5
|
+
export type ShortcutConflictInfo = {
|
|
6
|
+
/** True if shortcut is reserved by the application */
|
|
7
|
+
isReserved: boolean;
|
|
8
|
+
/** Info about the reservation if reserved */
|
|
9
|
+
reservedInfo: ReservedShortcutInfo | undefined;
|
|
10
|
+
/** Browser action description if conflicts with browser shortcut */
|
|
11
|
+
browserConflict: string | undefined;
|
|
12
|
+
};
|
|
13
|
+
type UseShortcutConflictsOptions = {
|
|
14
|
+
/**
|
|
15
|
+
* If true, skip conflict checking and warnings.
|
|
16
|
+
*
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Hook for checking keyboard shortcut conflicts.
|
|
23
|
+
*
|
|
24
|
+
* This hook checks if a shortcut conflicts with:
|
|
25
|
+
* - Reserved application shortcuts (host-level features)
|
|
26
|
+
* - Browser shortcuts (that cannot be reliably overridden)
|
|
27
|
+
*
|
|
28
|
+
* In development mode, it logs a warning if the shortcut conflicts with
|
|
29
|
+
* browser shortcuts. Reserved shortcuts are blocked at the type level.
|
|
30
|
+
*
|
|
31
|
+
* @param shortcut - The shortcut definition to check
|
|
32
|
+
* @param options - Optional configuration
|
|
33
|
+
* @returns {ShortcutConflictInfo} Conflict information for the shortcut
|
|
34
|
+
* @example
|
|
35
|
+
* const conflicts = useShortcutConflicts({ key: "k", modifiers: "mod" });
|
|
36
|
+
* if (conflicts.isReserved) {
|
|
37
|
+
* console.log(`Reserved by: ${conflicts.reservedInfo?.owner}`);
|
|
38
|
+
* }
|
|
39
|
+
*/
|
|
40
|
+
export declare const useShortcutConflicts: (shortcut: ShortcutDefinition, options?: UseShortcutConflictsOptions) => ShortcutConflictInfo;
|
|
41
|
+
export {};
|
package/src/index.d.ts
CHANGED
|
@@ -117,6 +117,7 @@ export * from "./hooks/useInfiniteScroll";
|
|
|
117
117
|
export * from "./hooks/useIsFirstRender";
|
|
118
118
|
export * from "./hooks/useIsFullScreen";
|
|
119
119
|
export * from "./hooks/useIsTextTruncated";
|
|
120
|
+
export { useKeyboardShortcut } from "./hooks/useKeyboardShortcut/useKeyboardShortcut";
|
|
120
121
|
export * from "./hooks/useMeasure";
|
|
121
122
|
export * from "./hooks/useMergeRefs";
|
|
122
123
|
export * from "./hooks/useModifierKey";
|