@symbiote-native/components 3.1.0 → 3.1.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 +17 -18
- package/build/behaviors/button.js +1 -1
- package/build/behaviors/scroll-view/shared.js +2 -6
- package/build/bootstrap/index.d.ts +1 -0
- package/build/bootstrap/index.js +2 -1
- package/build/scroll-view-commands.js +6 -6
- package/build/view/render-button.js +0 -9
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -20,17 +20,19 @@ supplies only the third:
|
|
|
20
20
|
|
|
21
21
|
1. **Logic — `src/state/*.ts`.** A pure reducer `(state, action) => state`, a
|
|
22
22
|
`createInitial*State` factory, and pure predicates. Zero framework, zero render —
|
|
23
|
-
`
|
|
24
|
-
the `virtualized-list` windowing math for the list family.
|
|
23
|
+
`modalReducer` for `Modal`, `shouldSnapBack` / `valueFromChange` for `Pressable`'s press
|
|
24
|
+
machine, the `virtualized-list` windowing math for the list family.
|
|
25
25
|
2. **View — `src/view/render-*.ts`.** A pure function `render*(viewState, platform) => Descriptor`.
|
|
26
26
|
State and visuals enter **only through arguments**; out comes a tree of `Descriptor` nodes
|
|
27
27
|
(`{ type, props, children, key }`, built with `el()` / `txt()`) over the intrinsic primitives
|
|
28
|
-
(`symbiote-view`, `symbiote-
|
|
28
|
+
(`symbiote-view`, `symbiote-scroll-view`, …). No framework, no state, no events.
|
|
29
29
|
3. **Lifecycle — the adapter.** React wires the reducer through `useReducer`/`useLayoutEffect` and
|
|
30
30
|
bridges the `Descriptor` to `React.createElement`; Vue wires it through `ref`/`watch` and
|
|
31
31
|
bridges to `h()`. This is the ONLY part a new adapter has to write.
|
|
32
32
|
|
|
33
|
-
`
|
|
33
|
+
`Modal` is the canonical reference for a full three-layer component. `Switch` used to be — its
|
|
34
|
+
`render*` function is gone now that the painting moved to the `switch` tag's own host behavior
|
|
35
|
+
(see "Host behaviors" below), so only its reducer and prop type still live at this layer.
|
|
34
36
|
|
|
35
37
|
### Install
|
|
36
38
|
|
|
@@ -45,28 +47,25 @@ npm install @symbiote-native/components
|
|
|
45
47
|
## Usage
|
|
46
48
|
|
|
47
49
|
Nearly every consumer reaches this package **through an adapter**, not directly — an app imports
|
|
48
|
-
`
|
|
50
|
+
`Modal` from `@symbiote-native/react` (or `@symbiote-native/vue`), and that adapter re-exports the prop
|
|
49
51
|
types and wires the reducer/render pair from here. Calling the render function directly is what an
|
|
50
52
|
adapter itself does, to build its lifecycle wrapper:
|
|
51
53
|
|
|
52
54
|
```ts
|
|
53
55
|
import {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
renderModal,
|
|
57
|
+
createInitialModalState,
|
|
58
|
+
modalReducer,
|
|
57
59
|
} from '@symbiote-native/components';
|
|
58
60
|
|
|
59
61
|
// inside an adapter's own hook/composable:
|
|
60
|
-
const state =
|
|
61
|
-
const next =
|
|
62
|
-
const descriptor =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}),
|
|
68
|
-
},
|
|
69
|
-
);
|
|
62
|
+
const state = createInitialModalState(visible);
|
|
63
|
+
const next = modalReducer(state, { type: visible ? 'show' : 'hide' });
|
|
64
|
+
const descriptor = renderModal({
|
|
65
|
+
visible,
|
|
66
|
+
transparent: false,
|
|
67
|
+
passthrough: { onDismiss, onRequestClose, ref },
|
|
68
|
+
});
|
|
70
69
|
// descriptor is then handed to the adapter's own descriptorToReact / descriptorToVue bridge
|
|
71
70
|
```
|
|
72
71
|
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
// since 2026-09-09, in the same commit that deleted the five wrappers, which is what makes it safe:
|
|
112
112
|
// while a wrapper still built its own view and text under this tag, registering would have given
|
|
113
113
|
// every Button a second copy of the subtree.
|
|
114
|
-
import { addDerivedNode, appendChild, createElement, createRawText, markPropsDirty, Platform, registerHostBehavior, requestCommitFor,
|
|
114
|
+
import { addDerivedNode, appendChild, createElement, createRawText, markPropsDirty, Platform, registerHostBehavior, requestCommitFor, } from '@symbiote-native/engine';
|
|
115
115
|
import { descriptorFor } from '../component-names';
|
|
116
116
|
import { resolveButtonDisabled } from '../view/render-button.js';
|
|
117
117
|
import { booleanOr, createPressBehavior, } from './pressable.js';
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
// The slot's fold is assigned to the node inside `buildStructure`, not declared on the behavior:
|
|
82
82
|
// `IHostBehavior.foldPayload` is the OWNER's, wired by `attachHostBehavior`, and a behavior that
|
|
83
83
|
// builds a node owns what that node carries.
|
|
84
|
-
import { appendChild, appListenerFor, createElement, dlog, registerHostBehavior, setBehaviorListener, setEventListener,
|
|
84
|
+
import { appendChild, appListenerFor, createElement, dlog, registerHostBehavior, setBehaviorListener, setEventListener, } from '@symbiote-native/engine';
|
|
85
85
|
import { descriptorFor } from '../../component-names';
|
|
86
86
|
import { didContentSizeChange, readLayoutDimension, } from '../../view/render-scroll-view.js';
|
|
87
87
|
import { installResponderPredicates, RESPONDER_OWNED_LISTENERS, } from './responder.js';
|
|
@@ -151,8 +151,7 @@ export const REFRESH_CONTROL = descriptorFor('refresh-control').component;
|
|
|
151
151
|
// `core/engine/cpp/tests/js/scroll-content-payload.itest.ts`.
|
|
152
152
|
// `rowStyle` USED TO BE A PARAMETER HERE and is not one any more: the content node's row direction
|
|
153
153
|
// is decided in the engine from that node's OWN tag (`horizontal-scroll-content`), so this builder
|
|
154
|
-
// no longer needs to know the axis to build it.
|
|
155
|
-
// row style for the things that DO still need it in JS.
|
|
154
|
+
// no longer needs to know the axis to build it.
|
|
156
155
|
function buildContent(contentIntrinsic) {
|
|
157
156
|
return (node) => {
|
|
158
157
|
const descriptor = descriptorFor(contentIntrinsic);
|
|
@@ -233,9 +232,6 @@ function syncOwnedListener(owner, name, wired) {
|
|
|
233
232
|
syncOwnerLayout(owner);
|
|
234
233
|
}
|
|
235
234
|
function scrollBehavior(contentIntrinsic, rowStyle, platform) {
|
|
236
|
-
// The row style is the horizontal tag's constant and nothing else carries it, so it IS the axis —
|
|
237
|
-
// deriving keeps the two from ever disagreeing about which behavior this is.
|
|
238
|
-
const horizontal = rowStyle !== undefined;
|
|
239
235
|
return {
|
|
240
236
|
// `scroll` and `layout` are owned for the collision reason rather than because the behavior
|
|
241
237
|
// consumes them: RN's ScrollView installs `_handleScroll` and `_handleLayout` on the native
|
|
@@ -2,6 +2,7 @@ import { type IColorValue, type IDeviceEventSource, type INativeViewConfigSource
|
|
|
2
2
|
export type IBootstrapHostOptions = {
|
|
3
3
|
colorProcessor?: (value: IColorValue) => unknown;
|
|
4
4
|
imageSourceResolver?: (source: unknown) => unknown;
|
|
5
|
+
assetSourceResolver?: (source: unknown) => unknown;
|
|
5
6
|
deviceEventSource?: IDeviceEventSource;
|
|
6
7
|
nativeViewConfigSource?: INativeViewConfigSource;
|
|
7
8
|
debug?: boolean;
|
package/build/bootstrap/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// export): react-native's own source is Flow syntax Vitest's transform can't parse, so anything
|
|
6
6
|
// importing it directly must stay unreachable from the tested main index.ts.
|
|
7
7
|
import { processColor, DeviceEventEmitter, Image, } from 'react-native';
|
|
8
|
-
import { installBackHandler, setColorProcessor, setDeviceEventSource, setImageSourceResolver, setNativeViewConfigSource, } from '@symbiote-native/engine';
|
|
8
|
+
import { setAssetSourceResolver, installBackHandler, setColorProcessor, setDeviceEventSource, setImageSourceResolver, setNativeViewConfigSource, } from '@symbiote-native/engine';
|
|
9
9
|
// @ts-expect-error react-native ships no types for this internal path (plain .js) - the
|
|
10
10
|
// try/catch below is what actually proves the shape, not TS.
|
|
11
11
|
import * as ReactNativeViewConfigRegistry from 'react-native/Libraries/Renderer/shims/ReactNativeViewConfigRegistry';
|
|
@@ -37,6 +37,7 @@ export function bootstrapHost(options = {}) {
|
|
|
37
37
|
globalThis.__SYMBIOTE_DEBUG__ = options.debug ?? process.env.DEBUG === '1';
|
|
38
38
|
setColorProcessor(options.colorProcessor ?? defaultColorProcessor);
|
|
39
39
|
setImageSourceResolver(options.imageSourceResolver ?? defaultImageSourceResolver);
|
|
40
|
+
setAssetSourceResolver(options.assetSourceResolver ?? defaultImageSourceResolver);
|
|
40
41
|
setDeviceEventSource(options.deviceEventSource ?? DeviceEventEmitter);
|
|
41
42
|
// After the event source: the back button subscribes through it (see installBackHandler).
|
|
42
43
|
installBackHandler();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// ScrollView: the imperative +
|
|
2
|
-
// ScrollView has no state machine). The imperative handle, the
|
|
3
|
-
// the
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
import { attachNativeEvent, dlog,
|
|
1
|
+
// ScrollView: the imperative + event-routing module (framework-agnostic, no 3-layer split:
|
|
2
|
+
// ScrollView has no state machine). The imperative handle, the scroll-event guard/forwarder, and
|
|
3
|
+
// the native sticky scroll-attach are platform- and framework-invariant, so they live here. The
|
|
4
|
+
// Android RefreshControl wrap's style split moved out — see the note below. The adapter supplies
|
|
5
|
+
// the lifecycle (the node getter, the effect) and re-exports these.
|
|
6
|
+
import { attachNativeEvent, dlog, isSymbioteEvent, } from '@symbiote-native/engine';
|
|
7
7
|
// THE ANDROID WRAP SPLIT LEFT THIS FILE ON 2026-09-18, and with it the last copy of RN's
|
|
8
8
|
// `splitLayoutProps` key partition. Both halves are `SymbioteFabricProps.cpp` now
|
|
9
9
|
// (`splitScrollViewStyle`, `foldRefreshWrapperProps`), reached off the tag and the tree rather than
|
|
@@ -11,15 +11,6 @@
|
|
|
11
11
|
// What is NOT here, because a layer below already does it: the `aria-*` -> `accessibilityState`
|
|
12
12
|
// fold RN performs in `Button.js:326-331`. The engine folds those for every node
|
|
13
13
|
// (`core/engine/src/accessibility-props.ts`), so repeating it here would fold twice.
|
|
14
|
-
import { Platform } from '@symbiote-native/engine';
|
|
15
|
-
// Button.js:394-437, one constant per literal so a value cannot drift silently. The LABEL's seven
|
|
16
|
-
// went with `resolveButtonTextStyle` on 2026-09-18 — they live in `SymbioteFabricProps.cpp` beside
|
|
17
|
-
// the rule that reads them and are deliberately not duplicated here.
|
|
18
|
-
const ANDROID_BUTTON_BLUE = '#2196F3';
|
|
19
|
-
const ANDROID_DISABLED_BACKGROUND = '#dfdfdf';
|
|
20
|
-
const ANDROID_ELEVATION = 4;
|
|
21
|
-
const ANDROID_DISABLED_ELEVATION = 0;
|
|
22
|
-
const ANDROID_BORDER_RADIUS = 2;
|
|
23
14
|
// `BUTTON_ACCESSIBILITY_ROLE` and `resolveButtonImportantForAccessibility` WERE HERE and are gone
|
|
24
15
|
// (2026-09-18). Both are `foldButtonProps` in `SymbioteFabricProps.cpp` now, and neither had a
|
|
25
16
|
// caller left afterwards — only its own unit test, which is the shape this project calls a mirror:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/components",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.1",
|
|
4
4
|
"description": "Framework-agnostic component logic (state machines + render functions) for SymbioteNative — written once, inherited by every adapter (React, Vue, Angular, ...).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -59,11 +59,11 @@
|
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"react-native": ">=0.86",
|
|
62
|
-
"@symbiote-native/engine": "^1.
|
|
62
|
+
"@symbiote-native/engine": "^1.3.0"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@types/node": "^26.0.0",
|
|
66
|
-
"@symbiote-native/engine": "1.
|
|
66
|
+
"@symbiote-native/engine": "1.3.0"
|
|
67
67
|
},
|
|
68
68
|
"scripts": {
|
|
69
69
|
"typecheck": "tsc --build",
|