@opentui/react 0.0.0-20250926-77b41db5 → 0.0.0-20250929-69eb6c87
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 +135 -0
- package/index.js +26 -7
- package/package.json +2 -2
- package/src/hooks/index.d.ts +5 -0
- package/src/hooks/use-timeline.d.ts +2 -0
- package/src/index.d.ts +1 -4
- package/src/reconciler/renderer.js +2 -1
package/README.md
CHANGED
|
@@ -188,6 +188,58 @@ function App() {
|
|
|
188
188
|
|
|
189
189
|
**Returns:** An object with `width` and `height` properties representing the current terminal dimensions.
|
|
190
190
|
|
|
191
|
+
#### `useTimeline(options?)`
|
|
192
|
+
|
|
193
|
+
Create and manage animations using OpenTUI's timeline system. This hook automatically registers and unregisters the timeline with the animation engine.
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
import { render, useTimeline } from "@opentui/react"
|
|
197
|
+
import { useEffect, useState } from "react"
|
|
198
|
+
|
|
199
|
+
function App() {
|
|
200
|
+
const [width, setWidth] = useState(0)
|
|
201
|
+
|
|
202
|
+
const timeline = useTimeline({
|
|
203
|
+
duration: 2000,
|
|
204
|
+
loop: false,
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
timeline.add(
|
|
209
|
+
{
|
|
210
|
+
width,
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
width: 50,
|
|
214
|
+
duration: 2000,
|
|
215
|
+
ease: "linear",
|
|
216
|
+
onUpdate: (animation) => {
|
|
217
|
+
setWidth(animation.targets[0].width)
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
)
|
|
221
|
+
}, [])
|
|
222
|
+
|
|
223
|
+
return <box style={{ width, backgroundColor: "#6a5acd" }} />
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Parameters:**
|
|
228
|
+
|
|
229
|
+
- `options?`: Optional `TimelineOptions` object with properties:
|
|
230
|
+
- `duration?`: Animation duration in milliseconds (default: 1000)
|
|
231
|
+
- `loop?`: Whether the timeline should loop (default: false)
|
|
232
|
+
- `autoplay?`: Whether to automatically start the timeline (default: true)
|
|
233
|
+
- `onComplete?`: Callback when timeline completes
|
|
234
|
+
- `onPause?`: Callback when timeline is paused
|
|
235
|
+
|
|
236
|
+
**Returns:** A `Timeline` instance with methods:
|
|
237
|
+
|
|
238
|
+
- `add(target, properties, startTime)`: Add animation to timeline
|
|
239
|
+
- `play()`: Start the timeline
|
|
240
|
+
- `pause()`: Pause the timeline
|
|
241
|
+
- `restart()`: Restart the timeline from beginning
|
|
242
|
+
|
|
191
243
|
## Components
|
|
192
244
|
|
|
193
245
|
### Text Component
|
|
@@ -504,6 +556,89 @@ function App() {
|
|
|
504
556
|
render(<App />)
|
|
505
557
|
```
|
|
506
558
|
|
|
559
|
+
### System Monitor Animation
|
|
560
|
+
|
|
561
|
+
```tsx
|
|
562
|
+
import { TextAttributes } from "@opentui/core"
|
|
563
|
+
import { render, useTimeline } from "@opentui/react"
|
|
564
|
+
import { useEffect, useState } from "react"
|
|
565
|
+
|
|
566
|
+
type Stats = {
|
|
567
|
+
cpu: number
|
|
568
|
+
memory: number
|
|
569
|
+
network: number
|
|
570
|
+
disk: number
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
export const App = () => {
|
|
574
|
+
const [stats, setAnimatedStats] = useState<Stats>({
|
|
575
|
+
cpu: 0,
|
|
576
|
+
memory: 0,
|
|
577
|
+
network: 0,
|
|
578
|
+
disk: 0,
|
|
579
|
+
})
|
|
580
|
+
|
|
581
|
+
const timeline = useTimeline({
|
|
582
|
+
duration: 3000,
|
|
583
|
+
loop: false,
|
|
584
|
+
})
|
|
585
|
+
|
|
586
|
+
useEffect(() => {
|
|
587
|
+
timeline.add(
|
|
588
|
+
stats,
|
|
589
|
+
{
|
|
590
|
+
cpu: 85,
|
|
591
|
+
memory: 70,
|
|
592
|
+
network: 95,
|
|
593
|
+
disk: 60,
|
|
594
|
+
duration: 3000,
|
|
595
|
+
ease: "linear",
|
|
596
|
+
onUpdate: (values) => {
|
|
597
|
+
setAnimatedStats({ ...values.targets[0] })
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
0,
|
|
601
|
+
)
|
|
602
|
+
}, [])
|
|
603
|
+
|
|
604
|
+
const statsMap = [
|
|
605
|
+
{ name: "CPU", key: "cpu", color: "#6a5acd" },
|
|
606
|
+
{ name: "Memory", key: "memory", color: "#4682b4" },
|
|
607
|
+
{ name: "Network", key: "network", color: "#20b2aa" },
|
|
608
|
+
{ name: "Disk", key: "disk", color: "#daa520" },
|
|
609
|
+
]
|
|
610
|
+
|
|
611
|
+
return (
|
|
612
|
+
<box
|
|
613
|
+
title="System Monitor"
|
|
614
|
+
style={{
|
|
615
|
+
margin: 1,
|
|
616
|
+
padding: 1,
|
|
617
|
+
border: true,
|
|
618
|
+
marginLeft: 2,
|
|
619
|
+
marginRight: 2,
|
|
620
|
+
borderStyle: "single",
|
|
621
|
+
borderColor: "#4a4a4a",
|
|
622
|
+
}}
|
|
623
|
+
>
|
|
624
|
+
{statsMap.map((stat) => (
|
|
625
|
+
<box key={stat.key}>
|
|
626
|
+
<box flexDirection="row" justifyContent="space-between">
|
|
627
|
+
<text>{stat.name}</text>
|
|
628
|
+
<text attributes={TextAttributes.DIM}>{Math.round(stats[stat.key as keyof Stats])}%</text>
|
|
629
|
+
</box>
|
|
630
|
+
<box style={{ backgroundColor: "#333333" }}>
|
|
631
|
+
<box style={{ width: `${stats[stat.key as keyof Stats]}%`, height: 1, backgroundColor: stat.color }} />
|
|
632
|
+
</box>
|
|
633
|
+
</box>
|
|
634
|
+
))}
|
|
635
|
+
</box>
|
|
636
|
+
)
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
render(<App />)
|
|
640
|
+
```
|
|
641
|
+
|
|
507
642
|
### Styled Text Showcase
|
|
508
643
|
|
|
509
644
|
```tsx
|
package/index.js
CHANGED
|
@@ -97,10 +97,10 @@ var AppContext = createContext({
|
|
|
97
97
|
var useAppContext = () => {
|
|
98
98
|
return useContext(AppContext);
|
|
99
99
|
};
|
|
100
|
-
// src/hooks/use-keyboard.
|
|
100
|
+
// src/hooks/use-keyboard.ts
|
|
101
101
|
import { useEffect } from "react";
|
|
102
102
|
|
|
103
|
-
// src/hooks/use-event.
|
|
103
|
+
// src/hooks/use-event.ts
|
|
104
104
|
import { useCallback, useLayoutEffect, useRef } from "react";
|
|
105
105
|
function useEvent(handler) {
|
|
106
106
|
const handlerRef = useRef(handler);
|
|
@@ -113,7 +113,7 @@ function useEvent(handler) {
|
|
|
113
113
|
}, []);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
// src/hooks/use-keyboard.
|
|
116
|
+
// src/hooks/use-keyboard.ts
|
|
117
117
|
var useKeyboard = (handler) => {
|
|
118
118
|
const { keyHandler } = useAppContext();
|
|
119
119
|
const stableHandler = useEvent(handler);
|
|
@@ -124,7 +124,7 @@ var useKeyboard = (handler) => {
|
|
|
124
124
|
};
|
|
125
125
|
}, [keyHandler, stableHandler]);
|
|
126
126
|
};
|
|
127
|
-
// src/hooks/use-renderer.
|
|
127
|
+
// src/hooks/use-renderer.ts
|
|
128
128
|
var useRenderer = () => {
|
|
129
129
|
const { renderer } = useAppContext();
|
|
130
130
|
if (!renderer) {
|
|
@@ -132,7 +132,7 @@ var useRenderer = () => {
|
|
|
132
132
|
}
|
|
133
133
|
return renderer;
|
|
134
134
|
};
|
|
135
|
-
// src/hooks/use-resize.
|
|
135
|
+
// src/hooks/use-resize.ts
|
|
136
136
|
import { useEffect as useEffect2 } from "react";
|
|
137
137
|
var useOnResize = (callback) => {
|
|
138
138
|
const renderer = useRenderer();
|
|
@@ -144,7 +144,7 @@ var useOnResize = (callback) => {
|
|
|
144
144
|
}, [renderer, callback]);
|
|
145
145
|
return renderer;
|
|
146
146
|
};
|
|
147
|
-
// src/hooks/use-terminal-dimensions.
|
|
147
|
+
// src/hooks/use-terminal-dimensions.ts
|
|
148
148
|
import { useState } from "react";
|
|
149
149
|
var useTerminalDimensions = () => {
|
|
150
150
|
const renderer = useRenderer();
|
|
@@ -158,8 +158,25 @@ var useTerminalDimensions = () => {
|
|
|
158
158
|
useOnResize(cb);
|
|
159
159
|
return dimensions;
|
|
160
160
|
};
|
|
161
|
+
// src/hooks/use-timeline.ts
|
|
162
|
+
import { engine, Timeline } from "@opentui/core";
|
|
163
|
+
import { useEffect as useEffect3 } from "react";
|
|
164
|
+
var useTimeline = (options = {}) => {
|
|
165
|
+
const timeline = new Timeline(options);
|
|
166
|
+
useEffect3(() => {
|
|
167
|
+
if (!options.autoplay) {
|
|
168
|
+
timeline.play();
|
|
169
|
+
}
|
|
170
|
+
engine.register(timeline);
|
|
171
|
+
return () => {
|
|
172
|
+
timeline.pause();
|
|
173
|
+
engine.unregister(timeline);
|
|
174
|
+
};
|
|
175
|
+
}, []);
|
|
176
|
+
return timeline;
|
|
177
|
+
};
|
|
161
178
|
// src/reconciler/renderer.ts
|
|
162
|
-
import { createCliRenderer } from "@opentui/core";
|
|
179
|
+
import { createCliRenderer, engine as engine2 } from "@opentui/core";
|
|
163
180
|
import React from "react";
|
|
164
181
|
|
|
165
182
|
// src/reconciler/reconciler.ts
|
|
@@ -458,9 +475,11 @@ function _render(element, root) {
|
|
|
458
475
|
// src/reconciler/renderer.ts
|
|
459
476
|
async function render(node, rendererConfig = {}) {
|
|
460
477
|
const renderer = await createCliRenderer(rendererConfig);
|
|
478
|
+
engine2.attach(renderer);
|
|
461
479
|
_render(React.createElement(AppContext.Provider, { value: { keyHandler: renderer.keyInput, renderer } }, node), renderer.root);
|
|
462
480
|
}
|
|
463
481
|
export {
|
|
482
|
+
useTimeline,
|
|
464
483
|
useTerminalDimensions,
|
|
465
484
|
useRenderer,
|
|
466
485
|
useOnResize,
|
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-20250929-69eb6c87",
|
|
8
8
|
"description": "React renderer for building terminal user interfaces using OpenTUI core",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"repository": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@opentui/core": "0.0.0-
|
|
38
|
+
"@opentui/core": "0.0.0-20250929-69eb6c87",
|
|
39
39
|
"react-reconciler": "^0.32.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
package/src/index.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
export * from "./components";
|
|
2
2
|
export * from "./components/app";
|
|
3
|
-
export * from "./hooks
|
|
4
|
-
export * from "./hooks/use-renderer";
|
|
5
|
-
export * from "./hooks/use-resize";
|
|
6
|
-
export * from "./hooks/use-terminal-dimensions";
|
|
3
|
+
export * from "./hooks";
|
|
7
4
|
export * from "./reconciler/renderer";
|
|
8
5
|
export * from "./types/components";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/reconciler/renderer.ts
|
|
3
|
-
import { createCliRenderer } from "@opentui/core";
|
|
3
|
+
import { createCliRenderer, engine } from "@opentui/core";
|
|
4
4
|
import React from "react";
|
|
5
5
|
|
|
6
6
|
// src/components/app.tsx
|
|
@@ -393,6 +393,7 @@ function _render(element, root) {
|
|
|
393
393
|
// src/reconciler/renderer.ts
|
|
394
394
|
async function render(node, rendererConfig = {}) {
|
|
395
395
|
const renderer = await createCliRenderer(rendererConfig);
|
|
396
|
+
engine.attach(renderer);
|
|
396
397
|
_render(React.createElement(AppContext.Provider, { value: { keyHandler: renderer.keyInput, renderer } }, node), renderer.root);
|
|
397
398
|
}
|
|
398
399
|
export {
|