@blender-ui/react 0.2.0 → 0.3.0

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
@@ -1,171 +1,173 @@
1
- # @blender-ui/react
2
-
3
- [![npm](https://img.shields.io/npm/v/@blender-ui/react)](https://www.npmjs.com/package/@blender-ui/react)
4
- [![license](https://img.shields.io/npm/l/@blender-ui/react)](https://github.com/ppmpreetham/BUI/blob/main/LICENSE)
5
-
6
- React 19 for the desktop, drawn by [BUI](https://github.com/ppmpreetham/BUI),
7
- Blender's UI toolkit. You write JSX with HTML elements, CSS and Tailwind
8
- classes, and BUI renders it in native windows on the CPU or the GPU. There's
9
- no browser, no webview and no Electron.
10
-
11
- - **React's hooks, by React's names, holding signals.** A change updates the
12
- one node that shows it, without re-rendering the component.
13
- - **Node.js and Bun.**
14
- - **One small executable:** `bui build` makes an app of about 5 MB that
15
- reaches its first frame in about 70 ms.
16
-
17
- ```sh
18
- npm install @blender-ui/react react # or: bun add @blender-ui/react react
19
- ```
20
-
21
- ```jsx
22
- /** @jsxImportSource @blender-ui/react */
23
- import { render, useState } from '@blender-ui/react'
24
-
25
- function Counter () {
26
- const [count, setCount] = useState(0)
27
- return (
28
- <main className="p-6 flex flex-col gap-3 bg-[#2b2b2b] text-[#e6e6e6]">
29
- <span>Clicks: {count}</span>
30
- <button onClick={() => setCount(c => c + 1)}>Add one</button>
31
- </main>
32
- )
33
- }
34
-
35
- render(<Counter />, { title: 'Counter', width: 360, height: 200, gpu: true })
36
- ```
37
-
38
- ```sh
39
- bun app.jsx # run it (Bun reads JSX as is)
40
- npx bui build app.jsx # ship it: app.exe, one ~5 MB file
41
- ```
42
-
43
- Put `"jsxImportSource": "@blender-ui/react"` in your `tsconfig.json`, or in
44
- your bundler's JSX options; the `/** @jsxImportSource */` comment works per
45
- file. Without JSX, use this package's `createElement`.
46
-
47
- ## Hooks
48
-
49
- The hooks have React's names, arguments and timing, but the state they hold
50
- is a **signal**:
51
-
52
- - **Passed into JSX** (`<span>{count}</span>`, `style={styleMemo}`,
53
- `style={{ color: colorSignal }}`): a change updates that node. The
54
- component doesn't re-render.
55
- - **Read while rendering** (`count.value`; in plain JavaScript also
56
- `count + 1` or `count > 5`): the component re-renders when it changes, as
57
- with React.
58
- - **Conditions and `===` need `.value`.** A signal is an object, so it's
59
- always truthy: write `{isPending.value && <Spinner />}` and
60
- `count.value === 0`. TypeScript also needs `.value` for arithmetic.
61
-
62
- | Hook | Returns |
63
- |---|---|
64
- | `useState(init)` | `[signal, setState]` |
65
- | `useReducer(reducer, arg, init?)` | `[signal, dispatch]` |
66
- | `useMemo(fn, deps?)` | a memo, recomputed when the signals it reads change |
67
- | `useRef(v)` | `{ current }`, observable by effects and memos |
68
- | `useCallback(fn, deps?)` / `useEffectEvent(fn)` | a function whose calls are batched |
69
- | `useEffect` / `useLayoutEffect` / `useInsertionEffect` | React's timing and deps, plus a re-run when the signals the effect read change |
70
- | `useSyncExternalStore(subscribe, get)` | a signal following the store |
71
- | `useTransition()` | `[isPending, startTransition]`; signal updates run after urgent ones |
72
- | `useDeferredValue(value, initial?)` | a signal that follows `value` at low priority |
73
- | `useActionState(action, initial)` | `[state, dispatch, isPending]` |
74
- | `useOptimistic(state, reducer?)` | `[optimistic, addOptimistic]` |
75
- | `use`, `useContext`, `useId`, `useDebugValue`, `useImperativeHandle` | React's own |
76
-
77
- Also exported:
78
-
79
- - **Rust-style names:** `useSignal(v)` and `useComputed(fn)`.
80
- - **`useSignalValue(sig)`:** re-renders its component when `sig` changes.
81
- - **Plain signals:** `signal`, `computed`, `effect`, `batch`, `untrack`,
82
- `startTransition`.
83
-
84
- React's plain-value hooks still work: import them from `react`.
85
-
86
- Every hook is built from React's public hooks. A conformance suite runs each
87
- one beside React's original, in development and production builds and under
88
- StrictMode. It fails when a React release adds a hook this package doesn't
89
- cover yet.
90
-
91
- ## The renderer
92
-
93
- - **Host components are HTML elements.** `className` takes Tailwind classes,
94
- `style` takes strings, objects or signals, and the mouse, keyboard and form
95
- events work (`onClick`, `onChange` ...). Events bubble, and
96
- `stopPropagation` works.
97
- - **One native batch per commit:** only what changed crosses to BUI's UI
98
- thread.
99
- - **React 19.3:** `<Suspense>`, `<Activity>`, transitions, actions and
100
- `<ViewTransition>`, which commits without animating.
101
- - **API:** `render(element, options)` opens a window. `createRoot(window)`
102
- renders into one you opened with
103
- [`@blender-ui/native`](https://www.npmjs.com/package/@blender-ui/native),
104
- and `act(fn)` is for tests.
105
- - Window options: `title`, `width`, `height`, `resizable`, `gpu`,
106
- `slug`, `headless`, and `theme` (`'dark'`, the default, or `'light'`:
107
- Blender's Light theme; `BUI_THEME` applies otherwise).
108
-
109
- ## Standalone apps
110
-
111
- `bui` comes with this package, through `@blender-ui/native`:
112
-
113
- ```sh
114
- npx bui build app.jsx # app.exe: BUI + embedded QuickJS, ~5 MB
115
- npx bui build app.jsx --bun # app.exe: Bun, with Node's APIs and a JIT, ~115 MB
116
- npx bui run app.jsx # run on the QuickJS runtime, no build
117
- ```
118
-
119
- Options:
120
-
121
- - `-o <file>`: the output file.
122
- - `--console`: keep a console window for logs.
123
- - `--dev`: React's development build.
124
-
125
- Bundling uses [Bun](https://bun.sh), so it must be installed.
126
-
127
- The default build runs your app on QuickJS, a small JavaScript engine embedded
128
- in BUI. It has no Node modules (`fs` and the like) and no JIT, so keep large
129
- lists updating through signals, or use `--bun`.
130
-
131
- ## Benchmarks
132
-
133
- Ryzen 7 5800U laptop, Windows 11, GPU renderer, React's production build,
134
- measured before the latest features landed.
135
- The full method is in the [guide](https://github.com/ppmpreetham/BUI/blob/main/docs/javascript.md#performance).
136
-
137
- **Startup:** a small React app that quits at its first frame; medians of 12
138
- launches.
139
-
140
- | | First frame | Launch to exit | RAM | Size |
141
- |---|---:|---:|---:|---:|
142
- | **`bui build`** (QuickJS) | **68 ms** | **104 ms** | **19 MB** | **4.9 MB** |
143
- | `bui build --bun` | 79 ms | 147 ms | 35 MB | 114 MB |
144
- | `bun app.js` | 80 ms | 152 ms | 35 MB | |
145
- | `node app.js` | 108 ms | 187 ms | 45 MB | |
146
-
147
- **Animation:** 3,000 cells, one changing per frame.
148
-
149
- - **With signals:** the changing values are signals, so the grid renders once.
150
- - **With state:** the grid re-renders every frame.
151
-
152
- | 3,000 cells | FPS | CPU per frame | RAM |
153
- |---|---:|---:|---:|
154
- | Bun: with signals / with state | 58.4 / 55.8 | 13.3 / 20.8 ms | 85 / 118 MB |
155
- | Node: with signals / with state | 56.7 / 54.8 | 14.0 / 18.9 ms | 93 / 121 MB |
156
- | QuickJS: with signals / with state | 58.7 / 19.7 | 14.9 / 51.0 ms | 61 / 67 MB |
157
- | *Rust, for reference* | 59.6 | 12.0 ms | 43 MB |
158
-
159
- ## Requirements
160
-
161
- - **Windows x64** prebuilt. On **Linux**, build the `@blender-ui/native`
162
- addon from source (`npm run build` in `bindings/node`) and windows are
163
- native X11 windows. On **macOS** it's headless for now. `headless: true`
164
- renders off-screen anywhere.
165
- - **Node.js 18** or newer, or Bun.
166
- - **React 19.3.**
167
-
168
- Guide: [docs/javascript.md](https://github.com/ppmpreetham/BUI/blob/main/docs/javascript.md) ·
169
- Website: [bui.preetham.top](https://bui.preetham.top) ·
170
- Source: [github.com/ppmpreetham/BUI](https://github.com/ppmpreetham/BUI) ·
171
- License: GPL-2.0-or-later
1
+ # @blender-ui/react
2
+
3
+ [![npm](https://img.shields.io/npm/v/@blender-ui/react)](https://www.npmjs.com/package/@blender-ui/react)
4
+ [![license](https://img.shields.io/npm/l/@blender-ui/react)](https://github.com/ppmpreetham/BUI/blob/main/LICENSE)
5
+
6
+ React 19 for the desktop, drawn by [BUI](https://github.com/ppmpreetham/BUI),
7
+ Blender's UI toolkit. You write JSX with HTML elements, CSS and Tailwind
8
+ classes, and BUI renders it in native windows on the CPU or the GPU. There's
9
+ no browser, no webview and no Electron.
10
+ Prefer Svelte? [`@blender-ui/svelte`](https://www.npmjs.com/package/@blender-ui/svelte)
11
+ is the same engine for Svelte 5.
12
+
13
+ - **React's hooks, by React's names, holding signals.** A change updates the
14
+ one node that shows it, without re-rendering the component.
15
+ - **Node.js and Bun.**
16
+ - **One small executable:** `bui build` makes an app of about 5 MB that
17
+ reaches its first frame in about 70 ms.
18
+
19
+ ```sh
20
+ npm install @blender-ui/react react # or: bun add @blender-ui/react react
21
+ ```
22
+
23
+ ```jsx
24
+ /** @jsxImportSource @blender-ui/react */
25
+ import { render, useState } from '@blender-ui/react'
26
+
27
+ function Counter () {
28
+ const [count, setCount] = useState(0)
29
+ return (
30
+ <main className="p-6 flex flex-col gap-3 bg-[#2b2b2b] text-[#e6e6e6]">
31
+ <span>Clicks: {count}</span>
32
+ <button onClick={() => setCount(c => c + 1)}>Add one</button>
33
+ </main>
34
+ )
35
+ }
36
+
37
+ render(<Counter />, { title: 'Counter', width: 360, height: 200, gpu: true })
38
+ ```
39
+
40
+ ```sh
41
+ bun app.jsx # run it (Bun reads JSX as is)
42
+ npx bui build app.jsx # ship it: app.exe, one ~5 MB file
43
+ ```
44
+
45
+ Put `"jsxImportSource": "@blender-ui/react"` in your `tsconfig.json`, or in
46
+ your bundler's JSX options; the `/** @jsxImportSource */` comment works per
47
+ file. Without JSX, use this package's `createElement`.
48
+
49
+ ## Hooks
50
+
51
+ The hooks have React's names, arguments and timing, but the state they hold
52
+ is a **signal**:
53
+
54
+ - **Passed into JSX** (`<span>{count}</span>`, `style={styleMemo}`,
55
+ `style={{ color: colorSignal }}`): a change updates that node. The
56
+ component doesn't re-render.
57
+ - **Read while rendering** (`count.value`; in plain JavaScript also
58
+ `count + 1` or `count > 5`): the component re-renders when it changes, as
59
+ with React.
60
+ - **Conditions and `===` need `.value`.** A signal is an object, so it's
61
+ always truthy: write `{isPending.value && <Spinner />}` and
62
+ `count.value === 0`. TypeScript also needs `.value` for arithmetic.
63
+
64
+ | Hook | Returns |
65
+ |---|---|
66
+ | `useState(init)` | `[signal, setState]` |
67
+ | `useReducer(reducer, arg, init?)` | `[signal, dispatch]` |
68
+ | `useMemo(fn, deps?)` | a memo, recomputed when the signals it reads change |
69
+ | `useRef(v)` | `{ current }`, observable by effects and memos |
70
+ | `useCallback(fn, deps?)` / `useEffectEvent(fn)` | a function whose calls are batched |
71
+ | `useEffect` / `useLayoutEffect` / `useInsertionEffect` | React's timing and deps, plus a re-run when the signals the effect read change |
72
+ | `useSyncExternalStore(subscribe, get)` | a signal following the store |
73
+ | `useTransition()` | `[isPending, startTransition]`; signal updates run after urgent ones |
74
+ | `useDeferredValue(value, initial?)` | a signal that follows `value` at low priority |
75
+ | `useActionState(action, initial)` | `[state, dispatch, isPending]` |
76
+ | `useOptimistic(state, reducer?)` | `[optimistic, addOptimistic]` |
77
+ | `use`, `useContext`, `useId`, `useDebugValue`, `useImperativeHandle` | React's own |
78
+
79
+ Also exported:
80
+
81
+ - **Rust-style names:** `useSignal(v)` and `useComputed(fn)`.
82
+ - **`useSignalValue(sig)`:** re-renders its component when `sig` changes.
83
+ - **Plain signals:** `signal`, `computed`, `effect`, `batch`, `untrack`,
84
+ `startTransition`.
85
+
86
+ React's plain-value hooks still work: import them from `react`.
87
+
88
+ Every hook is built from React's public hooks. A conformance suite runs each
89
+ one beside React's original, in development and production builds and under
90
+ StrictMode. It fails when a React release adds a hook this package doesn't
91
+ cover yet.
92
+
93
+ ## The renderer
94
+
95
+ - **Host components are HTML elements.** `className` takes Tailwind classes,
96
+ `style` takes strings, objects or signals, and the mouse, keyboard and form
97
+ events work (`onClick`, `onChange` ...). Events bubble, and
98
+ `stopPropagation` works.
99
+ - **One native batch per commit:** only what changed crosses to BUI's UI
100
+ thread.
101
+ - **React 19.3:** `<Suspense>`, `<Activity>`, transitions, actions and
102
+ `<ViewTransition>`, which commits without animating.
103
+ - **API:** `render(element, options)` opens a window. `createRoot(window)`
104
+ renders into one you opened with
105
+ [`@blender-ui/native`](https://www.npmjs.com/package/@blender-ui/native),
106
+ and `act(fn)` is for tests.
107
+ - Window options: `title`, `width`, `height`, `resizable`, `gpu`,
108
+ `slug`, `headless`, and `theme` (`'dark'`, the default, or `'light'`:
109
+ Blender's Light theme; `BUI_THEME` applies otherwise).
110
+
111
+ ## Standalone apps
112
+
113
+ `bui` comes with this package, through `@blender-ui/native`:
114
+
115
+ ```sh
116
+ npx bui build app.jsx # app.exe: BUI + embedded QuickJS, ~5 MB
117
+ npx bui build app.jsx --bun # app.exe: Bun, with Node's APIs and a JIT, ~115 MB
118
+ npx bui run app.jsx # run on the QuickJS runtime, no build
119
+ ```
120
+
121
+ Options:
122
+
123
+ - `-o <file>`: the output file.
124
+ - `--console`: keep a console window for logs.
125
+ - `--dev`: React's development build.
126
+
127
+ Bundling uses [Bun](https://bun.sh), so it must be installed.
128
+
129
+ The default build runs your app on QuickJS, a small JavaScript engine embedded
130
+ in BUI. It has no Node modules (`fs` and the like) and no JIT, so keep large
131
+ lists updating through signals, or use `--bun`.
132
+
133
+ ## Benchmarks
134
+
135
+ Ryzen 7 5800U laptop, Windows 11, GPU renderer, React's production build,
136
+ measured before the latest features landed.
137
+ The full method is in the [guide](https://github.com/ppmpreetham/BUI/blob/main/docs/javascript.md#performance).
138
+
139
+ **Startup:** a small React app that quits at its first frame; medians of 12
140
+ launches.
141
+
142
+ | | First frame | Launch to exit | RAM | Size |
143
+ |---|---:|---:|---:|---:|
144
+ | **`bui build`** (QuickJS) | **68 ms** | **104 ms** | **19 MB** | **4.9 MB** |
145
+ | `bui build --bun` | 79 ms | 147 ms | 35 MB | 114 MB |
146
+ | `bun app.js` | 80 ms | 152 ms | 35 MB | |
147
+ | `node app.js` | 108 ms | 187 ms | 45 MB | |
148
+
149
+ **Animation:** 3,000 cells, one changing per frame.
150
+
151
+ - **With signals:** the changing values are signals, so the grid renders once.
152
+ - **With state:** the grid re-renders every frame.
153
+
154
+ | 3,000 cells | FPS | CPU per frame | RAM |
155
+ |---|---:|---:|---:|
156
+ | Bun: with signals / with state | 58.4 / 55.8 | 13.3 / 20.8 ms | 85 / 118 MB |
157
+ | Node: with signals / with state | 56.7 / 54.8 | 14.0 / 18.9 ms | 93 / 121 MB |
158
+ | QuickJS: with signals / with state | 58.7 / 19.7 | 14.9 / 51.0 ms | 61 / 67 MB |
159
+ | *Rust, for reference* | 59.6 | 12.0 ms | 43 MB |
160
+
161
+ ## Requirements
162
+
163
+ - **Windows x64** prebuilt. On **Linux**, build the `@blender-ui/native`
164
+ addon from source (`npm run build` in `bindings/node`) and windows are
165
+ native X11 windows. On **macOS** it's headless for now. `headless: true`
166
+ renders off-screen anywhere.
167
+ - **Node.js 18** or newer, or Bun.
168
+ - **React 19.3.**
169
+
170
+ Guide: [docs/javascript.md](https://github.com/ppmpreetham/BUI/blob/main/docs/javascript.md) ·
171
+ Website: [bui.preetham.top](https://bui.preetham.top) ·
172
+ Source: [github.com/ppmpreetham/BUI](https://github.com/ppmpreetham/BUI) ·
173
+ License: GPL-2.0-or-later