@opentui/react 0.0.0-20260419-49f00f96 → 0.0.0-20260423-76a94f40
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/{chunk-mq7v1x2n.js → chunk-9fvvv225.js} +2 -1
- package/index.d.ts +1 -0
- package/index.js +25 -161
- package/package.json +3 -2
- package/scripts/runtime-plugin-support.ts +1 -1
- package/src/hooks/index.d.ts +0 -1
- package/test-utils.js +1 -1
- package/src/hooks/use-keymap.d.ts +0 -36
|
@@ -166,7 +166,7 @@ import { TextNodeRenderable as TextNodeRenderable2 } from "@opentui/core";
|
|
|
166
166
|
// package.json
|
|
167
167
|
var package_default = {
|
|
168
168
|
name: "@opentui/react",
|
|
169
|
-
version: "0.0.0-
|
|
169
|
+
version: "0.0.0-20260423-76a94f40",
|
|
170
170
|
description: "React renderer for building terminal user interfaces using OpenTUI core",
|
|
171
171
|
license: "MIT",
|
|
172
172
|
repository: {
|
|
@@ -208,6 +208,7 @@ var package_default = {
|
|
|
208
208
|
test: "bun test"
|
|
209
209
|
},
|
|
210
210
|
devDependencies: {
|
|
211
|
+
"@opentui/keymap": "workspace:*",
|
|
211
212
|
"@types/bun": "latest",
|
|
212
213
|
"@types/node": "^24.0.0",
|
|
213
214
|
"@types/react": "^19.0.0",
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src/index.js";
|
package/index.js
CHANGED
|
@@ -11,158 +11,19 @@ import {
|
|
|
11
11
|
getComponentCatalogue,
|
|
12
12
|
jsxDEV,
|
|
13
13
|
useAppContext
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-9fvvv225.js";
|
|
15
15
|
import"./chunk-2mx7fq49.js";
|
|
16
|
-
// src/hooks/use-keymap.ts
|
|
17
|
-
import {
|
|
18
|
-
getKeymap
|
|
19
|
-
} from "@opentui/core/extras";
|
|
20
|
-
import { useCallback, useEffect, useLayoutEffect, useMemo, useReducer, useRef } from "react";
|
|
21
|
-
|
|
22
|
-
// src/hooks/use-renderer.ts
|
|
23
|
-
var useRenderer = () => {
|
|
24
|
-
const { renderer } = useAppContext();
|
|
25
|
-
if (!renderer) {
|
|
26
|
-
throw new Error("Renderer not found.");
|
|
27
|
-
}
|
|
28
|
-
return renderer;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// src/hooks/use-keymap.ts
|
|
32
|
-
function resolveBindingsTarget(target) {
|
|
33
|
-
if (typeof target === "function") {
|
|
34
|
-
return target() ?? undefined;
|
|
35
|
-
}
|
|
36
|
-
return target ?? undefined;
|
|
37
|
-
}
|
|
38
|
-
var useKeymap = () => {
|
|
39
|
-
const renderer = useRenderer();
|
|
40
|
-
return useMemo(() => getKeymap(renderer), [renderer]);
|
|
41
|
-
};
|
|
42
|
-
function useKeymapStateVersion(keymap) {
|
|
43
|
-
const [version, bumpVersion] = useReducer((value) => value + 1, 0);
|
|
44
|
-
useLayoutEffect(() => {
|
|
45
|
-
const dispose = keymap.on("state", () => {
|
|
46
|
-
bumpVersion();
|
|
47
|
-
});
|
|
48
|
-
return () => {
|
|
49
|
-
dispose();
|
|
50
|
-
};
|
|
51
|
-
}, [keymap]);
|
|
52
|
-
return version;
|
|
53
|
-
}
|
|
54
|
-
var useActiveKeys = (options) => {
|
|
55
|
-
const keymap = useKeymap();
|
|
56
|
-
const version = useKeymapStateVersion(keymap);
|
|
57
|
-
return useMemo(() => {
|
|
58
|
-
return keymap.getActiveKeys(options);
|
|
59
|
-
}, [keymap, options, version]);
|
|
60
|
-
};
|
|
61
|
-
var usePendingSequence = () => {
|
|
62
|
-
const keymap = useKeymap();
|
|
63
|
-
const version = useKeymapStateVersion(keymap);
|
|
64
|
-
return useMemo(() => {
|
|
65
|
-
return keymap.getPendingSequence();
|
|
66
|
-
}, [keymap, version]);
|
|
67
|
-
};
|
|
68
|
-
function useBindings(createLayer, deps = []) {
|
|
69
|
-
const keymap = useKeymap();
|
|
70
|
-
const layer = useMemo(createLayer, deps);
|
|
71
|
-
const layerRef = useRef(layer);
|
|
72
|
-
const refTargetRef = useRef(undefined);
|
|
73
|
-
const disposeRef = useRef(undefined);
|
|
74
|
-
const mountedRef = useRef(false);
|
|
75
|
-
const registeredScopeRef = useRef(undefined);
|
|
76
|
-
const registeredTargetRef = useRef(undefined);
|
|
77
|
-
layerRef.current = layer;
|
|
78
|
-
const unregister = useCallback(() => {
|
|
79
|
-
disposeRef.current?.();
|
|
80
|
-
disposeRef.current = undefined;
|
|
81
|
-
registeredScopeRef.current = undefined;
|
|
82
|
-
registeredTargetRef.current = undefined;
|
|
83
|
-
}, []);
|
|
84
|
-
const register = useCallback(() => {
|
|
85
|
-
if (disposeRef.current) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const currentLayer = layerRef.current;
|
|
89
|
-
const explicitTarget = resolveBindingsTarget(currentLayer.target);
|
|
90
|
-
const resolvedTarget = explicitTarget ?? refTargetRef.current;
|
|
91
|
-
const resolvedScope = currentLayer.scope ?? (resolvedTarget ? "focus-within" : "global");
|
|
92
|
-
if (currentLayer.target !== undefined && !explicitTarget) {
|
|
93
|
-
throw new Error("useBindings target was not available during mount");
|
|
94
|
-
}
|
|
95
|
-
if (resolvedScope !== "global" && !resolvedTarget) {
|
|
96
|
-
throw new Error("useBindings local bindings need a target or the returned ref callback attached to a renderable");
|
|
97
|
-
}
|
|
98
|
-
const { scope: _scope, target: _target, ...baseLayer } = currentLayer;
|
|
99
|
-
const resolvedLayer = resolvedScope === "global" ? {
|
|
100
|
-
...baseLayer,
|
|
101
|
-
scope: "global"
|
|
102
|
-
} : {
|
|
103
|
-
...baseLayer,
|
|
104
|
-
scope: resolvedScope,
|
|
105
|
-
target: resolvedTarget
|
|
106
|
-
};
|
|
107
|
-
disposeRef.current = keymap.registerLayer(resolvedLayer);
|
|
108
|
-
registeredScopeRef.current = resolvedScope;
|
|
109
|
-
registeredTargetRef.current = resolvedScope === "global" ? undefined : resolvedTarget;
|
|
110
|
-
}, [keymap]);
|
|
111
|
-
const ref = useCallback((value) => {
|
|
112
|
-
refTargetRef.current = value ?? undefined;
|
|
113
|
-
}, []);
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
mountedRef.current = true;
|
|
116
|
-
unregister();
|
|
117
|
-
register();
|
|
118
|
-
return () => {
|
|
119
|
-
mountedRef.current = false;
|
|
120
|
-
unregister();
|
|
121
|
-
};
|
|
122
|
-
}, [layer, register, unregister]);
|
|
123
|
-
useEffect(() => {
|
|
124
|
-
if (!mountedRef.current) {
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
const currentLayer = layerRef.current;
|
|
128
|
-
if (currentLayer.target !== undefined || currentLayer.scope === "global") {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
const resolvedTarget = refTargetRef.current;
|
|
132
|
-
const resolvedScope = currentLayer.scope ?? (resolvedTarget ? "focus-within" : "global");
|
|
133
|
-
const nextTarget = resolvedScope === "global" ? undefined : resolvedTarget;
|
|
134
|
-
if (registeredScopeRef.current === resolvedScope && registeredTargetRef.current === nextTarget) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
unregister();
|
|
138
|
-
if (!nextTarget && currentLayer.scope !== undefined) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
register();
|
|
142
|
-
});
|
|
143
|
-
return ref;
|
|
144
|
-
}
|
|
145
|
-
function reactiveMatcherFromStore(subscribe, getSnapshot, predicate) {
|
|
146
|
-
return {
|
|
147
|
-
get() {
|
|
148
|
-
return predicate ? predicate(getSnapshot()) : Boolean(getSnapshot());
|
|
149
|
-
},
|
|
150
|
-
subscribe(onChange) {
|
|
151
|
-
return subscribe(onChange);
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
16
|
// src/hooks/use-keyboard.ts
|
|
156
|
-
import { useEffect
|
|
17
|
+
import { useEffect } from "react";
|
|
157
18
|
|
|
158
19
|
// src/hooks/use-event.ts
|
|
159
|
-
import { useCallback
|
|
20
|
+
import { useCallback, useLayoutEffect, useRef } from "react";
|
|
160
21
|
function useEffectEvent(handler) {
|
|
161
|
-
const handlerRef =
|
|
162
|
-
|
|
22
|
+
const handlerRef = useRef(handler);
|
|
23
|
+
useLayoutEffect(() => {
|
|
163
24
|
handlerRef.current = handler;
|
|
164
25
|
});
|
|
165
|
-
return
|
|
26
|
+
return useCallback((...args) => {
|
|
166
27
|
const fn = handlerRef.current;
|
|
167
28
|
return fn(...args);
|
|
168
29
|
}, []);
|
|
@@ -172,7 +33,7 @@ function useEffectEvent(handler) {
|
|
|
172
33
|
var useKeyboard = (handler, options = { release: false }) => {
|
|
173
34
|
const { keyHandler } = useAppContext();
|
|
174
35
|
const stableHandler = useEffectEvent(handler);
|
|
175
|
-
|
|
36
|
+
useEffect(() => {
|
|
176
37
|
keyHandler?.on("keypress", stableHandler);
|
|
177
38
|
if (options?.release) {
|
|
178
39
|
keyHandler?.on("keyrelease", stableHandler);
|
|
@@ -185,12 +46,20 @@ var useKeyboard = (handler, options = { release: false }) => {
|
|
|
185
46
|
};
|
|
186
47
|
}, [keyHandler, options.release]);
|
|
187
48
|
};
|
|
49
|
+
// src/hooks/use-renderer.ts
|
|
50
|
+
var useRenderer = () => {
|
|
51
|
+
const { renderer } = useAppContext();
|
|
52
|
+
if (!renderer) {
|
|
53
|
+
throw new Error("Renderer not found.");
|
|
54
|
+
}
|
|
55
|
+
return renderer;
|
|
56
|
+
};
|
|
188
57
|
// src/hooks/use-resize.ts
|
|
189
|
-
import { useEffect as
|
|
58
|
+
import { useEffect as useEffect2 } from "react";
|
|
190
59
|
var useOnResize = (callback) => {
|
|
191
60
|
const renderer = useRenderer();
|
|
192
61
|
const stableCallback = useEffectEvent(callback);
|
|
193
|
-
|
|
62
|
+
useEffect2(() => {
|
|
194
63
|
renderer.on("resize", stableCallback);
|
|
195
64
|
return () => {
|
|
196
65
|
renderer.off("resize", stableCallback);
|
|
@@ -214,10 +83,10 @@ var useTerminalDimensions = () => {
|
|
|
214
83
|
};
|
|
215
84
|
// src/hooks/use-timeline.ts
|
|
216
85
|
import { engine, Timeline } from "@opentui/core";
|
|
217
|
-
import { useEffect as
|
|
86
|
+
import { useEffect as useEffect3 } from "react";
|
|
218
87
|
var useTimeline = (options = {}) => {
|
|
219
88
|
const timeline = new Timeline(options);
|
|
220
|
-
|
|
89
|
+
useEffect3(() => {
|
|
221
90
|
if (!options.autoplay) {
|
|
222
91
|
timeline.play();
|
|
223
92
|
}
|
|
@@ -233,7 +102,7 @@ var useTimeline = (options = {}) => {
|
|
|
233
102
|
import {
|
|
234
103
|
createSlotRegistry
|
|
235
104
|
} from "@opentui/core";
|
|
236
|
-
import React, { Fragment as Fragment2, useEffect as
|
|
105
|
+
import React, { Fragment as Fragment2, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
237
106
|
function createReactSlotRegistry(renderer, context, options = {}) {
|
|
238
107
|
return createSlotRegistry(renderer, "react:slot-registry", context, options);
|
|
239
108
|
}
|
|
@@ -310,14 +179,14 @@ function Slot(props) {
|
|
|
310
179
|
const [version, setVersion] = useState2(0);
|
|
311
180
|
const registry = props.registry;
|
|
312
181
|
const slotName = String(props.name);
|
|
313
|
-
const renderFailuresByPluginRef =
|
|
314
|
-
const pendingRenderReportsRef =
|
|
315
|
-
|
|
182
|
+
const renderFailuresByPluginRef = useRef2(new Map);
|
|
183
|
+
const pendingRenderReportsRef = useRef2(new Map);
|
|
184
|
+
useEffect4(() => {
|
|
316
185
|
return registry.subscribe(() => {
|
|
317
186
|
setVersion((current) => current + 1);
|
|
318
187
|
});
|
|
319
188
|
}, [registry]);
|
|
320
|
-
|
|
189
|
+
useEffect4(() => {
|
|
321
190
|
if (pendingRenderReportsRef.current.size === 0) {
|
|
322
191
|
return;
|
|
323
192
|
}
|
|
@@ -334,7 +203,7 @@ function Slot(props) {
|
|
|
334
203
|
renderFailuresByPluginRef.current.set(`${report.slot}:${report.pluginId}:render`, failure);
|
|
335
204
|
}
|
|
336
205
|
});
|
|
337
|
-
const entries =
|
|
206
|
+
const entries = useMemo(() => registry.resolveEntries(props.name), [registry, props.name, version]);
|
|
338
207
|
const slotProps = getSlotProps(props);
|
|
339
208
|
const renderEntry = (entry, fallbackOnFailure) => {
|
|
340
209
|
const key = `${slotName}:${entry.id}`;
|
|
@@ -450,14 +319,9 @@ export {
|
|
|
450
319
|
useTimeline,
|
|
451
320
|
useTerminalDimensions,
|
|
452
321
|
useRenderer,
|
|
453
|
-
usePendingSequence,
|
|
454
322
|
useOnResize,
|
|
455
|
-
useKeymap,
|
|
456
323
|
useKeyboard,
|
|
457
|
-
useBindings,
|
|
458
324
|
useAppContext,
|
|
459
|
-
useActiveKeys,
|
|
460
|
-
reactiveMatcherFromStore,
|
|
461
325
|
getComponentCatalogue,
|
|
462
326
|
flushSync,
|
|
463
327
|
extend,
|
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.0.0-
|
|
7
|
+
"version": "0.0.0-20260423-76a94f40",
|
|
8
8
|
"description": "React renderer for building terminal user interfaces using OpenTUI core",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"repository": {
|
|
@@ -44,10 +44,11 @@
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@opentui/core": "0.0.0-
|
|
47
|
+
"@opentui/core": "0.0.0-20260423-76a94f40",
|
|
48
48
|
"react-reconciler": "^0.32.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
+
"@opentui/keymap": "workspace:*",
|
|
51
52
|
"@types/bun": "latest",
|
|
52
53
|
"@types/node": "^24.0.0",
|
|
53
54
|
"@types/react": "^19.0.0",
|
|
@@ -4,7 +4,7 @@ import { createRuntimePlugin, type RuntimeModuleEntry } from "@opentui/core/runt
|
|
|
4
4
|
import * as reactRuntime from "react"
|
|
5
5
|
import * as reactJsxRuntime from "react/jsx-runtime"
|
|
6
6
|
import * as reactJsxDevRuntime from "react/jsx-dev-runtime"
|
|
7
|
-
import * as opentuiReactRuntime from "../
|
|
7
|
+
import * as opentuiReactRuntime from "../index.js"
|
|
8
8
|
|
|
9
9
|
const runtimePluginSupportInstalledKey = "__opentuiReactRuntimePluginSupportInstalled__"
|
|
10
10
|
|
package/src/hooks/index.d.ts
CHANGED
package/test-utils.js
CHANGED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { Renderable } from "@opentui/core";
|
|
2
|
-
import { type ActiveKey, type ActiveKeyOptions, type LayerFields, type Keymap, type ReactiveMatcher, type KeySequencePart } from "@opentui/core/extras";
|
|
3
|
-
import { type DependencyList } from "react";
|
|
4
|
-
export type UseBindingsTarget<TRenderable extends Renderable = Renderable> = TRenderable | null | undefined | (() => TRenderable | null | undefined);
|
|
5
|
-
type UseBindingsLayerBase = LayerFields;
|
|
6
|
-
export type BindingsRef<TRenderable extends Renderable = Renderable> = (value: TRenderable | null) => void;
|
|
7
|
-
export interface UseGlobalBindingsLayer extends UseBindingsLayerBase {
|
|
8
|
-
scope?: "global";
|
|
9
|
-
target?: undefined;
|
|
10
|
-
}
|
|
11
|
-
export interface UseFocusBindingsLayer<TRenderable extends Renderable = Renderable> extends UseBindingsLayerBase {
|
|
12
|
-
scope: "focus";
|
|
13
|
-
target?: UseBindingsTarget<TRenderable>;
|
|
14
|
-
}
|
|
15
|
-
export interface UseFocusWithinBindingsLayer<TRenderable extends Renderable = Renderable> extends UseBindingsLayerBase {
|
|
16
|
-
scope: "focus-within";
|
|
17
|
-
target?: UseBindingsTarget<TRenderable>;
|
|
18
|
-
}
|
|
19
|
-
export interface UseInferredFocusWithinBindingsLayer<TRenderable extends Renderable = Renderable> extends UseBindingsLayerBase {
|
|
20
|
-
scope?: undefined;
|
|
21
|
-
target: UseBindingsTarget<TRenderable>;
|
|
22
|
-
}
|
|
23
|
-
export type UseTargetBindingsLayer<TRenderable extends Renderable = Renderable> = UseFocusBindingsLayer<TRenderable> | UseFocusWithinBindingsLayer<TRenderable> | UseInferredFocusWithinBindingsLayer<TRenderable>;
|
|
24
|
-
export type UseBindingsLayer<TRenderable extends Renderable = Renderable> = UseGlobalBindingsLayer | UseTargetBindingsLayer<TRenderable>;
|
|
25
|
-
export declare const useKeymap: () => Keymap;
|
|
26
|
-
export declare const useActiveKeys: (options?: ActiveKeyOptions) => readonly ActiveKey[];
|
|
27
|
-
export declare const usePendingSequence: () => readonly KeySequencePart[];
|
|
28
|
-
export declare function useBindings<TRenderable extends Renderable = Renderable>(createLayer: () => UseGlobalBindingsLayer, deps?: DependencyList): BindingsRef<TRenderable>;
|
|
29
|
-
export declare function useBindings<TRenderable extends Renderable = Renderable>(createLayer: () => UseTargetBindingsLayer<TRenderable>, deps?: DependencyList): BindingsRef<TRenderable>;
|
|
30
|
-
/**
|
|
31
|
-
* Adapts any `subscribe` + `getSnapshot` store to
|
|
32
|
-
* `ReactiveMatcher`. Pass `predicate` when the snapshot value is not
|
|
33
|
-
* already boolean.
|
|
34
|
-
*/
|
|
35
|
-
export declare function reactiveMatcherFromStore<T>(subscribe: (onStoreChange: () => void) => () => void, getSnapshot: () => T, predicate?: (value: T) => boolean): ReactiveMatcher;
|
|
36
|
-
export {};
|