@bun-native/react 0.33.0 → 0.33.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/README.md +1 -1
- package/bun-native-source.json +12 -12
- package/package.json +7 -5
- package/src/mount.ts +4 -3
- package/src/reconciler.ts +19 -49
- package/src/root-errors.ts +9 -4
package/README.md
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
|
|
3
3
|
React renderer for Bun Native desktop windows.
|
|
4
4
|
|
|
5
|
-
Part of [Bun Native](https://github.com/0xPlayerOne/bun-native), an experimental developer preview. Version 0.33.
|
|
5
|
+
Part of [Bun Native](https://github.com/0xPlayerOne/bun-native), an experimental developer preview. Version 0.33.1 was built from [c56fdd675365](https://github.com/0xPlayerOne/bun-native/tree/c56fdd6753653a10144a4167c1d3dfb3c38a0647) and published from GitHub Actions with npm provenance. Use the Bun revision pinned in that commit's toolchain.json. Start with the [getting-started guide](https://github.com/0xPlayerOne/bun-native/blob/c56fdd6753653a10144a4167c1d3dfb3c38a0647/docs/getting-started.md); `bun-native host install` fetches the matching release host. The license notice is in LICENSE.
|
package/bun-native-source.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"commit": "
|
|
4
|
-
"tree": "
|
|
3
|
+
"commit": "c56fdd6753653a10144a4167c1d3dfb3c38a0647",
|
|
4
|
+
"tree": "c6e81b3f9d041e11dd0413b5fdd7a50910383854",
|
|
5
5
|
"files": {
|
|
6
6
|
"package.json": {
|
|
7
|
-
"bytes":
|
|
8
|
-
"sha256": "
|
|
7
|
+
"bytes": 2115,
|
|
8
|
+
"sha256": "caf866d56f3cd7530d5735ecbf62512e9e22526bc44c75a4b48a18c26352c0b8"
|
|
9
9
|
},
|
|
10
10
|
"packages/react/package.json": {
|
|
11
11
|
"bytes": 402,
|
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
"sha256": "4458ba8196591d768d0c7d1a333e47fb2902f44b3e848b9fd7289f68092b8502"
|
|
33
33
|
},
|
|
34
34
|
"packages/react/src/mount.ts": {
|
|
35
|
-
"bytes":
|
|
36
|
-
"sha256": "
|
|
35
|
+
"bytes": 7595,
|
|
36
|
+
"sha256": "259ed7e24ef6f2943c889deadea3c337e627c3633c514a62dd2c1de781c3097f"
|
|
37
37
|
},
|
|
38
38
|
"packages/react/src/reconciler.ts": {
|
|
39
|
-
"bytes":
|
|
40
|
-
"sha256": "
|
|
39
|
+
"bytes": 8349,
|
|
40
|
+
"sha256": "6036ac4f997f965f0bfbcf73719d6cdf8a59e6706bc9f25e1e3d3db1777e8a6f"
|
|
41
41
|
},
|
|
42
42
|
"packages/react/src/root-errors.ts": {
|
|
43
|
-
"bytes":
|
|
44
|
-
"sha256": "
|
|
43
|
+
"bytes": 1234,
|
|
44
|
+
"sha256": "963071b9e1086f551fef172ee6d53a78d07aeaa674f6d3bf746f8774fabfe780"
|
|
45
45
|
},
|
|
46
46
|
"LICENSE": {
|
|
47
47
|
"bytes": 1075,
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"toolchain": {
|
|
52
|
-
"bytes":
|
|
53
|
-
"sha256": "
|
|
52
|
+
"bytes": 3234,
|
|
53
|
+
"sha256": "9f4d9362cb4cc38c0f4e705295789a0cbfec46ffdd007e0541b9441a7c3003a7"
|
|
54
54
|
},
|
|
55
55
|
"dependencyLock": {
|
|
56
56
|
"bytes": 28357,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bun-native/react",
|
|
3
|
-
"version": "0.33.
|
|
3
|
+
"version": "0.33.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -19,13 +19,15 @@
|
|
|
19
19
|
},
|
|
20
20
|
"description": "React renderer for Bun Native desktop windows.",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@bun-native/core": "0.33.
|
|
23
|
-
"@bun-native/renderer": "0.33.
|
|
24
|
-
"react": "19.3.1",
|
|
22
|
+
"@bun-native/core": "0.33.1",
|
|
23
|
+
"@bun-native/renderer": "0.33.1",
|
|
25
24
|
"react-reconciler": "0.34.0",
|
|
26
|
-
"@types/react": "19.3.0",
|
|
27
25
|
"@types/react-reconciler": "0.34.1"
|
|
28
26
|
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"react": "19.3.1",
|
|
29
|
+
"@types/react": "19.3.0"
|
|
30
|
+
},
|
|
29
31
|
"repository": {
|
|
30
32
|
"type": "git",
|
|
31
33
|
"url": "git+https://github.com/0xPlayerOne/bun-native.git",
|
package/src/mount.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { NativeStateError, type NativeWindow, type Style } from '@bun-native/cor
|
|
|
2
2
|
import { createRenderRoot, type RenderOptions, type RenderRoot } from '@bun-native/renderer'
|
|
3
3
|
import type { ErrorInfo, ReactNode } from 'react'
|
|
4
4
|
import { ConcurrentRoot } from 'react-reconciler/constants'
|
|
5
|
-
import { reconciler } from './reconciler.ts'
|
|
5
|
+
import { dispatchDiscrete, reconciler } from './reconciler.ts'
|
|
6
6
|
import { createRootErrors } from './root-errors.ts'
|
|
7
7
|
import { createCommitBarrier } from './commit-barrier.ts'
|
|
8
8
|
|
|
@@ -57,7 +57,7 @@ class Root implements ReactRenderRoot {
|
|
|
57
57
|
this.errors.uncaught,
|
|
58
58
|
this.errors.caught,
|
|
59
59
|
this.errors.recoverable,
|
|
60
|
-
this.errors.
|
|
60
|
+
this.errors.transitionIndicator,
|
|
61
61
|
null
|
|
62
62
|
)
|
|
63
63
|
onCleanup(() => {
|
|
@@ -82,7 +82,8 @@ class Root implements ReactRenderRoot {
|
|
|
82
82
|
if (this.failure !== undefined) throw this.failure
|
|
83
83
|
reconciler.flushPassiveEffects()
|
|
84
84
|
},
|
|
85
|
-
style === undefined ? {} : { style }
|
|
85
|
+
style === undefined ? {} : { style },
|
|
86
|
+
{ dispatch: dispatchDiscrete }
|
|
86
87
|
)
|
|
87
88
|
this.ready = this.native.ready.then(() => {
|
|
88
89
|
if (this.phase !== 'active')
|
package/src/reconciler.ts
CHANGED
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
replaceText,
|
|
9
9
|
setProperty,
|
|
10
10
|
type ElementTag,
|
|
11
|
-
type EventProperty,
|
|
12
11
|
type Node,
|
|
13
12
|
type PropertyName,
|
|
14
13
|
type RendererNode,
|
|
@@ -48,11 +47,6 @@ type Config = Reconciler.HostConfig<
|
|
|
48
47
|
const context: HostContext = Object.freeze({})
|
|
49
48
|
let updatePriority: Reconciler.EventPriority = NoEventPriority
|
|
50
49
|
let activeEvent: { type: string; observedAt: number } | undefined
|
|
51
|
-
type EventBinding = {
|
|
52
|
-
listener: Listener<NativeUIEvent> | undefined
|
|
53
|
-
dispatch: Listener<NativeUIEvent>
|
|
54
|
-
}
|
|
55
|
-
const bindings = new WeakMap<Node, Map<EventProperty, EventBinding>>()
|
|
56
50
|
|
|
57
51
|
function unsupported(feature: string): never {
|
|
58
52
|
throw new UnsupportedFeatureError('react-' + feature)
|
|
@@ -65,52 +59,30 @@ const noInstance = () => null
|
|
|
65
59
|
const returnFalse = () => false
|
|
66
60
|
const hostContext = () => context
|
|
67
61
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
function updateEvent(node: Node, name: EventProperty, value: unknown): void {
|
|
86
|
-
const registered = bindings.get(node)
|
|
87
|
-
const existing = registered?.get(name)
|
|
88
|
-
if (value === undefined) {
|
|
89
|
-
if (existing) existing.listener = undefined
|
|
90
|
-
registered?.delete(name)
|
|
91
|
-
setProperty(node, name, undefined)
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
if (typeof value !== 'function') throw new TypeError('Native event listeners must be functions')
|
|
95
|
-
// The callable boundary is checked here; core supplies the validated event.
|
|
96
|
-
const listener = value as Listener<NativeUIEvent>
|
|
97
|
-
if (existing) {
|
|
98
|
-
// React replaces inline closures on ordinary rerenders. Keep the node's
|
|
99
|
-
// native type/phase registration alive so queued events retain their ordering.
|
|
100
|
-
existing.listener = listener
|
|
101
|
-
return
|
|
62
|
+
/**
|
|
63
|
+
* Run a native callback as a discrete React update. The shared renderer keeps
|
|
64
|
+
* one registration per node/type/phase and calls the latest committed handler,
|
|
65
|
+
* so inline closures replaced on ordinary rerenders keep queued events.
|
|
66
|
+
*/
|
|
67
|
+
export function dispatchDiscrete(
|
|
68
|
+
listener: Listener<NativeUIEvent>,
|
|
69
|
+
event: NativeUIEvent
|
|
70
|
+
): void | Promise<void> {
|
|
71
|
+
const previous = activeEvent
|
|
72
|
+
activeEvent = { type: event.type, observedAt: performance.now() }
|
|
73
|
+
try {
|
|
74
|
+
return reconciler.discreteUpdates(listener, event, undefined, undefined, undefined)
|
|
75
|
+
} finally {
|
|
76
|
+
activeEvent = previous
|
|
77
|
+
reconciler.flushSyncWork()
|
|
102
78
|
}
|
|
103
|
-
const binding = createBinding(listener)
|
|
104
|
-
setProperty(node, name, binding.dispatch)
|
|
105
|
-
const next = registered ?? new Map<EventProperty, EventBinding>()
|
|
106
|
-
next.set(name, binding)
|
|
107
|
-
bindings.set(node, next)
|
|
108
79
|
}
|
|
109
80
|
|
|
110
81
|
function updateProperty(node: Node, name: string, value: unknown): void {
|
|
111
|
-
if (isEventProperty(name)
|
|
82
|
+
if (isEventProperty(name) && value !== undefined && typeof value !== 'function')
|
|
83
|
+
throw new TypeError('Native event listeners must be functions')
|
|
112
84
|
// React props arrive as strings; the renderer rejects unknown names at runtime.
|
|
113
|
-
|
|
85
|
+
setProperty(node, name as PropertyName, value)
|
|
114
86
|
}
|
|
115
87
|
|
|
116
88
|
const reserved = (name: string) => name === 'children' || name === 'ref' || name === 'key'
|
|
@@ -200,8 +172,6 @@ const host: Config = {
|
|
|
200
172
|
prepareScopeUpdate: unsupported.bind(null, 'scope'),
|
|
201
173
|
getInstanceFromScope: noInstance,
|
|
202
174
|
detachDeletedInstance(node) {
|
|
203
|
-
for (const binding of bindings.get(node)?.values() ?? []) binding.listener = undefined
|
|
204
|
-
bindings.delete(node)
|
|
205
175
|
node.children.length = 0
|
|
206
176
|
node.parent = undefined
|
|
207
177
|
for (const name of Object.keys(node.properties)) {
|
package/src/root-errors.ts
CHANGED
|
@@ -6,16 +6,21 @@ export interface RootErrorOwner {
|
|
|
6
6
|
report: ((error: unknown, info: Readonly<ErrorInfo>) => void) | undefined
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
function ignore(): void {}
|
|
10
|
-
|
|
11
9
|
/** Created outside the Root constructor so callback scopes cannot capture its arguments. */
|
|
12
10
|
export function createRootErrors(owner: RootErrorOwner) {
|
|
13
11
|
return {
|
|
14
12
|
uncaught(error: unknown): void {
|
|
15
13
|
owner.terminate?.(error)
|
|
16
14
|
},
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
/**
|
|
16
|
+
* An error a boundary handled is logged like React DOM's default instead
|
|
17
|
+
* of disappearing; it does not end the root.
|
|
18
|
+
*/
|
|
19
|
+
caught(error: unknown): void {
|
|
20
|
+
if (owner.terminate) console.error(error)
|
|
21
|
+
},
|
|
22
|
+
/** React's default transition indicator: native views show none. */
|
|
23
|
+
transitionIndicator(): void {},
|
|
19
24
|
recoverable(error: unknown, info: ErrorInfo): void {
|
|
20
25
|
const report = owner.report
|
|
21
26
|
if (!report) return
|