@opentui/react 0.1.13 → 0.1.15
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 +2 -2
- package/index.js +34 -13
- package/jsx-namespace.d.ts +4 -1
- package/package.json +2 -2
- package/src/components/index.d.ts +2 -1
- package/src/hooks/use-event.d.ts +9 -0
- package/src/reconciler/renderer.js +13 -8
- package/src/types/components.d.ts +4 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ function App() {
|
|
|
18
18
|
<box>
|
|
19
19
|
<text fg="#00FF00">Hello, Terminal!</text>
|
|
20
20
|
<box title="Welcome" padding={2}>
|
|
21
|
-
<text>Welcome to OpenTUI with React
|
|
21
|
+
<text>Welcome to OpenTUI with React!</text>
|
|
22
22
|
</box>
|
|
23
23
|
</box>
|
|
24
24
|
)
|
|
@@ -484,7 +484,7 @@ class ButtonRenderable extends BoxRenderable {
|
|
|
484
484
|
|
|
485
485
|
set label(value: string) {
|
|
486
486
|
this._label = value
|
|
487
|
-
this.
|
|
487
|
+
this.requestRender()
|
|
488
488
|
}
|
|
489
489
|
}
|
|
490
490
|
|
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ASCIIFontRenderable,
|
|
5
5
|
BoxRenderable,
|
|
6
6
|
InputRenderable,
|
|
7
|
+
ScrollBoxRenderable,
|
|
7
8
|
SelectRenderable,
|
|
8
9
|
TabSelectRenderable,
|
|
9
10
|
TextRenderable
|
|
@@ -13,6 +14,7 @@ var baseComponents = {
|
|
|
13
14
|
text: TextRenderable,
|
|
14
15
|
input: InputRenderable,
|
|
15
16
|
select: SelectRenderable,
|
|
17
|
+
scrollbox: ScrollBoxRenderable,
|
|
16
18
|
"ascii-font": ASCIIFontRenderable,
|
|
17
19
|
"tab-select": TabSelectRenderable
|
|
18
20
|
};
|
|
@@ -34,14 +36,30 @@ var useAppContext = () => {
|
|
|
34
36
|
};
|
|
35
37
|
// src/hooks/use-keyboard.tsx
|
|
36
38
|
import { useEffect } from "react";
|
|
39
|
+
|
|
40
|
+
// src/hooks/use-event.tsx
|
|
41
|
+
import { useCallback, useLayoutEffect, useRef } from "react";
|
|
42
|
+
function useEvent(handler) {
|
|
43
|
+
const handlerRef = useRef(handler);
|
|
44
|
+
useLayoutEffect(() => {
|
|
45
|
+
handlerRef.current = handler;
|
|
46
|
+
});
|
|
47
|
+
return useCallback((...args) => {
|
|
48
|
+
const fn = handlerRef.current;
|
|
49
|
+
return fn(...args);
|
|
50
|
+
}, []);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/hooks/use-keyboard.tsx
|
|
37
54
|
var useKeyboard = (handler) => {
|
|
38
55
|
const { keyHandler } = useAppContext();
|
|
56
|
+
const stableHandler = useEvent(handler);
|
|
39
57
|
useEffect(() => {
|
|
40
|
-
keyHandler?.on("keypress",
|
|
58
|
+
keyHandler?.on("keypress", stableHandler);
|
|
41
59
|
return () => {
|
|
42
|
-
keyHandler?.off("keypress",
|
|
60
|
+
keyHandler?.off("keypress", stableHandler);
|
|
43
61
|
};
|
|
44
|
-
}, [keyHandler,
|
|
62
|
+
}, [keyHandler, stableHandler]);
|
|
45
63
|
};
|
|
46
64
|
// src/hooks/use-renderer.tsx
|
|
47
65
|
var useRenderer = () => {
|
|
@@ -68,8 +86,8 @@ import { useState } from "react";
|
|
|
68
86
|
var useTerminalDimensions = () => {
|
|
69
87
|
const renderer = useRenderer();
|
|
70
88
|
const [dimensions, setDimensions] = useState({
|
|
71
|
-
width: renderer.
|
|
72
|
-
height: renderer.
|
|
89
|
+
width: renderer.width,
|
|
90
|
+
height: renderer.height
|
|
73
91
|
});
|
|
74
92
|
const cb = (width, height) => {
|
|
75
93
|
setDimensions({ width, height });
|
|
@@ -266,7 +284,10 @@ var hostConfig = {
|
|
|
266
284
|
if (!components[type]) {
|
|
267
285
|
throw new Error(`[Reconciler] Unknown component type: ${type}`);
|
|
268
286
|
}
|
|
269
|
-
return new components[type](rootContainerInstance.ctx, {
|
|
287
|
+
return new components[type](rootContainerInstance.ctx, {
|
|
288
|
+
id,
|
|
289
|
+
...props
|
|
290
|
+
});
|
|
270
291
|
},
|
|
271
292
|
appendChild(parent, child) {
|
|
272
293
|
parent.add(child);
|
|
@@ -287,7 +308,7 @@ var hostConfig = {
|
|
|
287
308
|
return null;
|
|
288
309
|
},
|
|
289
310
|
resetAfterCommit(containerInfo) {
|
|
290
|
-
containerInfo.
|
|
311
|
+
containerInfo.requestRender();
|
|
291
312
|
},
|
|
292
313
|
getRootHostContext(rootContainerInstance) {
|
|
293
314
|
return {};
|
|
@@ -321,11 +342,11 @@ var hostConfig = {
|
|
|
321
342
|
commitMount(instance, type, props, internalInstanceHandle) {},
|
|
322
343
|
commitUpdate(instance, type, oldProps, newProps, internalInstanceHandle) {
|
|
323
344
|
updateProperties(instance, type, oldProps, newProps);
|
|
324
|
-
instance.
|
|
345
|
+
instance.requestRender();
|
|
325
346
|
},
|
|
326
347
|
commitTextUpdate(textInstance, oldText, newText) {
|
|
327
348
|
textInstance.content = newText;
|
|
328
|
-
textInstance.
|
|
349
|
+
textInstance.requestRender();
|
|
329
350
|
},
|
|
330
351
|
appendChildToContainer(container, child) {
|
|
331
352
|
container.add(child);
|
|
@@ -335,19 +356,19 @@ var hostConfig = {
|
|
|
335
356
|
},
|
|
336
357
|
hideInstance(instance) {
|
|
337
358
|
instance.visible = false;
|
|
338
|
-
instance.
|
|
359
|
+
instance.requestRender();
|
|
339
360
|
},
|
|
340
361
|
unhideInstance(instance, props) {
|
|
341
362
|
instance.visible = true;
|
|
342
|
-
instance.
|
|
363
|
+
instance.requestRender();
|
|
343
364
|
},
|
|
344
365
|
hideTextInstance(textInstance) {
|
|
345
366
|
textInstance.visible = false;
|
|
346
|
-
textInstance.
|
|
367
|
+
textInstance.requestRender();
|
|
347
368
|
},
|
|
348
369
|
unhideTextInstance(textInstance, text) {
|
|
349
370
|
textInstance.visible = true;
|
|
350
|
-
textInstance.
|
|
371
|
+
textInstance.requestRender();
|
|
351
372
|
},
|
|
352
373
|
clearContainer(container) {
|
|
353
374
|
const children = container.getChildren();
|
package/jsx-namespace.d.ts
CHANGED
|
@@ -2,12 +2,14 @@ import type * as React from "react"
|
|
|
2
2
|
import type {
|
|
3
3
|
AsciiFontProps,
|
|
4
4
|
BoxProps,
|
|
5
|
+
ExtendedIntrinsicElements,
|
|
5
6
|
InputProps,
|
|
7
|
+
OpenTUIComponents,
|
|
8
|
+
ScrollBoxProps,
|
|
6
9
|
SelectProps,
|
|
7
10
|
TabSelectProps,
|
|
8
11
|
TextProps,
|
|
9
12
|
} from "./src/types/components"
|
|
10
|
-
import type { ExtendedIntrinsicElements, OpenTUIComponents } from "./src/types/components"
|
|
11
13
|
|
|
12
14
|
export namespace JSX {
|
|
13
15
|
type Element = React.ReactNode
|
|
@@ -29,6 +31,7 @@ export namespace JSX {
|
|
|
29
31
|
text: TextProps
|
|
30
32
|
input: InputProps
|
|
31
33
|
select: SelectProps
|
|
34
|
+
scrollbox: ScrollBoxProps
|
|
32
35
|
"ascii-font": AsciiFontProps
|
|
33
36
|
"tab-select": TabSelectProps
|
|
34
37
|
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "src/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"version": "0.1.
|
|
7
|
+
"version": "0.1.15",
|
|
8
8
|
"description": "React renderer for building terminal user interfaces using OpenTUI core",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"repository": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@opentui/core": "0.1.
|
|
38
|
+
"@opentui/core": "0.1.15",
|
|
39
39
|
"react-reconciler": "^0.32.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { ASCIIFontRenderable, BoxRenderable, InputRenderable, SelectRenderable, TabSelectRenderable, TextRenderable } from "@opentui/core";
|
|
1
|
+
import { ASCIIFontRenderable, BoxRenderable, InputRenderable, ScrollBoxRenderable, SelectRenderable, TabSelectRenderable, TextRenderable } from "@opentui/core";
|
|
2
2
|
import type { RenderableConstructor } from "../types/components";
|
|
3
3
|
export declare const baseComponents: {
|
|
4
4
|
box: typeof BoxRenderable;
|
|
5
5
|
text: typeof TextRenderable;
|
|
6
6
|
input: typeof InputRenderable;
|
|
7
7
|
select: typeof SelectRenderable;
|
|
8
|
+
scrollbox: typeof ScrollBoxRenderable;
|
|
8
9
|
"ascii-font": typeof ASCIIFontRenderable;
|
|
9
10
|
"tab-select": typeof TabSelectRenderable;
|
|
10
11
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a stable callback that always calls the latest version of the provided handler.
|
|
3
|
+
* This prevents unnecessary re-renders and effect re-runs while ensuring the callback
|
|
4
|
+
* always has access to the latest props and state.
|
|
5
|
+
*
|
|
6
|
+
* Useful for event handlers that need to be passed to effects with empty dependency arrays
|
|
7
|
+
* or memoized child components.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useEvent<T extends (...args: any[]) => any>(handler: T): T;
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
ASCIIFontRenderable,
|
|
24
24
|
BoxRenderable,
|
|
25
25
|
InputRenderable,
|
|
26
|
+
ScrollBoxRenderable,
|
|
26
27
|
SelectRenderable,
|
|
27
28
|
TabSelectRenderable,
|
|
28
29
|
TextRenderable
|
|
@@ -32,6 +33,7 @@ var baseComponents = {
|
|
|
32
33
|
text: TextRenderable,
|
|
33
34
|
input: InputRenderable,
|
|
34
35
|
select: SelectRenderable,
|
|
36
|
+
scrollbox: ScrollBoxRenderable,
|
|
35
37
|
"ascii-font": ASCIIFontRenderable,
|
|
36
38
|
"tab-select": TabSelectRenderable
|
|
37
39
|
};
|
|
@@ -217,7 +219,10 @@ var hostConfig = {
|
|
|
217
219
|
if (!components[type]) {
|
|
218
220
|
throw new Error(`[Reconciler] Unknown component type: ${type}`);
|
|
219
221
|
}
|
|
220
|
-
return new components[type](rootContainerInstance.ctx, {
|
|
222
|
+
return new components[type](rootContainerInstance.ctx, {
|
|
223
|
+
id,
|
|
224
|
+
...props
|
|
225
|
+
});
|
|
221
226
|
},
|
|
222
227
|
appendChild(parent, child) {
|
|
223
228
|
parent.add(child);
|
|
@@ -238,7 +243,7 @@ var hostConfig = {
|
|
|
238
243
|
return null;
|
|
239
244
|
},
|
|
240
245
|
resetAfterCommit(containerInfo) {
|
|
241
|
-
containerInfo.
|
|
246
|
+
containerInfo.requestRender();
|
|
242
247
|
},
|
|
243
248
|
getRootHostContext(rootContainerInstance) {
|
|
244
249
|
return {};
|
|
@@ -272,11 +277,11 @@ var hostConfig = {
|
|
|
272
277
|
commitMount(instance, type, props, internalInstanceHandle) {},
|
|
273
278
|
commitUpdate(instance, type, oldProps, newProps, internalInstanceHandle) {
|
|
274
279
|
updateProperties(instance, type, oldProps, newProps);
|
|
275
|
-
instance.
|
|
280
|
+
instance.requestRender();
|
|
276
281
|
},
|
|
277
282
|
commitTextUpdate(textInstance, oldText, newText) {
|
|
278
283
|
textInstance.content = newText;
|
|
279
|
-
textInstance.
|
|
284
|
+
textInstance.requestRender();
|
|
280
285
|
},
|
|
281
286
|
appendChildToContainer(container, child) {
|
|
282
287
|
container.add(child);
|
|
@@ -286,19 +291,19 @@ var hostConfig = {
|
|
|
286
291
|
},
|
|
287
292
|
hideInstance(instance) {
|
|
288
293
|
instance.visible = false;
|
|
289
|
-
instance.
|
|
294
|
+
instance.requestRender();
|
|
290
295
|
},
|
|
291
296
|
unhideInstance(instance, props) {
|
|
292
297
|
instance.visible = true;
|
|
293
|
-
instance.
|
|
298
|
+
instance.requestRender();
|
|
294
299
|
},
|
|
295
300
|
hideTextInstance(textInstance) {
|
|
296
301
|
textInstance.visible = false;
|
|
297
|
-
textInstance.
|
|
302
|
+
textInstance.requestRender();
|
|
298
303
|
},
|
|
299
304
|
unhideTextInstance(textInstance, text) {
|
|
300
305
|
textInstance.visible = true;
|
|
301
|
-
textInstance.
|
|
306
|
+
textInstance.requestRender();
|
|
302
307
|
},
|
|
303
308
|
clearContainer(container) {
|
|
304
309
|
const children = container.getChildren();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ASCIIFontOptions, ASCIIFontRenderable, BoxOptions, BoxRenderable, InputRenderable, InputRenderableOptions, Renderable, RenderableOptions, RenderContext, SelectOption, SelectRenderable, SelectRenderableOptions, StyledText, TabSelectOption, TabSelectRenderable, TabSelectRenderableOptions, TextChunk, TextOptions, TextRenderable } from "@opentui/core";
|
|
1
|
+
import type { ASCIIFontOptions, ASCIIFontRenderable, BoxOptions, BoxRenderable, InputRenderable, InputRenderableOptions, Renderable, RenderableOptions, RenderContext, ScrollBoxOptions, ScrollBoxRenderable, SelectOption, SelectRenderable, SelectRenderableOptions, StyledText, TabSelectOption, TabSelectRenderable, TabSelectRenderableOptions, TextChunk, TextOptions, TextRenderable } from "@opentui/core";
|
|
2
2
|
import type React from "react";
|
|
3
3
|
/** Properties that should not be included in the style prop */
|
|
4
4
|
export type NonStyledProps = "id" | "buffered" | "live" | "enableLayout" | "selectable" | "renderAfter" | "renderBefore" | `on${string}`;
|
|
@@ -40,6 +40,9 @@ export type SelectProps = ComponentProps<SelectRenderableOptions, SelectRenderab
|
|
|
40
40
|
onChange?: (index: number, option: SelectOption | null) => void;
|
|
41
41
|
onSelect?: (index: number, option: SelectOption | null) => void;
|
|
42
42
|
};
|
|
43
|
+
export type ScrollBoxProps = ComponentProps<ContainerProps<ScrollBoxOptions>, ScrollBoxRenderable> & {
|
|
44
|
+
focused?: boolean;
|
|
45
|
+
};
|
|
43
46
|
export type AsciiFontProps = ComponentProps<ASCIIFontOptions, ASCIIFontRenderable>;
|
|
44
47
|
export type TabSelectProps = ComponentProps<TabSelectRenderableOptions, TabSelectRenderable> & {
|
|
45
48
|
focused?: boolean;
|