@octanejs/opentui 0.0.1
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 +21 -0
- package/LICENSE.upstream +21 -0
- package/README.md +120 -0
- package/UPSTREAM.md +63 -0
- package/package.json +62 -0
- package/src/components.ts +63 -0
- package/src/config.ts +32 -0
- package/src/context.ts +16 -0
- package/src/driver.ts +538 -0
- package/src/hooks.ts +168 -0
- package/src/index.ts +9 -0
- package/src/intrinsics.ts +16 -0
- package/src/props.ts +198 -0
- package/src/renderer.ts +11 -0
- package/src/root.ts +120 -0
- package/src/scheduling.ts +78 -0
- package/src/slot.ts +322 -0
- package/src/slots.ts +21 -0
- package/src/test-utils.ts +38 -0
- package/src/text.ts +73 -0
- package/src/time-to-first-draw.ts +23 -0
- package/src/types.ts +230 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dominic Gannaway
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/LICENSE.upstream
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 opentui
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# `@octanejs/opentui`
|
|
2
|
+
|
|
3
|
+
An experimental Octane renderer for [OpenTUI](https://github.com/anomalyco/opentui),
|
|
4
|
+
tracking the public binding surface of `@opentui/react@0.5.8` without embedding
|
|
5
|
+
React Reconciler. Octane owns component execution, hooks, context, scheduling,
|
|
6
|
+
errors, refs, and effects; `@opentui/core` continues to own terminal layout,
|
|
7
|
+
input, rendering, and native resources.
|
|
8
|
+
|
|
9
|
+
## Runtime requirements
|
|
10
|
+
|
|
11
|
+
OpenTUI 0.5.8 requires either Bun 1.3 or newer, or Node.js 26.4 or newer with
|
|
12
|
+
`--experimental-ffi`. This package does not add a JavaScript fallback for
|
|
13
|
+
OpenTUI's native Zig renderer.
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pnpm add @octanejs/opentui @opentui/core
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Compiler configuration
|
|
20
|
+
|
|
21
|
+
OpenTUI components live in `*.opentui.tsrx` modules. Add the serializable
|
|
22
|
+
renderer preset to the Octane Vite, Rsbuild, or Rspack compiler configuration:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { defineConfig } from '@octanejs/vite-plugin';
|
|
26
|
+
import { opentuiRenderers } from '@octanejs/opentui/config';
|
|
27
|
+
|
|
28
|
+
export default defineConfig({
|
|
29
|
+
compiler: {
|
|
30
|
+
renderers: opentuiRenderers,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The preset uses OpenTUI host text, supports retained visibility and same-renderer
|
|
36
|
+
portals, and rejects server compilation. Terminal trees have no HTML SSR or
|
|
37
|
+
hydration path.
|
|
38
|
+
|
|
39
|
+
## Rendering an application
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
// App.opentui.tsrx
|
|
43
|
+
import { useKeyboard, useTerminalDimensions } from '@octanejs/opentui';
|
|
44
|
+
import { useState } from 'octane';
|
|
45
|
+
|
|
46
|
+
export function App() @{
|
|
47
|
+
const [count, setCount] = useState(0);
|
|
48
|
+
const size = useTerminalDimensions();
|
|
49
|
+
|
|
50
|
+
useKeyboard((event) => {
|
|
51
|
+
if (event.name === 'return') setCount((value) => value + 1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
<box style={{ flexDirection: 'column', padding: 1 }}>
|
|
55
|
+
<text>{'Count: ' + count}</text>
|
|
56
|
+
<text>{'Terminal: ' + size.width + 'x' + size.height}</text>
|
|
57
|
+
</box>
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { createCliRenderer } from '@opentui/core';
|
|
63
|
+
import { createRoot } from '@octanejs/opentui';
|
|
64
|
+
import { App } from './App.opentui.tsrx';
|
|
65
|
+
|
|
66
|
+
const renderer = await createCliRenderer();
|
|
67
|
+
const root = createRoot(renderer);
|
|
68
|
+
root.render(App);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`createRoot(renderer).render(Component, props)` follows Octane's programmatic
|
|
72
|
+
root convention. Destroying the `CliRenderer` unmounts the Octane root, and
|
|
73
|
+
`root.unmount()` releases component state, effects, listeners, refs, portals,
|
|
74
|
+
and owned renderables without destroying the caller-owned renderer.
|
|
75
|
+
|
|
76
|
+
## Surface
|
|
77
|
+
|
|
78
|
+
The built-in intrinsic catalogue matches OpenTUI React 0.5.8: `box`, `text`,
|
|
79
|
+
`code`, `diff`, `markdown`, `input`, `select`, `textarea`, `scrollbox`,
|
|
80
|
+
`ascii-font`, `tab-select`, `line-number`, `image`, `time-to-first-draw`, and
|
|
81
|
+
the text modifiers `span`, `br`, `b`, `strong`, `i`, `em`, `u`, and `a`.
|
|
82
|
+
Register application renderables with `extend()` and augment
|
|
83
|
+
`OpenTUIComponents` for their intrinsic types.
|
|
84
|
+
|
|
85
|
+
The binding exports `useRenderer`, `useKeyboard`, `usePaste`, `useFocus`,
|
|
86
|
+
`useBlur`, `useSelectionHandler`, `useOnResize`, `useTerminalDimensions`, and
|
|
87
|
+
`useTimeline`. OpenTUI callback names and argument lists are preserved: for
|
|
88
|
+
example, select `onChange(index, option)` remains a two-argument OpenTUI event,
|
|
89
|
+
not a DOM synthetic event.
|
|
90
|
+
|
|
91
|
+
`createPortal(children, target)` accepts a borrowed `RootRenderable` created
|
|
92
|
+
from the same `CliRenderer` context. Portal teardown removes only Octane-owned
|
|
93
|
+
children; the target remains caller-owned.
|
|
94
|
+
|
|
95
|
+
The OpenTUI slot system is available as `createOctaneSlotRegistry`, `Slot`, and
|
|
96
|
+
`createSlot`; `createReactSlotRegistry` and the upstream `React*` type names are
|
|
97
|
+
retained as migration aliases. Plugins return Octane universal renderables
|
|
98
|
+
instead of React nodes, and plugin failures are reported to the core registry
|
|
99
|
+
with source `"octane"`.
|
|
100
|
+
|
|
101
|
+
For native integration tests, `@octanejs/opentui/test-utils` exports
|
|
102
|
+
`testRender(Component, props, options)`. The package's focused test command runs
|
|
103
|
+
Vitest with Bun so the OpenTUI FFI-backed test renderer is available.
|
|
104
|
+
|
|
105
|
+
## Differences from `@opentui/react`
|
|
106
|
+
|
|
107
|
+
- Components are authored in `.opentui.tsrx`; the package does not export
|
|
108
|
+
React's `createElement` or accept React elements.
|
|
109
|
+
- Programmatic roots render an Octane component plus props rather than a React
|
|
110
|
+
node.
|
|
111
|
+
- Refs are ordinary Octane props and can be composed with `ref={[a, b]}`; there
|
|
112
|
+
is no `forwardRef` layer.
|
|
113
|
+
- Octane's compiler-assigned hook slots permit hooks behind conditions and
|
|
114
|
+
after early returns. The exported hooks forward manual slots internally.
|
|
115
|
+
- React DevTools integration and OpenTUI's React runtime-plugin bundling
|
|
116
|
+
subpaths are not included. Compiler setup uses `opentuiRenderers` instead.
|
|
117
|
+
- OpenTUI terminal rendering is client-only; SSR and hydration are unsupported.
|
|
118
|
+
|
|
119
|
+
The compatibility baseline and verified scope are recorded in
|
|
120
|
+
[`status.json`](./status.json).
|
package/UPSTREAM.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# OpenTUI React upstream contract
|
|
2
|
+
|
|
3
|
+
## Pin and source boundary
|
|
4
|
+
|
|
5
|
+
| Field | Value |
|
|
6
|
+
|---|---|
|
|
7
|
+
| Package | `@opentui/react` |
|
|
8
|
+
| Version | `0.5.8` |
|
|
9
|
+
| Canonical commit | `21b002174255ca2236ed3115e2bb2294642f2cf5` |
|
|
10
|
+
| Supported upstream range | exactly `0.5.8` |
|
|
11
|
+
| npm integrity | `sha512-l3N/Kbg5V+OABp60A5iCfEj3WK5pKVUDmUrVPf/xgct9R7Xy2Jbw/0MoSFpgr3odq3CuWprYajnoLCR9f81BRQ==` |
|
|
12
|
+
| License | MIT |
|
|
13
|
+
|
|
14
|
+
The complete `packages/react` subtree from the canonical commit is committed
|
|
15
|
+
byte-for-byte under `upstream/`. Every file verifies offline against its Git
|
|
16
|
+
blob hash in `audit/upstream.lock.json`. The repository-root license is retained
|
|
17
|
+
byte-for-byte as `LICENSE.upstream`; the Octane-authored binding remains under
|
|
18
|
+
the repository MIT license in `LICENSE`.
|
|
19
|
+
|
|
20
|
+
The authored port lives in `src/`. It reuses `@opentui/core@0.5.8` unchanged and
|
|
21
|
+
independently reimplements the React renderer, reconciliation, DevTools
|
|
22
|
+
transport boundary, and WebSocket dependency through Octane's universal host
|
|
23
|
+
driver and existing runtime instrumentation. No `react`, `react-reconciler`,
|
|
24
|
+
`react-devtools-core`, or `ws` source is copied into the binding.
|
|
25
|
+
|
|
26
|
+
## Export crosswalk
|
|
27
|
+
|
|
28
|
+
| Upstream export group | Octane disposition | Evidence |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `createRoot`, `Root`, `flushSync`, `createPortal` | Ported to Octane's universal renderer; roots take a component and props separately and portals target a same-renderer `RootRenderable` | `src/root.ts`, `src/scheduling.ts`, native integration tests |
|
|
31
|
+
| `baseComponents`, `componentCatalogue`, `extend`, `getComponentCatalogue` | Ported with the complete OpenTUI 0.5.8 built-in catalogue and custom renderable extension | `src/components.ts`, config tests |
|
|
32
|
+
| `AppContext`, `useAppContext` | Ported to Octane universal context | `src/context.ts`, native integration tests |
|
|
33
|
+
| `useRenderer`, keyboard, paste, focus, blur, selection, resize, dimensions, and timeline hooks | Ported to Octane hooks with compiler-owned slots and native OpenTUI subscriptions | `src/hooks.ts`, native integration tests |
|
|
34
|
+
| `createReactSlotRegistry`, `Slot`, `createSlot`, and `React*` slot types | Ported over OpenTUI core's slot registry; React-named APIs remain migration aliases for canonical `Octane*` APIs | `src/slot.ts`, native slot tests |
|
|
35
|
+
| `TimeToFirstDraw`, `TimeToFirstDrawProps` | Ported as a universal renderer component | `src/time-to-first-draw.ts`, public source typecheck |
|
|
36
|
+
| component prop types, `RenderableConstructor`, extension types, and `OpenTUIComponents` | Ported with `OctaneNode`, ordinary ref props, and renderer-specific intrinsic types | `src/types.ts`, published-source checks |
|
|
37
|
+
| `testRender` | Adapted to accept an Octane component plus props and execute against `@opentui/core/testing` | `src/test-utils.ts`, native integration tests |
|
|
38
|
+
| `./renderer` | Ported as the renderer/runtime surface plus the OpenTUI host driver | `src/renderer.ts` |
|
|
39
|
+
| `./jsx-runtime`, `./jsx-dev-runtime` | Replaced by the compiler-facing `./intrinsics` and `./intrinsics/jsx-runtime` entries | `src/intrinsics.ts`, config tests |
|
|
40
|
+
| `createElement` | Intentional divergence: Octane component trees are authored in `.opentui.tsrx`; nested runtime element construction is not supported | `README.md`, `docs/differences-from-react.md` |
|
|
41
|
+
| React runtime-plugin support entries | Inapplicable: applications configure the Octane compiler with `opentuiRenderers`; no runtime JSX rewrite is needed | `src/config.ts`, config tests |
|
|
42
|
+
| React Reconciler and React DevTools internals | Reimplemented by Octane's universal host driver and runtime instrumentation; these are not binding public exports | `src/driver.ts`, native lifecycle and identity tests |
|
|
43
|
+
|
|
44
|
+
## Upstream test-suite disposition
|
|
45
|
+
|
|
46
|
+
The pinned upstream suite contains 56 runtime registrations across seven test
|
|
47
|
+
files. It remains fully visible under `upstream/tests`; fixtures beside those
|
|
48
|
+
suites are preserved but are not registrations.
|
|
49
|
+
|
|
50
|
+
| Upstream area | Disposition |
|
|
51
|
+
|---|---|
|
|
52
|
+
| root teardown and renderer-destroy races | Covered by the native coordinated-cleanup test |
|
|
53
|
+
| image loading, rerender retention, prop reset, cancellation, and abandoned renders | Public image props and host lifecycle are ported; focused image parity remains an explicit follow-up rather than a claimed passing lane |
|
|
54
|
+
| text, layout, prop reset, keyed reconciliation, focus, and intrinsic catalogue behavior | Covered at the binding boundary by native frame, state/prop update, identity, callback, and config tests; the core layout engine itself is reused unchanged |
|
|
55
|
+
| link behavior | Intrinsic and prop surface ported; terminal escape rendering remains owned by unchanged `@opentui/core` |
|
|
56
|
+
| runtime-plugin configuration | Inapplicable because Octane compiles `.opentui.tsrx` ahead of time and exports a serializable renderer preset |
|
|
57
|
+
| slot modes, ordering, failures, context, identity, and teardown | Representative append/fallback, registration, error, identity, and teardown behavior covered by native slot tests |
|
|
58
|
+
| timeline identity | Hook implementation preserves one `Timeline` per component instance; direct adapted case remains an explicit follow-up |
|
|
59
|
+
|
|
60
|
+
The parity manifest is deliberately `recorded-unverified`: the pin and current
|
|
61
|
+
Octane-specific behavioral lanes are machine-checked, but this change does not
|
|
62
|
+
claim that all 56 React-owned upstream registrations have been adapted one for
|
|
63
|
+
one.
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@octanejs/opentui",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22.22.2"
|
|
9
|
+
},
|
|
10
|
+
"octane": {
|
|
11
|
+
"hookSlots": {
|
|
12
|
+
"manual": [
|
|
13
|
+
"src"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"description": "OpenTUI bindings for Octane — terminal components, hooks, and a universal renderer over @opentui/core.",
|
|
18
|
+
"author": {
|
|
19
|
+
"name": "Dominic Gannaway",
|
|
20
|
+
"email": "dg@domgan.com"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/octanejs/octane.git",
|
|
28
|
+
"directory": "packages/opentui"
|
|
29
|
+
},
|
|
30
|
+
"main": "src/index.ts",
|
|
31
|
+
"module": "src/index.ts",
|
|
32
|
+
"types": "src/index.ts",
|
|
33
|
+
"files": [
|
|
34
|
+
"src",
|
|
35
|
+
"LICENSE",
|
|
36
|
+
"LICENSE.upstream",
|
|
37
|
+
"README.md",
|
|
38
|
+
"UPSTREAM.md"
|
|
39
|
+
],
|
|
40
|
+
"exports": {
|
|
41
|
+
".": "./src/index.ts",
|
|
42
|
+
"./config": "./src/config.ts",
|
|
43
|
+
"./renderer": "./src/renderer.ts",
|
|
44
|
+
"./intrinsics": "./src/intrinsics.ts",
|
|
45
|
+
"./intrinsics/jsx-runtime": "./src/intrinsics.ts",
|
|
46
|
+
"./test-utils": "./src/test-utils.ts"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@opentui/core": ">=0.5.8 <0.6.0",
|
|
50
|
+
"octane": "0.1.46"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@opentui/core": "0.5.8",
|
|
54
|
+
"vitest": "^4.1.10",
|
|
55
|
+
"octane": "0.1.46"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"test": "vitest run --root ../.. --project opentui && pnpm test:native",
|
|
59
|
+
"test:native": "NODE_OPTIONS= REACT_PORT_TEST_REPORT_DIR= bun ../../node_modules/vitest/vitest.mjs run --config vitest.native.config.ts",
|
|
60
|
+
"typecheck": "tsrx-tsc --noEmit"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ASCIIFontRenderable,
|
|
3
|
+
BoxRenderable,
|
|
4
|
+
CodeRenderable,
|
|
5
|
+
DiffRenderable,
|
|
6
|
+
ImageRenderable,
|
|
7
|
+
InputRenderable,
|
|
8
|
+
LineNumberRenderable,
|
|
9
|
+
MarkdownRenderable,
|
|
10
|
+
ScrollBoxRenderable,
|
|
11
|
+
SelectRenderable,
|
|
12
|
+
TabSelectRenderable,
|
|
13
|
+
TextareaRenderable,
|
|
14
|
+
TextRenderable,
|
|
15
|
+
TimeToFirstDrawRenderable,
|
|
16
|
+
} from '@opentui/core';
|
|
17
|
+
import type { RenderableConstructor } from './types.js';
|
|
18
|
+
import {
|
|
19
|
+
BoldSpanRenderable,
|
|
20
|
+
ItalicSpanRenderable,
|
|
21
|
+
LineBreakRenderable,
|
|
22
|
+
LinkRenderable,
|
|
23
|
+
SpanRenderable,
|
|
24
|
+
UnderlineSpanRenderable,
|
|
25
|
+
} from './text.js';
|
|
26
|
+
|
|
27
|
+
export const baseComponents = {
|
|
28
|
+
box: BoxRenderable,
|
|
29
|
+
text: TextRenderable,
|
|
30
|
+
code: CodeRenderable,
|
|
31
|
+
diff: DiffRenderable,
|
|
32
|
+
markdown: MarkdownRenderable,
|
|
33
|
+
input: InputRenderable,
|
|
34
|
+
select: SelectRenderable,
|
|
35
|
+
textarea: TextareaRenderable,
|
|
36
|
+
scrollbox: ScrollBoxRenderable,
|
|
37
|
+
'ascii-font': ASCIIFontRenderable,
|
|
38
|
+
'tab-select': TabSelectRenderable,
|
|
39
|
+
'line-number': LineNumberRenderable,
|
|
40
|
+
image: ImageRenderable,
|
|
41
|
+
'time-to-first-draw': TimeToFirstDrawRenderable,
|
|
42
|
+
span: SpanRenderable,
|
|
43
|
+
br: LineBreakRenderable,
|
|
44
|
+
b: BoldSpanRenderable,
|
|
45
|
+
strong: BoldSpanRenderable,
|
|
46
|
+
i: ItalicSpanRenderable,
|
|
47
|
+
em: ItalicSpanRenderable,
|
|
48
|
+
u: UnderlineSpanRenderable,
|
|
49
|
+
a: LinkRenderable,
|
|
50
|
+
} as const;
|
|
51
|
+
|
|
52
|
+
export type ComponentCatalogue = Record<string, RenderableConstructor>;
|
|
53
|
+
|
|
54
|
+
export const componentCatalogue: ComponentCatalogue = { ...baseComponents };
|
|
55
|
+
|
|
56
|
+
/** Add application-specific OpenTUI renderables to the intrinsic catalogue. */
|
|
57
|
+
export function extend<T extends ComponentCatalogue>(objects: T): void {
|
|
58
|
+
Object.assign(componentCatalogue, objects);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function getComponentCatalogue(): ComponentCatalogue {
|
|
62
|
+
return componentCatalogue;
|
|
63
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Serializable compiler metadata for OpenTUI-rendered TSRX modules. */
|
|
2
|
+
export const OPENTUI_RENDERER_ID = 'opentui';
|
|
3
|
+
|
|
4
|
+
export const opentuiRenderer = {
|
|
5
|
+
module: '@octanejs/opentui/renderer',
|
|
6
|
+
target: 'universal',
|
|
7
|
+
server: 'unsupported',
|
|
8
|
+
intrinsics: '@octanejs/opentui/intrinsics',
|
|
9
|
+
text: 'host',
|
|
10
|
+
capabilities: ['portal', 'visibility'],
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
export const opentuiRendererRegistry = {
|
|
14
|
+
[OPENTUI_RENDERER_ID]: opentuiRenderer,
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
export const opentuiRendererRules = [
|
|
18
|
+
{
|
|
19
|
+
include: '**/*.opentui.tsrx',
|
|
20
|
+
renderer: OPENTUI_RENDERER_ID,
|
|
21
|
+
},
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
24
|
+
export const opentuiRenderers = {
|
|
25
|
+
registry: opentuiRendererRegistry,
|
|
26
|
+
rules: opentuiRendererRules,
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
/** Short compatibility name for application config files. */
|
|
30
|
+
export const renderers = opentuiRenderers;
|
|
31
|
+
|
|
32
|
+
export default opentuiRenderers;
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CliRenderer, KeyHandler } from '@opentui/core';
|
|
2
|
+
import { createContext, useContext } from 'octane/universal';
|
|
3
|
+
|
|
4
|
+
export interface AppContextValue {
|
|
5
|
+
keyHandler: KeyHandler | null;
|
|
6
|
+
renderer: CliRenderer | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const AppContext = createContext<AppContextValue>({
|
|
10
|
+
keyHandler: null,
|
|
11
|
+
renderer: null,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export function useAppContext(): AppContextValue {
|
|
15
|
+
return useContext(AppContext);
|
|
16
|
+
}
|