tinky-termcap 0.1.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/LICENSE +201 -0
- package/README.ja-JP.md +285 -0
- package/README.md +287 -0
- package/README.zh-CN.md +283 -0
- package/lib/TermcapContext.d.ts +62 -0
- package/lib/TermcapContext.d.ts.map +1 -0
- package/lib/TermcapContext.js +103 -0
- package/lib/TermcapContext.js.map +1 -0
- package/lib/contexts/TermcapContext.d.ts +237 -0
- package/lib/contexts/TermcapContext.js +157 -0
- package/lib/detect.d.ts +38 -0
- package/lib/detect.d.ts.map +1 -0
- package/lib/detect.js +243 -0
- package/lib/detect.js.map +1 -0
- package/lib/hooks/use-termcap.d.ts +151 -0
- package/lib/hooks/use-termcap.js +161 -0
- package/lib/index.d.ts +85 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +92 -0
- package/lib/index.js.map +1 -0
- package/lib/utils/detect-termcap.d.ts +328 -0
- package/lib/utils/detect-termcap.js +365 -0
- package/lib/utils/detect.d.ts +33 -0
- package/lib/utils/detect.js +233 -0
- package/lib/utils/term-features.d.ts +242 -0
- package/lib/utils/term-features.js +208 -0
- package/package.json +73 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
3
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
4
|
+
if (!m) return o;
|
|
5
|
+
var i = m.call(o), r, ar = [], e;
|
|
6
|
+
try {
|
|
7
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
8
|
+
}
|
|
9
|
+
catch (error) { e = { error: error }; }
|
|
10
|
+
finally {
|
|
11
|
+
try {
|
|
12
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
13
|
+
}
|
|
14
|
+
finally { if (e) throw e.error; }
|
|
15
|
+
}
|
|
16
|
+
return ar;
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.useTermcap = useTermcap;
|
|
20
|
+
exports.TermcapProvider = TermcapProvider;
|
|
21
|
+
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
22
|
+
var react_1 = require("react");
|
|
23
|
+
var detect_js_1 = require("./detect.js");
|
|
24
|
+
/**
|
|
25
|
+
* Default termcap info before detection completes.
|
|
26
|
+
*/
|
|
27
|
+
var defaultTermcapInfo = {
|
|
28
|
+
isReady: false,
|
|
29
|
+
backgroundColor: undefined,
|
|
30
|
+
terminalName: undefined,
|
|
31
|
+
kittyProtocol: false,
|
|
32
|
+
modifyOtherKeys: false,
|
|
33
|
+
};
|
|
34
|
+
var TermcapContext = (0, react_1.createContext)(undefined);
|
|
35
|
+
/**
|
|
36
|
+
* Hook to access terminal capability information.
|
|
37
|
+
*
|
|
38
|
+
* Must be used within a `TermcapProvider`.
|
|
39
|
+
*
|
|
40
|
+
* @returns Terminal capability information
|
|
41
|
+
* @throws If used outside of TermcapProvider
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* function MyComponent() {
|
|
46
|
+
* const { isReady, backgroundColor, kittyProtocol } = useTermcap();
|
|
47
|
+
*
|
|
48
|
+
* if (!isReady) return <Text>Detecting terminal...</Text>;
|
|
49
|
+
*
|
|
50
|
+
* return (
|
|
51
|
+
* <Box>
|
|
52
|
+
* <Text>Background: {backgroundColor ?? 'unknown'}</Text>
|
|
53
|
+
* <Text>Kitty: {kittyProtocol ? 'yes' : 'no'}</Text>
|
|
54
|
+
* </Box>
|
|
55
|
+
* );
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
function useTermcap() {
|
|
60
|
+
var context = (0, react_1.useContext)(TermcapContext);
|
|
61
|
+
if (!context) {
|
|
62
|
+
throw new Error("useTermcap must be used within a TermcapProvider");
|
|
63
|
+
}
|
|
64
|
+
return context;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Provider component that detects and provides terminal capabilities.
|
|
68
|
+
*
|
|
69
|
+
* Performs capability detection on mount and provides results to children
|
|
70
|
+
* via the `useTermcap` hook.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* function App() {
|
|
75
|
+
* return (
|
|
76
|
+
* <TermcapProvider>
|
|
77
|
+
* <MyTerminalApp />
|
|
78
|
+
* </TermcapProvider>
|
|
79
|
+
* );
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
function TermcapProvider(_a) {
|
|
84
|
+
var children = _a.children, _b = _a.timeout, timeout = _b === void 0 ? detect_js_1.DEFAULT_DETECTION_TIMEOUT : _b, initialCapabilities = _a.initialCapabilities;
|
|
85
|
+
var _c = __read((0, react_1.useState)(initialCapabilities !== null && initialCapabilities !== void 0 ? initialCapabilities : defaultTermcapInfo), 2), capabilities = _c[0], setCapabilities = _c[1];
|
|
86
|
+
(0, react_1.useEffect)(function () {
|
|
87
|
+
// Skip detection if initial capabilities provided
|
|
88
|
+
if (initialCapabilities) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
var mounted = true;
|
|
92
|
+
(0, detect_js_1.detectTerminalCapabilities)(timeout).then(function (result) {
|
|
93
|
+
if (mounted) {
|
|
94
|
+
setCapabilities(result);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
return function () {
|
|
98
|
+
mounted = false;
|
|
99
|
+
};
|
|
100
|
+
}, [timeout, initialCapabilities]);
|
|
101
|
+
var value = (0, react_1.useMemo)(function () { return capabilities; }, [capabilities]);
|
|
102
|
+
return ((0, jsx_runtime_1.jsx)(TermcapContext.Provider, { value: value, children: children }));
|
|
103
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TermcapContext.js","sourceRoot":"","sources":["../src/TermcapContext.tsx"],"names":[],"mappings":";AAOA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChF,OAAO,EACL,0BAA0B,EAE1B,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,MAAM,kBAAkB,GAAgB;IACtC,OAAO,EAAE,KAAK;IACd,eAAe,EAAE,SAAS;IAC1B,YAAY,EAAE,SAAS;IACvB,aAAa,EAAE,KAAK;IACpB,eAAe,EAAE,KAAK;CACvB,CAAC;AAEF,MAAM,cAAc,GAAG,aAAa,CAA0B,SAAS,CAAC,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,OAAO,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAcD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,QAAQ,EACR,OAAO,GAAG,yBAAyB,EACnC,mBAAmB,GACE;IACrB,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAC9C,mBAAmB,IAAI,kBAAkB,CAC1C,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,kDAAkD;QAClD,IAAI,mBAAmB,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QAED,IAAI,OAAO,GAAG,IAAI,CAAC;QAEnB,0BAA0B,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YAClD,IAAI,OAAO,EAAE,CAAC;gBACZ,eAAe,CAAC,MAAM,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAEnC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;IAE1D,OAAO,CACL,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAA2B,CAC5E,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview React context and provider for terminal capability detection.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the `TermcapProvider` component, which performs terminal
|
|
5
|
+
* capability detection on mount and makes the results available to child
|
|
6
|
+
* components via the `useTermcap` hook.
|
|
7
|
+
*
|
|
8
|
+
* @example Basic setup
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import { render } from "tinky";
|
|
11
|
+
* import { TermcapProvider, useTermcap } from "tinky-termcap";
|
|
12
|
+
*
|
|
13
|
+
* function App() {
|
|
14
|
+
* const { isReady, terminalName } = useTermcap();
|
|
15
|
+
*
|
|
16
|
+
* if (!isReady) {
|
|
17
|
+
* return <Text>Detecting terminal...</Text>;
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* return <Text>Running in {terminalName ?? "unknown terminal"}</Text>;
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* render(
|
|
24
|
+
* <TermcapProvider>
|
|
25
|
+
* <App />
|
|
26
|
+
* </TermcapProvider>
|
|
27
|
+
* );
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @packageDocumentation
|
|
31
|
+
*/
|
|
32
|
+
import type React from "react";
|
|
33
|
+
import { type TermcapInfo } from "../utils/detect-termcap.js";
|
|
34
|
+
/**
|
|
35
|
+
* React context for terminal capability information.
|
|
36
|
+
*
|
|
37
|
+
* This context provides `TermcapInfo` to descendant components. Use the
|
|
38
|
+
* `useTermcap` hook instead of accessing this context directly.
|
|
39
|
+
*
|
|
40
|
+
* @example Direct context access (not recommended)
|
|
41
|
+
* ```tsx
|
|
42
|
+
* import { useContext } from "react";
|
|
43
|
+
* import { TermcapContext } from "tinky-termcap";
|
|
44
|
+
*
|
|
45
|
+
* function MyComponent() {
|
|
46
|
+
* const caps = useContext(TermcapContext);
|
|
47
|
+
* // Note: caps may be undefined if not within TermcapProvider
|
|
48
|
+
* // Use useTermcap() hook instead for automatic error handling
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @see {@link useTermcap} - The recommended way to access capabilities
|
|
53
|
+
*/
|
|
54
|
+
export declare const TermcapContext: React.Context<TermcapInfo | undefined>;
|
|
55
|
+
/**
|
|
56
|
+
* Props for the `TermcapProvider` component.
|
|
57
|
+
*
|
|
58
|
+
* @example With all props
|
|
59
|
+
* ```tsx
|
|
60
|
+
* <TermcapProvider
|
|
61
|
+
* timeout={500}
|
|
62
|
+
* initialCapabilities={{
|
|
63
|
+
* isReady: true,
|
|
64
|
+
* backgroundColor: "#000000",
|
|
65
|
+
* terminalName: "test-terminal",
|
|
66
|
+
* kittyProtocol: true,
|
|
67
|
+
* modifyOtherKeys: false,
|
|
68
|
+
* }}
|
|
69
|
+
* >
|
|
70
|
+
* <App />
|
|
71
|
+
* </TermcapProvider>
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export interface TermcapProviderProps {
|
|
75
|
+
/**
|
|
76
|
+
* Child components that will have access to terminal capabilities
|
|
77
|
+
* via the `useTermcap` hook.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```tsx
|
|
81
|
+
* <TermcapProvider>
|
|
82
|
+
* <Header />
|
|
83
|
+
* <MainContent />
|
|
84
|
+
* <Footer />
|
|
85
|
+
* </TermcapProvider>
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
children: React.ReactNode;
|
|
89
|
+
/**
|
|
90
|
+
* Detection timeout in milliseconds.
|
|
91
|
+
*
|
|
92
|
+
* The maximum time to wait for terminal responses before returning
|
|
93
|
+
* with whatever capabilities have been detected. Lower values mean
|
|
94
|
+
* faster startup but may miss slow-responding features.
|
|
95
|
+
*
|
|
96
|
+
* @defaultValue 1000 (1 second)
|
|
97
|
+
*
|
|
98
|
+
* @example Fast startup (may miss some features)
|
|
99
|
+
* ```tsx
|
|
100
|
+
* <TermcapProvider timeout={200}>
|
|
101
|
+
* <App />
|
|
102
|
+
* </TermcapProvider>
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @example Extended timeout for slow connections
|
|
106
|
+
* ```tsx
|
|
107
|
+
* <TermcapProvider timeout={3000}>
|
|
108
|
+
* <App />
|
|
109
|
+
* </TermcapProvider>
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
timeout?: number;
|
|
113
|
+
/**
|
|
114
|
+
* Skip detection and use provided capabilities.
|
|
115
|
+
*
|
|
116
|
+
* When provided, the component will not perform any terminal queries
|
|
117
|
+
* and will immediately use these values. This is primarily useful for:
|
|
118
|
+
* - Testing components that depend on specific capabilities
|
|
119
|
+
* - Server-side rendering where detection is not possible
|
|
120
|
+
* - Programmatic control of capability values
|
|
121
|
+
*
|
|
122
|
+
* @example Testing with mock capabilities
|
|
123
|
+
* ```tsx
|
|
124
|
+
* import { render } from "@testing-library/react";
|
|
125
|
+
*
|
|
126
|
+
* test("renders with Kitty support", () => {
|
|
127
|
+
* const { getByText } = render(
|
|
128
|
+
* <TermcapProvider
|
|
129
|
+
* initialCapabilities={{
|
|
130
|
+
* isReady: true,
|
|
131
|
+
* backgroundColor: "#1a1a1a",
|
|
132
|
+
* terminalName: "kitty(0.31.0)",
|
|
133
|
+
* kittyProtocol: true,
|
|
134
|
+
* modifyOtherKeys: true,
|
|
135
|
+
* }}
|
|
136
|
+
* >
|
|
137
|
+
* <MyComponent />
|
|
138
|
+
* </TermcapProvider>
|
|
139
|
+
* );
|
|
140
|
+
*
|
|
141
|
+
* expect(getByText("Kitty: yes")).toBeInTheDocument();
|
|
142
|
+
* });
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* @example Server-side rendering
|
|
146
|
+
* ```tsx
|
|
147
|
+
* // On the server, detection is not possible
|
|
148
|
+
* const ssrCapabilities: TermcapInfo = {
|
|
149
|
+
* isReady: true,
|
|
150
|
+
* backgroundColor: undefined,
|
|
151
|
+
* terminalName: undefined,
|
|
152
|
+
* kittyProtocol: false,
|
|
153
|
+
* modifyOtherKeys: false,
|
|
154
|
+
* };
|
|
155
|
+
*
|
|
156
|
+
* function SSRApp() {
|
|
157
|
+
* return (
|
|
158
|
+
* <TermcapProvider initialCapabilities={ssrCapabilities}>
|
|
159
|
+
* <App />
|
|
160
|
+
* </TermcapProvider>
|
|
161
|
+
* );
|
|
162
|
+
* }
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
initialCapabilities?: TermcapInfo;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Provider component that detects and provides terminal capabilities.
|
|
169
|
+
*
|
|
170
|
+
* This component performs terminal capability detection on mount and provides
|
|
171
|
+
* the results to descendant components via the `useTermcap` hook. It integrates
|
|
172
|
+
* with Tinky's `useStdin` and `useStdout` hooks to access terminal streams.
|
|
173
|
+
*
|
|
174
|
+
* ## Lifecycle
|
|
175
|
+
*
|
|
176
|
+
* 1. **Mount**: Enables raw mode and sends detection queries to the terminal
|
|
177
|
+
* 2. **Detection**: Listens for terminal responses and parses capabilities
|
|
178
|
+
* 3. **Complete**: Either:
|
|
179
|
+
* - All responses received (triggered by Device Attributes response)
|
|
180
|
+
* - Timeout reached (returns whatever was detected)
|
|
181
|
+
* 4. **Unmount**: Cleanup (detection may be aborted if still in progress)
|
|
182
|
+
*
|
|
183
|
+
* ## Raw Mode
|
|
184
|
+
*
|
|
185
|
+
* The provider enables raw mode for detection. After detection completes,
|
|
186
|
+
* raw mode remains enabled as Tinky applications typically need it. If you
|
|
187
|
+
* need to manage raw mode differently, use `initialCapabilities` to skip
|
|
188
|
+
* detection and manage the terminal state yourself.
|
|
189
|
+
*
|
|
190
|
+
* @param props - Component props
|
|
191
|
+
* @returns React element wrapping children with capability context
|
|
192
|
+
*
|
|
193
|
+
* @example Basic usage
|
|
194
|
+
* ```tsx
|
|
195
|
+
* import { render } from "tinky";
|
|
196
|
+
* import { TermcapProvider, useTermcap } from "tinky-termcap";
|
|
197
|
+
*
|
|
198
|
+
* function App() {
|
|
199
|
+
* const caps = useTermcap();
|
|
200
|
+
* return <Text>Terminal: {caps.terminalName ?? "Unknown"}</Text>;
|
|
201
|
+
* }
|
|
202
|
+
*
|
|
203
|
+
* render(
|
|
204
|
+
* <TermcapProvider>
|
|
205
|
+
* <App />
|
|
206
|
+
* </TermcapProvider>
|
|
207
|
+
* );
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* @example With custom timeout
|
|
211
|
+
* ```tsx
|
|
212
|
+
* <TermcapProvider timeout={500}>
|
|
213
|
+
* <App />
|
|
214
|
+
* </TermcapProvider>
|
|
215
|
+
* ```
|
|
216
|
+
*
|
|
217
|
+
* @example For testing
|
|
218
|
+
* ```tsx
|
|
219
|
+
* <TermcapProvider
|
|
220
|
+
* initialCapabilities={{
|
|
221
|
+
* isReady: true,
|
|
222
|
+
* backgroundColor: "#000000",
|
|
223
|
+
* terminalName: "test",
|
|
224
|
+
* kittyProtocol: true,
|
|
225
|
+
* modifyOtherKeys: false,
|
|
226
|
+
* }}
|
|
227
|
+
* >
|
|
228
|
+
* <ComponentUnderTest />
|
|
229
|
+
* </TermcapProvider>
|
|
230
|
+
* ```
|
|
231
|
+
*
|
|
232
|
+
* @see {@link useTermcap} - Hook to access capabilities in child components
|
|
233
|
+
* @see {@link TermcapProviderProps} - Available props
|
|
234
|
+
* @see {@link TermcapInfo} - Shape of the provided capabilities
|
|
235
|
+
*/
|
|
236
|
+
export declare function TermcapProvider({ children, timeout, initialCapabilities, }: TermcapProviderProps): React.ReactElement;
|
|
237
|
+
export type { TermcapInfo };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
3
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
4
|
+
if (!m) return o;
|
|
5
|
+
var i = m.call(o), r, ar = [], e;
|
|
6
|
+
try {
|
|
7
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
8
|
+
}
|
|
9
|
+
catch (error) { e = { error: error }; }
|
|
10
|
+
finally {
|
|
11
|
+
try {
|
|
12
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
13
|
+
}
|
|
14
|
+
finally { if (e) throw e.error; }
|
|
15
|
+
}
|
|
16
|
+
return ar;
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.TermcapContext = void 0;
|
|
20
|
+
exports.TermcapProvider = TermcapProvider;
|
|
21
|
+
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
22
|
+
var react_1 = require("react");
|
|
23
|
+
var tinky_1 = require("tinky");
|
|
24
|
+
var detect_termcap_js_1 = require("../utils/detect-termcap.js");
|
|
25
|
+
/**
|
|
26
|
+
* Default termcap info before detection completes.
|
|
27
|
+
*
|
|
28
|
+
* This object is used as the initial state while capability detection
|
|
29
|
+
* is in progress. Note that `isReady` is `false` to indicate detection
|
|
30
|
+
* has not yet completed.
|
|
31
|
+
*
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
var defaultTermcapInfo = {
|
|
35
|
+
isReady: false,
|
|
36
|
+
backgroundColor: undefined,
|
|
37
|
+
terminalName: undefined,
|
|
38
|
+
kittyProtocol: false,
|
|
39
|
+
modifyOtherKeys: false,
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* React context for terminal capability information.
|
|
43
|
+
*
|
|
44
|
+
* This context provides `TermcapInfo` to descendant components. Use the
|
|
45
|
+
* `useTermcap` hook instead of accessing this context directly.
|
|
46
|
+
*
|
|
47
|
+
* @example Direct context access (not recommended)
|
|
48
|
+
* ```tsx
|
|
49
|
+
* import { useContext } from "react";
|
|
50
|
+
* import { TermcapContext } from "tinky-termcap";
|
|
51
|
+
*
|
|
52
|
+
* function MyComponent() {
|
|
53
|
+
* const caps = useContext(TermcapContext);
|
|
54
|
+
* // Note: caps may be undefined if not within TermcapProvider
|
|
55
|
+
* // Use useTermcap() hook instead for automatic error handling
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @see {@link useTermcap} - The recommended way to access capabilities
|
|
60
|
+
*/
|
|
61
|
+
exports.TermcapContext = (0, react_1.createContext)(undefined);
|
|
62
|
+
/**
|
|
63
|
+
* Provider component that detects and provides terminal capabilities.
|
|
64
|
+
*
|
|
65
|
+
* This component performs terminal capability detection on mount and provides
|
|
66
|
+
* the results to descendant components via the `useTermcap` hook. It integrates
|
|
67
|
+
* with Tinky's `useStdin` and `useStdout` hooks to access terminal streams.
|
|
68
|
+
*
|
|
69
|
+
* ## Lifecycle
|
|
70
|
+
*
|
|
71
|
+
* 1. **Mount**: Enables raw mode and sends detection queries to the terminal
|
|
72
|
+
* 2. **Detection**: Listens for terminal responses and parses capabilities
|
|
73
|
+
* 3. **Complete**: Either:
|
|
74
|
+
* - All responses received (triggered by Device Attributes response)
|
|
75
|
+
* - Timeout reached (returns whatever was detected)
|
|
76
|
+
* 4. **Unmount**: Cleanup (detection may be aborted if still in progress)
|
|
77
|
+
*
|
|
78
|
+
* ## Raw Mode
|
|
79
|
+
*
|
|
80
|
+
* The provider enables raw mode for detection. After detection completes,
|
|
81
|
+
* raw mode remains enabled as Tinky applications typically need it. If you
|
|
82
|
+
* need to manage raw mode differently, use `initialCapabilities` to skip
|
|
83
|
+
* detection and manage the terminal state yourself.
|
|
84
|
+
*
|
|
85
|
+
* @param props - Component props
|
|
86
|
+
* @returns React element wrapping children with capability context
|
|
87
|
+
*
|
|
88
|
+
* @example Basic usage
|
|
89
|
+
* ```tsx
|
|
90
|
+
* import { render } from "tinky";
|
|
91
|
+
* import { TermcapProvider, useTermcap } from "tinky-termcap";
|
|
92
|
+
*
|
|
93
|
+
* function App() {
|
|
94
|
+
* const caps = useTermcap();
|
|
95
|
+
* return <Text>Terminal: {caps.terminalName ?? "Unknown"}</Text>;
|
|
96
|
+
* }
|
|
97
|
+
*
|
|
98
|
+
* render(
|
|
99
|
+
* <TermcapProvider>
|
|
100
|
+
* <App />
|
|
101
|
+
* </TermcapProvider>
|
|
102
|
+
* );
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @example With custom timeout
|
|
106
|
+
* ```tsx
|
|
107
|
+
* <TermcapProvider timeout={500}>
|
|
108
|
+
* <App />
|
|
109
|
+
* </TermcapProvider>
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* @example For testing
|
|
113
|
+
* ```tsx
|
|
114
|
+
* <TermcapProvider
|
|
115
|
+
* initialCapabilities={{
|
|
116
|
+
* isReady: true,
|
|
117
|
+
* backgroundColor: "#000000",
|
|
118
|
+
* terminalName: "test",
|
|
119
|
+
* kittyProtocol: true,
|
|
120
|
+
* modifyOtherKeys: false,
|
|
121
|
+
* }}
|
|
122
|
+
* >
|
|
123
|
+
* <ComponentUnderTest />
|
|
124
|
+
* </TermcapProvider>
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @see {@link useTermcap} - Hook to access capabilities in child components
|
|
128
|
+
* @see {@link TermcapProviderProps} - Available props
|
|
129
|
+
* @see {@link TermcapInfo} - Shape of the provided capabilities
|
|
130
|
+
*/
|
|
131
|
+
function TermcapProvider(_a) {
|
|
132
|
+
var children = _a.children, _b = _a.timeout, timeout = _b === void 0 ? detect_termcap_js_1.DEFAULT_DETECTION_TIMEOUT : _b, initialCapabilities = _a.initialCapabilities;
|
|
133
|
+
var _c = __read((0, react_1.useState)(initialCapabilities !== null && initialCapabilities !== void 0 ? initialCapabilities : defaultTermcapInfo), 2), capabilities = _c[0], setCapabilities = _c[1];
|
|
134
|
+
var _d = (0, tinky_1.useStdin)(), stdin = _d.stdin, setRawMode = _d.setRawMode;
|
|
135
|
+
var stdout = (0, tinky_1.useStdout)().stdout;
|
|
136
|
+
(0, react_1.useEffect)(function () {
|
|
137
|
+
// Skip detection if initial capabilities provided
|
|
138
|
+
if (initialCapabilities) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
var mounted = true;
|
|
142
|
+
// Enable raw mode for detection
|
|
143
|
+
setRawMode(true);
|
|
144
|
+
(0, detect_termcap_js_1.detectTermcap)(stdin, stdout, timeout).then(function (result) {
|
|
145
|
+
if (mounted) {
|
|
146
|
+
setCapabilities(result);
|
|
147
|
+
// We don't disable raw mode here as Tinky applications usually need it.
|
|
148
|
+
// If necessary, the consumer can manage raw mode.
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
return function () {
|
|
152
|
+
mounted = false;
|
|
153
|
+
};
|
|
154
|
+
}, [timeout, initialCapabilities, stdin, stdout, setRawMode]);
|
|
155
|
+
var value = (0, react_1.useMemo)(function () { return capabilities; }, [capabilities]);
|
|
156
|
+
return ((0, jsx_runtime_1.jsx)(exports.TermcapContext.Provider, { value: value, children: children }));
|
|
157
|
+
}
|
package/lib/detect.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Detected terminal capabilities.
|
|
8
|
+
*/
|
|
9
|
+
export interface TermcapInfo {
|
|
10
|
+
/** Whether detection is complete */
|
|
11
|
+
isReady: boolean;
|
|
12
|
+
/** Terminal background color in #rrggbb format, or undefined if not detected */
|
|
13
|
+
backgroundColor: string | undefined;
|
|
14
|
+
/** Terminal name/version string, or undefined if not detected */
|
|
15
|
+
terminalName: string | undefined;
|
|
16
|
+
/** Whether Kitty keyboard protocol is supported */
|
|
17
|
+
kittyProtocol: boolean;
|
|
18
|
+
/** Whether modifyOtherKeys mode is supported (level >= 2) */
|
|
19
|
+
modifyOtherKeys: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Default timeout for capability detection (in milliseconds).
|
|
23
|
+
*/
|
|
24
|
+
export declare const DEFAULT_DETECTION_TIMEOUT = 1000;
|
|
25
|
+
/**
|
|
26
|
+
* Detect terminal capabilities by querying the terminal.
|
|
27
|
+
*
|
|
28
|
+
* This sends escape sequences to query terminal features and parses responses.
|
|
29
|
+
* Should only be called once at app startup.
|
|
30
|
+
*
|
|
31
|
+
* @param timeout - Maximum time to wait for responses (default: 1000ms)
|
|
32
|
+
* @returns Promise resolving to detected capabilities
|
|
33
|
+
*/
|
|
34
|
+
export declare function detectTerminalCapabilities(timeout?: number): Promise<TermcapInfo>;
|
|
35
|
+
/**
|
|
36
|
+
* For testing purposes only - reset module state.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resetForTesting(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAwBH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,iEAAiE;IACjE,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,mDAAmD;IACnD,aAAa,EAAE,OAAO,CAAC;IACvB,6DAA6D;IAC7D,eAAe,EAAE,OAAO,CAAC;CAC1B;AAuBD;;GAEG;AACH,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,GAAE,MAAkC,GAC1C,OAAO,CAAC,WAAW,CAAC,CAqHtB;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|