@opentui/react 0.2.1 → 0.2.3

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 CHANGED
@@ -60,6 +60,10 @@ For optimal TypeScript support, configure your `tsconfig.json`:
60
60
  - [Hooks](#hooks)
61
61
  - [useRenderer()](#userenderer)
62
62
  - [useKeyboard(handler, options?)](#usekeyboardhandler-options)
63
+ - [usePaste(handler)](#usepastehandler)
64
+ - [useFocus(handler)](#usefocushandler)
65
+ - [useBlur(handler)](#useblurhandler)
66
+ - [useSelectionHandler(handler)](#useselectionhandlerhandler)
63
67
  - [useOnResize(callback)](#useonresizecallback)
64
68
  - [useTerminalDimensions()](#useterminaldimensions)
65
69
  - [useTimeline(options?)](#usetimelineoptions)
@@ -239,6 +243,89 @@ function App() {
239
243
  }
240
244
  ```
241
245
 
246
+ #### `usePaste(handler)`
247
+
248
+ Handle terminal paste events (bracketed paste).
249
+
250
+ ```tsx
251
+ import { decodePasteBytes } from "@opentui/core"
252
+ import { usePaste } from "@opentui/react"
253
+
254
+ function App() {
255
+ usePaste((event) => {
256
+ const text = decodePasteBytes(event.bytes)
257
+ console.log("Pasted text:", text)
258
+ })
259
+
260
+ return <text>Paste something into the terminal</text>
261
+ }
262
+ ```
263
+
264
+ **Parameters:**
265
+
266
+ - `handler`: Callback function that receives a `PasteEvent` object with `bytes: Uint8Array` (decode with `decodePasteBytes` from `@opentui/core`)
267
+
268
+ #### `useFocus(handler)`
269
+
270
+ Subscribe to terminal window focus events. Fires when the terminal window gains focus.
271
+
272
+ ```tsx
273
+ import { useFocus } from "@opentui/react"
274
+
275
+ function App() {
276
+ useFocus(() => {
277
+ console.log("Terminal gained focus")
278
+ })
279
+
280
+ return <text>Focus-aware component</text>
281
+ }
282
+ ```
283
+
284
+ **Parameters:**
285
+
286
+ - `handler`: Callback function invoked when the terminal gains focus
287
+
288
+ #### `useBlur(handler)`
289
+
290
+ Subscribe to terminal window blur events. Fires when the terminal window loses focus.
291
+
292
+ ```tsx
293
+ import { useBlur } from "@opentui/react"
294
+
295
+ function App() {
296
+ useBlur(() => {
297
+ console.log("Terminal lost focus")
298
+ })
299
+
300
+ return <text>Blur-aware component</text>
301
+ }
302
+ ```
303
+
304
+ **Parameters:**
305
+
306
+ - `handler`: Callback function invoked when the terminal loses focus
307
+
308
+ #### `useSelectionHandler(handler)`
309
+
310
+ Handle text selection events (e.g., when the user selects text via mouse drag).
311
+
312
+ ```tsx
313
+ import { useSelectionHandler } from "@opentui/react"
314
+
315
+ function App() {
316
+ useSelectionHandler((selection) => {
317
+ const text = selection.getSelectedText()
318
+ console.log("Selected:", text)
319
+ })
320
+
321
+ return <text selectable>Select this text with your mouse</text>
322
+ }
323
+ ```
324
+
325
+ **Parameters:**
326
+
327
+ - `handler`: Callback function that receives a `Selection` object with methods like `getSelectedText()`
328
+
242
329
  #### `useOnResize(callback)`
243
330
 
244
331
  Handle terminal resize events.
@@ -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.2.1",
169
+ version: "0.2.3",
170
170
  description: "React renderer for building terminal user interfaces using OpenTUI core",
171
171
  license: "MIT",
172
172
  repository: {
@@ -191,6 +191,10 @@ var package_default = {
191
191
  import: "./scripts/runtime-plugin-support.ts",
192
192
  types: "./scripts/runtime-plugin-support.ts"
193
193
  },
194
+ "./runtime-plugin-support/configure": {
195
+ import: "./scripts/runtime-plugin-support-configure.ts",
196
+ types: "./scripts/runtime-plugin-support-configure.ts"
197
+ },
194
198
  "./jsx-runtime": {
195
199
  import: "./jsx-runtime.js",
196
200
  types: "./jsx-runtime.d.ts"
@@ -211,16 +215,16 @@ var package_default = {
211
215
  "@opentui/keymap": "workspace:*",
212
216
  "@types/bun": "latest",
213
217
  "@types/node": "^24.0.0",
214
- "@types/react": "^19.0.0",
215
- "@types/react-reconciler": "^0.32.0",
218
+ "@types/react": "^19.2.0",
219
+ "@types/react-reconciler": "^0.33.0",
216
220
  "@types/ws": "^8.18.1",
217
- react: ">=19.0.0",
221
+ react: ">=19.2.0",
218
222
  "react-devtools-core": "^7.0.1",
219
223
  typescript: "^5",
220
224
  ws: "^8.18.0"
221
225
  },
222
226
  peerDependencies: {
223
- react: ">=19.0.0",
227
+ react: ">=19.2.0",
224
228
  "react-devtools-core": "^7.0.1",
225
229
  ws: "^8.18.0"
226
230
  },
@@ -234,7 +238,7 @@ var package_default = {
234
238
  },
235
239
  dependencies: {
236
240
  "@opentui/core": "workspace:*",
237
- "react-reconciler": "^0.32.0"
241
+ "react-reconciler": "^0.33.0"
238
242
  }
239
243
  };
240
244
 
@@ -376,6 +380,8 @@ var hostConfig = {
376
380
  supportsMutation: true,
377
381
  supportsPersistence: false,
378
382
  supportsHydration: false,
383
+ supportsMicrotasks: true,
384
+ scheduleMicrotask: queueMicrotask,
379
385
  createInstance(type, props, rootContainerInstance, hostContext) {
380
386
  if (textNodeKeys.includes(type) && !hostContext.isInsideText) {
381
387
  throw new Error(`Component of type "${type}" must be created inside of a text node`);
@@ -431,7 +437,7 @@ var hostConfig = {
431
437
  cancelTimeout: clearTimeout,
432
438
  noTimeout: -1,
433
439
  shouldAttemptEagerTransition() {
434
- return false;
440
+ return true;
435
441
  },
436
442
  finalizeInitialChildren(instance, type, props, rootContainerInstance, hostContext) {
437
443
  setInitialProperties(instance, type, props);
@@ -440,11 +446,9 @@ var hostConfig = {
440
446
  commitMount(instance, type, props, internalInstanceHandle) {},
441
447
  commitUpdate(instance, type, oldProps, newProps, internalInstanceHandle) {
442
448
  updateProperties(instance, type, oldProps, newProps);
443
- instance.requestRender();
444
449
  },
445
450
  commitTextUpdate(textInstance, oldText, newText) {
446
451
  textInstance.children = [newText];
447
- textInstance.requestRender();
448
452
  },
449
453
  appendChildToContainer(container, child) {
450
454
  container.add(child);
@@ -454,19 +458,15 @@ var hostConfig = {
454
458
  },
455
459
  hideInstance(instance) {
456
460
  instance.visible = false;
457
- instance.requestRender();
458
461
  },
459
462
  unhideInstance(instance, props) {
460
463
  instance.visible = true;
461
- instance.requestRender();
462
464
  },
463
465
  hideTextInstance(textInstance) {
464
466
  textInstance.visible = false;
465
- textInstance.requestRender();
466
467
  },
467
468
  unhideTextInstance(textInstance, text) {
468
469
  textInstance.visible = true;
469
- textInstance.requestRender();
470
470
  },
471
471
  clearContainer(container) {
472
472
  const children = container.getChildren();
@@ -485,6 +485,12 @@ var hostConfig = {
485
485
  maySuspendCommit() {
486
486
  return false;
487
487
  },
488
+ maySuspendCommitOnUpdate() {
489
+ return false;
490
+ },
491
+ maySuspendCommitInSyncRender() {
492
+ return false;
493
+ },
488
494
  NotPendingTransition: null,
489
495
  HostTransitionContext: createContext2(null),
490
496
  resetFormInstance() {},
@@ -550,7 +556,7 @@ $ bun add react-devtools-core@7 -d
550
556
  }
551
557
  reconciler.injectIntoDevTools();
552
558
  function _render(element, root) {
553
- const container = reconciler.createContainer(root, ConcurrentRoot, null, false, null, "", console.error, console.error, console.error, console.error, null);
559
+ const container = reconciler.createContainer(root, ConcurrentRoot, null, false, null, "", console.error, console.error, console.error, () => {});
554
560
  reconciler.updateContainer(element, container, null, () => {});
555
561
  return container;
556
562
  }
package/index.js CHANGED
@@ -11,9 +11,9 @@ import {
11
11
  getComponentCatalogue,
12
12
  jsxDEV,
13
13
  useAppContext
14
- } from "./chunk-pr7s7hvy.js";
14
+ } from "./chunk-nczcqb5q.js";
15
15
  import"./chunk-2mx7fq49.js";
16
- // src/hooks/use-keyboard.ts
16
+ // src/hooks/use-blur.ts
17
17
  import { useEffect } from "react";
18
18
 
19
19
  // src/hooks/use-event.ts
@@ -29,11 +29,44 @@ function useEffectEvent(handler) {
29
29
  }, []);
30
30
  }
31
31
 
32
+ // src/hooks/use-renderer.ts
33
+ var useRenderer = () => {
34
+ const { renderer } = useAppContext();
35
+ if (!renderer) {
36
+ throw new Error("Renderer not found.");
37
+ }
38
+ return renderer;
39
+ };
40
+
41
+ // src/hooks/use-blur.ts
42
+ var useBlur = (handler) => {
43
+ const renderer = useRenderer();
44
+ const stableHandler = useEffectEvent(handler);
45
+ useEffect(() => {
46
+ renderer.on("blur", stableHandler);
47
+ return () => {
48
+ renderer.off("blur", stableHandler);
49
+ };
50
+ }, [renderer]);
51
+ };
52
+ // src/hooks/use-focus.ts
53
+ import { useEffect as useEffect2 } from "react";
54
+ var useFocus = (handler) => {
55
+ const renderer = useRenderer();
56
+ const stableHandler = useEffectEvent(handler);
57
+ useEffect2(() => {
58
+ renderer.on("focus", stableHandler);
59
+ return () => {
60
+ renderer.off("focus", stableHandler);
61
+ };
62
+ }, [renderer]);
63
+ };
32
64
  // src/hooks/use-keyboard.ts
65
+ import { useEffect as useEffect3 } from "react";
33
66
  var useKeyboard = (handler, options = { release: false }) => {
34
67
  const { keyHandler } = useAppContext();
35
68
  const stableHandler = useEffectEvent(handler);
36
- useEffect(() => {
69
+ useEffect3(() => {
37
70
  keyHandler?.on("keypress", stableHandler);
38
71
  if (options?.release) {
39
72
  keyHandler?.on("keyrelease", stableHandler);
@@ -46,20 +79,24 @@ var useKeyboard = (handler, options = { release: false }) => {
46
79
  };
47
80
  }, [keyHandler, options.release]);
48
81
  };
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;
82
+ // src/hooks/use-paste.ts
83
+ import { useEffect as useEffect4 } from "react";
84
+ var usePaste = (handler) => {
85
+ const { keyHandler } = useAppContext();
86
+ const stableHandler = useEffectEvent(handler);
87
+ useEffect4(() => {
88
+ keyHandler?.on("paste", stableHandler);
89
+ return () => {
90
+ keyHandler?.off("paste", stableHandler);
91
+ };
92
+ }, [keyHandler]);
56
93
  };
57
94
  // src/hooks/use-resize.ts
58
- import { useEffect as useEffect2 } from "react";
95
+ import { useEffect as useEffect5 } from "react";
59
96
  var useOnResize = (callback) => {
60
97
  const renderer = useRenderer();
61
98
  const stableCallback = useEffectEvent(callback);
62
- useEffect2(() => {
99
+ useEffect5(() => {
63
100
  renderer.on("resize", stableCallback);
64
101
  return () => {
65
102
  renderer.off("resize", stableCallback);
@@ -67,6 +104,18 @@ var useOnResize = (callback) => {
67
104
  }, [renderer]);
68
105
  return renderer;
69
106
  };
107
+ // src/hooks/use-selection.ts
108
+ import { useEffect as useEffect6 } from "react";
109
+ var useSelectionHandler = (handler) => {
110
+ const renderer = useRenderer();
111
+ const stableHandler = useEffectEvent(handler);
112
+ useEffect6(() => {
113
+ renderer.on("selection", stableHandler);
114
+ return () => {
115
+ renderer.off("selection", stableHandler);
116
+ };
117
+ }, [renderer]);
118
+ };
70
119
  // src/hooks/use-terminal-dimensions.ts
71
120
  import { useState } from "react";
72
121
  var useTerminalDimensions = () => {
@@ -83,10 +132,10 @@ var useTerminalDimensions = () => {
83
132
  };
84
133
  // src/hooks/use-timeline.ts
85
134
  import { engine, Timeline } from "@opentui/core";
86
- import { useEffect as useEffect3 } from "react";
135
+ import { useEffect as useEffect7 } from "react";
87
136
  var useTimeline = (options = {}) => {
88
137
  const timeline = new Timeline(options);
89
- useEffect3(() => {
138
+ useEffect7(() => {
90
139
  if (!options.autoplay) {
91
140
  timeline.play();
92
141
  }
@@ -102,7 +151,7 @@ var useTimeline = (options = {}) => {
102
151
  import {
103
152
  createSlotRegistry
104
153
  } from "@opentui/core";
105
- import React, { Fragment as Fragment2, useEffect as useEffect4, useMemo, useRef as useRef2, useState as useState2 } from "react";
154
+ import React, { Fragment as Fragment2, useEffect as useEffect8, useMemo, useRef as useRef2, useState as useState2 } from "react";
106
155
  function createReactSlotRegistry(renderer, context, options = {}) {
107
156
  return createSlotRegistry(renderer, "react:slot-registry", context, options);
108
157
  }
@@ -181,12 +230,12 @@ function Slot(props) {
181
230
  const slotName = String(props.name);
182
231
  const renderFailuresByPluginRef = useRef2(new Map);
183
232
  const pendingRenderReportsRef = useRef2(new Map);
184
- useEffect4(() => {
233
+ useEffect8(() => {
185
234
  return registry.subscribe(() => {
186
235
  setVersion((current) => current + 1);
187
236
  });
188
237
  }, [registry]);
189
- useEffect4(() => {
238
+ useEffect8(() => {
190
239
  if (pendingRenderReportsRef.current.size === 0) {
191
240
  return;
192
241
  }
@@ -318,9 +367,13 @@ import { createElement as createElement2 } from "react";
318
367
  export {
319
368
  useTimeline,
320
369
  useTerminalDimensions,
370
+ useSelectionHandler,
321
371
  useRenderer,
372
+ usePaste,
322
373
  useOnResize,
323
374
  useKeyboard,
375
+ useFocus,
376
+ useBlur,
324
377
  useAppContext,
325
378
  getComponentCatalogue,
326
379
  flushSync,
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.2.1",
7
+ "version": "0.2.3",
8
8
  "description": "React renderer for building terminal user interfaces using OpenTUI core",
9
9
  "license": "MIT",
10
10
  "repository": {
@@ -32,6 +32,10 @@
32
32
  "types": "./scripts/runtime-plugin-support.d.ts",
33
33
  "import": "./scripts/runtime-plugin-support.ts"
34
34
  },
35
+ "./runtime-plugin-support/configure": {
36
+ "types": "./scripts/runtime-plugin-support-configure.d.ts",
37
+ "import": "./scripts/runtime-plugin-support-configure.ts"
38
+ },
35
39
  "./jsx-runtime": {
36
40
  "types": "./jsx-runtime.d.ts",
37
41
  "import": "./jsx-runtime.js",
@@ -44,23 +48,23 @@
44
48
  }
45
49
  },
46
50
  "dependencies": {
47
- "@opentui/core": "0.2.1",
48
- "react-reconciler": "^0.32.0"
51
+ "@opentui/core": "0.2.3",
52
+ "react-reconciler": "^0.33.0"
49
53
  },
50
54
  "devDependencies": {
51
55
  "@opentui/keymap": "workspace:*",
52
56
  "@types/bun": "latest",
53
57
  "@types/node": "^24.0.0",
54
- "@types/react": "^19.0.0",
55
- "@types/react-reconciler": "^0.32.0",
58
+ "@types/react": "^19.2.0",
59
+ "@types/react-reconciler": "^0.33.0",
56
60
  "@types/ws": "^8.18.1",
57
- "react": ">=19.0.0",
61
+ "react": ">=19.2.0",
58
62
  "react-devtools-core": "^7.0.1",
59
63
  "typescript": "^5",
60
64
  "ws": "^8.18.0"
61
65
  },
62
66
  "peerDependencies": {
63
- "react": ">=19.0.0",
67
+ "react": ">=19.2.0",
64
68
  "react-devtools-core": "^7.0.1",
65
69
  "ws": "^8.18.0"
66
70
  }
@@ -0,0 +1,7 @@
1
+ import { type RuntimeModuleEntry, type RuntimePluginRewriteOptions } from "@opentui/core/runtime-plugin";
2
+ export interface ReactRuntimePluginSupportOptions {
3
+ additional?: Record<string, RuntimeModuleEntry>;
4
+ core?: RuntimeModuleEntry;
5
+ rewrite?: RuntimePluginRewriteOptions;
6
+ }
7
+ export declare function ensureRuntimePluginSupport(options?: ReactRuntimePluginSupportOptions): boolean;
@@ -0,0 +1,99 @@
1
+ import { plugin as registerBunPlugin } from "bun"
2
+ import * as coreRuntime from "@opentui/core"
3
+ import {
4
+ createRuntimePlugin,
5
+ type RuntimeModuleEntry,
6
+ type RuntimePluginRewriteOptions,
7
+ } from "@opentui/core/runtime-plugin"
8
+ import * as reactRuntime from "react"
9
+ import * as reactJsxRuntime from "react/jsx-runtime"
10
+ import * as reactJsxDevRuntime from "react/jsx-dev-runtime"
11
+ import * as opentuiReactRuntime from "../index.js"
12
+
13
+ const runtimePluginSupportInstalledKey = "__opentuiReactRuntimePluginSupportInstalled__"
14
+
15
+ export interface ReactRuntimePluginSupportOptions {
16
+ additional?: Record<string, RuntimeModuleEntry>
17
+ core?: RuntimeModuleEntry
18
+ rewrite?: RuntimePluginRewriteOptions
19
+ }
20
+
21
+ interface RuntimePluginSupportInstall {
22
+ specifiers: ReadonlySet<string>
23
+ core: RuntimeModuleEntry
24
+ rewriteKey: string
25
+ }
26
+
27
+ type RuntimePluginSupportState = typeof globalThis & {
28
+ [runtimePluginSupportInstalledKey]?: RuntimePluginSupportInstall
29
+ }
30
+
31
+ const defaultRuntimeModules: Record<string, RuntimeModuleEntry> = {
32
+ "@opentui/react": opentuiReactRuntime as Record<string, unknown>,
33
+ "@opentui/react/jsx-runtime": reactJsxRuntime as Record<string, unknown>,
34
+ "@opentui/react/jsx-dev-runtime": reactJsxDevRuntime as Record<string, unknown>,
35
+ react: reactRuntime as Record<string, unknown>,
36
+ "react/jsx-runtime": reactJsxRuntime as Record<string, unknown>,
37
+ "react/jsx-dev-runtime": reactJsxDevRuntime as Record<string, unknown>,
38
+ }
39
+
40
+ function normalizeRewriteKey(rewrite: RuntimePluginRewriteOptions | undefined): string {
41
+ return `${rewrite?.nodeModulesRuntimeSpecifiers ?? true}:${rewrite?.nodeModulesBareSpecifiers ?? false}`
42
+ }
43
+
44
+ function createRuntimeModules(options?: ReactRuntimePluginSupportOptions): Record<string, RuntimeModuleEntry> {
45
+ return {
46
+ ...defaultRuntimeModules,
47
+ ...(options?.additional ?? {}),
48
+ }
49
+ }
50
+
51
+ function assertCompatibleInstall(
52
+ install: RuntimePluginSupportInstall,
53
+ modules: Record<string, RuntimeModuleEntry>,
54
+ options?: ReactRuntimePluginSupportOptions,
55
+ ): void {
56
+ for (const specifier of Object.keys(modules)) {
57
+ if (!install.specifiers.has(specifier)) {
58
+ throw new Error(
59
+ `OpenTUI React runtime plugin support is already installed without ${specifier}. Call ensureRuntimePluginSupport({ additional }) from @opentui/react/runtime-plugin-support/configure before importing @opentui/react/runtime-plugin-support.`,
60
+ )
61
+ }
62
+ }
63
+
64
+ if (options?.core && options.core !== install.core) {
65
+ throw new Error("OpenTUI React runtime plugin support is already installed with a different core runtime module.")
66
+ }
67
+
68
+ if (options?.rewrite && normalizeRewriteKey(options.rewrite) !== install.rewriteKey) {
69
+ throw new Error("OpenTUI React runtime plugin support is already installed with different rewrite options.")
70
+ }
71
+ }
72
+
73
+ export function ensureRuntimePluginSupport(options: ReactRuntimePluginSupportOptions = {}): boolean {
74
+ const state = globalThis as RuntimePluginSupportState
75
+ const modules = createRuntimeModules(options)
76
+ const core = options.core ?? (coreRuntime as Record<string, unknown>)
77
+ const rewriteKey = normalizeRewriteKey(options.rewrite)
78
+
79
+ const install = state[runtimePluginSupportInstalledKey]
80
+ if (install) {
81
+ assertCompatibleInstall(install, modules, options)
82
+ return false
83
+ }
84
+
85
+ registerBunPlugin(
86
+ createRuntimePlugin({
87
+ core,
88
+ additional: modules,
89
+ rewrite: options.rewrite,
90
+ }),
91
+ )
92
+
93
+ state[runtimePluginSupportInstalledKey] = {
94
+ specifiers: new Set(Object.keys(modules)),
95
+ core,
96
+ rewriteKey,
97
+ }
98
+ return true
99
+ }
@@ -1 +1,3 @@
1
- export declare function ensureRuntimePluginSupport(): boolean;
1
+ import { ensureRuntimePluginSupport } from "./runtime-plugin-support-configure.js";
2
+ export { ensureRuntimePluginSupport };
3
+ export type { ReactRuntimePluginSupportOptions } from "./runtime-plugin-support-configure.js";
@@ -1,42 +1,6 @@
1
- import { plugin as registerBunPlugin } from "bun"
2
- import * as coreRuntime from "@opentui/core"
3
- import { createRuntimePlugin, type RuntimeModuleEntry } from "@opentui/core/runtime-plugin"
4
- import * as reactRuntime from "react"
5
- import * as reactJsxRuntime from "react/jsx-runtime"
6
- import * as reactJsxDevRuntime from "react/jsx-dev-runtime"
7
- import * as opentuiReactRuntime from "../index.js"
1
+ import { ensureRuntimePluginSupport } from "./runtime-plugin-support-configure.js"
8
2
 
9
- const runtimePluginSupportInstalledKey = "__opentuiReactRuntimePluginSupportInstalled__"
10
-
11
- type RuntimePluginSupportState = typeof globalThis & {
12
- [runtimePluginSupportInstalledKey]?: boolean
13
- }
14
-
15
- const additionalRuntimeModules: Record<string, RuntimeModuleEntry> = {
16
- "@opentui/react": opentuiReactRuntime as Record<string, unknown>,
17
- "@opentui/react/jsx-runtime": reactJsxRuntime as Record<string, unknown>,
18
- "@opentui/react/jsx-dev-runtime": reactJsxDevRuntime as Record<string, unknown>,
19
- react: reactRuntime as Record<string, unknown>,
20
- "react/jsx-runtime": reactJsxRuntime as Record<string, unknown>,
21
- "react/jsx-dev-runtime": reactJsxDevRuntime as Record<string, unknown>,
22
- }
23
-
24
- export function ensureRuntimePluginSupport(): boolean {
25
- const state = globalThis as RuntimePluginSupportState
26
-
27
- if (state[runtimePluginSupportInstalledKey]) {
28
- return false
29
- }
30
-
31
- registerBunPlugin(
32
- createRuntimePlugin({
33
- core: coreRuntime as Record<string, unknown>,
34
- additional: additionalRuntimeModules,
35
- }),
36
- )
37
-
38
- state[runtimePluginSupportInstalledKey] = true
39
- return true
40
- }
3
+ export { ensureRuntimePluginSupport }
4
+ export type { ReactRuntimePluginSupportOptions } from "./runtime-plugin-support-configure.js"
41
5
 
42
6
  ensureRuntimePluginSupport()
@@ -1,5 +1,9 @@
1
+ export * from "./use-blur.js";
2
+ export * from "./use-focus.js";
1
3
  export * from "./use-keyboard.js";
4
+ export * from "./use-paste.js";
2
5
  export * from "./use-renderer.js";
3
6
  export * from "./use-resize.js";
7
+ export * from "./use-selection.js";
4
8
  export * from "./use-terminal-dimensions.js";
5
9
  export * from "./use-timeline.js";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Subscribe to terminal window blur events.
3
+ * Fires when the terminal window loses focus.
4
+ *
5
+ * @example
6
+ * useBlur(() => {
7
+ * console.log("Terminal lost focus")
8
+ * })
9
+ */
10
+ export declare const useBlur: (handler: () => void) => void;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Subscribe to terminal window focus events.
3
+ * Fires when the terminal window gains focus.
4
+ *
5
+ * @example
6
+ * useFocus(() => {
7
+ * console.log("Terminal gained focus")
8
+ * })
9
+ */
10
+ export declare const useFocus: (handler: () => void) => void;
@@ -0,0 +1,10 @@
1
+ import type { PasteEvent } from "@opentui/core";
2
+ /**
3
+ * Subscribe to terminal paste events (bracketed paste).
4
+ *
5
+ * @example
6
+ * usePaste((event) => {
7
+ * console.log("Pasted:", event.text)
8
+ * })
9
+ */
10
+ export declare const usePaste: (handler: (event: PasteEvent) => void) => void;
@@ -0,0 +1,12 @@
1
+ import type { Selection } from "@opentui/core";
2
+ /**
3
+ * Subscribe to text selection events.
4
+ * Fires when the user selects text in the terminal (e.g., via mouse drag).
5
+ *
6
+ * @example
7
+ * useSelectionHandler((selection) => {
8
+ * const text = selection.getSelectedText()
9
+ * console.log("Selected:", text)
10
+ * })
11
+ */
12
+ export declare const useSelectionHandler: (handler: (selection: Selection) => void) => void;
@@ -1,9 +1,16 @@
1
1
  import type { HostConfig } from "react-reconciler";
2
2
  import type { Container, HostContext, Instance, Props, PublicInstance, TextInstance, Type } from "../types/host.js";
3
+ type ReconcilerExtensions = {
4
+ maySuspendCommitOnUpdate(type: Type, oldProps: Props, newProps: Props): boolean;
5
+ maySuspendCommitInSyncRender(type: Type, props: Props): boolean;
6
+ rendererPackageName: string;
7
+ rendererVersion: string;
8
+ };
3
9
  export declare const hostConfig: HostConfig<Type, Props, Container, Instance, TextInstance, unknown, // SuspenseInstance
4
10
  unknown, // HydratableInstance
5
11
  unknown, // FormInstance
6
12
  PublicInstance, HostContext, unknown, // ChildSet
7
13
  unknown, // TimeoutHandle
8
14
  unknown, // NoTimeout
9
- unknown>;
15
+ unknown> & ReconcilerExtensions;
16
+ export {};
@@ -3,6 +3,9 @@ import { type ReactNode } from "react";
3
3
  declare const flushSync: {
4
4
  (): void;
5
5
  <R>(fn: () => R): R;
6
+ } & {
7
+ (): void;
8
+ <R>(fn: () => R): R;
6
9
  };
7
10
  declare const createPortal: (children: ReactNode, containerInfo: any, implementation: any, key?: string | null) => import("react-reconciler").ReactPortal;
8
11
  export type Root = {
package/test-utils.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  createRoot
4
- } from "./chunk-pr7s7hvy.js";
4
+ } from "./chunk-nczcqb5q.js";
5
5
  import"./chunk-2mx7fq49.js";
6
6
 
7
7
  // src/test-utils.ts