@mdxui/terminal 2.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 +571 -0
- package/dist/ansi-css-Sk5mWtdK.d.ts +119 -0
- package/dist/ansi-css-V6JIHGsM.d.ts +119 -0
- package/dist/ansi-css-_3eSEU9d.d.ts +119 -0
- package/dist/chunk-3EFDH7PK.js +5235 -0
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/chunk-3X5IR6WE.js +884 -0
- package/dist/chunk-4FV5ZDCE.js +5236 -0
- package/dist/chunk-4OVMSF2J.js +243 -0
- package/dist/chunk-63FEETIS.js +4048 -0
- package/dist/chunk-B43KP7XJ.js +884 -0
- package/dist/chunk-BMTJXWUV.js +655 -0
- package/dist/chunk-C3SVH4N7.js +882 -0
- package/dist/chunk-EVWR7Y47.js +874 -0
- package/dist/chunk-F6A5VWUC.js +1285 -0
- package/dist/chunk-FD7KW7GE.js +882 -0
- package/dist/chunk-GBQ6UD6I.js +655 -0
- package/dist/chunk-GMDD3M6U.js +5227 -0
- package/dist/chunk-JBHRXOXM.js +1058 -0
- package/dist/chunk-JFOO3EYO.js +1182 -0
- package/dist/chunk-JQ5H3WXL.js +1291 -0
- package/dist/chunk-JQD5NASE.js +234 -0
- package/dist/chunk-KRHJP5R7.js +592 -0
- package/dist/chunk-KWF6WVJE.js +962 -0
- package/dist/chunk-LHYQVN3H.js +1038 -0
- package/dist/chunk-M3TLQLGC.js +1032 -0
- package/dist/chunk-MVW4Q5OP.js +240 -0
- package/dist/chunk-NXCZSWLU.js +1294 -0
- package/dist/chunk-O25TNRO6.js +607 -0
- package/dist/chunk-PNECDA2I.js +884 -0
- package/dist/chunk-QIHWRLJR.js +962 -0
- package/dist/chunk-QW5YMQ7K.js +882 -0
- package/dist/chunk-R5U7XKVJ.js +16 -0
- package/dist/chunk-RP2MVQLR.js +962 -0
- package/dist/chunk-TP6RXGXA.js +1087 -0
- package/dist/chunk-TQQSTITZ.js +655 -0
- package/dist/chunk-X24GWXQV.js +1281 -0
- package/dist/components/index.d.ts +802 -0
- package/dist/components/index.js +149 -0
- package/dist/data/index.d.ts +2554 -0
- package/dist/data/index.js +51 -0
- package/dist/forms/index.d.ts +1596 -0
- package/dist/forms/index.js +464 -0
- package/dist/index-CQRFZntR.d.ts +867 -0
- package/dist/index.d.ts +579 -0
- package/dist/index.js +786 -0
- package/dist/interactive-D0JkWosD.d.ts +217 -0
- package/dist/keyboard/index.d.ts +2 -0
- package/dist/keyboard/index.js +43 -0
- package/dist/renderers/index.d.ts +546 -0
- package/dist/renderers/index.js +2157 -0
- package/dist/storybook/index.d.ts +396 -0
- package/dist/storybook/index.js +641 -0
- package/dist/theme/index.d.ts +1339 -0
- package/dist/theme/index.js +123 -0
- package/dist/types-Bxu5PAgA.d.ts +710 -0
- package/dist/types-CIlop5Ji.d.ts +701 -0
- package/dist/types-Ca8p_p5X.d.ts +710 -0
- package/package.json +90 -0
- package/src/__tests__/components/data/card.test.ts +458 -0
- package/src/__tests__/components/data/list.test.ts +473 -0
- package/src/__tests__/components/data/metrics.test.ts +541 -0
- package/src/__tests__/components/data/table.test.ts +448 -0
- package/src/__tests__/components/input/field.test.ts +555 -0
- package/src/__tests__/components/input/form.test.ts +870 -0
- package/src/__tests__/components/input/search.test.ts +1238 -0
- package/src/__tests__/components/input/select.test.ts +658 -0
- package/src/__tests__/components/navigation/breadcrumb.test.ts +923 -0
- package/src/__tests__/components/navigation/command-palette.test.ts +1095 -0
- package/src/__tests__/components/navigation/sidebar.test.ts +1018 -0
- package/src/__tests__/components/navigation/tabs.test.ts +995 -0
- package/src/__tests__/components.test.tsx +1197 -0
- package/src/__tests__/core/compiler.test.ts +986 -0
- package/src/__tests__/core/parser.test.ts +785 -0
- package/src/__tests__/core/tier-switcher.test.ts +1103 -0
- package/src/__tests__/core/types.test.ts +1398 -0
- package/src/__tests__/data/collections.test.ts +1337 -0
- package/src/__tests__/data/db.test.ts +1265 -0
- package/src/__tests__/data/reactive.test.ts +1010 -0
- package/src/__tests__/data/sync.test.ts +1614 -0
- package/src/__tests__/errors.test.ts +660 -0
- package/src/__tests__/forms/integration.test.ts +444 -0
- package/src/__tests__/integration.test.ts +905 -0
- package/src/__tests__/keyboard.test.ts +1791 -0
- package/src/__tests__/renderer.test.ts +489 -0
- package/src/__tests__/renderers/ansi-css.test.ts +948 -0
- package/src/__tests__/renderers/ansi.test.ts +1366 -0
- package/src/__tests__/renderers/ascii.test.ts +1360 -0
- package/src/__tests__/renderers/interactive.test.ts +2353 -0
- package/src/__tests__/renderers/markdown.test.ts +1483 -0
- package/src/__tests__/renderers/text.test.ts +1369 -0
- package/src/__tests__/renderers/unicode.test.ts +1307 -0
- package/src/__tests__/theme.test.ts +639 -0
- package/src/__tests__/utils/assertions.ts +685 -0
- package/src/__tests__/utils/index.ts +115 -0
- package/src/__tests__/utils/test-renderer.ts +381 -0
- package/src/__tests__/utils/utils.test.ts +560 -0
- package/src/components/containers/card.ts +56 -0
- package/src/components/containers/dialog.ts +53 -0
- package/src/components/containers/index.ts +9 -0
- package/src/components/containers/panel.ts +59 -0
- package/src/components/feedback/badge.ts +40 -0
- package/src/components/feedback/index.ts +8 -0
- package/src/components/feedback/spinner.ts +23 -0
- package/src/components/helpers.ts +81 -0
- package/src/components/index.ts +153 -0
- package/src/components/layout/breadcrumb.ts +31 -0
- package/src/components/layout/index.ts +10 -0
- package/src/components/layout/list.ts +29 -0
- package/src/components/layout/sidebar.ts +79 -0
- package/src/components/layout/table.ts +62 -0
- package/src/components/primitives/box.ts +95 -0
- package/src/components/primitives/button.ts +54 -0
- package/src/components/primitives/index.ts +11 -0
- package/src/components/primitives/input.ts +88 -0
- package/src/components/primitives/select.ts +97 -0
- package/src/components/primitives/text.ts +60 -0
- package/src/components/render.ts +155 -0
- package/src/components/templates/app.ts +43 -0
- package/src/components/templates/index.ts +8 -0
- package/src/components/templates/site.ts +54 -0
- package/src/components/types.ts +777 -0
- package/src/core/compiler.ts +718 -0
- package/src/core/parser.ts +127 -0
- package/src/core/tier-switcher.ts +607 -0
- package/src/core/types.ts +672 -0
- package/src/data/collection.ts +316 -0
- package/src/data/collections.ts +50 -0
- package/src/data/context.tsx +174 -0
- package/src/data/db.ts +127 -0
- package/src/data/hooks.ts +532 -0
- package/src/data/index.ts +138 -0
- package/src/data/reactive.ts +1225 -0
- package/src/data/saas-collections.ts +375 -0
- package/src/data/sync.ts +1213 -0
- package/src/data/types.ts +660 -0
- package/src/forms/converters.ts +512 -0
- package/src/forms/index.ts +133 -0
- package/src/forms/schemas.ts +403 -0
- package/src/forms/types.ts +476 -0
- package/src/index.ts +542 -0
- package/src/keyboard/focus.ts +748 -0
- package/src/keyboard/index.ts +96 -0
- package/src/keyboard/integration.ts +371 -0
- package/src/keyboard/manager.ts +377 -0
- package/src/keyboard/presets.ts +90 -0
- package/src/renderers/ansi-css.ts +576 -0
- package/src/renderers/ansi.ts +802 -0
- package/src/renderers/ascii.ts +680 -0
- package/src/renderers/breadcrumb.ts +480 -0
- package/src/renderers/command-palette.ts +802 -0
- package/src/renderers/components/field.ts +210 -0
- package/src/renderers/components/form.ts +327 -0
- package/src/renderers/components/index.ts +21 -0
- package/src/renderers/components/search.ts +449 -0
- package/src/renderers/components/select.ts +222 -0
- package/src/renderers/index.ts +101 -0
- package/src/renderers/interactive/component-handlers.ts +622 -0
- package/src/renderers/interactive/cursor-manager.ts +147 -0
- package/src/renderers/interactive/focus-manager.ts +279 -0
- package/src/renderers/interactive/index.ts +661 -0
- package/src/renderers/interactive/input-handler.ts +164 -0
- package/src/renderers/interactive/keyboard-handler.ts +212 -0
- package/src/renderers/interactive/mouse-handler.ts +167 -0
- package/src/renderers/interactive/state-manager.ts +109 -0
- package/src/renderers/interactive/types.ts +338 -0
- package/src/renderers/interactive-string.ts +299 -0
- package/src/renderers/interactive.ts +59 -0
- package/src/renderers/markdown.ts +950 -0
- package/src/renderers/sidebar.ts +549 -0
- package/src/renderers/tabs.ts +682 -0
- package/src/renderers/text.ts +791 -0
- package/src/renderers/unicode.ts +917 -0
- package/src/renderers/utils.ts +942 -0
- package/src/router/adapters.ts +383 -0
- package/src/router/types.ts +140 -0
- package/src/router/utils.ts +452 -0
- package/src/schemas.ts +205 -0
- package/src/storybook/index.ts +91 -0
- package/src/storybook/interactive-decorator.tsx +659 -0
- package/src/storybook/keyboard-simulator.ts +501 -0
- package/src/theme/ansi-codes.ts +80 -0
- package/src/theme/box-drawing.ts +132 -0
- package/src/theme/color-convert.ts +254 -0
- package/src/theme/color-support.ts +321 -0
- package/src/theme/index.ts +134 -0
- package/src/theme/strip-ansi.ts +50 -0
- package/src/theme/tailwind-map.ts +469 -0
- package/src/theme/text-styles.ts +206 -0
- package/src/theme/theme-system.ts +568 -0
- package/src/types.ts +103 -0
|
@@ -0,0 +1,867 @@
|
|
|
1
|
+
import React__default, { ReactNode, ReactElement } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Keyboard Manager
|
|
5
|
+
*
|
|
6
|
+
* Core keyboard binding manager for handling key bindings and sequences.
|
|
7
|
+
* Supports single keys, modifier combinations, and multi-key sequences.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Modifier key state for a key press event.
|
|
13
|
+
*
|
|
14
|
+
* Tracks which modifier keys are held during a key press.
|
|
15
|
+
*/
|
|
16
|
+
interface KeyModifiers {
|
|
17
|
+
/** Control key is pressed */
|
|
18
|
+
ctrl: boolean;
|
|
19
|
+
/** Alt/Option key is pressed */
|
|
20
|
+
alt: boolean;
|
|
21
|
+
/** Shift key is pressed */
|
|
22
|
+
shift: boolean;
|
|
23
|
+
/** Meta/Command key is pressed */
|
|
24
|
+
meta: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A keyboard action - either a string action name or a callback function.
|
|
28
|
+
*
|
|
29
|
+
* String actions are dispatched via the onAction handler.
|
|
30
|
+
* Function actions are called directly when the key is pressed.
|
|
31
|
+
*/
|
|
32
|
+
type KeyboardAction = string | (() => void);
|
|
33
|
+
/**
|
|
34
|
+
* Maps key names/sequences to actions.
|
|
35
|
+
*
|
|
36
|
+
* Keys can be:
|
|
37
|
+
* - Single characters: 'j', 'k', 'q'
|
|
38
|
+
* - Special keys: 'enter', 'escape', 'tab'
|
|
39
|
+
* - Modifier combinations: 'ctrl+c', 'shift+tab'
|
|
40
|
+
* - Key sequences: 'gg', 'dd' (multi-character without '+')
|
|
41
|
+
*/
|
|
42
|
+
type KeyBindings = Record<string, KeyboardAction>;
|
|
43
|
+
/**
|
|
44
|
+
* Context passed to action handlers with the triggering key and optional extra data.
|
|
45
|
+
*/
|
|
46
|
+
interface ActionContext {
|
|
47
|
+
/** The key or sequence that triggered this action */
|
|
48
|
+
key: string;
|
|
49
|
+
/** Optional context data set via setContext() */
|
|
50
|
+
context?: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Callback invoked when a keyboard action is triggered.
|
|
54
|
+
*
|
|
55
|
+
* @param action - The action name (string actions only)
|
|
56
|
+
* @param context - Context including the key and optional data
|
|
57
|
+
*/
|
|
58
|
+
type ActionHandler = (action: string, context: ActionContext) => void;
|
|
59
|
+
/**
|
|
60
|
+
* Configuration options for creating a keyboard manager.
|
|
61
|
+
*/
|
|
62
|
+
interface KeyboardManagerOptions {
|
|
63
|
+
/** Key-to-action bindings */
|
|
64
|
+
bindings: KeyBindings;
|
|
65
|
+
/** Handler called when string actions are triggered */
|
|
66
|
+
onAction?: ActionHandler;
|
|
67
|
+
/** Whether the manager starts enabled (default: true) */
|
|
68
|
+
enabled?: boolean;
|
|
69
|
+
/** Optional context data passed to action handlers */
|
|
70
|
+
context?: Record<string, unknown> | null;
|
|
71
|
+
/** Timeout in ms for key sequences (default: 1000) */
|
|
72
|
+
sequenceTimeout?: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Interface for the keyboard manager returned by createKeyboardManager.
|
|
76
|
+
*/
|
|
77
|
+
interface KeyboardManager {
|
|
78
|
+
/** Get the action bound to a specific key */
|
|
79
|
+
getAction(key: string): KeyboardAction | undefined;
|
|
80
|
+
/** Handle a key press, returns true if the key was handled */
|
|
81
|
+
handleKey(key: string, handler?: ActionHandler): boolean;
|
|
82
|
+
/** Add a new key binding */
|
|
83
|
+
addBinding(key: string, action: KeyboardAction): void;
|
|
84
|
+
/** Remove a key binding */
|
|
85
|
+
removeBinding(key: string): void;
|
|
86
|
+
/** Replace all bindings */
|
|
87
|
+
setBindings(bindings: KeyBindings): void;
|
|
88
|
+
/** Get all string bindings (excludes function bindings) */
|
|
89
|
+
getBindings(): Record<string, string>;
|
|
90
|
+
/** Disable the keyboard manager */
|
|
91
|
+
disable(): void;
|
|
92
|
+
/** Enable the keyboard manager */
|
|
93
|
+
enable(): void;
|
|
94
|
+
/** Toggle enabled state */
|
|
95
|
+
toggle(): void;
|
|
96
|
+
/** Check if the manager is enabled */
|
|
97
|
+
isEnabled(): boolean;
|
|
98
|
+
/** Get the current pending key sequence */
|
|
99
|
+
getPendingSequence(): string;
|
|
100
|
+
/** Set context data passed to action handlers */
|
|
101
|
+
setContext(context: Record<string, unknown>): void;
|
|
102
|
+
/** Clean up resources (clears pending sequence timer to prevent memory leaks) */
|
|
103
|
+
destroy(): void;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Common key constants for keyboard handling.
|
|
107
|
+
* Use these with matchKey() for consistent key comparisons.
|
|
108
|
+
*/
|
|
109
|
+
declare const KEY: {
|
|
110
|
+
readonly ENTER: "enter";
|
|
111
|
+
readonly ESCAPE: "escape";
|
|
112
|
+
readonly UP: "up";
|
|
113
|
+
readonly DOWN: "down";
|
|
114
|
+
readonly LEFT: "left";
|
|
115
|
+
readonly RIGHT: "right";
|
|
116
|
+
readonly TAB: "tab";
|
|
117
|
+
readonly SPACE: "space";
|
|
118
|
+
readonly BACKSPACE: "backspace";
|
|
119
|
+
readonly DELETE: "delete";
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Check if a key matches an expected key.
|
|
123
|
+
*
|
|
124
|
+
* @param key - The key to check
|
|
125
|
+
* @param expected - The expected key value
|
|
126
|
+
* @returns true if keys match
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```tsx
|
|
130
|
+
* import { matchKey, KEY } from '@mdxui/terminal'
|
|
131
|
+
*
|
|
132
|
+
* if (matchKey(pressedKey, KEY.ENTER)) {
|
|
133
|
+
* handleSubmit()
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
declare function matchKey(key: string, expected: string): boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Creates a keyboard manager for handling key bindings and sequences.
|
|
140
|
+
*
|
|
141
|
+
* The manager supports:
|
|
142
|
+
* - Single key bindings ('j', 'enter', 'q')
|
|
143
|
+
* - Modifier combinations ('ctrl+c', 'shift+tab')
|
|
144
|
+
* - Multi-key sequences ('gg', 'dd') with configurable timeout
|
|
145
|
+
* - Dynamic binding changes at runtime
|
|
146
|
+
* - Enable/disable toggling
|
|
147
|
+
*
|
|
148
|
+
* @param options - Configuration options
|
|
149
|
+
* @returns A keyboard manager instance
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```tsx
|
|
153
|
+
* const keyboard = createKeyboardManager({
|
|
154
|
+
* bindings: { ...VIM_BINDINGS, ...ARROW_BINDINGS },
|
|
155
|
+
* onAction: (action, ctx) => {
|
|
156
|
+
* switch (action) {
|
|
157
|
+
* case 'move-down': moveDown(); break
|
|
158
|
+
* case 'select': handleSelect(); break
|
|
159
|
+
* }
|
|
160
|
+
* }
|
|
161
|
+
* })
|
|
162
|
+
*
|
|
163
|
+
* // Later, handle input
|
|
164
|
+
* process.stdin.on('keypress', (ch, key) => {
|
|
165
|
+
* keyboard.handleKey(key.name || ch)
|
|
166
|
+
* })
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
declare function createKeyboardManager(options: KeyboardManagerOptions): KeyboardManager;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Preset Key Bindings
|
|
173
|
+
*
|
|
174
|
+
* Common keyboard binding presets for terminal applications.
|
|
175
|
+
* Includes Vim-style, arrow key, and common UI bindings.
|
|
176
|
+
*
|
|
177
|
+
* @packageDocumentation
|
|
178
|
+
*/
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Vim-style navigation bindings.
|
|
182
|
+
*
|
|
183
|
+
* Includes:
|
|
184
|
+
* - h/j/k/l for directional movement
|
|
185
|
+
* - gg/G for first/last
|
|
186
|
+
* - / and : for search/command
|
|
187
|
+
* - i for insert mode
|
|
188
|
+
* - enter/escape/q for select/back/quit
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```tsx
|
|
192
|
+
* const keyboard = createKeyboardManager({
|
|
193
|
+
* bindings: VIM_BINDINGS,
|
|
194
|
+
* onAction: handleAction
|
|
195
|
+
* })
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
declare const VIM_BINDINGS: KeyBindings;
|
|
199
|
+
/**
|
|
200
|
+
* Arrow key navigation bindings.
|
|
201
|
+
*
|
|
202
|
+
* Maps arrow keys to directional movement actions.
|
|
203
|
+
*/
|
|
204
|
+
declare const ARROW_BINDINGS: KeyBindings;
|
|
205
|
+
/**
|
|
206
|
+
* Common UI bindings for Enter, Escape, Tab, and Space.
|
|
207
|
+
*
|
|
208
|
+
* Maps common interaction keys to semantic actions:
|
|
209
|
+
* - enter: 'select'
|
|
210
|
+
* - escape: 'back'
|
|
211
|
+
* - tab/shift+tab: focus navigation
|
|
212
|
+
* - space: 'toggle'
|
|
213
|
+
*/
|
|
214
|
+
declare const COMMON_BINDINGS: KeyBindings;
|
|
215
|
+
/**
|
|
216
|
+
* Emacs-style navigation bindings.
|
|
217
|
+
*
|
|
218
|
+
* Includes:
|
|
219
|
+
* - ctrl+f/b/n/p for forward/back/next/previous
|
|
220
|
+
* - ctrl+a/e for start/end of line
|
|
221
|
+
* - ctrl+g for cancel
|
|
222
|
+
*/
|
|
223
|
+
declare const EMACS_BINDINGS: KeyBindings;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* @mdxui/terminal Type Definitions
|
|
227
|
+
*
|
|
228
|
+
* Branded types and type utilities for type-safe terminal components.
|
|
229
|
+
*
|
|
230
|
+
* @packageDocumentation
|
|
231
|
+
*/
|
|
232
|
+
/**
|
|
233
|
+
* Brand symbol for FocusId type.
|
|
234
|
+
* Used to create a nominal/branded type that prevents accidental string usage.
|
|
235
|
+
*/
|
|
236
|
+
declare const FocusIdBrand: unique symbol;
|
|
237
|
+
/**
|
|
238
|
+
* Branded type for focus element IDs.
|
|
239
|
+
*
|
|
240
|
+
* This is a nominal/branded type that appears as a string at runtime but
|
|
241
|
+
* provides compile-time type safety. You cannot accidentally pass an
|
|
242
|
+
* arbitrary string where a FocusId is expected.
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```tsx
|
|
246
|
+
* import { createFocusId, type FocusId } from '@mdxui/terminal'
|
|
247
|
+
*
|
|
248
|
+
* // Correct - use createFocusId to get a valid FocusId
|
|
249
|
+
* const id: FocusId = createFocusId('my-element')
|
|
250
|
+
*
|
|
251
|
+
* // Error - cannot assign plain string to FocusId
|
|
252
|
+
* const badId: FocusId = 'some-string' // TypeScript error!
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
type FocusId = string & {
|
|
256
|
+
readonly [FocusIdBrand]: true;
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* Creates a branded FocusId from an optional string.
|
|
260
|
+
*
|
|
261
|
+
* If no id is provided, generates a unique id like `focus-1`, `focus-2`, etc.
|
|
262
|
+
* The returned value is typed as FocusId, which provides compile-time
|
|
263
|
+
* safety against accidentally using wrong strings.
|
|
264
|
+
*
|
|
265
|
+
* @param id - Optional custom ID string. If not provided, auto-generates one.
|
|
266
|
+
* @returns A branded FocusId that can be used with focus management APIs.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```tsx
|
|
270
|
+
* import { createFocusId } from '@mdxui/terminal'
|
|
271
|
+
*
|
|
272
|
+
* // Auto-generate an ID
|
|
273
|
+
* const autoId = createFocusId() // 'focus-1', 'focus-2', etc.
|
|
274
|
+
*
|
|
275
|
+
* // Use a custom ID
|
|
276
|
+
* const customId = createFocusId('submit-button')
|
|
277
|
+
*
|
|
278
|
+
* // Use with useFocus
|
|
279
|
+
* const focusable = useFocus({ id: 'my-element' })
|
|
280
|
+
* console.log(focusable.id) // FocusId typed
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
declare function createFocusId(id?: string): FocusId;
|
|
284
|
+
/**
|
|
285
|
+
* Type guard to check if a value is a valid FocusId.
|
|
286
|
+
*
|
|
287
|
+
* At runtime, FocusId is just a string, so this check validates that
|
|
288
|
+
* the value is a non-empty string. For compile-time safety, use the
|
|
289
|
+
* branded type system instead.
|
|
290
|
+
*
|
|
291
|
+
* @param value - Value to check
|
|
292
|
+
* @returns True if value could be a valid FocusId
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```tsx
|
|
296
|
+
* const maybeId: unknown = getUserInput()
|
|
297
|
+
* if (isFocusId(maybeId)) {
|
|
298
|
+
* // maybeId is now typed as FocusId
|
|
299
|
+
* focusManager.focusById(maybeId)
|
|
300
|
+
* }
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
declare function isFocusId(value: unknown): value is FocusId;
|
|
304
|
+
/**
|
|
305
|
+
* Resets the focus ID counter. For testing purposes only.
|
|
306
|
+
* @internal
|
|
307
|
+
*/
|
|
308
|
+
declare function __resetFocusIdCounter(): void;
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Focus Management System
|
|
312
|
+
*
|
|
313
|
+
* React hooks and context for managing focus state across terminal UI components.
|
|
314
|
+
* Provides focus tracking, navigation, and keyboard integration.
|
|
315
|
+
*
|
|
316
|
+
* @packageDocumentation
|
|
317
|
+
*/
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Options for the useKeyboard hook.
|
|
321
|
+
*/
|
|
322
|
+
interface UseKeyboardOptions {
|
|
323
|
+
/** Whether keyboard handling is enabled (default: true) */
|
|
324
|
+
enabled?: boolean;
|
|
325
|
+
/** Priority for keyboard event handling (higher wins) */
|
|
326
|
+
priority?: number;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Return value from the useKeyboard hook.
|
|
330
|
+
*/
|
|
331
|
+
interface UseKeyboardResult {
|
|
332
|
+
/** Whether keyboard handling is currently enabled */
|
|
333
|
+
enabled: boolean;
|
|
334
|
+
/** Current priority level */
|
|
335
|
+
priority: number;
|
|
336
|
+
/** Enable keyboard handling */
|
|
337
|
+
enable: () => void;
|
|
338
|
+
/** Disable keyboard handling */
|
|
339
|
+
disable: () => void;
|
|
340
|
+
/** Cleanup function (called on unmount) */
|
|
341
|
+
cleanup: () => void;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* React hook for handling keyboard input with modifier key support.
|
|
345
|
+
*
|
|
346
|
+
* Provides a handler that receives key presses along with modifier state.
|
|
347
|
+
* Useful for building custom keyboard interaction patterns.
|
|
348
|
+
*
|
|
349
|
+
* @param handler - Callback receiving key name and modifier state
|
|
350
|
+
* @param options - Configuration options
|
|
351
|
+
* @returns Controls for enabling/disabling keyboard handling
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```tsx
|
|
355
|
+
* function MyComponent() {
|
|
356
|
+
* const keyboard = useKeyboard((key, modifiers) => {
|
|
357
|
+
* if (modifiers.ctrl && key === 'c') {
|
|
358
|
+
* handleCopy()
|
|
359
|
+
* }
|
|
360
|
+
* })
|
|
361
|
+
*
|
|
362
|
+
* return <div>...</div>
|
|
363
|
+
* }
|
|
364
|
+
* ```
|
|
365
|
+
*/
|
|
366
|
+
declare function useKeyboard(handler: (key: string, modifiers: KeyModifiers) => void, options?: UseKeyboardOptions): UseKeyboardResult;
|
|
367
|
+
/**
|
|
368
|
+
* Options for the useFocus hook.
|
|
369
|
+
*/
|
|
370
|
+
interface UseFocusOptions {
|
|
371
|
+
/** Custom ID for the focusable element */
|
|
372
|
+
id?: string;
|
|
373
|
+
/** Whether to focus on mount (default: false) */
|
|
374
|
+
autoFocus?: boolean;
|
|
375
|
+
/** Tab order index */
|
|
376
|
+
tabIndex?: number;
|
|
377
|
+
/** Callback when element receives focus */
|
|
378
|
+
onFocus?: () => void;
|
|
379
|
+
/** Callback when element loses focus */
|
|
380
|
+
onBlur?: () => void;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Interface for a focusable element returned by useFocus.
|
|
384
|
+
*/
|
|
385
|
+
interface FocusableElement {
|
|
386
|
+
/** Unique ID for this focusable element */
|
|
387
|
+
id: FocusId;
|
|
388
|
+
/** Whether this element currently has focus */
|
|
389
|
+
focused: boolean;
|
|
390
|
+
/** Tab order index */
|
|
391
|
+
tabIndex: number;
|
|
392
|
+
/** Programmatically focus this element */
|
|
393
|
+
focus: () => void;
|
|
394
|
+
/** Programmatically blur this element */
|
|
395
|
+
blur: () => void;
|
|
396
|
+
/** Move focus to the next focusable element */
|
|
397
|
+
focusNext: () => void;
|
|
398
|
+
/** Move focus to the previous focusable element */
|
|
399
|
+
focusPrev: () => void;
|
|
400
|
+
/** Move focus to the first focusable element */
|
|
401
|
+
focusFirst: () => void;
|
|
402
|
+
/** Move focus to the last focusable element */
|
|
403
|
+
focusLast: () => void;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* React hook for focus management in terminal UIs.
|
|
407
|
+
*
|
|
408
|
+
* Provides focus state and navigation helpers for building
|
|
409
|
+
* accessible keyboard-navigable interfaces.
|
|
410
|
+
*
|
|
411
|
+
* @param options - Configuration options
|
|
412
|
+
* @returns Focus state and control methods
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* ```tsx
|
|
416
|
+
* function MenuItem({ label }: { label: string }) {
|
|
417
|
+
* const { focused, focus, blur } = useFocus({
|
|
418
|
+
* onFocus: () => console.log('focused'),
|
|
419
|
+
* onBlur: () => console.log('blurred')
|
|
420
|
+
* })
|
|
421
|
+
*
|
|
422
|
+
* return (
|
|
423
|
+
* <Text color={focused ? 'primary' : undefined}>
|
|
424
|
+
* {focused ? '> ' : ' '}{label}
|
|
425
|
+
* </Text>
|
|
426
|
+
* )
|
|
427
|
+
* }
|
|
428
|
+
* ```
|
|
429
|
+
*/
|
|
430
|
+
declare function useFocus(options?: UseFocusOptions): FocusableElement;
|
|
431
|
+
/**
|
|
432
|
+
* State and controls from the focus manager context.
|
|
433
|
+
*/
|
|
434
|
+
interface FocusManagerState {
|
|
435
|
+
/** IDs of all registered focusable elements */
|
|
436
|
+
focusableIds: FocusId[];
|
|
437
|
+
/** ID of the currently focused element, or null */
|
|
438
|
+
focusedId: FocusId | null;
|
|
439
|
+
/** Whether focus is trapped within a container */
|
|
440
|
+
isTrapped: boolean;
|
|
441
|
+
/** Focus a specific element by ID */
|
|
442
|
+
focusById: (id: FocusId) => void;
|
|
443
|
+
/** Move focus to the next element */
|
|
444
|
+
focusNext: () => void;
|
|
445
|
+
/** Move focus to the previous element */
|
|
446
|
+
focusPrev: () => void;
|
|
447
|
+
/** Move focus to the first element */
|
|
448
|
+
focusFirst: () => void;
|
|
449
|
+
/** Move focus to the last element */
|
|
450
|
+
focusLast: () => void;
|
|
451
|
+
/** Register a focusable element with the provider */
|
|
452
|
+
registerFocusable: (id: FocusId, tabIndex: number) => void;
|
|
453
|
+
/** Unregister a focusable element from the provider */
|
|
454
|
+
unregisterFocusable: (id: FocusId) => void;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* React context for focus manager state.
|
|
458
|
+
*/
|
|
459
|
+
declare const FocusContext: React__default.Context<FocusManagerState | null>;
|
|
460
|
+
/**
|
|
461
|
+
* React hook to access the focus manager context.
|
|
462
|
+
*
|
|
463
|
+
* Must be used within a FocusProvider. Returns a default
|
|
464
|
+
* no-op implementation if used outside a provider.
|
|
465
|
+
*
|
|
466
|
+
* @returns Focus manager state and controls
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* ```tsx
|
|
470
|
+
* function NavigationHelp() {
|
|
471
|
+
* const { focusFirst, focusLast } = useFocusManager()
|
|
472
|
+
*
|
|
473
|
+
* return (
|
|
474
|
+
* <Box>
|
|
475
|
+
* <Button onPress={focusFirst}>Go to start</Button>
|
|
476
|
+
* <Button onPress={focusLast}>Go to end</Button>
|
|
477
|
+
* </Box>
|
|
478
|
+
* )
|
|
479
|
+
* }
|
|
480
|
+
* ```
|
|
481
|
+
*/
|
|
482
|
+
declare function useFocusManager(): FocusManagerState;
|
|
483
|
+
/**
|
|
484
|
+
* Options for the useNavigableList hook.
|
|
485
|
+
*/
|
|
486
|
+
interface UseNavigableListOptions<T> {
|
|
487
|
+
/** Array of items to navigate */
|
|
488
|
+
items: T[];
|
|
489
|
+
/** Initial selected index (default: 0) */
|
|
490
|
+
initialIndex?: number;
|
|
491
|
+
/** Wrap around at list boundaries (default: false) */
|
|
492
|
+
wrap?: boolean;
|
|
493
|
+
/** Enable keyboard navigation (default: false) */
|
|
494
|
+
useKeyboard?: boolean;
|
|
495
|
+
/** Callback when an item is selected */
|
|
496
|
+
onSelect?: (item: T, index: number) => void;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Return value from the useNavigableList hook.
|
|
500
|
+
*/
|
|
501
|
+
interface UseNavigableListResult<T> {
|
|
502
|
+
/** Current selected index */
|
|
503
|
+
currentIndex: number;
|
|
504
|
+
/** Current selected item */
|
|
505
|
+
currentItem: T | undefined;
|
|
506
|
+
/** Whether wrapping is enabled */
|
|
507
|
+
wrap: boolean;
|
|
508
|
+
/** Whether keyboard navigation is enabled */
|
|
509
|
+
keyboardEnabled: boolean;
|
|
510
|
+
/** Move selection up (decrease index) */
|
|
511
|
+
moveUp: () => void;
|
|
512
|
+
/** Move selection down (increase index) */
|
|
513
|
+
moveDown: () => void;
|
|
514
|
+
/** Move selection to the first item */
|
|
515
|
+
moveToFirst: () => void;
|
|
516
|
+
/** Move selection to the last item */
|
|
517
|
+
moveToLast: () => void;
|
|
518
|
+
/** Set the selection to a specific index */
|
|
519
|
+
setIndex: (index: number) => void;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* React hook for keyboard-navigable lists.
|
|
523
|
+
*
|
|
524
|
+
* Manages selection state and provides navigation methods
|
|
525
|
+
* for building interactive list interfaces.
|
|
526
|
+
*
|
|
527
|
+
* @param options - Configuration options
|
|
528
|
+
* @returns Selection state and navigation controls
|
|
529
|
+
*
|
|
530
|
+
* @example
|
|
531
|
+
* ```tsx
|
|
532
|
+
* function Menu() {
|
|
533
|
+
* const items = ['File', 'Edit', 'View', 'Help']
|
|
534
|
+
* const { currentIndex, moveUp, moveDown } = useNavigableList({
|
|
535
|
+
* items,
|
|
536
|
+
* wrap: true,
|
|
537
|
+
* onSelect: (item) => console.log('Selected:', item)
|
|
538
|
+
* })
|
|
539
|
+
*
|
|
540
|
+
* return (
|
|
541
|
+
* <List items={items} selectedIndex={currentIndex} />
|
|
542
|
+
* )
|
|
543
|
+
* }
|
|
544
|
+
* ```
|
|
545
|
+
*/
|
|
546
|
+
declare function useNavigableList<T>(options: UseNavigableListOptions<T>): UseNavigableListResult<T>;
|
|
547
|
+
/**
|
|
548
|
+
* Options for the useNavigableGrid hook.
|
|
549
|
+
*/
|
|
550
|
+
interface UseNavigableGridOptions {
|
|
551
|
+
/** Number of rows in the grid */
|
|
552
|
+
rows: number;
|
|
553
|
+
/** Number of columns in the grid */
|
|
554
|
+
cols: number;
|
|
555
|
+
/** Initial row (default: 0) */
|
|
556
|
+
initialRow?: number;
|
|
557
|
+
/** Initial column (default: 0) */
|
|
558
|
+
initialCol?: number;
|
|
559
|
+
/** Wrap horizontally at column boundaries (default: false) */
|
|
560
|
+
wrapHorizontal?: boolean;
|
|
561
|
+
/** Wrap vertically at row boundaries (default: false) */
|
|
562
|
+
wrapVertical?: boolean;
|
|
563
|
+
/** Enable keyboard navigation (default: false) */
|
|
564
|
+
useKeyboard?: boolean;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Return value from the useNavigableGrid hook.
|
|
568
|
+
*/
|
|
569
|
+
interface UseNavigableGridResult {
|
|
570
|
+
/** Current row position */
|
|
571
|
+
row: number;
|
|
572
|
+
/** Current column position */
|
|
573
|
+
col: number;
|
|
574
|
+
/** Whether horizontal wrapping is enabled */
|
|
575
|
+
wrapHorizontal: boolean;
|
|
576
|
+
/** Whether vertical wrapping is enabled */
|
|
577
|
+
wrapVertical: boolean;
|
|
578
|
+
/** Whether keyboard navigation is enabled */
|
|
579
|
+
keyboardEnabled: boolean;
|
|
580
|
+
/** Move up one row */
|
|
581
|
+
moveUp: () => void;
|
|
582
|
+
/** Move down one row */
|
|
583
|
+
moveDown: () => void;
|
|
584
|
+
/** Move left one column */
|
|
585
|
+
moveLeft: () => void;
|
|
586
|
+
/** Move right one column */
|
|
587
|
+
moveRight: () => void;
|
|
588
|
+
/** Move to a specific cell */
|
|
589
|
+
moveToCell: (row: number, col: number) => void;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* React hook for keyboard-navigable grids.
|
|
593
|
+
*
|
|
594
|
+
* Manages 2D position state and provides navigation methods
|
|
595
|
+
* for building grid-based interactive interfaces.
|
|
596
|
+
*
|
|
597
|
+
* @param options - Configuration options
|
|
598
|
+
* @returns Position state and navigation controls
|
|
599
|
+
*
|
|
600
|
+
* @example
|
|
601
|
+
* ```tsx
|
|
602
|
+
* function Calendar() {
|
|
603
|
+
* const { row, col, moveUp, moveDown, moveLeft, moveRight } = useNavigableGrid({
|
|
604
|
+
* rows: 5,
|
|
605
|
+
* cols: 7,
|
|
606
|
+
* wrapHorizontal: true
|
|
607
|
+
* })
|
|
608
|
+
*
|
|
609
|
+
* // Render 5x7 calendar grid with selection at [row, col]
|
|
610
|
+
* }
|
|
611
|
+
* ```
|
|
612
|
+
*/
|
|
613
|
+
declare function useNavigableGrid(options: UseNavigableGridOptions): UseNavigableGridResult;
|
|
614
|
+
/**
|
|
615
|
+
* Props for the FocusProvider component.
|
|
616
|
+
*/
|
|
617
|
+
interface FocusProviderProps {
|
|
618
|
+
/** Child components */
|
|
619
|
+
children?: ReactNode;
|
|
620
|
+
/** Trap focus within this provider (default: false) */
|
|
621
|
+
trap?: boolean;
|
|
622
|
+
/** Wrap focus when reaching boundaries (default: false) */
|
|
623
|
+
wrapFocus?: boolean;
|
|
624
|
+
/** ID of element to focus initially */
|
|
625
|
+
initialFocus?: FocusId;
|
|
626
|
+
/** Focus first element on mount (default: false) */
|
|
627
|
+
focusFirstOnMount?: boolean;
|
|
628
|
+
/** Restore focus to previous element when provider unmounts */
|
|
629
|
+
restoreFocus?: boolean;
|
|
630
|
+
/** Group name for nested focus management */
|
|
631
|
+
group?: string;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Focus provider component for managing focus state across components.
|
|
635
|
+
*
|
|
636
|
+
* Provides focus management context to child components, enabling
|
|
637
|
+
* coordinated focus navigation within a container.
|
|
638
|
+
*
|
|
639
|
+
* **Features:**
|
|
640
|
+
* - Focus tracking across registered focusable elements
|
|
641
|
+
* - Focus trapping for modals and dialogs
|
|
642
|
+
* - Wrap-around navigation at boundaries
|
|
643
|
+
* - Initial focus and focus restoration support
|
|
644
|
+
* - Named focus groups for scoped management
|
|
645
|
+
*
|
|
646
|
+
* @param props - Configuration and children
|
|
647
|
+
* @returns React element with focus context
|
|
648
|
+
*
|
|
649
|
+
* @example
|
|
650
|
+
* ```tsx
|
|
651
|
+
* function Dialog() {
|
|
652
|
+
* return (
|
|
653
|
+
* <FocusProvider trap focusFirstOnMount>
|
|
654
|
+
* <Input label="Name" />
|
|
655
|
+
* <Input label="Email" />
|
|
656
|
+
* <Button>Submit</Button>
|
|
657
|
+
* </FocusProvider>
|
|
658
|
+
* )
|
|
659
|
+
* }
|
|
660
|
+
* ```
|
|
661
|
+
*/
|
|
662
|
+
declare function FocusProvider(props: FocusProviderProps): ReactElement;
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Terminal Input Integration
|
|
666
|
+
*
|
|
667
|
+
* Integration helpers for connecting keyboard managers to terminal input sources.
|
|
668
|
+
* Supports Node.js readline and OpenTUI key events.
|
|
669
|
+
*
|
|
670
|
+
* @packageDocumentation
|
|
671
|
+
*/
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Normalized key event structure for keyboard handling.
|
|
675
|
+
*
|
|
676
|
+
* This is the standardized format used internally by the keyboard manager.
|
|
677
|
+
* Input from various sources (readline, OpenTUI) is normalized to this format.
|
|
678
|
+
*/
|
|
679
|
+
interface NormalizedKey {
|
|
680
|
+
/** The key name (e.g., 'a', 'enter', 'up', 'escape') */
|
|
681
|
+
name: string;
|
|
682
|
+
/** Whether Ctrl was held */
|
|
683
|
+
ctrl: boolean;
|
|
684
|
+
/** Whether Alt/Option was held */
|
|
685
|
+
alt: boolean;
|
|
686
|
+
/** Whether Shift was held */
|
|
687
|
+
shift: boolean;
|
|
688
|
+
/** Whether Meta/Cmd was held */
|
|
689
|
+
meta: boolean;
|
|
690
|
+
/** Raw character sequence if available */
|
|
691
|
+
sequence?: string;
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Readline key event structure from Node.js readline module.
|
|
695
|
+
* @see https://nodejs.org/api/readline.html#event-keypress
|
|
696
|
+
*/
|
|
697
|
+
interface ReadlineKey {
|
|
698
|
+
/** Key name */
|
|
699
|
+
name?: string;
|
|
700
|
+
/** Whether Ctrl was held */
|
|
701
|
+
ctrl?: boolean;
|
|
702
|
+
/** Whether Meta/Cmd was held */
|
|
703
|
+
meta?: boolean;
|
|
704
|
+
/** Whether Shift was held */
|
|
705
|
+
shift?: boolean;
|
|
706
|
+
/** Raw sequence */
|
|
707
|
+
sequence?: string;
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Normalizes a readline key event to our standard NormalizedKey format.
|
|
711
|
+
*
|
|
712
|
+
* @param str - The character string from the keypress event
|
|
713
|
+
* @param key - The readline key object
|
|
714
|
+
* @returns Normalized key event
|
|
715
|
+
*
|
|
716
|
+
* @example
|
|
717
|
+
* ```typescript
|
|
718
|
+
* import { emitKeypressEvents } from 'readline'
|
|
719
|
+
*
|
|
720
|
+
* emitKeypressEvents(process.stdin)
|
|
721
|
+
* process.stdin.on('keypress', (str, key) => {
|
|
722
|
+
* const normalized = normalizeReadlineKey(str, key)
|
|
723
|
+
* console.log(normalized) // { name: 'a', ctrl: false, ... }
|
|
724
|
+
* })
|
|
725
|
+
* ```
|
|
726
|
+
*/
|
|
727
|
+
declare function normalizeReadlineKey(str: string | undefined, key: ReadlineKey | undefined): NormalizedKey;
|
|
728
|
+
/**
|
|
729
|
+
* Converts a NormalizedKey to a string format for binding lookup.
|
|
730
|
+
*
|
|
731
|
+
* Produces strings like:
|
|
732
|
+
* - 'a' (plain key)
|
|
733
|
+
* - 'ctrl+c' (with ctrl modifier)
|
|
734
|
+
* - 'shift+tab' (with shift modifier)
|
|
735
|
+
* - 'ctrl+shift+s' (combined modifiers)
|
|
736
|
+
*
|
|
737
|
+
* @param key - The normalized key event
|
|
738
|
+
* @returns String representation for binding lookup
|
|
739
|
+
*
|
|
740
|
+
* @example
|
|
741
|
+
* ```typescript
|
|
742
|
+
* const key: NormalizedKey = { name: 'c', ctrl: true, alt: false, shift: false, meta: false }
|
|
743
|
+
* console.log(keyToBindingString(key)) // 'ctrl+c'
|
|
744
|
+
* ```
|
|
745
|
+
*/
|
|
746
|
+
declare function keyToBindingString(key: NormalizedKey): string;
|
|
747
|
+
/**
|
|
748
|
+
* Configuration for attaching a keyboard manager to terminal input.
|
|
749
|
+
*/
|
|
750
|
+
interface AttachKeyboardOptions {
|
|
751
|
+
/** Custom input stream (defaults to process.stdin) */
|
|
752
|
+
input?: NodeJS.ReadStream;
|
|
753
|
+
/** Whether to exit on Ctrl+C (defaults to true) */
|
|
754
|
+
exitOnCtrlC?: boolean;
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Cleanup function returned by attachKeyboardManager.
|
|
758
|
+
* Call this to detach the keyboard manager from input.
|
|
759
|
+
*/
|
|
760
|
+
type DetachKeyboard = () => void;
|
|
761
|
+
/**
|
|
762
|
+
* Attaches a keyboard manager to terminal stdin for receiving key events.
|
|
763
|
+
*
|
|
764
|
+
* This function sets up raw mode on stdin and processes keypress events,
|
|
765
|
+
* normalizing them and passing them to the keyboard manager.
|
|
766
|
+
*
|
|
767
|
+
* **Important:** This function requires a TTY stdin. It will throw if
|
|
768
|
+
* stdin is not a TTY (e.g., when input is piped).
|
|
769
|
+
*
|
|
770
|
+
* @param manager - The keyboard manager to receive key events
|
|
771
|
+
* @param options - Configuration options
|
|
772
|
+
* @returns A cleanup function to detach the keyboard manager
|
|
773
|
+
*
|
|
774
|
+
* @example
|
|
775
|
+
* ```typescript
|
|
776
|
+
* import { createKeyboardManager, attachKeyboardManager, VIM_BINDINGS } from '@mdxui/terminal'
|
|
777
|
+
*
|
|
778
|
+
* const manager = createKeyboardManager({
|
|
779
|
+
* bindings: VIM_BINDINGS,
|
|
780
|
+
* onAction: (action) => console.log('Action:', action),
|
|
781
|
+
* })
|
|
782
|
+
*
|
|
783
|
+
* const detach = attachKeyboardManager(manager)
|
|
784
|
+
*
|
|
785
|
+
* // Later, to clean up:
|
|
786
|
+
* detach()
|
|
787
|
+
* ```
|
|
788
|
+
*
|
|
789
|
+
* @example
|
|
790
|
+
* ```typescript
|
|
791
|
+
* // With custom options
|
|
792
|
+
* const detach = attachKeyboardManager(manager, {
|
|
793
|
+
* exitOnCtrlC: false, // Don't exit on Ctrl+C, let manager handle it
|
|
794
|
+
* })
|
|
795
|
+
* ```
|
|
796
|
+
*/
|
|
797
|
+
declare function attachKeyboardManager(manager: KeyboardManager, options?: AttachKeyboardOptions): DetachKeyboard;
|
|
798
|
+
/**
|
|
799
|
+
* OpenTUI key event structure.
|
|
800
|
+
* Matches the KeyEvent interface from @opentui/core.
|
|
801
|
+
*/
|
|
802
|
+
interface OpenTUIKeyEvent {
|
|
803
|
+
/** Key name (e.g., 'a', 'enter', 'escape') */
|
|
804
|
+
name: string;
|
|
805
|
+
/** Ctrl modifier */
|
|
806
|
+
ctrl: boolean;
|
|
807
|
+
/** Meta/Cmd modifier */
|
|
808
|
+
meta: boolean;
|
|
809
|
+
/** Shift modifier */
|
|
810
|
+
shift: boolean;
|
|
811
|
+
/** Option/Alt modifier */
|
|
812
|
+
option: boolean;
|
|
813
|
+
/** Raw sequence */
|
|
814
|
+
sequence: string;
|
|
815
|
+
/** Event type: 'press', 'repeat', or 'release' */
|
|
816
|
+
eventType?: 'press' | 'repeat' | 'release';
|
|
817
|
+
/** Whether this is a repeated key */
|
|
818
|
+
repeated?: boolean;
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Normalizes an OpenTUI KeyEvent to our standard NormalizedKey format.
|
|
822
|
+
*
|
|
823
|
+
* @param event - The OpenTUI KeyEvent
|
|
824
|
+
* @returns Normalized key event
|
|
825
|
+
*
|
|
826
|
+
* @example
|
|
827
|
+
* ```typescript
|
|
828
|
+
* import { useKeyboard } from '@opentui/react'
|
|
829
|
+
*
|
|
830
|
+
* useKeyboard((event) => {
|
|
831
|
+
* const normalized = normalizeOpenTUIKey(event)
|
|
832
|
+
* manager.handleKey(keyToBindingString(normalized))
|
|
833
|
+
* })
|
|
834
|
+
* ```
|
|
835
|
+
*/
|
|
836
|
+
declare function normalizeOpenTUIKey(event: OpenTUIKeyEvent): NormalizedKey;
|
|
837
|
+
/**
|
|
838
|
+
* Creates a keyboard event handler for use with OpenTUI's useKeyboard hook.
|
|
839
|
+
*
|
|
840
|
+
* This function returns a handler that can be passed directly to OpenTUI's
|
|
841
|
+
* useKeyboard hook to connect it to a KeyboardManager.
|
|
842
|
+
*
|
|
843
|
+
* @param manager - The keyboard manager to receive key events
|
|
844
|
+
* @returns A handler function for OpenTUI's useKeyboard hook
|
|
845
|
+
*
|
|
846
|
+
* @example
|
|
847
|
+
* ```tsx
|
|
848
|
+
* import { useKeyboard } from '@opentui/react'
|
|
849
|
+
* import { createKeyboardManager, createOpenTUIKeyHandler, VIM_BINDINGS } from '@mdxui/terminal'
|
|
850
|
+
*
|
|
851
|
+
* function MyComponent() {
|
|
852
|
+
* const manager = useMemo(() => createKeyboardManager({
|
|
853
|
+
* bindings: VIM_BINDINGS,
|
|
854
|
+
* onAction: (action) => console.log('Action:', action),
|
|
855
|
+
* }), [])
|
|
856
|
+
*
|
|
857
|
+
* const handler = useMemo(() => createOpenTUIKeyHandler(manager), [manager])
|
|
858
|
+
*
|
|
859
|
+
* useKeyboard(handler)
|
|
860
|
+
*
|
|
861
|
+
* return <div>...</div>
|
|
862
|
+
* }
|
|
863
|
+
* ```
|
|
864
|
+
*/
|
|
865
|
+
declare function createOpenTUIKeyHandler(manager: KeyboardManager): (event: OpenTUIKeyEvent) => void;
|
|
866
|
+
|
|
867
|
+
export { type ActionContext as A, keyToBindingString as B, COMMON_BINDINGS as C, type DetachKeyboard as D, EMACS_BINDINGS as E, type FocusableElement as F, attachKeyboardManager as G, normalizeOpenTUIKey as H, createOpenTUIKeyHandler as I, type FocusId as J, type KeyModifiers as K, createFocusId as L, isFocusId as M, type NormalizedKey as N, type OpenTUIKeyEvent as O, type ReadlineKey as R, type UseKeyboardOptions as U, VIM_BINDINGS as V, __resetFocusIdCounter as _, type KeyboardAction as a, type KeyBindings as b, type ActionHandler as c, type KeyboardManagerOptions as d, type KeyboardManager as e, KEY as f, createKeyboardManager as g, ARROW_BINDINGS as h, type UseKeyboardResult as i, type UseFocusOptions as j, type FocusManagerState as k, type UseNavigableListOptions as l, matchKey as m, type UseNavigableListResult as n, type UseNavigableGridOptions as o, type UseNavigableGridResult as p, type FocusProviderProps as q, FocusContext as r, useFocus as s, useFocusManager as t, useKeyboard as u, useNavigableList as v, useNavigableGrid as w, FocusProvider as x, type AttachKeyboardOptions as y, normalizeReadlineKey as z };
|