@symbiote-native/solid 3.0.3 → 3.0.5
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
|
@@ -40,7 +40,7 @@ app.
|
|
|
40
40
|
|
|
41
41
|
</details>
|
|
42
42
|
|
|
43
|
-
Targets **Solid 1.9**, deliberately not 2.0 (RC
|
|
43
|
+
Targets **Solid 1.9**, deliberately not 2.0 (still RC) — 2.0 moves the package to
|
|
44
44
|
`@solidjs/universal`, changes `RendererOptions`, and changes the compiled-output shape. Moving to
|
|
45
45
|
it is a rewrite of `src/renderer.ts`, not a range bump.
|
|
46
46
|
|
|
@@ -14,13 +14,9 @@
|
|
|
14
14
|
// and assembles the host elements. Lists have no Descriptor render fn — the cell content is the
|
|
15
15
|
// user's own subtree (`symbiote-add-component` §0, category 2).
|
|
16
16
|
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// second one — building one here too would nest a content view inside the behavior's own
|
|
21
|
-
// (`core/components/src/behaviors/scroll-view/shared.ts`'s header names this precondition). The
|
|
22
|
-
// RefreshControl placement (a sibling on iOS, an inverting wrap on Android) moved the same way: it is
|
|
23
|
-
// an ordinary child now, and the behavior's `claimedChildren` decides where it lands.
|
|
17
|
+
// THIS FILE NO LONGER BUILDS THE CONTENT NODE ITSELF: `registerScrollViewBehavior()`'s tag-owned
|
|
18
|
+
// `buildStructure` does that, read back off `scroll.childHost` rather than built a second time
|
|
19
|
+
// here. RefreshControl is an ordinary child now; `claimedChildren` decides where it lands.
|
|
24
20
|
//
|
|
25
21
|
// WHY THIS FILE STILL HAND-AUTHORS THE SCROLL TAG VIA `createElement` INSTEAD OF PLAIN JSX
|
|
26
22
|
// (`<scroll-view>{listBody}</scroll-view>`), unlike a component with no dynamic children. Solid's
|
|
@@ -496,24 +492,12 @@ export function createVirtualizedList() {
|
|
|
496
492
|
// A spread of a CALL compiles to mergeProps(() => …), so the separator's props stay live.
|
|
497
493
|
return <Separator {...separatorPropsFor(index)}/>;
|
|
498
494
|
}
|
|
499
|
-
// RN renders a separator in the gap AFTER a cell,
|
|
500
|
-
// cell — never after the window's last one
|
|
501
|
-
//
|
|
502
|
-
// cell — never after the window's last one, and never after the force-mounted sticky cell, which
|
|
503
|
-
// is not adjacent to the window.
|
|
495
|
+
// RN renders a separator in the gap AFTER a cell, only while there is a following rendered
|
|
496
|
+
// cell — never after the window's last one, and never after the force-mounted sticky cell,
|
|
497
|
+
// which is not adjacent to the window.
|
|
504
498
|
// RN gates the separator on the last index of the DATA, not of the WINDOW
|
|
505
|
-
// (VirtualizedList.js:793
|
|
506
|
-
//
|
|
507
|
-
// would make a cell's own measured height change as the window slides past it. Device-measured
|
|
508
|
-
// 2026-08-19 as a run of cells all shifting by exactly the divider's 1px.
|
|
509
|
-
// Nothing about the WINDOW may enter this predicate. The separator lives inside the measuring
|
|
510
|
-
// wrapper, so whatever decides to render it decides the cell's own height — and a height that
|
|
511
|
-
// depends on where the window happens to sit moves the content under the user every time the
|
|
512
|
-
// window slides. Two window-dependent terms were removed after being measured on device
|
|
513
|
-
// 2026-08-19, each as a run of cells shifting by exactly the divider's 1px: gating on the
|
|
514
|
-
// window's `last` (RN gates on the data's, VirtualizedList.js:793), and excluding the
|
|
515
|
-
// force-mounted sticky cell. RN excludes neither — its sticky header keeps its separator like
|
|
516
|
-
// any other cell.
|
|
499
|
+
// (VirtualizedList.js:793): the separator lives INSIDE the measuring wrapper, so gating on the
|
|
500
|
+
// window would make a cell's own measured height change as the window slides past it.
|
|
517
501
|
const hasSeparatorAfter = (index) => props.ItemSeparatorComponent !== undefined && index < metrics().count - 1;
|
|
518
502
|
// Records a sticky header's measured y (RN's _headerLayoutYs) so the header AHEAD of it can
|
|
519
503
|
// compute its collision point; without it every header would stick indefinitely.
|
|
@@ -554,13 +538,9 @@ export function createVirtualizedList() {
|
|
|
554
538
|
index: index(),
|
|
555
539
|
separators: makeSeparators(index()),
|
|
556
540
|
})));
|
|
557
|
-
// The separator rides INSIDE the measuring wrapper
|
|
558
|
-
//
|
|
559
|
-
//
|
|
560
|
-
// replaces it with one gap — every cell below the leading spacer then lands short by
|
|
561
|
-
// (separator + gap), and the content jumps by that much each time the window's first index
|
|
562
|
-
// moves. Measured at exactly 17px on device 2026-08-19 (a 1px divider under a 16px container
|
|
563
|
-
// gap); see .claude/rules/list-geometry-feedback-loop.md.
|
|
541
|
+
// The separator rides INSIDE the measuring wrapper (VirtualizedListCellRenderer.js:218-221).
|
|
542
|
+
// As a SIBLING it would be an extra flex child, landing every cell below the leading spacer
|
|
543
|
+
// short by (separator + gap) — see `list-geometry-feedback-loop.md`.
|
|
564
544
|
const separator = (<Show when={hasSeparatorAfter(index())}>
|
|
565
545
|
<view>{separatorElement(index())}</view>
|
|
566
546
|
</Show>);
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
// Sticky headers — the Solid lifecycle half of the JS layer RN implements in ScrollView.js /
|
|
2
2
|
// ScrollViewStickyHeader.js.
|
|
3
3
|
//
|
|
4
|
-
// PRIVATE TO VIRTUALIZED-LIST
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// with no adapter code at all — see that primitive's props header. VirtualizedList still needs its
|
|
8
|
-
// OWN implementation because it hand-builds its scroll host (`shared.tsx`'s own header explains
|
|
9
|
-
// why) rather than emitting the tag, so it wraps a flagged CELL itself instead of leaning on the
|
|
10
|
-
// engine's per-child walk. `wrapStickyHeaders`/`IStickyWrapInputs` — the generic child-array wrapper
|
|
11
|
-
// ScrollView used and this file never called — were dropped with the move; `virtualized-list/
|
|
12
|
-
// shared.tsx` wraps the cell it already owns directly.
|
|
4
|
+
// PRIVATE TO VIRTUALIZED-LIST: `<scroll-view>` honors `stickyHeaderIndices` via the engine's own
|
|
5
|
+
// `sticky-header` intrinsic with no adapter code. VirtualizedList still needs its OWN
|
|
6
|
+
// implementation because it hand-builds its scroll host, so `shared.tsx` wraps the cell directly.
|
|
13
7
|
//
|
|
14
8
|
// RN does stickiness PURELY IN JS: ScrollView wraps each flagged child in a ScrollViewStickyHeader
|
|
15
9
|
// fed by ONE scroll AnimatedValue, and the native scroll view ignores `stickyHeaderIndices`
|
package/build/renderer.js
CHANGED
|
@@ -60,17 +60,11 @@ export function replaceText(textNode, value) {
|
|
|
60
60
|
setEngineText(textNode, asText(value));
|
|
61
61
|
requestCommit();
|
|
62
62
|
}
|
|
63
|
-
// solid-js/universal hands createTextNode/replaceText the JSX child value UNCONVERTED
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
// lands on RCTRawText's `text`, which Fabric parses as a std::string: a number fails the
|
|
69
|
-
// conversion, convertRawProp logs and falls back to the DEFAULT empty string, and an empty first
|
|
70
|
-
// fragment then ABORTS the app inside BaseTextShadowNode::buildAttributedString — a native SIGABRT
|
|
71
|
-
// with nothing in the JS stack to point at. Diagnosed on the iOS simulator 2026-08-19. The
|
|
72
|
-
// parameter is typed `string` by RendererOptions, so the guard reads as redundant; it is not, and
|
|
73
|
-
// `unknown` is what makes that honest rather than a cast.
|
|
63
|
+
// solid-js/universal hands createTextNode/replaceText the JSX child value UNCONVERTED —
|
|
64
|
+
// `<Text>{list().length} tiles</Text>` arrives here as the NUMBER 3. RCTRawText's `text` parses
|
|
65
|
+
// as a std::string: a number falls back to empty, aborting inside buildAttributedString.
|
|
66
|
+
// Typed `unknown` rather than `string` (which RendererOptions declares) so the runtime guard
|
|
67
|
+
// below isn't erased as dead code.
|
|
74
68
|
function asText(value) {
|
|
75
69
|
return typeof value === 'string' ? value : String(value);
|
|
76
70
|
}
|
|
@@ -102,20 +96,11 @@ export function removeNode(parent, node) {
|
|
|
102
96
|
removeEngineChild(parent, node);
|
|
103
97
|
requestCommit();
|
|
104
98
|
}
|
|
105
|
-
// RN's two Text defaults
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
// All three were answering a question the layer below now answers for everyone: the rule reads the
|
|
112
|
-
// AUTHORED bag at payload time (`foldTextDefaults`, `SymbioteFabricProps.cpp`), where a null, an
|
|
113
|
-
// explicit `undefined` and an absent prop are all simply "not a value the author chose". The
|
|
114
|
-
// null case that cost this file two revisions is `ellipsize->isNull()` there, in one place, for
|
|
115
|
-
// every adapter.
|
|
116
|
-
// The `id` -> `nativeID` fold and its `aliasedNodes` WeakSet left this file on 2026-09-18. The
|
|
117
|
-
// memory was the right shape and the wrong LAYER: `routeProp` carries it now, so all five adapters
|
|
118
|
-
// resolve the precedence identically instead of three of them doing it three ways.
|
|
99
|
+
// RN's two Text defaults are answered below the adapter now: the rule reads the AUTHORED bag at
|
|
100
|
+
// payload time (`foldTextDefaults`, `SymbioteFabricProps.cpp`), where a null, an explicit
|
|
101
|
+
// `undefined` and an absent prop are all "not a value the author chose" — one rule, every adapter.
|
|
102
|
+
// The `id` -> `nativeID` fold lives in `routeProp` now, so all five adapters resolve the
|
|
103
|
+
// precedence identically instead of each doing it their own way.
|
|
119
104
|
// `multiline` selects between TWO Fabric views, so the TAG decides and no prop write moves a node
|
|
120
105
|
// between them. An author writing `<text-input multiline>` instead of `<text-input-multiline>` gets
|
|
121
106
|
// the single-line view with a prop no ViewConfig on it declares — two silent divergences.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/solid",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.5",
|
|
4
4
|
"description": "SymbioteNative's Solid adapter — a solid-js/universal createRenderer driving real native iOS/Android views through the same engine as every other adapter.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -62,19 +62,19 @@
|
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"babel-preset-solid": "^1.9.12",
|
|
64
64
|
"typescript": "~6.0.0",
|
|
65
|
-
"@symbiote-native/components": "3.1.
|
|
66
|
-
"@symbiote-native/css-parser": "0.5.
|
|
65
|
+
"@symbiote-native/components": "3.1.3",
|
|
66
|
+
"@symbiote-native/css-parser": "0.5.2"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"solid-js": ">=1.9.0",
|
|
70
70
|
"react-native": ">=0.86",
|
|
71
|
-
"@symbiote-native/engine": "^1.
|
|
71
|
+
"@symbiote-native/engine": "^1.4.0"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@babel/core": "^7.25.2",
|
|
75
75
|
"solid-js": "^1.9.14",
|
|
76
|
-
"@symbiote-native/engine": "1.
|
|
77
|
-
"@symbiote-native/test-utils": "0.4.
|
|
76
|
+
"@symbiote-native/engine": "1.4.0",
|
|
77
|
+
"@symbiote-native/test-utils": "0.4.5"
|
|
78
78
|
},
|
|
79
79
|
"scripts": {
|
|
80
80
|
"typecheck": "tsc --build",
|