Core API
Most app code should import from @symbiote-native/react, @symbiote-native/vue,
@symbiote-native/angular, @symbiote-native/svelte, or @symbiote-native/solid. The core
packages explain why those adapters can stay thin and consistent.
Installation
Section titled “Installation”pnpm add @symbiote-native/engineMost apps never install this directly — @symbiote-native/react,
@symbiote-native/vue, @symbiote-native/angular, @symbiote-native/svelte,
and @symbiote-native/solid all declare it as a peer
dependency, so it arrives with the adapter. Install it by hand only when you are
writing or debugging an adapter yourself. react-native (>=0.86) is a peer
dependency and stays your app’s own top-level dependency either way.
@symbiote-native/components installs the same way — see the
Components API.
@symbiote-native/engine
Section titled “@symbiote-native/engine”The engine owns the native route:
adapter mutation → JS command buffer → SymbioteTree (C++) → Fabric clone-on-write commit → native viewsThe retained tree used to live in the JS package itself; it now lives in C++
(core/engine/cpp), and the JS side’s job is building the buffer and crossing into it once per
commit instead of once per mutation. The public API below is unchanged either way.
Its public surface includes:
- the mutation API used by adapters:
createElement,appendChild,insertBefore,removeChild,setProp,setEventListener,commit-related operations through surfaces; - host instance helpers such as
measure,setNativeProps, anddispatchViewCommand; - style utilities such as
StyleSheet,flattenStyle, and native style processors; - platform/runtime utilities such as
Platform,PixelRatio,Dimensions,Appearance,Alert,Share,Linking, andKeyboard; - native-view metadata hooks such as
setNativeViewConfigSource; createAppRegistry, the framework-agnostic core ofAppRegistry(registry bookkeeping, sections, the native host-registrar bridge, headless tasks) — see App entry point below.
Users normally reach these through adapter re-exports.
App entry point (AppRegistry)
Section titled “App entry point (AppRegistry)”Every adapter exports the same AppRegistry.registerComponent(appKey, () => App)
entry point RN apps already use, plus setHostRegistrar to hand it RN’s own
AppRegistry so the native Fabric host can find the registered runnable by app
key:
import { AppRegistry, setHostRegistrar } from '@symbiote-native/react'; // or '@symbiote-native/vue' / '@symbiote-native/angular' / '@symbiote-native/svelte' / '@symbiote-native/solid'import { AppRegistry as RNAppRegistry } from 'react-native';
setHostRegistrar(RNAppRegistry);AppRegistry.registerComponent('MyApp', () => App);registerSection, runApplication, unmountApplicationComponentAtRootTag,
setWrapperComponentProvider, and the headless-task methods
(registerHeadlessTask, registerCancellableHeadlessTask,
startHeadlessTask, cancelHeadlessTask) round out the same surface RN’s
AppRegistry exposes. All of this bookkeeping lives once in
@symbiote-native/engine’s createAppRegistry — the only framework-specific piece
each adapter supplies is runnableFor, the function that turns a component
provider into a mount call (createElement + mount for React, createApp/h
for Vue, createComponent for Angular, its own mount for Svelte, and
solid-js/universal’s createComponent for Solid).
@symbiote-native/components
Section titled “@symbiote-native/components”The component package owns framework-agnostic component logic:
- pure state machines, for example
Switch,Pressable,TextInput, and list windowing logic; - pure render helpers that produce
Descriptortrees; - shared accessibility folding and native component-name resolution;
- shared event payload helpers and command helpers.
Adapters provide only lifecycle and element bridges:
| Layer | React | Vue | Angular | Svelte | Solid |
|---|---|---|---|---|---|
| State lifecycle | hooks / refs | refs / watches / expose | zoneless change detection (signals / fields) | $state / $effect runes |
signals / effects (createSignal / createEffect) |
| Render bridge | descriptorToReact |
descriptorToVue |
DescriptorOutlet (proven on some components, migration in progress) |
a DOM shim over stock compiled output (adapters/svelte/src/dom-shim/), no generic Descriptor walker; each component hand-authors its fixed host tag(s) and reads props/children off known positions, mountDescriptorChildren syncing an already-fixed shape |
descriptorToSolid: builds a host node once, then re-props it through a spread render effect; a component taking live children (View, Pressable, Modal, …) skips the bridge and emits real JSX instead |
| Public framework shape | callbacks / children | emits / slots | @Output() EventEmitters / <ng-content> |
callback props, same names as React, no emits, no @Output() |
callback props (class for styling); a render-prop child (Pressable, list renderItem) takes a Solid Accessor, not a snapshot value |
Wrapper authors
Section titled “Wrapper authors”Native-view wrapper packages can use the same seam:
- derive native metadata with
setNativeViewConfigSource; - keep shared view logic in a framework-agnostic package;
- expose thin React, Vue, Angular, Svelte, and Solid wrappers that map framework props/events to engine props and native events.
Do not import a third-party React Native JavaScript component into Vue. Wrap the native view, not the React component body.