@opentui/react 0.1.62 → 0.1.64
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 +29 -0
- package/chunk-e11q5a3p.js +20 -0
- package/chunk-fcedq94e.js +29 -0
- package/index.js +127 -13
- package/jsx-namespace.d.ts +2 -0
- package/package.json +10 -4
- package/src/components/index.d.ts +2 -1
- package/src/components/text.d.ts +7 -1
- package/src/reconciler/chunk-e11q5a3p.js +20 -0
- package/src/reconciler/chunk-fcedq94e.js +29 -0
- package/src/reconciler/devtools-polyfill.d.ts +1 -0
- package/src/reconciler/devtools.d.ts +1 -0
- package/src/reconciler/renderer.d.ts +5 -0
- package/src/reconciler/renderer.js +128 -14
- package/src/test-utils/chunk-e11q5a3p.js +20 -0
- package/src/test-utils/chunk-fcedq94e.js +29 -0
- package/src/test-utils/test-utils.js +124 -13
- package/src/types/components.d.ts +3 -0
package/README.md
CHANGED
|
@@ -83,6 +83,7 @@ For optimal TypeScript support, configure your `tsconfig.json`:
|
|
|
83
83
|
- [System Monitor Animation](#system-monitor-animation)
|
|
84
84
|
- [Styled Text Showcase](#styled-text-showcase)
|
|
85
85
|
- [Component Extension](#component-extension)
|
|
86
|
+
- [Using React DevTools](#using-react-devtools)
|
|
86
87
|
|
|
87
88
|
## Core Concepts
|
|
88
89
|
|
|
@@ -970,3 +971,31 @@ function App() {
|
|
|
970
971
|
const renderer = await createCliRenderer()
|
|
971
972
|
createRoot(renderer).render(<App />)
|
|
972
973
|
```
|
|
974
|
+
|
|
975
|
+
## Using React DevTools
|
|
976
|
+
|
|
977
|
+
OpenTUI React supports [React DevTools](https://github.com/facebook/react/tree/master/packages/react-devtools) for debugging your terminal applications. To enable DevTools integration:
|
|
978
|
+
|
|
979
|
+
1. Install the optional peer dependency:
|
|
980
|
+
|
|
981
|
+
```bash
|
|
982
|
+
bun add --dev react-devtools-core@7
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
2. Start the standalone React DevTools:
|
|
986
|
+
|
|
987
|
+
```bash
|
|
988
|
+
npx npx react-devtools@7
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
3. Run your app with the `DEV` environment variable:
|
|
992
|
+
|
|
993
|
+
```bash
|
|
994
|
+
DEV=true bun run your-app.ts
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
After the app starts, you should see the component tree in React DevTools. You can inspect and modify props in real-time, and changes will be reflected immediately in your terminal UI.
|
|
998
|
+
|
|
999
|
+
### Process Exit with DevTools
|
|
1000
|
+
|
|
1001
|
+
When DevTools is connected, the WebSocket connection may prevent your process from exiting naturally.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = import.meta.require;
|
|
19
|
+
|
|
20
|
+
export { __toESM, __require };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
__require,
|
|
4
|
+
__toESM
|
|
5
|
+
} from "./chunk-e11q5a3p.js";
|
|
6
|
+
|
|
7
|
+
// src/reconciler/devtools-polyfill.ts
|
|
8
|
+
var g = globalThis;
|
|
9
|
+
if (typeof g.WebSocket === "undefined") {
|
|
10
|
+
try {
|
|
11
|
+
const ws = await import("ws");
|
|
12
|
+
g.WebSocket = ws.default;
|
|
13
|
+
} catch {}
|
|
14
|
+
}
|
|
15
|
+
g.window ||= globalThis;
|
|
16
|
+
g.self ||= globalThis;
|
|
17
|
+
g.window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = [
|
|
18
|
+
{
|
|
19
|
+
type: 2,
|
|
20
|
+
value: "ErrorBoundary",
|
|
21
|
+
isEnabled: true,
|
|
22
|
+
isValid: true
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
// src/reconciler/devtools.ts
|
|
27
|
+
import devtools from "react-devtools-core";
|
|
28
|
+
devtools.initialize();
|
|
29
|
+
devtools.connectToDevTools();
|
package/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
__require,
|
|
4
|
+
__toESM
|
|
5
|
+
} from "./chunk-e11q5a3p.js";
|
|
6
|
+
|
|
2
7
|
// src/components/index.ts
|
|
3
8
|
import {
|
|
4
9
|
ASCIIFontRenderable,
|
|
@@ -16,7 +21,7 @@ import {
|
|
|
16
21
|
|
|
17
22
|
// src/components/text.ts
|
|
18
23
|
import { TextAttributes, TextNodeRenderable } from "@opentui/core";
|
|
19
|
-
var textNodeKeys = ["span", "b", "strong", "i", "em", "u", "br"];
|
|
24
|
+
var textNodeKeys = ["span", "b", "strong", "i", "em", "u", "br", "a"];
|
|
20
25
|
|
|
21
26
|
class SpanRenderable extends TextNodeRenderable {
|
|
22
27
|
ctx;
|
|
@@ -68,6 +73,16 @@ class LineBreakRenderable extends SpanRenderable {
|
|
|
68
73
|
}
|
|
69
74
|
}
|
|
70
75
|
|
|
76
|
+
class LinkRenderable extends SpanRenderable {
|
|
77
|
+
constructor(_ctx, options) {
|
|
78
|
+
const linkOptions = {
|
|
79
|
+
...options,
|
|
80
|
+
link: { url: options.href }
|
|
81
|
+
};
|
|
82
|
+
super(null, linkOptions);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
71
86
|
// src/components/index.ts
|
|
72
87
|
var baseComponents = {
|
|
73
88
|
box: BoxRenderable,
|
|
@@ -87,7 +102,8 @@ var baseComponents = {
|
|
|
87
102
|
strong: BoldSpanRenderable,
|
|
88
103
|
i: ItalicSpanRenderable,
|
|
89
104
|
em: ItalicSpanRenderable,
|
|
90
|
-
u: UnderlineSpanRenderable
|
|
105
|
+
u: UnderlineSpanRenderable,
|
|
106
|
+
a: LinkRenderable
|
|
91
107
|
};
|
|
92
108
|
var componentCatalogue = { ...baseComponents };
|
|
93
109
|
function extend(objects) {
|
|
@@ -229,6 +245,76 @@ import { ConcurrentRoot } from "react-reconciler/constants";
|
|
|
229
245
|
|
|
230
246
|
// src/reconciler/host-config.ts
|
|
231
247
|
import { TextNodeRenderable as TextNodeRenderable2 } from "@opentui/core";
|
|
248
|
+
// package.json
|
|
249
|
+
var package_default = {
|
|
250
|
+
name: "@opentui/react",
|
|
251
|
+
version: "0.1.64",
|
|
252
|
+
description: "React renderer for building terminal user interfaces using OpenTUI core",
|
|
253
|
+
license: "MIT",
|
|
254
|
+
repository: {
|
|
255
|
+
type: "git",
|
|
256
|
+
url: "https://github.com/sst/opentui",
|
|
257
|
+
directory: "packages/react"
|
|
258
|
+
},
|
|
259
|
+
module: "src/index.ts",
|
|
260
|
+
type: "module",
|
|
261
|
+
private: true,
|
|
262
|
+
main: "src/index.ts",
|
|
263
|
+
exports: {
|
|
264
|
+
".": {
|
|
265
|
+
import: "./src/index.ts",
|
|
266
|
+
types: "./src/index.ts"
|
|
267
|
+
},
|
|
268
|
+
"./test-utils": {
|
|
269
|
+
import: "./src/test-utils.ts",
|
|
270
|
+
types: "./src/test-utils.d.ts"
|
|
271
|
+
},
|
|
272
|
+
"./jsx-runtime": {
|
|
273
|
+
import: "./jsx-runtime.js",
|
|
274
|
+
types: "./jsx-runtime.d.ts"
|
|
275
|
+
},
|
|
276
|
+
"./jsx-dev-runtime": {
|
|
277
|
+
import: "./jsx-dev-runtime.js",
|
|
278
|
+
types: "./jsx-dev-runtime.d.ts"
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
scripts: {
|
|
282
|
+
build: "bun run scripts/build.ts",
|
|
283
|
+
"build:dev": "bun run scripts/build.ts --dev",
|
|
284
|
+
publish: "bun run scripts/publish.ts",
|
|
285
|
+
test: "bun test"
|
|
286
|
+
},
|
|
287
|
+
devDependencies: {
|
|
288
|
+
"@types/bun": "latest",
|
|
289
|
+
"@types/node": "^24.0.0",
|
|
290
|
+
"@types/react": "^19.0.0",
|
|
291
|
+
"@types/react-reconciler": "^0.32.0",
|
|
292
|
+
"@types/ws": "^8.18.1",
|
|
293
|
+
react: ">=19.0.0",
|
|
294
|
+
"react-devtools-core": "^7.0.1",
|
|
295
|
+
typescript: "^5",
|
|
296
|
+
ws: "^8.18.0"
|
|
297
|
+
},
|
|
298
|
+
peerDependencies: {
|
|
299
|
+
react: ">=19.0.0",
|
|
300
|
+
"react-devtools-core": "^7.0.1",
|
|
301
|
+
ws: "^8.18.0"
|
|
302
|
+
},
|
|
303
|
+
peerDependenciesMeta: {
|
|
304
|
+
"react-devtools-core": {
|
|
305
|
+
optional: true
|
|
306
|
+
},
|
|
307
|
+
ws: {
|
|
308
|
+
optional: true
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
dependencies: {
|
|
312
|
+
"@opentui/core": "workspace:*",
|
|
313
|
+
"react-reconciler": "^0.32.0"
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// src/reconciler/host-config.ts
|
|
232
318
|
import { createContext as createContext2 } from "react";
|
|
233
319
|
import { DefaultEventPriority, NoEventPriority } from "react-reconciler/constants";
|
|
234
320
|
|
|
@@ -262,18 +348,21 @@ function initEventListeners(instance, eventName, listener, previousListener) {
|
|
|
262
348
|
}
|
|
263
349
|
}
|
|
264
350
|
function setStyle(instance, styles, oldStyles) {
|
|
265
|
-
if (
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
instance[styleName] = value;
|
|
351
|
+
if (oldStyles != null && typeof oldStyles === "object") {
|
|
352
|
+
for (const styleName in oldStyles) {
|
|
353
|
+
if (oldStyles.hasOwnProperty(styleName)) {
|
|
354
|
+
if (styles == null || !styles.hasOwnProperty(styleName)) {
|
|
355
|
+
instance[styleName] = null;
|
|
271
356
|
}
|
|
272
357
|
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (styles != null && typeof styles === "object") {
|
|
361
|
+
for (const styleName in styles) {
|
|
362
|
+
if (styles.hasOwnProperty(styleName)) {
|
|
363
|
+
const value = styles[styleName];
|
|
364
|
+
const oldValue = oldStyles?.[styleName];
|
|
365
|
+
if (value !== oldValue) {
|
|
277
366
|
instance[styleName] = value;
|
|
278
367
|
}
|
|
279
368
|
}
|
|
@@ -506,11 +595,33 @@ var hostConfig = {
|
|
|
506
595
|
prepareScopeUpdate() {},
|
|
507
596
|
getInstanceFromScope() {
|
|
508
597
|
return null;
|
|
509
|
-
}
|
|
598
|
+
},
|
|
599
|
+
rendererPackageName: "@opentui/react",
|
|
600
|
+
rendererVersion: package_default.version
|
|
510
601
|
};
|
|
511
602
|
|
|
512
603
|
// src/reconciler/reconciler.ts
|
|
513
604
|
var reconciler = ReactReconciler(hostConfig);
|
|
605
|
+
if (process.env["DEV"] === "true") {
|
|
606
|
+
try {
|
|
607
|
+
await import("./chunk-fcedq94e.js");
|
|
608
|
+
} catch (error) {
|
|
609
|
+
if (error.code === "ERR_MODULE_NOT_FOUND") {
|
|
610
|
+
console.warn(`
|
|
611
|
+
The environment variable DEV is set to true, so opentui tried to import \`react-devtools-core\`,
|
|
612
|
+
but this failed as it was not installed. Debugging with React DevTools requires it.
|
|
613
|
+
|
|
614
|
+
To install use this command:
|
|
615
|
+
|
|
616
|
+
$ bun add react-devtools-core@7 -d
|
|
617
|
+
`.trim() + `
|
|
618
|
+
`);
|
|
619
|
+
} else {
|
|
620
|
+
throw error;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
reconciler.injectIntoDevTools();
|
|
514
625
|
function _render(element, root) {
|
|
515
626
|
const container = reconciler.createContainer(root, ConcurrentRoot, null, false, null, "", console.error, console.error, console.error, console.error, null);
|
|
516
627
|
reconciler.updateContainer(element, container, null, () => {});
|
|
@@ -518,6 +629,7 @@ function _render(element, root) {
|
|
|
518
629
|
}
|
|
519
630
|
|
|
520
631
|
// src/reconciler/renderer.ts
|
|
632
|
+
var { flushSync, createPortal } = reconciler;
|
|
521
633
|
function createRoot(renderer) {
|
|
522
634
|
let container = null;
|
|
523
635
|
return {
|
|
@@ -546,8 +658,10 @@ export {
|
|
|
546
658
|
useKeyboard,
|
|
547
659
|
useAppContext,
|
|
548
660
|
getComponentCatalogue,
|
|
661
|
+
flushSync,
|
|
549
662
|
extend,
|
|
550
663
|
createRoot,
|
|
664
|
+
createPortal,
|
|
551
665
|
createElement,
|
|
552
666
|
componentCatalogue,
|
|
553
667
|
baseComponents,
|
package/jsx-namespace.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
InputProps,
|
|
9
9
|
LineBreakProps,
|
|
10
10
|
LineNumberProps,
|
|
11
|
+
LinkProps,
|
|
11
12
|
OpenTUIComponents,
|
|
12
13
|
ScrollBoxProps,
|
|
13
14
|
SelectProps,
|
|
@@ -54,5 +55,6 @@ export namespace JSX {
|
|
|
54
55
|
strong: SpanProps
|
|
55
56
|
em: SpanProps
|
|
56
57
|
br: LineBreakProps
|
|
58
|
+
a: LinkProps
|
|
57
59
|
}
|
|
58
60
|
}
|
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.64",
|
|
8
8
|
"description": "React renderer for building terminal user interfaces using OpenTUI core",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"repository": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@opentui/core": "0.1.
|
|
43
|
+
"@opentui/core": "0.1.64",
|
|
44
44
|
"react-reconciler": "^0.32.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
@@ -48,9 +48,15 @@
|
|
|
48
48
|
"@types/node": "^24.0.0",
|
|
49
49
|
"@types/react": "^19.0.0",
|
|
50
50
|
"@types/react-reconciler": "^0.32.0",
|
|
51
|
-
"
|
|
51
|
+
"@types/ws": "^8.18.1",
|
|
52
|
+
"react": ">=19.0.0",
|
|
53
|
+
"react-devtools-core": "^7.0.1",
|
|
54
|
+
"typescript": "^5",
|
|
55
|
+
"ws": "^8.18.0"
|
|
52
56
|
},
|
|
53
57
|
"peerDependencies": {
|
|
54
|
-
"react": ">=19.0.0"
|
|
58
|
+
"react": ">=19.0.0",
|
|
59
|
+
"react-devtools-core": "^7.0.1",
|
|
60
|
+
"ws": "^8.18.0"
|
|
55
61
|
}
|
|
56
62
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ASCIIFontRenderable, BoxRenderable, CodeRenderable, DiffRenderable, InputRenderable, LineNumberRenderable, ScrollBoxRenderable, SelectRenderable, TabSelectRenderable, TextareaRenderable, TextRenderable } from "@opentui/core";
|
|
2
2
|
import type { RenderableConstructor } from "../types/components";
|
|
3
|
-
import { BoldSpanRenderable, ItalicSpanRenderable, LineBreakRenderable, SpanRenderable, UnderlineSpanRenderable } from "./text";
|
|
3
|
+
import { BoldSpanRenderable, ItalicSpanRenderable, LineBreakRenderable, LinkRenderable, SpanRenderable, UnderlineSpanRenderable } from "./text";
|
|
4
4
|
export declare const baseComponents: {
|
|
5
5
|
box: typeof BoxRenderable;
|
|
6
6
|
text: typeof TextRenderable;
|
|
@@ -20,6 +20,7 @@ export declare const baseComponents: {
|
|
|
20
20
|
i: typeof ItalicSpanRenderable;
|
|
21
21
|
em: typeof ItalicSpanRenderable;
|
|
22
22
|
u: typeof UnderlineSpanRenderable;
|
|
23
|
+
a: typeof LinkRenderable;
|
|
23
24
|
};
|
|
24
25
|
type ComponentCatalogue = Record<string, RenderableConstructor>;
|
|
25
26
|
export declare const componentCatalogue: ComponentCatalogue;
|
package/src/components/text.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TextNodeRenderable, type RenderContext, type TextNodeOptions } from "@opentui/core";
|
|
2
|
-
export declare const textNodeKeys: readonly ["span", "b", "strong", "i", "em", "u", "br"];
|
|
2
|
+
export declare const textNodeKeys: readonly ["span", "b", "strong", "i", "em", "u", "br", "a"];
|
|
3
3
|
export type TextNodeKey = (typeof textNodeKeys)[number];
|
|
4
4
|
export declare class SpanRenderable extends TextNodeRenderable {
|
|
5
5
|
private readonly ctx;
|
|
@@ -21,4 +21,10 @@ export declare class LineBreakRenderable extends SpanRenderable {
|
|
|
21
21
|
constructor(_ctx: RenderContext | null, options: TextNodeOptions);
|
|
22
22
|
add(): number;
|
|
23
23
|
}
|
|
24
|
+
export interface LinkOptions extends TextNodeOptions {
|
|
25
|
+
href: string;
|
|
26
|
+
}
|
|
27
|
+
export declare class LinkRenderable extends SpanRenderable {
|
|
28
|
+
constructor(_ctx: RenderContext | null, options: LinkOptions);
|
|
29
|
+
}
|
|
24
30
|
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = import.meta.require;
|
|
19
|
+
|
|
20
|
+
export { __toESM, __require };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
__require,
|
|
4
|
+
__toESM
|
|
5
|
+
} from "./chunk-e11q5a3p.js";
|
|
6
|
+
|
|
7
|
+
// src/reconciler/devtools-polyfill.ts
|
|
8
|
+
var g = globalThis;
|
|
9
|
+
if (typeof g.WebSocket === "undefined") {
|
|
10
|
+
try {
|
|
11
|
+
const ws = await import("ws");
|
|
12
|
+
g.WebSocket = ws.default;
|
|
13
|
+
} catch {}
|
|
14
|
+
}
|
|
15
|
+
g.window ||= globalThis;
|
|
16
|
+
g.self ||= globalThis;
|
|
17
|
+
g.window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = [
|
|
18
|
+
{
|
|
19
|
+
type: 2,
|
|
20
|
+
value: "ErrorBoundary",
|
|
21
|
+
isEnabled: true,
|
|
22
|
+
isValid: true
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
// src/reconciler/devtools.ts
|
|
27
|
+
import devtools from "react-devtools-core";
|
|
28
|
+
devtools.initialize();
|
|
29
|
+
devtools.connectToDevTools();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./devtools-polyfill";
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { CliRenderer } from "@opentui/core";
|
|
2
2
|
import { type ReactNode } from "react";
|
|
3
|
+
declare const flushSync: {
|
|
4
|
+
(): void;
|
|
5
|
+
<R>(fn: () => R): R;
|
|
6
|
+
}, createPortal: (children: ReactNode, containerInfo: any, implementation: any, key?: string | null) => import("react-reconciler").ReactPortal;
|
|
3
7
|
export type Root = {
|
|
4
8
|
render: (node: ReactNode) => void;
|
|
5
9
|
unmount: () => void;
|
|
@@ -15,3 +19,4 @@ export type Root = {
|
|
|
15
19
|
* ```
|
|
16
20
|
*/
|
|
17
21
|
export declare function createRoot(renderer: CliRenderer): Root;
|
|
22
|
+
export { createPortal, flushSync };
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
__require,
|
|
4
|
+
__toESM
|
|
5
|
+
} from "./chunk-e11q5a3p.js";
|
|
6
|
+
|
|
2
7
|
// src/reconciler/renderer.ts
|
|
3
8
|
import { engine } from "@opentui/core";
|
|
4
9
|
import React2 from "react";
|
|
@@ -45,6 +50,76 @@ import { ConcurrentRoot } from "react-reconciler/constants";
|
|
|
45
50
|
|
|
46
51
|
// src/reconciler/host-config.ts
|
|
47
52
|
import { TextNodeRenderable as TextNodeRenderable2 } from "@opentui/core";
|
|
53
|
+
// package.json
|
|
54
|
+
var package_default = {
|
|
55
|
+
name: "@opentui/react",
|
|
56
|
+
version: "0.1.64",
|
|
57
|
+
description: "React renderer for building terminal user interfaces using OpenTUI core",
|
|
58
|
+
license: "MIT",
|
|
59
|
+
repository: {
|
|
60
|
+
type: "git",
|
|
61
|
+
url: "https://github.com/sst/opentui",
|
|
62
|
+
directory: "packages/react"
|
|
63
|
+
},
|
|
64
|
+
module: "src/index.ts",
|
|
65
|
+
type: "module",
|
|
66
|
+
private: true,
|
|
67
|
+
main: "src/index.ts",
|
|
68
|
+
exports: {
|
|
69
|
+
".": {
|
|
70
|
+
import: "./src/index.ts",
|
|
71
|
+
types: "./src/index.ts"
|
|
72
|
+
},
|
|
73
|
+
"./test-utils": {
|
|
74
|
+
import: "./src/test-utils.ts",
|
|
75
|
+
types: "./src/test-utils.d.ts"
|
|
76
|
+
},
|
|
77
|
+
"./jsx-runtime": {
|
|
78
|
+
import: "./jsx-runtime.js",
|
|
79
|
+
types: "./jsx-runtime.d.ts"
|
|
80
|
+
},
|
|
81
|
+
"./jsx-dev-runtime": {
|
|
82
|
+
import: "./jsx-dev-runtime.js",
|
|
83
|
+
types: "./jsx-dev-runtime.d.ts"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
scripts: {
|
|
87
|
+
build: "bun run scripts/build.ts",
|
|
88
|
+
"build:dev": "bun run scripts/build.ts --dev",
|
|
89
|
+
publish: "bun run scripts/publish.ts",
|
|
90
|
+
test: "bun test"
|
|
91
|
+
},
|
|
92
|
+
devDependencies: {
|
|
93
|
+
"@types/bun": "latest",
|
|
94
|
+
"@types/node": "^24.0.0",
|
|
95
|
+
"@types/react": "^19.0.0",
|
|
96
|
+
"@types/react-reconciler": "^0.32.0",
|
|
97
|
+
"@types/ws": "^8.18.1",
|
|
98
|
+
react: ">=19.0.0",
|
|
99
|
+
"react-devtools-core": "^7.0.1",
|
|
100
|
+
typescript: "^5",
|
|
101
|
+
ws: "^8.18.0"
|
|
102
|
+
},
|
|
103
|
+
peerDependencies: {
|
|
104
|
+
react: ">=19.0.0",
|
|
105
|
+
"react-devtools-core": "^7.0.1",
|
|
106
|
+
ws: "^8.18.0"
|
|
107
|
+
},
|
|
108
|
+
peerDependenciesMeta: {
|
|
109
|
+
"react-devtools-core": {
|
|
110
|
+
optional: true
|
|
111
|
+
},
|
|
112
|
+
ws: {
|
|
113
|
+
optional: true
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
dependencies: {
|
|
117
|
+
"@opentui/core": "workspace:*",
|
|
118
|
+
"react-reconciler": "^0.32.0"
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// src/reconciler/host-config.ts
|
|
48
123
|
import { createContext as createContext2 } from "react";
|
|
49
124
|
import { DefaultEventPriority, NoEventPriority } from "react-reconciler/constants";
|
|
50
125
|
|
|
@@ -65,7 +140,7 @@ import {
|
|
|
65
140
|
|
|
66
141
|
// src/components/text.ts
|
|
67
142
|
import { TextAttributes, TextNodeRenderable } from "@opentui/core";
|
|
68
|
-
var textNodeKeys = ["span", "b", "strong", "i", "em", "u", "br"];
|
|
143
|
+
var textNodeKeys = ["span", "b", "strong", "i", "em", "u", "br", "a"];
|
|
69
144
|
|
|
70
145
|
class SpanRenderable extends TextNodeRenderable {
|
|
71
146
|
ctx;
|
|
@@ -117,6 +192,16 @@ class LineBreakRenderable extends SpanRenderable {
|
|
|
117
192
|
}
|
|
118
193
|
}
|
|
119
194
|
|
|
195
|
+
class LinkRenderable extends SpanRenderable {
|
|
196
|
+
constructor(_ctx, options) {
|
|
197
|
+
const linkOptions = {
|
|
198
|
+
...options,
|
|
199
|
+
link: { url: options.href }
|
|
200
|
+
};
|
|
201
|
+
super(null, linkOptions);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
120
205
|
// src/components/index.ts
|
|
121
206
|
var baseComponents = {
|
|
122
207
|
box: BoxRenderable,
|
|
@@ -136,7 +221,8 @@ var baseComponents = {
|
|
|
136
221
|
strong: BoldSpanRenderable,
|
|
137
222
|
i: ItalicSpanRenderable,
|
|
138
223
|
em: ItalicSpanRenderable,
|
|
139
|
-
u: UnderlineSpanRenderable
|
|
224
|
+
u: UnderlineSpanRenderable,
|
|
225
|
+
a: LinkRenderable
|
|
140
226
|
};
|
|
141
227
|
var componentCatalogue = { ...baseComponents };
|
|
142
228
|
function getComponentCatalogue() {
|
|
@@ -173,18 +259,21 @@ function initEventListeners(instance, eventName, listener, previousListener) {
|
|
|
173
259
|
}
|
|
174
260
|
}
|
|
175
261
|
function setStyle(instance, styles, oldStyles) {
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
instance[styleName] = value;
|
|
262
|
+
if (oldStyles != null && typeof oldStyles === "object") {
|
|
263
|
+
for (const styleName in oldStyles) {
|
|
264
|
+
if (oldStyles.hasOwnProperty(styleName)) {
|
|
265
|
+
if (styles == null || !styles.hasOwnProperty(styleName)) {
|
|
266
|
+
instance[styleName] = null;
|
|
182
267
|
}
|
|
183
268
|
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (styles != null && typeof styles === "object") {
|
|
272
|
+
for (const styleName in styles) {
|
|
273
|
+
if (styles.hasOwnProperty(styleName)) {
|
|
274
|
+
const value = styles[styleName];
|
|
275
|
+
const oldValue = oldStyles?.[styleName];
|
|
276
|
+
if (value !== oldValue) {
|
|
188
277
|
instance[styleName] = value;
|
|
189
278
|
}
|
|
190
279
|
}
|
|
@@ -417,11 +506,33 @@ var hostConfig = {
|
|
|
417
506
|
prepareScopeUpdate() {},
|
|
418
507
|
getInstanceFromScope() {
|
|
419
508
|
return null;
|
|
420
|
-
}
|
|
509
|
+
},
|
|
510
|
+
rendererPackageName: "@opentui/react",
|
|
511
|
+
rendererVersion: package_default.version
|
|
421
512
|
};
|
|
422
513
|
|
|
423
514
|
// src/reconciler/reconciler.ts
|
|
424
515
|
var reconciler = ReactReconciler(hostConfig);
|
|
516
|
+
if (process.env["DEV"] === "true") {
|
|
517
|
+
try {
|
|
518
|
+
await import("./chunk-fcedq94e.js");
|
|
519
|
+
} catch (error) {
|
|
520
|
+
if (error.code === "ERR_MODULE_NOT_FOUND") {
|
|
521
|
+
console.warn(`
|
|
522
|
+
The environment variable DEV is set to true, so opentui tried to import \`react-devtools-core\`,
|
|
523
|
+
but this failed as it was not installed. Debugging with React DevTools requires it.
|
|
524
|
+
|
|
525
|
+
To install use this command:
|
|
526
|
+
|
|
527
|
+
$ bun add react-devtools-core@7 -d
|
|
528
|
+
`.trim() + `
|
|
529
|
+
`);
|
|
530
|
+
} else {
|
|
531
|
+
throw error;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
reconciler.injectIntoDevTools();
|
|
425
536
|
function _render(element, root) {
|
|
426
537
|
const container = reconciler.createContainer(root, ConcurrentRoot, null, false, null, "", console.error, console.error, console.error, console.error, null);
|
|
427
538
|
reconciler.updateContainer(element, container, null, () => {});
|
|
@@ -429,6 +540,7 @@ function _render(element, root) {
|
|
|
429
540
|
}
|
|
430
541
|
|
|
431
542
|
// src/reconciler/renderer.ts
|
|
543
|
+
var { flushSync, createPortal } = reconciler;
|
|
432
544
|
function createRoot(renderer) {
|
|
433
545
|
let container = null;
|
|
434
546
|
return {
|
|
@@ -447,5 +559,7 @@ function createRoot(renderer) {
|
|
|
447
559
|
};
|
|
448
560
|
}
|
|
449
561
|
export {
|
|
450
|
-
|
|
562
|
+
flushSync,
|
|
563
|
+
createRoot,
|
|
564
|
+
createPortal
|
|
451
565
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = import.meta.require;
|
|
19
|
+
|
|
20
|
+
export { __toESM, __require };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
__require,
|
|
4
|
+
__toESM
|
|
5
|
+
} from "./chunk-e11q5a3p.js";
|
|
6
|
+
|
|
7
|
+
// src/reconciler/devtools-polyfill.ts
|
|
8
|
+
var g = globalThis;
|
|
9
|
+
if (typeof g.WebSocket === "undefined") {
|
|
10
|
+
try {
|
|
11
|
+
const ws = await import("ws");
|
|
12
|
+
g.WebSocket = ws.default;
|
|
13
|
+
} catch {}
|
|
14
|
+
}
|
|
15
|
+
g.window ||= globalThis;
|
|
16
|
+
g.self ||= globalThis;
|
|
17
|
+
g.window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = [
|
|
18
|
+
{
|
|
19
|
+
type: 2,
|
|
20
|
+
value: "ErrorBoundary",
|
|
21
|
+
isEnabled: true,
|
|
22
|
+
isValid: true
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
// src/reconciler/devtools.ts
|
|
27
|
+
import devtools from "react-devtools-core";
|
|
28
|
+
devtools.initialize();
|
|
29
|
+
devtools.connectToDevTools();
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
__require,
|
|
4
|
+
__toESM
|
|
5
|
+
} from "./chunk-e11q5a3p.js";
|
|
6
|
+
|
|
2
7
|
// src/test-utils.ts
|
|
3
8
|
import { createTestRenderer } from "@opentui/core/testing";
|
|
4
9
|
import { act } from "react";
|
|
@@ -49,6 +54,76 @@ import { ConcurrentRoot } from "react-reconciler/constants";
|
|
|
49
54
|
|
|
50
55
|
// src/reconciler/host-config.ts
|
|
51
56
|
import { TextNodeRenderable as TextNodeRenderable2 } from "@opentui/core";
|
|
57
|
+
// package.json
|
|
58
|
+
var package_default = {
|
|
59
|
+
name: "@opentui/react",
|
|
60
|
+
version: "0.1.64",
|
|
61
|
+
description: "React renderer for building terminal user interfaces using OpenTUI core",
|
|
62
|
+
license: "MIT",
|
|
63
|
+
repository: {
|
|
64
|
+
type: "git",
|
|
65
|
+
url: "https://github.com/sst/opentui",
|
|
66
|
+
directory: "packages/react"
|
|
67
|
+
},
|
|
68
|
+
module: "src/index.ts",
|
|
69
|
+
type: "module",
|
|
70
|
+
private: true,
|
|
71
|
+
main: "src/index.ts",
|
|
72
|
+
exports: {
|
|
73
|
+
".": {
|
|
74
|
+
import: "./src/index.ts",
|
|
75
|
+
types: "./src/index.ts"
|
|
76
|
+
},
|
|
77
|
+
"./test-utils": {
|
|
78
|
+
import: "./src/test-utils.ts",
|
|
79
|
+
types: "./src/test-utils.d.ts"
|
|
80
|
+
},
|
|
81
|
+
"./jsx-runtime": {
|
|
82
|
+
import: "./jsx-runtime.js",
|
|
83
|
+
types: "./jsx-runtime.d.ts"
|
|
84
|
+
},
|
|
85
|
+
"./jsx-dev-runtime": {
|
|
86
|
+
import: "./jsx-dev-runtime.js",
|
|
87
|
+
types: "./jsx-dev-runtime.d.ts"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
scripts: {
|
|
91
|
+
build: "bun run scripts/build.ts",
|
|
92
|
+
"build:dev": "bun run scripts/build.ts --dev",
|
|
93
|
+
publish: "bun run scripts/publish.ts",
|
|
94
|
+
test: "bun test"
|
|
95
|
+
},
|
|
96
|
+
devDependencies: {
|
|
97
|
+
"@types/bun": "latest",
|
|
98
|
+
"@types/node": "^24.0.0",
|
|
99
|
+
"@types/react": "^19.0.0",
|
|
100
|
+
"@types/react-reconciler": "^0.32.0",
|
|
101
|
+
"@types/ws": "^8.18.1",
|
|
102
|
+
react: ">=19.0.0",
|
|
103
|
+
"react-devtools-core": "^7.0.1",
|
|
104
|
+
typescript: "^5",
|
|
105
|
+
ws: "^8.18.0"
|
|
106
|
+
},
|
|
107
|
+
peerDependencies: {
|
|
108
|
+
react: ">=19.0.0",
|
|
109
|
+
"react-devtools-core": "^7.0.1",
|
|
110
|
+
ws: "^8.18.0"
|
|
111
|
+
},
|
|
112
|
+
peerDependenciesMeta: {
|
|
113
|
+
"react-devtools-core": {
|
|
114
|
+
optional: true
|
|
115
|
+
},
|
|
116
|
+
ws: {
|
|
117
|
+
optional: true
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
dependencies: {
|
|
121
|
+
"@opentui/core": "workspace:*",
|
|
122
|
+
"react-reconciler": "^0.32.0"
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// src/reconciler/host-config.ts
|
|
52
127
|
import { createContext as createContext2 } from "react";
|
|
53
128
|
import { DefaultEventPriority, NoEventPriority } from "react-reconciler/constants";
|
|
54
129
|
|
|
@@ -69,7 +144,7 @@ import {
|
|
|
69
144
|
|
|
70
145
|
// src/components/text.ts
|
|
71
146
|
import { TextAttributes, TextNodeRenderable } from "@opentui/core";
|
|
72
|
-
var textNodeKeys = ["span", "b", "strong", "i", "em", "u", "br"];
|
|
147
|
+
var textNodeKeys = ["span", "b", "strong", "i", "em", "u", "br", "a"];
|
|
73
148
|
|
|
74
149
|
class SpanRenderable extends TextNodeRenderable {
|
|
75
150
|
ctx;
|
|
@@ -121,6 +196,16 @@ class LineBreakRenderable extends SpanRenderable {
|
|
|
121
196
|
}
|
|
122
197
|
}
|
|
123
198
|
|
|
199
|
+
class LinkRenderable extends SpanRenderable {
|
|
200
|
+
constructor(_ctx, options) {
|
|
201
|
+
const linkOptions = {
|
|
202
|
+
...options,
|
|
203
|
+
link: { url: options.href }
|
|
204
|
+
};
|
|
205
|
+
super(null, linkOptions);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
124
209
|
// src/components/index.ts
|
|
125
210
|
var baseComponents = {
|
|
126
211
|
box: BoxRenderable,
|
|
@@ -140,7 +225,8 @@ var baseComponents = {
|
|
|
140
225
|
strong: BoldSpanRenderable,
|
|
141
226
|
i: ItalicSpanRenderable,
|
|
142
227
|
em: ItalicSpanRenderable,
|
|
143
|
-
u: UnderlineSpanRenderable
|
|
228
|
+
u: UnderlineSpanRenderable,
|
|
229
|
+
a: LinkRenderable
|
|
144
230
|
};
|
|
145
231
|
var componentCatalogue = { ...baseComponents };
|
|
146
232
|
function getComponentCatalogue() {
|
|
@@ -177,18 +263,21 @@ function initEventListeners(instance, eventName, listener, previousListener) {
|
|
|
177
263
|
}
|
|
178
264
|
}
|
|
179
265
|
function setStyle(instance, styles, oldStyles) {
|
|
180
|
-
if (
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
instance[styleName] = value;
|
|
266
|
+
if (oldStyles != null && typeof oldStyles === "object") {
|
|
267
|
+
for (const styleName in oldStyles) {
|
|
268
|
+
if (oldStyles.hasOwnProperty(styleName)) {
|
|
269
|
+
if (styles == null || !styles.hasOwnProperty(styleName)) {
|
|
270
|
+
instance[styleName] = null;
|
|
186
271
|
}
|
|
187
272
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (styles != null && typeof styles === "object") {
|
|
276
|
+
for (const styleName in styles) {
|
|
277
|
+
if (styles.hasOwnProperty(styleName)) {
|
|
278
|
+
const value = styles[styleName];
|
|
279
|
+
const oldValue = oldStyles?.[styleName];
|
|
280
|
+
if (value !== oldValue) {
|
|
192
281
|
instance[styleName] = value;
|
|
193
282
|
}
|
|
194
283
|
}
|
|
@@ -421,11 +510,33 @@ var hostConfig = {
|
|
|
421
510
|
prepareScopeUpdate() {},
|
|
422
511
|
getInstanceFromScope() {
|
|
423
512
|
return null;
|
|
424
|
-
}
|
|
513
|
+
},
|
|
514
|
+
rendererPackageName: "@opentui/react",
|
|
515
|
+
rendererVersion: package_default.version
|
|
425
516
|
};
|
|
426
517
|
|
|
427
518
|
// src/reconciler/reconciler.ts
|
|
428
519
|
var reconciler = ReactReconciler(hostConfig);
|
|
520
|
+
if (process.env["DEV"] === "true") {
|
|
521
|
+
try {
|
|
522
|
+
await import("./chunk-fcedq94e.js");
|
|
523
|
+
} catch (error) {
|
|
524
|
+
if (error.code === "ERR_MODULE_NOT_FOUND") {
|
|
525
|
+
console.warn(`
|
|
526
|
+
The environment variable DEV is set to true, so opentui tried to import \`react-devtools-core\`,
|
|
527
|
+
but this failed as it was not installed. Debugging with React DevTools requires it.
|
|
528
|
+
|
|
529
|
+
To install use this command:
|
|
530
|
+
|
|
531
|
+
$ bun add react-devtools-core@7 -d
|
|
532
|
+
`.trim() + `
|
|
533
|
+
`);
|
|
534
|
+
} else {
|
|
535
|
+
throw error;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
reconciler.injectIntoDevTools();
|
|
429
540
|
function _render(element, root) {
|
|
430
541
|
const container = reconciler.createContainer(root, ConcurrentRoot, null, false, null, "", console.error, console.error, console.error, console.error, null);
|
|
431
542
|
reconciler.updateContainer(element, container, null, () => {});
|
|
@@ -31,6 +31,9 @@ export type TextProps = ComponentProps<TextOptions, TextRenderable> & {
|
|
|
31
31
|
export type SpanProps = ComponentProps<TextNodeOptions, TextNodeRenderable> & {
|
|
32
32
|
children?: TextChildren;
|
|
33
33
|
};
|
|
34
|
+
export type LinkProps = SpanProps & {
|
|
35
|
+
href: string;
|
|
36
|
+
};
|
|
34
37
|
export type LineBreakProps = Pick<SpanProps, "id">;
|
|
35
38
|
export type BoxProps = ComponentProps<ContainerProps<BoxOptions>, BoxRenderable>;
|
|
36
39
|
export type InputProps = ComponentProps<InputRenderableOptions, InputRenderable> & {
|