@symbiote-native/components 2.0.0 → 3.0.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 +8 -9
- package/build/accessibility-props.d.ts +1 -1
- package/build/accessibility-props.js +2 -2
- package/build/behaviors/activity-indicator/shared.js +41 -70
- package/build/behaviors/button.d.ts +11 -0
- package/build/behaviors/button.js +101 -89
- package/build/behaviors/image-background.d.ts +1 -0
- package/build/behaviors/image-background.js +97 -81
- package/build/behaviors/image.d.ts +0 -1
- package/build/behaviors/image.js +24 -105
- package/build/behaviors/input-accessory-view.d.ts +0 -1
- package/build/behaviors/input-accessory-view.js +47 -53
- package/build/behaviors/pressable.d.ts +1 -1
- package/build/behaviors/pressable.js +68 -97
- package/build/behaviors/refresh-control.js +15 -2
- package/build/behaviors/scroll-view/index.android.js +25 -37
- package/build/behaviors/scroll-view/index.d.ts +1 -0
- package/build/behaviors/scroll-view/index.js +3 -0
- package/build/behaviors/scroll-view/responder.d.ts +4 -0
- package/build/behaviors/scroll-view/responder.js +202 -0
- package/build/behaviors/scroll-view/shared.d.ts +1 -3
- package/build/behaviors/scroll-view/shared.js +95 -95
- package/build/behaviors/scroll-view/sticky.d.ts +1 -0
- package/build/behaviors/scroll-view/sticky.js +62 -49
- package/build/behaviors/switch.js +43 -86
- package/build/behaviors/text-input.js +219 -107
- package/build/behaviors/touchable-highlight.js +74 -61
- package/build/behaviors/touchable-native-feedback.js +43 -122
- package/build/behaviors/touchable-opacity.js +71 -59
- package/build/behaviors/touchable-without-feedback.js +35 -100
- package/build/component-names/index.android.js +7 -11
- package/build/component-names/index.ios.js +0 -7
- package/build/component-names/shared.d.ts +1 -1
- package/build/index.d.ts +15 -21
- package/build/index.js +21 -28
- package/build/resolve-intrinsic.js +3 -9
- package/build/scroll-view-commands.d.ts +1 -9
- package/build/scroll-view-commands.js +13 -74
- package/build/state/flat-list.d.ts +2 -2
- package/build/state/flat-list.js +10 -2
- package/build/state/pressable.d.ts +6 -1
- package/build/state/pressable.js +63 -28
- package/build/state/section-list.d.ts +2 -0
- package/build/state/section-list.js +14 -7
- package/build/state/text-input.d.ts +7 -40
- package/build/state/text-input.js +17 -186
- package/build/state/touchable.d.ts +1 -0
- package/build/state/touchable.js +11 -8
- package/build/state/virtualized-list-reducer.d.ts +2 -2
- package/build/state/virtualized-list.d.ts +6 -6
- package/build/state/virtualized-list.js +71 -37
- package/build/text-props.d.ts +0 -8
- package/build/text-props.js +14 -25
- package/build/view/render-button.d.ts +1 -29
- package/build/view/render-button.js +44 -81
- package/build/view/render-image/index.d.ts +14 -1
- package/build/view/render-image/index.js +22 -147
- package/build/view/render-input-accessory-view.d.ts +1 -5
- package/build/view/render-input-accessory-view.js +26 -48
- package/build/view/render-keyboard-avoiding-view.d.ts +7 -1
- package/build/view/render-keyboard-avoiding-view.js +40 -1
- package/build/view/render-modal.d.ts +1 -1
- package/build/view/render-modal.js +15 -5
- package/build/view/render-pressable/index.d.ts +1 -0
- package/build/view/render-pressable/index.js +4 -0
- package/build/view/render-scroll-view.d.ts +0 -4
- package/build/view/render-scroll-view.js +3 -49
- package/build/view/render-switch.d.ts +0 -14
- package/build/view/render-switch.js +4 -42
- package/build/view/render-touchable-highlight.d.ts +1 -0
- package/build/view/render-touchable-native-feedback.d.ts +0 -1
- package/build/view/render-touchable-native-feedback.js +15 -9
- package/host-primitives.cjs +49 -203
- package/host-primitives.d.cts +0 -1
- package/package.json +3 -7
- package/build/fold-host-bag.d.ts +0 -15
- package/build/fold-host-bag.js +0 -99
- package/build/view/render-text-input.d.ts +0 -11
- package/build/view/render-text-input.js +0 -39
|
@@ -35,63 +35,23 @@
|
|
|
35
35
|
// REGISTRATION IS THE HAZARD, not the machine — see `./pressable`. Registered in the same commit
|
|
36
36
|
// that deletes the five wrappers, because the registry is keyed by TAG and a wrapper still emitting
|
|
37
37
|
// its own `pressable` would put two press machines on one tree.
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import { accessibleUnlessOptedOut, asAccessibilityState, attachPressMachine, booleanOr, detachPressMachine, } from './pressable.js';
|
|
38
|
+
import { SLOT_DERIVED_ALL, appListenerFor, markPropsDirty, registerHostBehavior, requestCommitFor, setBehaviorListener, propOf, } from '@symbiote-native/engine';
|
|
39
|
+
import { attachPressMachine, detachPressMachine, } from './pressable.js';
|
|
41
40
|
import { createTouchableFeedbackHandlers, createTouchableFeedbackRuntime, TOUCHABLE_MIN_PRESS_DURATION_MS, } from '../state/touchable.js';
|
|
42
41
|
export const TOUCHABLE_WITHOUT_FEEDBACK_TAG = 'touchable-without-feedback';
|
|
43
|
-
//
|
|
44
|
-
// the four `on*` names (forwarded as LISTENERS by `FORWARDED_LISTENERS`) and the five raw `aria-*`
|
|
45
|
-
// entries. RN passes those raw because its TWF folds no aria itself and leaves the child View to do
|
|
46
|
-
// it; we fold the owner's bag before the clone runs, so `aria-valuemax` has already become
|
|
47
|
-
// `accessibilityValue` and `aria-modal` `accessibilityViewIsModal` by this point.
|
|
42
|
+
// WHAT THE OWNER'S WRITES DIRTY, and it is EVERY name rather than a list of thirty.
|
|
48
43
|
//
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
'testID',
|
|
61
|
-
];
|
|
62
|
-
// :253-276, assigned whatever their value — including `undefined`, which clears the child's, the
|
|
63
|
-
// same `cloneElement` semantics TNF relies on. Three of them (`accessibilityElementsHidden`,
|
|
64
|
-
// `accessibilityLiveRegion`, `importantForAccessibility`) are in RN's passthrough list TOO, and the
|
|
65
|
-
// later conditional copy can only re-assign the same value the aria fold already resolved — so they
|
|
66
|
-
// belong here, not above.
|
|
67
|
-
const CLONED_ALWAYS = [
|
|
68
|
-
'accessibilityElementsHidden',
|
|
69
|
-
'accessibilityLiveRegion',
|
|
70
|
-
'importantForAccessibility',
|
|
71
|
-
];
|
|
72
|
-
// Owner props the four COMPUTED clones read, on top of the two lists above. `focusable` also
|
|
73
|
-
// derives from the `press` LISTENER, which is not a prop — see `onOwnedListenerChange`.
|
|
74
|
-
const DERIVED_FROM = [
|
|
75
|
-
'accessible',
|
|
76
|
-
'accessibilityState',
|
|
77
|
-
'disabled',
|
|
78
|
-
'focusable',
|
|
79
|
-
'id',
|
|
80
|
-
'nativeID',
|
|
81
|
-
// Not cloned at all: they configure the scheduler, which reads them live at gesture start. Listed
|
|
82
|
-
// so a mid-mount change still dirties the child and the next commit re-reads them.
|
|
83
|
-
'delayPressIn',
|
|
84
|
-
'delayPressOut',
|
|
85
|
-
'minPressDuration',
|
|
86
|
-
];
|
|
87
|
-
// Every owner name the child's payload reads. Without it the clone is correct at mount and frozen
|
|
88
|
-
// forever after: `markPropsDirty` bubbles UP, so an owner write never reaches the child on its own.
|
|
89
|
-
const SLOT_DERIVED = [
|
|
90
|
-
...CLONED_WHEN_SET,
|
|
91
|
-
...CLONED_ALWAYS,
|
|
92
|
-
...DERIVED_FROM,
|
|
93
|
-
...ARIA_ALIAS_KEYS,
|
|
94
|
-
];
|
|
44
|
+
// RN's two clone lists (`TouchableWithoutFeedback.js:130-153` when-set, `:253-276` always) lived
|
|
45
|
+
// here until 2026-09-18, feeding `slotDerived` alongside the six computed names and the three
|
|
46
|
+
// scheduler ones. The clone is `foldCloneOntoChild` in `SymbioteFabricProps.cpp` now, which turned
|
|
47
|
+
// the list from the RULE into a MIRROR of `kWithoutFeedbackWhenSetKeys` +
|
|
48
|
+
// `kWithoutFeedbackAlwaysKeys` — two lists that must agree, failing silently when they drift.
|
|
49
|
+
//
|
|
50
|
+
// See `touchable-native-feedback.ts` for the same note and what the wildcard costs. The three
|
|
51
|
+
// scheduler names (`delayPressIn`, `delayPressOut`, `minPressDuration`) were the one entry here that
|
|
52
|
+
// was NEVER about the clone — they configure the press machine, which reads them live at gesture
|
|
53
|
+
// start — and a wildcard covers them for free where a list had to remember them.
|
|
54
|
+
const SLOT_DERIVED = [SLOT_DERIVED_ALL];
|
|
95
55
|
// :148-153. Owned, so the app's callback stashes on the owner and a trampoline on the child reads it
|
|
96
56
|
// at dispatch time. `layout` and `accessibilityAction` are Fabric BOOLEAN-GATED events
|
|
97
57
|
// (`.claude/rules/fabric-boolean-event-gates.md`), so the trampoline goes in only while the app has
|
|
@@ -117,47 +77,18 @@ const states = new WeakMap();
|
|
|
117
77
|
function numberOr(value, fallback) {
|
|
118
78
|
return typeof value === 'number' ? value : fallback;
|
|
119
79
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
// The owner's aria props are on the OWNER, so the engine's own fold at `fabricProps` — which
|
|
133
|
-
// reads the node being committed — never sees them. Run it here over the source bag; the fold
|
|
134
|
-
// returns its input by identity when there is nothing to do.
|
|
135
|
-
const source = owner.hasAriaAlias
|
|
136
|
-
? foldAriaProps(owner.props)
|
|
137
|
-
: owner.props;
|
|
138
|
-
for (const key of CLONED_ALWAYS)
|
|
139
|
-
next[key] = source[key];
|
|
140
|
-
for (const key of CLONED_WHEN_SET) {
|
|
141
|
-
if (source[key] !== undefined)
|
|
142
|
-
next[key] = source[key];
|
|
143
|
-
}
|
|
144
|
-
// :255-266. `onPress` is an OWNED name, so it lives in the stash and never in `props`.
|
|
145
|
-
const disabled = booleanOr(source.disabled);
|
|
146
|
-
next.accessible = accessibleUnlessOptedOut(source);
|
|
147
|
-
next.focusable = resolveTouchableFocusable(booleanOr(source.focusable), appListenerFor(owner, 'press') !== undefined, disabled);
|
|
148
|
-
// :275 gives `id` priority; the passthrough loop then re-assigns a set `nativeID` over it
|
|
149
|
-
// (:280-284), so upstream an explicit `nativeID` wins where TNF's `id` does. NOT reproduced,
|
|
150
|
-
// and deliberately: the spec entry declares `ID_ALIAS`, so on the three adapters that fold in
|
|
151
|
-
// the renderer `id` has already become `nativeID` before this runs and the quirk is
|
|
152
|
-
// unobservable — reproducing it would make the answer depend on WHICH adapter is driving,
|
|
153
|
-
// which is the divergence `.claude/rules/adapter-parity-audit.md` exists to prevent.
|
|
154
|
-
next.nativeID = stringOr(source.id) ?? stringOr(source.nativeID);
|
|
155
|
-
// :257-262 folded by the engine above, then :258-263: an explicit `disabled` overrides the
|
|
156
|
-
// aria/accessibilityState answer.
|
|
157
|
-
next.accessibilityState = resolveDisabledAccessibilityState(asAccessibilityState(source.accessibilityState), disabled);
|
|
158
|
-
return next;
|
|
159
|
-
};
|
|
160
|
-
}
|
|
80
|
+
// `cloneFold` LEFT THIS FILE ON 2026-09-18 — `foldCloneOntoChild` in `SymbioteFabricProps.cpp`,
|
|
81
|
+
// reached through the first rule keyed on the PARENT'S tag (`IOwner`). TWF's two lists are NOT
|
|
82
|
+
// TNF's: the passthrough half is copied only when SET (`:281`), and the C++ rule keeps that split
|
|
83
|
+
// rather than collapsing the two into one.
|
|
84
|
+
//
|
|
85
|
+
// One quirk of upstream's that IS reproduced, and it is NOT free: `:280-284`'s passthrough loop
|
|
86
|
+
// re-assigns a set `nativeID` over the `id` it just resolved, so an explicit `nativeID` wins here
|
|
87
|
+
// where TNF's `id` does. `routeProp` settles the two names into one value before any rule runs, so
|
|
88
|
+
// getting this right needed the collapse itself to know which of the two components it is running
|
|
89
|
+
// for — `node.nativeIdWinsOverId`, set only by this behavior's registration, flips it.
|
|
90
|
+
//
|
|
91
|
+
// Contract: `core/engine/cpp/tests/js/clone-onto-child-payload.itest.ts`.
|
|
161
92
|
/**
|
|
162
93
|
* `delayPressIn` / `delayPressOut` (:186-188) plus RN's unconditional `minPressDuration: 0` (:190).
|
|
163
94
|
*
|
|
@@ -168,11 +99,11 @@ function cloneFold(owner, inner) {
|
|
|
168
99
|
function refinementFor(owner, state) {
|
|
169
100
|
return (_node, config) => {
|
|
170
101
|
const handlers = createTouchableFeedbackHandlers({
|
|
171
|
-
delayPressIn: numberOr(owner
|
|
172
|
-
delayPressOut: numberOr(owner
|
|
102
|
+
delayPressIn: numberOr(propOf(owner, 'delayPressIn'), 0),
|
|
103
|
+
delayPressOut: numberOr(propOf(owner, 'delayPressOut'), 0),
|
|
173
104
|
// Read raw rather than off `config`, which has already defaulted the absent case to the
|
|
174
105
|
// press machine's own 130 ms — a floor RN's Touchables never see.
|
|
175
|
-
minPressDuration: numberOr(owner
|
|
106
|
+
minPressDuration: numberOr(propOf(owner, 'minPressDuration'), TOUCHABLE_MIN_PRESS_DURATION_MS),
|
|
176
107
|
schedule: (callback, ms) => {
|
|
177
108
|
const id = setTimeout(() => {
|
|
178
109
|
state.timers.delete(id);
|
|
@@ -258,10 +189,11 @@ function onChildInserted(node, child) {
|
|
|
258
189
|
if (previous !== undefined)
|
|
259
190
|
detachPressMachine(previous);
|
|
260
191
|
node.childHost = child;
|
|
261
|
-
child.payloadFold = cloneFold(node, child.payloadFold);
|
|
262
192
|
// The owner's props were very likely written BEFORE this child existed (React and Solid set props
|
|
263
|
-
// at createInstance), so the
|
|
193
|
+
// at createInstance), so the CLONE owes a run even though nothing was written since. Witnessed by
|
|
264
194
|
// the MOVED-child case, not by a fresh one — `appendChild` already dirties a node it created.
|
|
195
|
+
// Still owed now that the rule is in C++: it runs on the child's commit, and a child nothing
|
|
196
|
+
// dirtied has no commit.
|
|
265
197
|
markPropsDirty(child);
|
|
266
198
|
arm(node, child);
|
|
267
199
|
}
|
|
@@ -291,6 +223,9 @@ export function registerTouchableWithoutFeedbackBehavior() {
|
|
|
291
223
|
// the child (`attachPressMachine`'s `source`) and by the trampolines above.
|
|
292
224
|
ownedListeners: [...PRESS_LISTENERS, ...FORWARDED_LISTENERS],
|
|
293
225
|
slotDerived: SLOT_DERIVED,
|
|
226
|
+
// TouchableWithoutFeedback.js's clone overwrites `nativeID` with the raw authored value
|
|
227
|
+
// (`:279-282`), the reverse of every other component's `id ?? nativeID` — see `routeIdAlias`.
|
|
228
|
+
nativeIdWinsOverId: true,
|
|
294
229
|
};
|
|
295
230
|
registerHostBehavior(TOUCHABLE_WITHOUT_FEEDBACK_TAG, behavior);
|
|
296
231
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Each name is the ViewManager's REACT_CLASS in react-native/ReactAndroid/.../views/**.
|
|
3
3
|
// device-verify-pending: source-confirmed from RN's Android ViewManagers, proven on a
|
|
4
4
|
// real host by the absence of a "Can't find ViewManager '<name>'" red box.
|
|
5
|
-
import { ANCHOR_COMPONENT } from '@symbiote-native/engine';
|
|
5
|
+
import { ANCHOR_COMPONENT, VOID_COMPONENT } from '@symbiote-native/engine';
|
|
6
6
|
import { buildDescriptors, makeDescriptorFor, } from './shared.js';
|
|
7
7
|
const ANDROID_NAMES = {
|
|
8
8
|
view: 'RCTView',
|
|
@@ -28,14 +28,7 @@ const ANDROID_NAMES = {
|
|
|
28
28
|
// Android has one text-input ViewManager for both single- and multiline.
|
|
29
29
|
'text-input': 'AndroidTextInput',
|
|
30
30
|
'text-input-multiline': 'AndroidTextInput',
|
|
31
|
-
// The component path's pair — same native views, a tag the behavior registry does not
|
|
32
|
-
// carry. See `shared.ts` for why the wrapper may not share the lowered tag.
|
|
33
|
-
'text-input-managed': 'AndroidTextInput',
|
|
34
|
-
'text-input-multiline-managed': 'AndroidTextInput',
|
|
35
31
|
switch: 'AndroidSwitch',
|
|
36
|
-
// The wrapper's tag — same native view, a tag the behavior registry does not carry. See
|
|
37
|
-
// `shared.ts` for why the wrapper may not share the lowered tag.
|
|
38
|
-
'switch-managed': 'AndroidSwitch',
|
|
39
32
|
'activity-indicator': 'RCTView',
|
|
40
33
|
'activity-indicator-spinner': 'AndroidProgressBar',
|
|
41
34
|
// KNOWN DIVERGENCE FROM REACT NATIVE, and it is in our favour — recorded 2026-09-01 because it
|
|
@@ -56,9 +49,12 @@ const ANDROID_NAMES = {
|
|
|
56
49
|
modal: 'RCTModalHostView',
|
|
57
50
|
'refresh-control': 'AndroidSwipeRefreshLayout',
|
|
58
51
|
'sticky-header': 'RCTView',
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
|
|
52
|
+
// `InputAccessoryView.js` on Android does `console.warn(...); return null` — the WHOLE component,
|
|
53
|
+
// children included, renders NOTHING. A plain `RCTView` container (this file's answer until
|
|
54
|
+
// 2026-09-20) committed a real, laid-out, potentially visible node plus its whole child subtree —
|
|
55
|
+
// a real divergence from vendor, not a harmless degrade. `VOID_COMPONENT` matches vendor exactly:
|
|
56
|
+
// no node, no children, on this platform only.
|
|
57
|
+
'input-accessory-view': VOID_COMPONENT,
|
|
62
58
|
};
|
|
63
59
|
export const COMPONENT_DESCRIPTORS = buildDescriptors(ANDROID_NAMES);
|
|
64
60
|
export const descriptorFor = makeDescriptorFor(COMPONENT_DESCRIPTORS);
|
|
@@ -26,14 +26,7 @@ const IOS_NAMES = {
|
|
|
26
26
|
'horizontal-scroll-content': 'RCTScrollContentView',
|
|
27
27
|
'text-input': 'RCTSinglelineTextInputView',
|
|
28
28
|
'text-input-multiline': 'RCTMultilineTextInputView',
|
|
29
|
-
// The component path's pair — same native views, a tag the behavior registry does not
|
|
30
|
-
// carry. See `shared.ts` for why the wrapper may not share the lowered tag.
|
|
31
|
-
'text-input-managed': 'RCTSinglelineTextInputView',
|
|
32
|
-
'text-input-multiline-managed': 'RCTMultilineTextInputView',
|
|
33
29
|
switch: 'Switch',
|
|
34
|
-
// The wrapper's tag — same native view, a tag the behavior registry does not carry. See
|
|
35
|
-
// `shared.ts` for why the wrapper may not share the lowered tag.
|
|
36
|
-
'switch-managed': 'Switch',
|
|
37
30
|
'activity-indicator': 'RCTView',
|
|
38
31
|
'activity-indicator-spinner': 'ActivityIndicatorView',
|
|
39
32
|
'safe-area-view': 'SafeAreaView',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ISymbioteIntrinsic = 'view' | 'pressable' | 'touchable-opacity' | 'touchable-native-feedback' | 'touchable-without-feedback' | 'touchable-highlight' | 'button' | 'text' | 'image' | 'image-background' | 'scroll-view' | 'scroll-content' | 'horizontal-scroll-view' | 'horizontal-scroll-content' | 'text-input' | 'text-input-multiline' | '
|
|
1
|
+
export type ISymbioteIntrinsic = 'view' | 'pressable' | 'touchable-opacity' | 'touchable-native-feedback' | 'touchable-without-feedback' | 'touchable-highlight' | 'button' | 'text' | 'image' | 'image-background' | 'scroll-view' | 'scroll-content' | 'horizontal-scroll-view' | 'horizontal-scroll-content' | 'text-input' | 'text-input-multiline' | 'switch' | 'activity-indicator' | 'activity-indicator-spinner' | 'safe-area-view' | 'modal' | 'refresh-control' | 'sticky-header' | 'input-accessory-view';
|
|
2
2
|
export type ICrossTypedIntrinsics<LooseProps, Crossed extends Partial<Record<ISymbioteIntrinsic, unknown>>> = Omit<Record<ISymbioteIntrinsic, LooseProps>, keyof Crossed> & Crossed;
|
|
3
3
|
export interface IComponentDescriptor {
|
|
4
4
|
component: string;
|
package/build/index.d.ts
CHANGED
|
@@ -3,20 +3,18 @@ export type { IDescriptor, IDescriptorType, IDescriptorProps, IDescriptorChild,
|
|
|
3
3
|
export { createDescriptorShapeGuard } from './descriptor';
|
|
4
4
|
export type { IDescriptorShapeGuard } from './descriptor';
|
|
5
5
|
export { resolveAccessibilityProps } from './accessibility-props';
|
|
6
|
-
export {
|
|
7
|
-
export type { IEllipsizeMode, ITextDefaultableProps } from './text-props';
|
|
6
|
+
export type { IEllipsizeMode } from './text-props';
|
|
8
7
|
export type { IAccessibilityProps, IAriaProps, IAccessibilityRole, IRole, IAccessibilityStateValue, IAccessibilityValue, IAccessibilityActionInfo, } from './accessibility-props';
|
|
9
8
|
export { descriptorFor, COMPONENT_DESCRIPTORS } from './component-names';
|
|
10
9
|
export { buildDescriptors, makeDescriptorFor } from './component-names/shared';
|
|
11
10
|
export type { ISymbioteIntrinsic, IComponentDescriptor, ICrossTypedIntrinsics, } from './component-names/shared';
|
|
12
|
-
export {
|
|
13
|
-
export type { ISwitchProps, ISwitchViewProps, ISwitchPlatform, ISwitchTrackColor, ISwitchChangeEvent, } from './view/render-switch';
|
|
11
|
+
export type { ISwitchProps, ISwitchTrackColor, ISwitchChangeEvent, } from './view/render-switch';
|
|
14
12
|
export type { IResponderProps } from './responder-props';
|
|
15
13
|
export { switchReducer, createInitialSwitchState, shouldSnapBack, valueFromChange, } from './state/switch';
|
|
16
14
|
export type { ISwitchState, ISwitchAction } from './state/switch';
|
|
17
|
-
export {
|
|
15
|
+
export { selectScrollIntrinsics, readLayoutDimension, didContentSizeChange, resolveScrollForwarding, } from './view/render-scroll-view';
|
|
18
16
|
export type { IScrollIntrinsics, IContentSize, IScrollForwarding, IScrollForwardingInputs, IScrollForwardMode, } from './view/render-scroll-view';
|
|
19
|
-
export { buildScrollViewHandle,
|
|
17
|
+
export { buildScrollViewHandle, attachStickyScroll, isSymbioteEvent, forwardScrollEvent, } from './scroll-view-commands';
|
|
20
18
|
export type { IScrollViewHandle } from './scroll-view-commands';
|
|
21
19
|
export { computeStickyInterpolation, nextStickyHeaderY, stickyDebounceMs, readLayoutNumber, STICKY_HEADER_Z_INDEX, } from './view/render-scroll-sticky';
|
|
22
20
|
export type { IStickyHeaderProps, IStickyInterpolationParams, } from './view/render-scroll-sticky';
|
|
@@ -26,31 +24,27 @@ export type { IImageSource, IImageSourceProp, IResizeMode, IImageProps, IImageVi
|
|
|
26
24
|
export { renderImage } from './view/render-image';
|
|
27
25
|
export type { IImageStatics, IImageSize, IImageCacheStatus, } from '@symbiote-native/engine';
|
|
28
26
|
export { imageStatics, setImageSourceResolver } from '@symbiote-native/engine';
|
|
29
|
-
export { renderInputAccessoryView } from './view/render-input-accessory-view';
|
|
30
27
|
export type { IInputAccessoryViewViewProps } from './view/render-input-accessory-view';
|
|
31
28
|
export { renderModal } from './view/render-modal';
|
|
32
29
|
export type { IModalViewProps, IModalAnimationType, IModalPresentationStyle, IModalOrientation, IModalOrientationChangeEvent, } from './view/render-modal';
|
|
33
30
|
export { modalReducer, createInitialModalState, shouldRenderModal, } from './state/modal';
|
|
34
31
|
export type { IModalState, IModalAction } from './state/modal';
|
|
35
|
-
export { computeInset, keyboardAvoidingEventNamesFor, readPrefersCrossFadeTransitions, readKeyboardFrame, readLayoutFrame, resolveKeyboardAvoidingLayout, DEFAULT_VERTICAL_OFFSET, } from './view/render-keyboard-avoiding-view';
|
|
36
|
-
export type { IComputeInsetOptions, IKeyboardAvoidingBehavior, IKeyboardAvoidingEventNames, IMeasuredFrame, IKeyboardFrame, IKeyboardAvoidingLayout, IResolveKeyboardAvoidingLayoutParams, } from './view/render-keyboard-avoiding-view';
|
|
37
|
-
export { createPressHandlers, createPressRuntime, disposePressRuntime, normalizeRect, maxEdge, isTouchWithinRegion, readPoint, computeRegion,
|
|
32
|
+
export { computeInset, configureKeyboardAvoidingAnimation, keyboardAvoidingEventNamesFor, readKeyboardAnimationTiming, readPrefersCrossFadeTransitions, readKeyboardFrame, readLayoutFrame, resolveKeyboardAvoidingLayout, DEFAULT_VERTICAL_OFFSET, } from './view/render-keyboard-avoiding-view';
|
|
33
|
+
export type { IComputeInsetOptions, IKeyboardAnimationTiming, IKeyboardAvoidingBehavior, IKeyboardAvoidingEventNames, IMeasuredFrame, IKeyboardFrame, IKeyboardAvoidingLayout, IResolveKeyboardAvoidingLayoutParams, } from './view/render-keyboard-avoiding-view';
|
|
34
|
+
export { createPressHandlers, createPressRuntime, disposePressRuntime, normalizeRect, maxEdge, isTouchWithinRegion, readPoint, computeRegion, DEFAULT_DELAY_LONG_PRESS_MS, DEFAULT_MIN_PRESS_DURATION_MS, DEFAULT_PRESS_RECT_OFFSETS, } from './state/pressable';
|
|
38
35
|
export type { IPressState, IPressHandler, IPressHandlers, IPressHost, IPressRuntime, IPressMachineConfig, IFrameCallback, IRectOffset, IEdgeInsets, IResponderRegion, IPressableAndroidRippleConfig, IRippleBackground as IPressableRippleBackground, } from './state/pressable';
|
|
39
36
|
export { buildPressableListeners, resolveDisabledAccessibilityState, noteHoverNoop, shouldSuppressPress, shouldClaimResponder, isTerminationAllowed, resolvePressableFocusable, resolveTouchableFocusable, } from './view/render-pressable';
|
|
40
37
|
export { computePressOutWait, createTouchableFeedbackRuntime, createTouchableFeedbackHandlers, DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_GRANT_DURATION_MS, OPACITY_ACTIVE_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, DEFAULT_HIGHLIGHT_CHILD_OPACITY, DEFAULT_UNDERLAY_COLOR, TOUCHABLE_MIN_PRESS_DURATION_MS, restingOpacityFromStyle, hasTouchablePressHandler, createHighlightUnderlayRuntime, createHighlightUnderlayHandlers, } from './state/touchable';
|
|
41
38
|
export type { IPressTimingProps, ITouchableHandler, ITouchableFeedbackRuntime, ITouchableFeedbackConfig, ITouchableFeedbackCallbacks, ITouchableFeedbackHandlers, ITouchablePressHandlerProps, IHighlightUnderlayRuntime, IHighlightUnderlayConfig, IHighlightUnderlayCallbacks, IHighlightUnderlayHandlers, } from './state/touchable';
|
|
42
39
|
export { resolveHighlightExtraStyles } from './view/render-touchable-highlight';
|
|
43
40
|
export type { ITouchableHighlightExtraStyles, ITouchableHighlightUnderlayView, } from './view/render-touchable-highlight';
|
|
44
|
-
export {
|
|
41
|
+
export { canUseNativeForeground, selectableBackground, selectableBackgroundBorderless, rippleBackground, TouchableNativeFeedback, } from './view/render-touchable-native-feedback';
|
|
45
42
|
export type { INativeFeedbackBackground, IThemeAttrBackground, IRippleBackground, } from './view/render-touchable-native-feedback';
|
|
46
|
-
export {
|
|
43
|
+
export { resolveButtonDisabled } from './view/render-button';
|
|
47
44
|
export type { IButtonProps } from './view/render-button';
|
|
48
|
-
export {
|
|
49
|
-
export type { ITextInputProps, ITextInputHandle, ITextInputSelection, ITextInputEventHandler,
|
|
50
|
-
export {
|
|
51
|
-
export { renderTextInput } from './view/render-text-input';
|
|
52
|
-
export type { ITextInputViewProps } from './view/render-text-input';
|
|
53
|
-
export { DEFAULT_WINDOW_SIZE, DEFAULT_INITIAL_NUM_TO_RENDER, DEFAULT_END_REACHED_THRESHOLD, DEFAULT_MAX_TO_RENDER_PER_BATCH, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD, DEFAULT_VIEW_AREA_COVERAGE_PERCENT_THRESHOLD, DEFAULT_START_REACHED_THRESHOLD, FIRST_INDEX, EMPTY_OFFSET, NO_INDEX, NO_CONTENT_LENGTH_SENT, INVERTED_Y_STYLE, INVERTED_X_STYLE, readScrollOffset, readLayoutLength, readLayoutOffset, buildOffsets, computeWindow, throttleWindow, visiblePercent, isCellViewable, offsetForIndex, averageMeasuredLength, averageMeasuredStride, highestMeasuredIndex, computeEndReached, computeStartReached, buildViewabilityPairs, computeViewableSet, diffViewable, maxMinimumViewTime, buildListPlan, computeMvcpAdjustment, resolveItemKey, indexOfItem, offsetForEnd, isSeparatorGapInRange, decideEdgeReached, resolveStickySectionHeaders, wrapFixedLayout, resolveAverageLength, } from './state/virtualized-list';
|
|
45
|
+
export { foldText, textFromChange, eventCountFromChange, shouldCommandText, INITIAL_EVENT_COUNT, SELECTION_NONE, } from './state/text-input';
|
|
46
|
+
export type { ITextInputProps, ITextInputHandle, ITextInputSelection, ITextInputEventHandler, IInputMode, IEnterKeyHint, ISubmitBehavior, ITextInputChangeEvent, } from './state/text-input';
|
|
47
|
+
export { DEFAULT_WINDOW_SIZE, DEFAULT_INITIAL_NUM_TO_RENDER, DEFAULT_MAX_TO_RENDER_PER_BATCH, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD, DEFAULT_VIEW_AREA_COVERAGE_PERCENT_THRESHOLD, FIRST_INDEX, EMPTY_OFFSET, NO_INDEX, NO_CONTENT_LENGTH_SENT, INVERTED_Y_STYLE, INVERTED_X_STYLE, readScrollOffset, readLayoutLength, readLayoutOffset, buildOffsets, computeWindow, throttleWindow, isCellViewable, offsetForIndex, averageMeasuredLength, averageMeasuredStride, highestMeasuredIndex, computeEndReached, computeStartReached, buildViewabilityPairs, computeViewableSet, diffViewable, maxMinimumViewTime, buildListPlan, computeMvcpAdjustment, resolveItemKey, indexOfItem, offsetForEnd, isSeparatorGapInRange, decideEdgeReached, resolveStickySectionHeaders, wrapFixedLayout, resolveAverageLength, } from './state/virtualized-list';
|
|
54
48
|
export type { IMvcpAction, IMvcpAdjustmentParams, IMvcpAdjustmentResult, ICellLayout, ISeparators, ISeparatorProps, IViewToken, IViewableItemsChangedInfo, IViewabilityConfig, IViewabilityConfigCallbackPair, IVirtualizedListHandle, IViewableSetParams, IListCellPlan, IListPlan, IListPlanParams, } from './state/virtualized-list';
|
|
55
49
|
export { reduceList, createInitialListState, listEffectSignature, } from './state/virtualized-list-reducer';
|
|
56
50
|
export type { IListState, IListMetrics, IListReducerInputs, IListAction, IListEffect, IListReduceResult, } from './state/virtualized-list-reducer';
|
|
@@ -68,10 +62,10 @@ export { registerTouchableNativeFeedbackBehavior, TOUCHABLE_NATIVE_FEEDBACK_TAG,
|
|
|
68
62
|
export { registerTouchableWithoutFeedbackBehavior, TOUCHABLE_WITHOUT_FEEDBACK_TAG, } from './behaviors/touchable-without-feedback';
|
|
69
63
|
export { ACTIVITY_INDICATOR_SPINNER_TAG, ACTIVITY_INDICATOR_TAG, registerActivityIndicatorBehavior, } from './behaviors/activity-indicator';
|
|
70
64
|
export type { IActivityIndicatorProps, IActivityIndicatorSize, } from './behaviors/activity-indicator';
|
|
71
|
-
export {
|
|
65
|
+
export { IMAGE_TAG, registerImageBehavior } from './behaviors/image';
|
|
72
66
|
export { IMAGE_BACKGROUND_TAG, registerImageBackgroundBehavior, } from './behaviors/image-background';
|
|
73
|
-
export {
|
|
67
|
+
export { INPUT_ACCESSORY_VIEW_TAG, registerInputAccessoryViewBehavior, } from './behaviors/input-accessory-view';
|
|
74
68
|
export { registerTextInputBehavior, buildTextInputHandle, TEXT_INPUT_TAG, TEXT_INPUT_MULTILINE_TAG, } from './behaviors/text-input';
|
|
75
69
|
export { registerSwitchBehavior, SWITCH_TAG } from './behaviors/switch';
|
|
76
70
|
export { registerRefreshControlBehavior, REFRESH_CONTROL_TAG, } from './behaviors/refresh-control';
|
|
77
|
-
export { HORIZONTAL_SCROLL_VIEW_TAG, registerScrollViewBehavior, SCROLL_VIEW_TAG, } from './behaviors/scroll-view';
|
|
71
|
+
export { HORIZONTAL_SCROLL_VIEW_TAG, registerScrollViewBehavior, SCROLL_VIEW_TAG, STICKY_HEADER_TAG, } from './behaviors/scroll-view';
|
package/build/index.js
CHANGED
|
@@ -11,22 +11,20 @@ export { createDescriptorShapeGuard } from './descriptor.js';
|
|
|
11
11
|
// and its types. Framework-agnostic, so React, Vue, and the next adapter all fold
|
|
12
12
|
// identically; moved here from @symbiote-native/react. RefreshControl/SafeAreaView/ScrollView consume it.
|
|
13
13
|
export { resolveAccessibilityProps } from './accessibility-props.js';
|
|
14
|
-
export { resolveTextProps } from './text-props.js';
|
|
15
14
|
// Intrinsic (`symbiote-*`) → Fabric view-name resolution. Shared by every adapter so the
|
|
16
15
|
// names CANNOT drift between them (one engine, one Fabric). The name tables are
|
|
17
16
|
// Metro-split (.ios/.android, filename selects, no Platform.OS read); the base
|
|
18
17
|
// re-exports iOS for headless. descriptorFor is the per-platform-bound resolver.
|
|
19
18
|
export { descriptorFor, COMPONENT_DESCRIPTORS } from './component-names';
|
|
20
19
|
export { buildDescriptors, makeDescriptorFor } from './component-names/shared.js';
|
|
21
|
-
export { renderSwitch } from './view/render-switch.js';
|
|
22
20
|
// Switch is the first STATE machine off this layer (ActivityIndicator was render-only):
|
|
23
21
|
// the reducer + the two pure predicates are the logic half, the adapter supplies the hook.
|
|
24
22
|
export { switchReducer, createInitialSwitchState, shouldSnapBack, valueFromChange, } from './state/switch.js';
|
|
25
23
|
// ScrollView: pure render/command helpers (no state machine, no 3-layer split). The adapter
|
|
26
24
|
// owns the refs/effects/element assembly and the sticky-header component; these supply the
|
|
27
25
|
// platform-invariant math and plumbing every adapter shares.
|
|
28
|
-
export {
|
|
29
|
-
export { buildScrollViewHandle,
|
|
26
|
+
export { selectScrollIntrinsics, readLayoutDimension, didContentSizeChange, resolveScrollForwarding, } from './view/render-scroll-view.js';
|
|
27
|
+
export { buildScrollViewHandle, attachStickyScroll, isSymbioteEvent, forwardScrollEvent, } from './scroll-view-commands.js';
|
|
30
28
|
export { computeStickyInterpolation, nextStickyHeaderY, stickyDebounceMs, readLayoutNumber, STICKY_HEADER_Z_INDEX, } from './view/render-scroll-sticky.js';
|
|
31
29
|
// The per-header sticky effect machine: the one pure state machine every sticky-header consumer drives
|
|
32
30
|
// (React/Vue header component, Angular header component, Angular projection wrapper), folding the
|
|
@@ -35,47 +33,42 @@ export { computeStickyInterpolation, nextStickyHeaderY, stickyDebounceMs, readLa
|
|
|
35
33
|
export { reduceSticky, createInitialStickyState, stickyEffectSignature, } from './state/sticky-header-reducer.js';
|
|
36
34
|
export { renderImage } from './view/render-image/index.js';
|
|
37
35
|
export { imageStatics, setImageSourceResolver } from '@symbiote-native/engine';
|
|
38
|
-
// ImageBackground: render-only composition (absolute-fill image behind, children on top).
|
|
39
|
-
// No render fn: the only composition this primitive had is the two nodes the behavior builds, so
|
|
40
|
-
// `view/render-image-background.ts` went with the wrappers — same as ActivityIndicator's.
|
|
41
|
-
// InputAccessoryView: render-only host assembly (nativeID/backgroundColor).
|
|
42
|
-
export { renderInputAccessoryView } from './view/render-input-accessory-view.js';
|
|
43
36
|
// Modal: full 3-layer split (state machine gates the iOS keep-alive frame).
|
|
44
37
|
export { renderModal } from './view/render-modal.js';
|
|
45
38
|
export { modalReducer, createInitialModalState, shouldRenderModal, } from './state/modal.js';
|
|
46
39
|
// KeyboardAvoidingView: pure inset/behavior math; the adapter owns the Keyboard subscription.
|
|
47
|
-
export { computeInset, keyboardAvoidingEventNamesFor, readPrefersCrossFadeTransitions, readKeyboardFrame, readLayoutFrame, resolveKeyboardAvoidingLayout, DEFAULT_VERTICAL_OFFSET, } from './view/render-keyboard-avoiding-view.js';
|
|
40
|
+
export { computeInset, configureKeyboardAvoidingAnimation, keyboardAvoidingEventNamesFor, readKeyboardAnimationTiming, readPrefersCrossFadeTransitions, readKeyboardFrame, readLayoutFrame, resolveKeyboardAvoidingLayout, DEFAULT_VERTICAL_OFFSET, } from './view/render-keyboard-avoiding-view.js';
|
|
48
41
|
// Pressable: the press state machine (logic) + render decisions. The pure lifecycle (timers,
|
|
49
42
|
// geometry, drift test, suppression flags) lives in state/pressable; the responder-listener +
|
|
50
43
|
// accessibilityState + ripple render decisions in view/render-pressable. Every adapter supplies
|
|
51
44
|
// only its reactive `pressed` cell + the View's measure handle (see the 3-layer split).
|
|
52
|
-
export { createPressHandlers, createPressRuntime, disposePressRuntime, normalizeRect, maxEdge, isTouchWithinRegion, readPoint, computeRegion,
|
|
45
|
+
export { createPressHandlers, createPressRuntime, disposePressRuntime, normalizeRect, maxEdge, isTouchWithinRegion, readPoint, computeRegion, DEFAULT_DELAY_LONG_PRESS_MS, DEFAULT_MIN_PRESS_DURATION_MS, DEFAULT_PRESS_RECT_OFFSETS, } from './state/pressable.js';
|
|
53
46
|
export { buildPressableListeners, resolveDisabledAccessibilityState, noteHoverNoop, shouldSuppressPress, shouldClaimResponder, isTerminationAllowed, resolvePressableFocusable, resolveTouchableFocusable, } from './view/render-pressable/index.js';
|
|
54
47
|
// Touchable*: shared press-timing constants + the deactivation-floor math (the Animated feedback
|
|
55
48
|
// itself stays per-adapter), and TouchableNativeFeedback's pure static factories + background map.
|
|
56
49
|
export { computePressOutWait, createTouchableFeedbackRuntime, createTouchableFeedbackHandlers, DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_GRANT_DURATION_MS, OPACITY_ACTIVE_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, DEFAULT_HIGHLIGHT_CHILD_OPACITY, DEFAULT_UNDERLAY_COLOR, TOUCHABLE_MIN_PRESS_DURATION_MS, restingOpacityFromStyle, hasTouchablePressHandler, createHighlightUnderlayRuntime, createHighlightUnderlayHandlers, } from './state/touchable.js';
|
|
57
50
|
export { resolveHighlightExtraStyles } from './view/render-touchable-highlight.js';
|
|
58
|
-
export {
|
|
51
|
+
export { canUseNativeForeground, selectableBackground, selectableBackgroundBorderless, rippleBackground,
|
|
59
52
|
// RN's own static namespace, the only part of the deleted wrappers with nowhere else to go: the
|
|
60
53
|
// element is a tag now, and a tag is a string that cannot carry `.Ripple`.
|
|
61
54
|
TouchableNativeFeedback, } from './view/render-touchable-native-feedback.js';
|
|
62
|
-
// Button:
|
|
63
|
-
//
|
|
64
|
-
// 2026-09-
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
export {
|
|
55
|
+
// Button: `resolveButtonDisabled` alone now — the `props.disabled ?? aria ?? state.disabled`
|
|
56
|
+
// precedence, which the press MACHINE reads and which is therefore still JS. Every platform fold
|
|
57
|
+
// Button.js performs left this barrel between 2026-09-17 and 2026-09-18 for
|
|
58
|
+
// `SymbioteFabricProps.cpp`; the last two, `buttonViewStyle` and `resolveButtonViewStyle`, went with
|
|
59
|
+
// the Android arm of the test host that finally made their branch assertable.
|
|
60
|
+
export { resolveButtonDisabled } from './view/render-button.js';
|
|
61
|
+
// TextInput: the controlled-value / event-count handshake, and ONLY that now — the machine. The
|
|
62
|
+
// W3C->native prop resolution that used to sit beside it is the engine's (`foldTextInputAliases`,
|
|
63
|
+
// `SymbioteFabricProps.cpp`), so `resolveTextInputProps` and the four lookup tables under it are
|
|
64
|
+
// gone rather than exported-and-unused: a tag's platform props are resolved once, natively, for
|
|
65
|
+
// every adapter, and a JS copy would only be a second answer to the same question.
|
|
66
|
+
export { foldText, textFromChange, eventCountFromChange, shouldCommandText, INITIAL_EVENT_COUNT, SELECTION_NONE, } from './state/text-input.js';
|
|
74
67
|
// VirtualizedList family: the framework-agnostic windowing engine + data shapes. Lists
|
|
75
68
|
// have NO view/render-*.ts (the cell content is the framework's own children, so there is
|
|
76
69
|
// no Descriptor render fn) — the shared layer for lists is this STATE/logic, reused
|
|
77
70
|
// verbatim by React and Vue.
|
|
78
|
-
export { DEFAULT_WINDOW_SIZE, DEFAULT_INITIAL_NUM_TO_RENDER,
|
|
71
|
+
export { DEFAULT_WINDOW_SIZE, DEFAULT_INITIAL_NUM_TO_RENDER, DEFAULT_MAX_TO_RENDER_PER_BATCH, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD, DEFAULT_VIEW_AREA_COVERAGE_PERCENT_THRESHOLD, FIRST_INDEX, EMPTY_OFFSET, NO_INDEX, NO_CONTENT_LENGTH_SENT, INVERTED_Y_STYLE, INVERTED_X_STYLE, readScrollOffset, readLayoutLength, readLayoutOffset, buildOffsets, computeWindow, throttleWindow, isCellViewable, offsetForIndex, averageMeasuredLength, averageMeasuredStride, highestMeasuredIndex, computeEndReached, computeStartReached, buildViewabilityPairs, computeViewableSet, diffViewable, maxMinimumViewTime, buildListPlan, computeMvcpAdjustment, resolveItemKey, indexOfItem, offsetForEnd, isSeparatorGapInRange, decideEdgeReached, resolveStickySectionHeaders, wrapFixedLayout, resolveAverageLength, } from './state/virtualized-list.js';
|
|
79
72
|
// The orchestration reducer: the one pure state machine every list adapter drives, folding the
|
|
80
73
|
// after-commit effect skeleton (window recompute -> edge -> viewability -> initial-scroll -> MVCP)
|
|
81
74
|
// out of each adapter's reactive glue. The adapter maps events to actions and runs the effects.
|
|
@@ -102,12 +95,12 @@ export { registerTouchableWithoutFeedbackBehavior, TOUCHABLE_WITHOUT_FEEDBACK_TA
|
|
|
102
95
|
// The prop type rides along: there is no `view/render-activity-indicator.ts` any more, because the
|
|
103
96
|
// only render this primitive had was the two nodes the behavior now builds.
|
|
104
97
|
export { ACTIVITY_INDICATOR_SPINNER_TAG, ACTIVITY_INDICATOR_TAG, registerActivityIndicatorBehavior, } from './behaviors/activity-indicator';
|
|
105
|
-
export {
|
|
98
|
+
export { IMAGE_TAG, registerImageBehavior } from './behaviors/image.js';
|
|
106
99
|
// Registered by all five adapters since 2026-09-09, in the same commit that deleted the five
|
|
107
100
|
// wrappers — the tag builds the background image itself, so a surviving wrapper would have
|
|
108
101
|
// committed a second one under it.
|
|
109
102
|
export { IMAGE_BACKGROUND_TAG, registerImageBackgroundBehavior, } from './behaviors/image-background.js';
|
|
110
|
-
export {
|
|
103
|
+
export { INPUT_ACCESSORY_VIEW_TAG, registerInputAccessoryViewBehavior, } from './behaviors/input-accessory-view.js';
|
|
111
104
|
export { registerTextInputBehavior, buildTextInputHandle, TEXT_INPUT_TAG, TEXT_INPUT_MULTILINE_TAG, } from './behaviors/text-input.js';
|
|
112
105
|
export { registerSwitchBehavior, SWITCH_TAG } from './behaviors/switch.js';
|
|
113
106
|
export { registerRefreshControlBehavior, REFRESH_CONTROL_TAG, } from './behaviors/refresh-control.js';
|
|
@@ -119,4 +112,4 @@ export { registerRefreshControlBehavior, REFRESH_CONTROL_TAG, } from './behavior
|
|
|
119
112
|
// EVERY ADAPTER CALLS IT since 2026-09-11, through `@symbiote-native/components/register`. It was
|
|
120
113
|
// withheld while the wrappers built their own content node — registering then would have
|
|
121
114
|
// double-nested every ScrollView. They are gone; the engine is the single owner.
|
|
122
|
-
export { HORIZONTAL_SCROLL_VIEW_TAG, registerScrollViewBehavior, SCROLL_VIEW_TAG, } from './behaviors/scroll-view';
|
|
115
|
+
export { HORIZONTAL_SCROLL_VIEW_TAG, registerScrollViewBehavior, SCROLL_VIEW_TAG, STICKY_HEADER_TAG, } from './behaviors/scroll-view';
|
|
@@ -2,15 +2,9 @@
|
|
|
2
2
|
// commits, from the props it was created with.
|
|
3
3
|
//
|
|
4
4
|
// Why this has to exist at runtime at all. `intrinsicWhen` lets one primitive map to two native
|
|
5
|
-
// views (`TextInput` -> `RCTSinglelineTextInputView` / `RCTMultilineTextInputView`), and
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// `multiline={isLong}` cannot know the value, so it refused to lower the element at all.
|
|
9
|
-
//
|
|
10
|
-
// A public primitive TAG has no transform in front of it on three of the five adapters, so the
|
|
11
|
-
// choice has to be made where the value is actually known — here, at element creation. That is a
|
|
12
|
-
// capability the compiler never had, and it is why the refusal category disappears WITH the
|
|
13
|
-
// transform rather than migrating into it.
|
|
5
|
+
// views (`TextInput` -> `RCTSinglelineTextInputView` / `RCTMultilineTextInputView`), and the
|
|
6
|
+
// deciding prop can be a RUNTIME value: `multiline={isLong}` is knowable only once the element is
|
|
7
|
+
// created. So the choice is made here, where the value is.
|
|
14
8
|
//
|
|
15
9
|
// WHAT THIS DELIBERATELY DOES NOT DO: react to the prop CHANGING later. A node's native view is
|
|
16
10
|
// fixed at `createNode` and no prop write moves a node between view types, so flipping `multiline`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isSymbioteEvent, type AnimatedValue, type
|
|
1
|
+
import { isSymbioteEvent, type AnimatedValue, type ISymbioteEvent, type ISymbioteNode } from '@symbiote-native/engine';
|
|
2
2
|
type IScrollHandler = (event: ISymbioteEvent) => void;
|
|
3
3
|
export interface IScrollViewHandle {
|
|
4
4
|
scrollTo(options?: {
|
|
@@ -12,14 +12,6 @@ export interface IScrollViewHandle {
|
|
|
12
12
|
flashScrollIndicators(): void;
|
|
13
13
|
getScrollNode(): ISymbioteNode | null;
|
|
14
14
|
}
|
|
15
|
-
export declare function splitLayoutProps(style: IStyleProp<IViewStyle> | undefined): {
|
|
16
|
-
outer: Record<string, unknown>;
|
|
17
|
-
inner: Record<string, unknown>;
|
|
18
|
-
};
|
|
19
|
-
export declare function splitScrollViewStyle(base: IStyleProp<IViewStyle> | undefined, style: unknown): {
|
|
20
|
-
outer: IStyleProp<IViewStyle>;
|
|
21
|
-
inner: IStyleProp<IViewStyle>;
|
|
22
|
-
};
|
|
23
15
|
export { isSymbioteEvent };
|
|
24
16
|
export declare function forwardScrollEvent(handler: IScrollHandler, args: readonly unknown[]): void;
|
|
25
17
|
export declare function buildScrollViewHandle(getNode: () => ISymbioteNode | null): IScrollViewHandle;
|
|
@@ -4,78 +4,17 @@
|
|
|
4
4
|
// scroll-attach are all platform- and framework-invariant, so they live here. The adapter
|
|
5
5
|
// supplies the lifecycle (the node getter, the effect) and re-exports these.
|
|
6
6
|
import { attachNativeEvent, dlog, flattenStyle, isSymbioteEvent, } from '@symbiote-native/engine';
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
const LAYOUT_KEYS = new Set([
|
|
13
|
-
'margin',
|
|
14
|
-
'marginHorizontal',
|
|
15
|
-
'marginVertical',
|
|
16
|
-
'marginBottom',
|
|
17
|
-
'marginTop',
|
|
18
|
-
'marginLeft',
|
|
19
|
-
'marginRight',
|
|
20
|
-
'flex',
|
|
21
|
-
'flexGrow',
|
|
22
|
-
'flexShrink',
|
|
23
|
-
'flexBasis',
|
|
24
|
-
'alignSelf',
|
|
25
|
-
'height',
|
|
26
|
-
'minHeight',
|
|
27
|
-
'maxHeight',
|
|
28
|
-
'width',
|
|
29
|
-
'minWidth',
|
|
30
|
-
'maxWidth',
|
|
31
|
-
'position',
|
|
32
|
-
'left',
|
|
33
|
-
'right',
|
|
34
|
-
'bottom',
|
|
35
|
-
'top',
|
|
36
|
-
'transform',
|
|
37
|
-
'transformOrigin',
|
|
38
|
-
'rowGap',
|
|
39
|
-
'columnGap',
|
|
40
|
-
'gap',
|
|
41
|
-
]);
|
|
42
|
-
// Split a flattened style into the LAYOUT props that drive the outer wrapper's frame and the
|
|
43
|
-
// VISUAL props that paint the inner content, RN's splitLayoutProps. The Android build uses
|
|
44
|
-
// this when a RefreshControl wraps the scroll view: layout (margin/flex/size/position/…) goes
|
|
45
|
-
// on the AndroidSwipeRefreshLayout wrapper, visual (background/padding/border/…) stays on the
|
|
46
|
-
// inner scroll view, instead of dumping the whole style on the wrapper and hardcoding flex:1.
|
|
47
|
-
export function splitLayoutProps(style) {
|
|
48
|
-
const outer = {};
|
|
49
|
-
const inner = {};
|
|
50
|
-
// Reads keys off the style, so flatten the StyleProp (array/nested) to one object first.
|
|
51
|
-
const flat = flattenStyle(style);
|
|
52
|
-
for (const key of Object.keys(flat)) {
|
|
53
|
-
const value = Reflect.get(flat, key);
|
|
54
|
-
if (LAYOUT_KEYS.has(key))
|
|
55
|
-
outer[key] = value;
|
|
56
|
-
else
|
|
57
|
-
inner[key] = value;
|
|
58
|
-
}
|
|
59
|
-
return { outer, inner };
|
|
60
|
-
}
|
|
61
|
-
// The whole Android wrap style decision: the layout/visual split, AND the axis base composed onto
|
|
62
|
-
// BOTH boxes. RN does the second half too (`StyleSheet.compose(baseStyle, outer)` beside
|
|
63
|
-
// `compose(baseStyle, inner)`, ScrollView.js:1856), and every adapter had dropped it from the
|
|
64
|
-
// wrapper — so an AndroidSwipeRefreshLayout with no explicit user layout style lost `flexGrow: 1`
|
|
65
|
-
// and collapsed to its content height inside a flex parent, where RN's grows.
|
|
7
|
+
// THE ANDROID WRAP SPLIT LEFT THIS FILE ON 2026-09-18, and with it the last copy of RN's
|
|
8
|
+
// `splitLayoutProps` key partition. Both halves are `SymbioteFabricProps.cpp` now
|
|
9
|
+
// (`splitScrollViewStyle`, `foldRefreshWrapperProps`), reached off the tag and the tree rather than
|
|
10
|
+
// from a `payloadFold` per node — see `behaviors/scroll-view/index.android.ts` for what made the
|
|
11
|
+
// wrapper's half possible at all.
|
|
66
12
|
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
// `tests/
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
// Narrowing it would buy a guard at every fold call site and no safety.
|
|
73
|
-
export function splitScrollViewStyle(base, style) {
|
|
74
|
-
const { outer, inner } = splitLayoutProps(flattenStyle(style));
|
|
75
|
-
// Base UNDER the split half on both, so an explicit user value still wins — the same order the
|
|
76
|
-
// unwrapped scroll view composes.
|
|
77
|
-
return { outer: [base, outer], inner: [base, inner] };
|
|
78
|
-
}
|
|
13
|
+
// Nothing replaced them here on purpose: a JS copy kept for a caller that no longer exists is the
|
|
14
|
+
// mirror shape this migration keeps deleting, and the twenty-eight layout keys are exactly the kind
|
|
15
|
+
// of list that drifts in silence. `core/engine/cpp/tests/js/scroll-view-wrap-payload.itest.ts`
|
|
16
|
+
// asserts the split on the payload a commit actually sent, which is the only place it can now be
|
|
17
|
+
// wrong.
|
|
79
18
|
// Re-exported so the package barrel (index.ts) can still export this guard to
|
|
80
19
|
// '@symbiote-native/components' callers, now that it lives in the engine, next to ISymbioteEvent.
|
|
81
20
|
export { isSymbioteEvent };
|
|
@@ -92,9 +31,9 @@ export function forwardScrollEvent(handler, args) {
|
|
|
92
31
|
// platform files back it with their scroll node getter.
|
|
93
32
|
//
|
|
94
33
|
// It DELEGATES to the node's own methods rather than dispatching commands itself. The commands and
|
|
95
|
-
// their defaults live on `ISymbioteNode` because a
|
|
96
|
-
//
|
|
97
|
-
//
|
|
34
|
+
// their defaults live on `ISymbioteNode` because a `<scroll-view>` hands the app its engine node
|
|
35
|
+
// directly, with no wrapper to build a handle: two implementations would let `scrollTo()` with no
|
|
36
|
+
// argument mean one thing through a ref and another through a tag, and nothing would report it.
|
|
98
37
|
//
|
|
99
38
|
// `getNode` is a LAZY getter (React `() => ref.current`, Vue `() => nodeRef.value`), read on
|
|
100
39
|
// every call, NOT the node captured once. The node is null at mount and only set after the
|