@symbiote-native/react 3.0.2 → 3.0.4
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
|
@@ -22,43 +22,75 @@ adapter, not the core.
|
|
|
22
22
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
25
|
+
```bash
|
|
26
|
+
npx @symbiote-native/cli new my-app --framework react
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
One command, nothing to wire by hand: scaffolds the Metro config, the entry seam below, and
|
|
30
|
+
`@symbiote-native/react`/`react-native`/`react` as your app's own dependencies.
|
|
31
|
+
|
|
32
|
+
<details>
|
|
33
|
+
<summary>Manual install (no generator — an existing app, or you want to wire it yourself)</summary>
|
|
34
|
+
|
|
25
35
|
```bash
|
|
26
36
|
npm install @symbiote-native/react react-native react
|
|
27
37
|
```
|
|
28
38
|
|
|
29
39
|
`react-native` and `react` stay your app's own top-level dependencies — SymbioteNative doesn't hide
|
|
30
|
-
them, it only replaces the JS renderer that drives them. `
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
them, it only replaces the JS renderer that drives them. Follow [`examples/react`](../../examples/react)
|
|
41
|
+
for the Metro config and the entry seam below; there is no wiring script for an existing app.
|
|
42
|
+
|
|
43
|
+
</details>
|
|
33
44
|
|
|
34
45
|
---
|
|
35
46
|
|
|
36
47
|
## Use it
|
|
37
48
|
|
|
38
|
-
The app is ordinary React — the native primitives are plain intrinsic tags, no import needed
|
|
49
|
+
The app is ordinary React — the native primitives are plain intrinsic tags, no import needed.
|
|
50
|
+
Styling is a CSS class against a plain `.css` file, the convention every example app here
|
|
51
|
+
follows (`StyleSheet.create` still works, but isn't what any example uses):
|
|
39
52
|
|
|
40
53
|
```jsx
|
|
41
54
|
import { useState } from 'react';
|
|
55
|
+
import './App.css';
|
|
42
56
|
|
|
43
57
|
export default function App() {
|
|
44
58
|
const [count, setCount] = useState(0);
|
|
45
59
|
return (
|
|
46
|
-
<view
|
|
60
|
+
<safe-area-view className="screen">
|
|
47
61
|
<text>Taps: {count}</text>
|
|
48
62
|
<pressable onPress={() => setCount(c => c + 1)}>
|
|
49
63
|
<text>Tap me</text>
|
|
50
64
|
</pressable>
|
|
51
|
-
</view>
|
|
65
|
+
</safe-area-view>
|
|
52
66
|
);
|
|
53
67
|
}
|
|
54
68
|
```
|
|
55
69
|
|
|
70
|
+
```css
|
|
71
|
+
/* App.css */
|
|
72
|
+
.screen {
|
|
73
|
+
flex: 1;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: center;
|
|
76
|
+
padding: 24px;
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
<details>
|
|
81
|
+
<summary>Native entry point (index.js) — already scaffolded by <code>npx @symbiote-native/cli new</code></summary>
|
|
82
|
+
|
|
56
83
|
The zero-config entry wires the RN-backed host seams (colors, images, device events,
|
|
57
84
|
third-party ViewConfigs) and registers the app in one call — this is what
|
|
58
85
|
[`examples/react`](../../examples/react) actually uses:
|
|
59
86
|
|
|
60
87
|
```js
|
|
61
88
|
// index.js
|
|
89
|
+
|
|
90
|
+
// Registers host behaviors (Image, Pressable, Switch, ...) that /bootstrap alone doesn't
|
|
91
|
+
// reach; deleting this breaks them silently (Metro's production inlineRequires makes a
|
|
92
|
+
// side-effect-only barrel import go lazy, see register.ts).
|
|
93
|
+
import '@symbiote-native/react';
|
|
62
94
|
import { registerApp } from '@symbiote-native/react/bootstrap';
|
|
63
95
|
import App from './App';
|
|
64
96
|
import { name as appName } from './app.json';
|
|
@@ -91,6 +123,8 @@ AppRegistry.registerRunnable(appName, ({ rootTag }) => {
|
|
|
91
123
|
});
|
|
92
124
|
```
|
|
93
125
|
|
|
126
|
+
</details>
|
|
127
|
+
|
|
94
128
|
Either way, the full canary ([`App.tsx`](../../examples/react/App.tsx)) exercises every block of
|
|
95
129
|
the surface below.
|
|
96
130
|
|
|
@@ -141,8 +175,9 @@ the future scaffolder).
|
|
|
141
175
|
|
|
142
176
|
## Run it
|
|
143
177
|
|
|
144
|
-
[`examples/react`](../../examples/react) is a stock React Native 0.86 app. Requires Node ≥ 22
|
|
145
|
-
|
|
178
|
+
[`examples/react`](../../examples/react) is a stock React Native 0.86 app. Requires Node ≥ 22.13
|
|
179
|
+
(react-native 0.86's own `package.json#engines`) and the [RN environment
|
|
180
|
+
setup](https://reactnative.dev/docs/set-up-your-environment) (Xcode, CocoaPods):
|
|
146
181
|
|
|
147
182
|
```bash
|
|
148
183
|
cd examples/react
|
|
@@ -68,7 +68,7 @@ export const KeyboardAvoidingView = props => {
|
|
|
68
68
|
for (const subscription of subscriptions)
|
|
69
69
|
subscription.remove();
|
|
70
70
|
};
|
|
71
|
-
}, [behavior, keyboardVerticalOffset]);
|
|
71
|
+
}, [behavior, keyboardVerticalOffset, enabled]);
|
|
72
72
|
const handleLayout = (event) => {
|
|
73
73
|
const frame = readLayoutFrame(event.nativeEvent.layout);
|
|
74
74
|
if (frame !== undefined) {
|
|
@@ -146,7 +146,7 @@ export function VirtualizedList(props) {
|
|
|
146
146
|
}
|
|
147
147
|
dlog(`VirtualizedList scrollTo offset=${clamped} pending-ref (horizontal=${isHorizontal})`);
|
|
148
148
|
setCommandedOffset(target);
|
|
149
|
-
}, []);
|
|
149
|
+
}, [scrollHandle]);
|
|
150
150
|
// dispatch and runEffects are mutually recursive (a schedule-refill / fire-viewable effect
|
|
151
151
|
// dispatches a follow-up action), so runEffects reaches dispatch through a ref.
|
|
152
152
|
const dispatchRef = useRef(() => { });
|
|
@@ -436,21 +436,13 @@ export function VirtualizedList(props) {
|
|
|
436
436
|
index: planCell.index,
|
|
437
437
|
separators: makeSeparators(planCell.index),
|
|
438
438
|
});
|
|
439
|
-
//
|
|
440
|
-
//
|
|
441
|
-
//
|
|
442
|
-
// gap + separator + gap while a spacer collapsing that region replaces it with one gap — the
|
|
443
|
-
// leading spacer then lands every cell below it short by (separator + gap), and the content
|
|
444
|
-
// visibly jumps by that amount each time the window's first index moves. Measured at exactly
|
|
445
|
-
// 17px on device 2026-08-19 (a 1px divider under a 16px container gap); see
|
|
446
|
-
// .claude/rules/list-geometry-feedback-loop.md. Inside the wrapper it is part of the cell's
|
|
447
|
-
// measured length instead, and every cell stays exactly one child.
|
|
439
|
+
// The separator lives INSIDE the cell's own measuring wrapper, not as a sibling: a sibling
|
|
440
|
+
// is an extra flex child, so a leading-spacer collapse would land every cell below it short
|
|
441
|
+
// by (separator + gap). See .claude/rules/list-geometry-feedback-loop.md.
|
|
448
442
|
const separator =
|
|
449
|
-
//
|
|
450
|
-
//
|
|
451
|
-
//
|
|
452
|
-
// would make a cell's own measured height change as the window slides past it. Device-measured
|
|
453
|
-
// 2026-08-19 as a run of cells all shifting by exactly the divider's 1px.
|
|
443
|
+
// Gated on the last index of the DATA, not the WINDOW: since the separator lives inside
|
|
444
|
+
// the measuring wrapper, gating on the window would make a cell's own measured height
|
|
445
|
+
// change as the window slides past it.
|
|
454
446
|
planCell.index < count - 1
|
|
455
447
|
? renderSeparatorElement(ItemSeparatorComponent, item, getItem(data, planCell.index + 1), separatorOverridesRef.current.get(planCell.index))
|
|
456
448
|
: undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/react",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.4",
|
|
4
4
|
"description": "SymbioteNative's React adapter — a react-reconciler host config (mutation mode) driving real native iOS/Android views through stock React Native Fabric.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -57,20 +57,20 @@
|
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"react-reconciler": "^0.33.0",
|
|
60
|
-
"@symbiote-native/components": "3.1.
|
|
61
|
-
"@symbiote-native/css-parser": "0.5.
|
|
60
|
+
"@symbiote-native/components": "3.1.2",
|
|
61
|
+
"@symbiote-native/css-parser": "0.5.2"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"react": ">=19.0.0",
|
|
65
65
|
"react-native": ">=0.86",
|
|
66
|
-
"@symbiote-native/engine": "^1.3.
|
|
66
|
+
"@symbiote-native/engine": "^1.3.1"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@types/react": "^19.2.0",
|
|
70
70
|
"@types/react-reconciler": "^0.32.2",
|
|
71
71
|
"react": "19.2.3",
|
|
72
|
-
"@symbiote-native/engine": "1.3.
|
|
73
|
-
"@symbiote-native/test-utils": "0.4.
|
|
72
|
+
"@symbiote-native/engine": "1.3.1",
|
|
73
|
+
"@symbiote-native/test-utils": "0.4.4"
|
|
74
74
|
},
|
|
75
75
|
"scripts": {
|
|
76
76
|
"typecheck": "tsc --build",
|