@symbiote-native/react 0.2.1 → 0.2.3

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.
Files changed (52) hide show
  1. package/README.md +2 -2
  2. package/build/bootstrap.js +1 -1
  3. package/build/components/activity-indicator/index.android.js +2 -2
  4. package/build/components/activity-indicator/index.ios.js +2 -2
  5. package/build/components/activity-indicator/index.js +2 -2
  6. package/build/components/activity-indicator/shared.js +1 -1
  7. package/build/components/button.js +2 -2
  8. package/build/components/flat-list/index.js +1 -1
  9. package/build/components/image/index.js +1 -1
  10. package/build/components/image-background/index.js +1 -1
  11. package/build/components/keyboard-avoiding-view/index.js +2 -2
  12. package/build/components/pressable/index.js +1 -1
  13. package/build/components/scroll-view/index.android.js +3 -3
  14. package/build/components/scroll-view/index.ios.js +3 -3
  15. package/build/components/scroll-view/index.js +2 -2
  16. package/build/components/scroll-view/shared.js +3 -3
  17. package/build/components/scroll-view/sticky-header.js +2 -2
  18. package/build/components/section-list/index.js +1 -1
  19. package/build/components/switch/index.android.js +1 -1
  20. package/build/components/switch/index.ios.js +1 -1
  21. package/build/components/switch/index.js +4 -4
  22. package/build/components/switch/shared.js +1 -1
  23. package/build/components/text-input/index.js +2 -2
  24. package/build/components/touchable/index.js +2 -2
  25. package/build/components/touchable-native-feedback/index.js +2 -2
  26. package/build/components/virtualized-list/index.js +3 -3
  27. package/build/components/virtualized-section-list/index.js +1 -1
  28. package/build/create-portal.js +1 -1
  29. package/build/create-tunnel.js +2 -2
  30. package/build/descriptor-to-react/index.js +1 -1
  31. package/build/hooks/use-color-scheme.js +1 -1
  32. package/build/hooks/use-window-dimensions.js +1 -1
  33. package/build/host-config.js +4 -4
  34. package/build/index.js +55 -53
  35. package/build/modules/accessibility-info/index.js +2 -2
  36. package/build/modules/action-sheet-ios.js +2 -2
  37. package/build/modules/alert.js +2 -2
  38. package/build/modules/animated/create-animated-component.js +2 -2
  39. package/build/modules/animated/index.js +9 -9
  40. package/build/modules/app-registry/index.js +1 -1
  41. package/build/modules/i18n-manager.js +1 -1
  42. package/build/modules/linking.js +1 -1
  43. package/build/modules/settings.js +1 -1
  44. package/build/modules/share.js +1 -1
  45. package/build/modules/status-bar/index.android.js +1 -1
  46. package/build/modules/status-bar/index.ios.js +2 -2
  47. package/build/modules/status-bar/index.js +1 -1
  48. package/build/modules/toast-android.js +2 -2
  49. package/build/modules/vibration.js +2 -2
  50. package/build/render.js +2 -2
  51. package/metro-css-parser.cjs +1 -2
  52. package/package.json +5 -5
package/README.md CHANGED
@@ -85,7 +85,7 @@ canary ([`App.tsx`](../../examples/react/App.tsx)) exercises every block of the
85
85
  ## Surface — verified on device, iOS + Android
86
86
 
87
87
  Every interaction commits through `@symbiote-native/engine` into Fabric, with RN's renderer never in the
88
- path (R1 + R2 + R3 — decision record 0009):
88
+ path:
89
89
 
90
90
  - **Primitives** — `View` · `Text` · `Image` · `ImageBackground` · `ScrollView` · `TextInput` ·
91
91
  `Pressable` · `Touchable*` · `Button` · `Switch` · `Modal` · `ActivityIndicator` ·
@@ -96,7 +96,7 @@ path (R1 + R2 + R3 — decision record 0009):
96
96
  bridgeless host.
97
97
  - **`Animated`, both drivers** — JS *and* native driver side by side (`timing` · `spring` · `loop` ·
98
98
  `interpolate` · `ValueXY` · tracking · `diffClamp`). Native offload is proven by jamming the JS
99
- thread 1.5 s: the native-driven animations keep moving, the JS-driven one stalls (ADR 0016 · 0017).
99
+ thread 1.5 s: the native-driven animations keep moving, the JS-driven one stalls.
100
100
  - **Third-party native views** — `@react-native-community/slider` used straight from the package
101
101
  with zero SymbioteNative metadata; the engine derives its events and prop processors from the library's
102
102
  own ViewConfig at runtime — the "install the package, use its component" path.
@@ -6,7 +6,7 @@
6
6
  // @symbiote-native/components/bootstrap for the full reason).
7
7
  import { AppRegistry as RNAppRegistry } from 'react-native';
8
8
  import { bootstrapHost } from '@symbiote-native/components/bootstrap';
9
- import { AppRegistry, setHostRegistrar } from './modules/app-registry';
9
+ import { AppRegistry, setHostRegistrar } from './modules/app-registry/index.js';
10
10
  // Mirrors bare RN's own `AppRegistry.registerComponent(appName, () => App)` idiom, minus the
11
11
  // manual host wiring in front of it.
12
12
  export function registerApp(App, options) {
@@ -2,10 +2,10 @@
2
2
  // ProgressBar's setStyle(); without it the view throws "setStyle() not called") and
3
3
  // `indeterminate: true`, and its default color is the theme (null), per RN's
4
4
  // ActivityIndicator.js android branch ({styleAttr:'Normal', indeterminate:true}). Metro
5
- // picks this on an Android host; no Platform.OS read. See ADR 0020.
5
+ // picks this on an Android host; no Platform.OS read.
6
6
  // device-verify-pending: prop names mirror RN's AndroidProgressBar, proven on a real
7
7
  // host by the absence of the "setStyle() not called" red box.
8
- import { createActivityIndicator } from './shared';
8
+ import { createActivityIndicator } from './shared.js';
9
9
  export const ActivityIndicator = createActivityIndicator({
10
10
  // RN: `color = Platform.OS === 'ios' ? GRAY : null`; Android lets the theme color it.
11
11
  defaultColor: null,
@@ -1,7 +1,7 @@
1
1
  // ActivityIndicator on iOS: RCTActivityIndicatorView takes the size enum + a GRAY
2
2
  // default color and no extra native props. Also the base (activity-indicator.ts
3
- // re-exports it) for headless / web. See ADR 0020.
4
- import { createActivityIndicator } from './shared';
3
+ // re-exports it) for headless / web.
4
+ import { createActivityIndicator } from './shared.js';
5
5
  // RN's iOS default spinner color (Libraries/.../ActivityIndicator.js GRAY).
6
6
  const IOS_DEFAULT_COLOR = '#999999';
7
7
  export const ActivityIndicator = createActivityIndicator({
@@ -1,4 +1,4 @@
1
1
  // Base / default ActivityIndicator: re-exports the iOS build. Metro overrides this with
2
2
  // activity-indicator.ios.ts / .android.ts on a real host; under tsx / tsc / web the host
3
- // config resolves here. Filename is the selector, no Platform.OS read. See ADR 0020.
4
- export * from './index.ios';
3
+ // config resolves here. Filename is the selector, no Platform.OS read.
4
+ export * from './index.ios.js';
@@ -6,7 +6,7 @@
6
6
  // The per-platform bits (iOS GRAY default + no extras; Android theme/null + styleAttr +
7
7
  // indeterminate) are supplied by the .ios/.android files via `IActivityIndicatorPlatform`.
8
8
  import { renderActivityIndicator, resolveAccessibilityProps } from '@symbiote-native/components';
9
- import { descriptorToReact } from '../../descriptor-to-react';
9
+ import { descriptorToReact } from '../../descriptor-to-react/index.js';
10
10
  export function createActivityIndicator(platform) {
11
11
  return rawProps => {
12
12
  // The wrapper is a raw symbiote-view, not the View FC, so it never runs
@@ -3,8 +3,8 @@
3
3
  // (caller color tints the label; disabled greys it) are shared in @symbiote-native/components/view; here
4
4
  // React only composes its TouchableOpacity + Text and forwards the native-only props.
5
5
  import { createElement } from 'react';
6
- import { Text } from '../components';
7
- import { TouchableOpacity } from './touchable';
6
+ import { Text } from '../components.js';
7
+ import { TouchableOpacity } from './touchable/index.js';
8
8
  import { BUTTON_ACCESSIBILITY_ROLE, resolveButtonTextStyle } from '@symbiote-native/components';
9
9
  export const Button = props => {
10
10
  const { title, onPress, color, disabled, touchSoundDisabled, testID, hasTVPreferredFocus, nextFocusDown, nextFocusForward, nextFocusLeft, nextFocusRight, nextFocusUp, ...accessibilityRest } = props;
@@ -8,7 +8,7 @@
8
8
  import { createElement, } from 'react';
9
9
  import { dlog, resolveClassName } from '@symbiote-native/engine';
10
10
  import { SINGLE_COLUMN, chunkIntoRows, expandRowViewability, firstItemOfRow, lastItemOfRow, rowKeyExtractor, } from '@symbiote-native/components';
11
- import { VirtualizedList, } from '../virtualized-list';
11
+ import { VirtualizedList, } from '../virtualized-list/index.js';
12
12
  export function FlatList(props) {
13
13
  const { ref, data, renderItem, keyExtractor, numColumns = SINGLE_COLUMN, columnWrapperStyle,
14
14
  // onViewableItemsChanged/viewability are typed against ItemT here; in the multi-column path
@@ -1,6 +1,6 @@
1
1
  import {} from 'react';
2
2
  import { imageStatics, renderImage, resolveAccessibilityProps, } from '@symbiote-native/components';
3
- import { descriptorToReact } from '../../descriptor-to-react';
3
+ import { descriptorToReact } from '../../descriptor-to-react/index.js';
4
4
  // renderImage takes a pre-resolved view + passthrough (the ISwitchViewProps shape), so the
5
5
  // adapter folds aria/role and splits the typed transform fields from the forward-only rest.
6
6
  // The W3C source aliases (src/srcSet/crossOrigin/referrerPolicy) and width/height become typed
@@ -6,7 +6,7 @@
6
6
  import { createElement } from 'react';
7
7
  import { resolveClassName } from '@symbiote-native/engine';
8
8
  import { renderImageBackground, resolveAccessibilityProps, } from '@symbiote-native/components';
9
- import { descriptorToReact } from '../../descriptor-to-react';
9
+ import { descriptorToReact } from '../../descriptor-to-react/index.js';
10
10
  function toChild(child) {
11
11
  return typeof child === 'string' ? child : descriptorToReact(child);
12
12
  }
@@ -10,8 +10,8 @@
10
10
  import { createElement, useEffect, useRef, useState, } from 'react';
11
11
  import { dlog } from '@symbiote-native/engine';
12
12
  import { computeInset, readKeyboardFrame, readLayoutFrame, resolveKeyboardAvoidingLayout, DEFAULT_VERTICAL_OFFSET, } from '@symbiote-native/components';
13
- import { View } from '../../components';
14
- import { Keyboard, KEYBOARD_EVENT } from '../../modules/keyboard';
13
+ import { View } from '../../components.js';
14
+ import { Keyboard, KEYBOARD_EVENT } from '../../modules/keyboard.js';
15
15
  export const KeyboardAvoidingView = props => {
16
16
  const { behavior, enabled = true, keyboardVerticalOffset = DEFAULT_VERTICAL_OFFSET, contentContainerStyle, style, children, onLayout,
17
17
  // The wrapper is the View FC, which runs resolveAccessibilityProps itself, so
@@ -13,7 +13,7 @@
13
13
  // shared machine; here we only wire its host + render the View.
14
14
  import { createElement, useMemo, useRef, useState } from 'react';
15
15
  import { createPressHandlers, createPressRuntime, rippleProps, buildPressableListeners, resolveDisabledAccessibilityState, noteHoverNoop, DEFAULT_DELAY_LONG_PRESS_MS, } from '@symbiote-native/components';
16
- import { View } from '../../components';
16
+ import { View } from '../../components.js';
17
17
  function resolveStyle(style, state) {
18
18
  if (typeof style === 'function')
19
19
  return style(state);
@@ -5,20 +5,20 @@
5
5
  // scroll handles the gesture before the refresh parent, which mirrors RN's ScrollView.js
6
6
  // android branch (cloneElement(refreshControl, {style}, <ScrollView nestedScrollEnabled
7
7
  // style={flex:1}>{content}</ScrollView>)). Metro picks this on an Android host; no
8
- // Platform.OS read. See ADR 0020.
8
+ // Platform.OS read.
9
9
  // device-verify-pending: the wrap shape mirrors RN, proven on a real host by the absence
10
10
  // of the "addViewAt: failed to insert" crash.
11
11
  import { cloneElement, createElement, forwardRef, useImperativeHandle, useRef } from 'react';
12
12
  import { dlog } from '@symbiote-native/engine';
13
13
  import { buildScrollViewHandle, splitLayoutProps } from '@symbiote-native/components';
14
- import { usePreparedScrollView, useNativeStickyScrollAttach, } from './shared';
14
+ import { usePreparedScrollView, useNativeStickyScrollAttach, } from './shared.js';
15
15
  export const ScrollView = forwardRef((props, forwardedRef) => {
16
16
  const { scrollViewIntrinsic, scrollViewBaseStyle, outerProps, style, layoutSplitStyle, content, refreshControl, scrollAnimatedValue, nativeStickyAvailable, } = usePreparedScrollView(props);
17
17
  // The node ref backs the imperative handle; it attaches to the inner scroll-view element
18
18
  // (the wrap shape leaves the scroll view as the command target, not the RefreshControl).
19
19
  const ref = useRef(null);
20
20
  // Lazy getter, not the ref itself: the node is null until the element commits, so the handle
21
- // must read ref.current on each command (ADR 0024 §3), an eager capture would freeze null.
21
+ // must read ref.current on each command, an eager capture would freeze null.
22
22
  useImperativeHandle(forwardedRef, () => buildScrollViewHandle(() => ref.current), []);
23
23
  // Drive the sticky scroll value on the native UI thread (RN attachNativeEvent). No-op on a
24
24
  // host without the native animated module. The JS sticky path stays in effect.
@@ -1,16 +1,16 @@
1
1
  // ScrollView on iOS: the RefreshControl is a CHILD of the scroll view, rendered as a
2
2
  // sibling BEFORE the content container (RN ScrollView.js: {refreshControl}{contentContainer}).
3
- // Also the base (scroll-view.ts re-exports it) for headless / web. See ADR 0020.
3
+ // Also the base (scroll-view.ts re-exports it) for headless / web.
4
4
  import { createElement, forwardRef, useImperativeHandle, useRef } from 'react';
5
5
  import { buildScrollViewHandle } from '@symbiote-native/components';
6
- import { usePreparedScrollView, useNativeStickyScrollAttach, } from './shared';
6
+ import { usePreparedScrollView, useNativeStickyScrollAttach, } from './shared.js';
7
7
  export const ScrollView = forwardRef((props, forwardedRef) => {
8
8
  const { scrollViewIntrinsic, scrollViewBaseStyle, outerProps, style, content, refreshControl, scrollAnimatedValue, nativeStickyAvailable, } = usePreparedScrollView(props);
9
9
  // The node ref backs the imperative handle; it attaches to the scroll-view element below
10
10
  // (passing `ref` through createElement props binds it to the SymbioteNode, as TextInput does).
11
11
  const ref = useRef(null);
12
12
  // Lazy getter, not the ref itself: the node is null until the element commits, so the handle
13
- // must read ref.current on each command (ADR 0024 §3), an eager capture would freeze null.
13
+ // must read ref.current on each command, an eager capture would freeze null.
14
14
  useImperativeHandle(forwardedRef, () => buildScrollViewHandle(() => ref.current), []);
15
15
  // Drive the sticky scroll value on the native UI thread (RN attachNativeEvent). No-op on a
16
16
  // host without the native animated module. The JS sticky path stays in effect.
@@ -1,4 +1,4 @@
1
1
  // Base / default ScrollView: re-exports the iOS build. Metro overrides this with
2
2
  // scroll-view.ios.ts / .android.ts on a real host; under tsx / tsc / web the host config
3
- // resolves here. Filename is the selector, no Platform.OS read. See ADR 0020.
4
- export * from './index.ios';
3
+ // resolves here. Filename is the selector, no Platform.OS read.
4
+ export * from './index.ios.js';
@@ -1,20 +1,20 @@
1
1
  // ScrollView: shared core. The Fabric tree is nested: the scroll view wraps a content
2
2
  // view that holds the children (RN's own ScrollView.js shape). Building that content
3
3
  // node, resolving decelerationRate, and the prop plumbing are platform-invariant and
4
- // live here. What diverges (ADR 0020) is how a RefreshControl integrates: on iOS it is a
4
+ // live here. What diverges is how a RefreshControl integrates: on iOS it is a
5
5
  // CHILD of the scroll view (sibling of the content), on Android it WRAPS the scroll view
6
6
  // (AndroidSwipeRefreshLayout is the parent, ScrollView nested inside). So the .ios/.android
7
7
  // files assemble the final element; the filename selects, no Platform.OS read.
8
8
  //
9
9
  // The framework-agnostic pieces (decelerationRate, the per-axis intrinsics/base style, the
10
10
  // content-size dedupe, the imperative handle, splitLayoutProps, the sticky math, the native
11
- // scroll-attach) live in @symbiote-native/components (ADR 0024); this file holds only the React
11
+ // scroll-attach) live in @symbiote-native/components; this file holds only the React
12
12
  // lifecycle (refs/state/effects) and the element assembly that consumes them.
13
13
  import { createElement, useEffect, useRef, useState, } from 'react';
14
14
  import { AnimatedValue, dlog, event as animatedEvent, isClassNameValue, isNativeAnimatedAvailable, resolveClassName, } from '@symbiote-native/engine';
15
15
  import { attachStickyScroll, didContentSizeChange, forwardScrollEvent, readLayoutDimension, resolveDecelerationRate, selectScrollIntrinsics, } from '@symbiote-native/components';
16
16
  import { resolveAccessibilityProps, } from '@symbiote-native/components';
17
- import { wrapStickyHeaders } from './sticky-header';
17
+ import { wrapStickyHeaders } from './sticky-header.js';
18
18
  export function usePreparedScrollView(rawProps) {
19
19
  // ScrollView forwards its outer props straight to the native scroll view (not a View
20
20
  // wrapper), so it folds aria/role into accessibility* here before forwarding.
@@ -7,12 +7,12 @@
7
7
  // its own. Forwarding `stickyHeaderIndices` to native is a silent no-op. So we replicate the
8
8
  // JS layer: subscribe each flagged child to the scroll offset and translate it to stay pinned.
9
9
  // The interpolation mirrors ScrollViewStickyHeader.js (non-inverted + inverted branches) and now
10
- // lives, framework-agnostic, in @symbiote-native/components (computeStickyInterpolation, ADR 0024); this
10
+ // lives, framework-agnostic, in @symbiote-native/components (computeStickyInterpolation); this
11
11
  // file holds the React component shell, the layout state, and the child-wrapping.
12
12
  import { Children, createElement, isValidElement, useCallback, useEffect, useRef, useState, } from 'react';
13
13
  import { AnimatedInterpolation, AnimatedValue, Platform, dlog, } from '@symbiote-native/engine';
14
14
  import { computeStickyInterpolation, nextStickyHeaderY, readLayoutNumber, stickyDebounceMs, STICKY_HEADER_Z_INDEX, } from '@symbiote-native/components';
15
- import { Animated } from '../../modules/animated';
15
+ import { Animated } from '../../modules/animated/index.js';
16
16
  function readChildOnLayout(child) {
17
17
  const childProps = child.props;
18
18
  if (typeof childProps !== 'object' || childProps === null)
@@ -6,7 +6,7 @@
6
6
  // SectionList name so existing consumers and the canary keep importing it from
7
7
  // here, threading the imperative ref straight through.
8
8
  import { createElement } from 'react';
9
- import { VirtualizedSectionList, } from '../virtualized-section-list';
9
+ import { VirtualizedSectionList, } from '../virtualized-section-list/index.js';
10
10
  export function SectionList(props) {
11
11
  return createElement((VirtualizedSectionList), props);
12
12
  }
@@ -1,7 +1,7 @@
1
1
  // Switch, Android host binding. AndroidSwitch takes trackColorForTrue / trackColorForFalse
2
2
  // plus trackTintColor (the color for the CURRENT value, which RN computes as value ? true :
3
3
  // false), and snaps native back via the `setNativeValue` command (Switch.js:221-225).
4
- import { createSwitch } from './shared';
4
+ import { createSwitch } from './shared.js';
5
5
  export const Switch = createSwitch({
6
6
  snapBackCommand: 'setNativeValue',
7
7
  trackColorProps: (value, trackColor) => ({
@@ -1,6 +1,6 @@
1
1
  // Switch, iOS host binding. iOS's native Switch takes onTintColor (ON-track) / tintColor
2
2
  // (OFF-track), and snaps native back via the `setValue` command (Switch.js:221-225).
3
- import { createSwitch } from './shared';
3
+ import { createSwitch } from './shared.js';
4
4
  export const Switch = createSwitch({
5
5
  snapBackCommand: 'setValue',
6
6
  trackColorProps: (_value, trackColor) => ({
@@ -1,6 +1,6 @@
1
1
  // Base / default Switch: re-exports the iOS build. Metro overrides this with switch.ios.ts /
2
2
  // switch.android.ts on a real host; under tsx / tsc / web the host config resolves here.
3
- // Filename is the selector, no Platform.OS read. See ADR 0020. The three-layer split (logic
4
- // in @symbiote-native/components/state, render in @symbiote-native/components/view, hook in switch-shared)
5
- // replaced the former monolithic Platform.OS-branching component.
6
- export * from './index.ios';
3
+ // Filename is the selector, no Platform.OS read. The logic lives in
4
+ // @symbiote-native/components/state, the render in @symbiote-native/components/view, and the
5
+ // hook in switch-shared.
6
+ export * from './index.ios.js';
@@ -13,7 +13,7 @@ import { useCallback, useLayoutEffect, useReducer, useRef } from 'react';
13
13
  import { renderSwitch, switchReducer, createInitialSwitchState, shouldSnapBack, valueFromChange, } from '@symbiote-native/components';
14
14
  import { dispatchViewCommand, dlog, } from '@symbiote-native/engine';
15
15
  import { resolveAccessibilityProps } from '@symbiote-native/components';
16
- import { descriptorToReact } from '../../descriptor-to-react';
16
+ import { descriptorToReact } from '../../descriptor-to-react/index.js';
17
17
  export function createSwitch(platform) {
18
18
  return rawProps => {
19
19
  // Switch owns its host element rather than rendering through a symbiote View, so it folds
@@ -10,9 +10,9 @@
10
10
  // (setTextAndSelection), never a plain prop re-push. See @symbiote-native/components/state/text-input.
11
11
  import { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState, } from 'react';
12
12
  import { dispatchViewCommand, dlog, } from '@symbiote-native/engine';
13
- import { blurTextInput, setInputBlurred, setInputFocused } from '../../modules/text-input-state';
13
+ import { blurTextInput, setInputBlurred, setInputFocused } from '../../modules/text-input-state.js';
14
14
  import { resolveAccessibilityProps, resolveTextInputProps, renderTextInput, foldText, textFromChange, eventCountFromChange, shouldCommandText, INITIAL_EVENT_COUNT, SELECTION_NONE, } from '@symbiote-native/components';
15
- import { descriptorToReact } from '../../descriptor-to-react';
15
+ import { descriptorToReact } from '../../descriptor-to-react/index.js';
16
16
  export const TextInput = forwardRef((rawProps, forwardedRef) => {
17
17
  // TextInput is its own host element (not a View wrapper), so it folds aria/role here.
18
18
  const props = resolveAccessibilityProps(rawProps);
@@ -10,8 +10,8 @@
10
10
  import { createElement, useRef } from 'react';
11
11
  import { dlog } from '@symbiote-native/engine';
12
12
  import { computePressOutWait, DEFAULT_ACTIVE_OPACITY, DEFAULT_HIGHLIGHT_CHILD_OPACITY, DEFAULT_MIN_PRESS_DURATION_MS, DEFAULT_UNDERLAY_COLOR, OPACITY_ACTIVE_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, } from '@symbiote-native/components';
13
- import { Pressable } from '../pressable';
14
- import { Animated } from '../../modules/animated';
13
+ import { Pressable } from '../pressable/index.js';
14
+ import { Animated } from '../../modules/animated/index.js';
15
15
  export const TouchableOpacity = props => {
16
16
  const { activeOpacity = DEFAULT_ACTIVE_OPACITY, style,
17
17
  // className is pulled out here, like style, and applied to the inner Animated.View below —
@@ -9,8 +9,8 @@
9
9
  import { createElement } from 'react';
10
10
  import { dlog } from '@symbiote-native/engine';
11
11
  import { backgroundProps, canUseNativeForeground, rippleBackground, selectableBackground, selectableBackgroundBorderless, } from '@symbiote-native/components';
12
- import { View } from '../../components';
13
- import { Pressable } from '../pressable';
12
+ import { View } from '../../components.js';
13
+ import { Pressable } from '../pressable/index.js';
14
14
  const TouchableNativeFeedbackImpl = props => {
15
15
  const { background, useForeground = false, children, ...rest } = props;
16
16
  // RN defaults a missing background to SelectableBackground() so the touchable always has
@@ -10,7 +10,7 @@
10
10
  // viewability bug is fixed once for all adapters (<adapters_reach_full_feature_parity>).
11
11
  // React supplies only its lifecycle (state/refs/effects), the imperative-handle wiring,
12
12
  // and the per-cell element creation (createElement). Lists have no Descriptor render fn
13
- // (the cell content is React's own children); see core/components/.docs-note-lists.md.
13
+ // (the cell content is React's own children).
14
14
  //
15
15
  // Imperative scrolling (scrollToIndex / scrollToOffset / scrollToItem / scrollToEnd)
16
16
  // resolves to an offset and rides the ScrollView's native scrollTo command via its handle
@@ -19,8 +19,8 @@
19
19
  import { createElement, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, } from 'react';
20
20
  import { dlog } from '@symbiote-native/engine';
21
21
  import { DEFAULT_END_REACHED_THRESHOLD, DEFAULT_INITIAL_NUM_TO_RENDER, DEFAULT_MAX_TO_RENDER_PER_BATCH, DEFAULT_START_REACHED_THRESHOLD, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD, DEFAULT_WINDOW_SIZE, EMPTY_OFFSET, FIRST_INDEX, INVERTED_X_STYLE, INVERTED_Y_STYLE, NO_CONTENT_LENGTH_SENT, averageMeasuredLength, buildListPlan, buildOffsets, buildViewabilityPairs, computeEndReached, computeStartReached, computeViewableSet, computeWindow, diffViewable, highestMeasuredIndex as findHighestMeasuredIndex, maxMinimumViewTime, offsetForIndex as resolveOffsetForIndex, readLayoutLength, readScrollOffset, throttleWindow, } from '@symbiote-native/components';
22
- import { ScrollView } from '../scroll-view';
23
- import { RefreshControl } from '../refresh-control';
22
+ import { ScrollView } from '../scroll-view/index.js';
23
+ import { RefreshControl } from '../refresh-control/index.js';
24
24
  function resolveElement(component) {
25
25
  if (component === undefined)
26
26
  return undefined;
@@ -8,7 +8,7 @@
8
8
  import { createElement, useImperativeHandle, useRef, } from 'react';
9
9
  import { dlog, Platform } from '@symbiote-native/engine';
10
10
  import { flattenSections, scrollLocationToFlatIndex, sectionEntryKey, unwrapEntryItem, } from '@symbiote-native/components';
11
- import { VirtualizedList, } from '../virtualized-list';
11
+ import { VirtualizedList, } from '../virtualized-list/index.js';
12
12
  function resolveSeparator(component) {
13
13
  if (component === undefined)
14
14
  return undefined;
@@ -11,7 +11,7 @@
11
11
  // independently-mounted SymbioteSurface. Cross-surface targets aren't wired: resetAfterCommit only
12
12
  // fires for the primary root's own container, so a different surface's tree would never repaint.
13
13
  import { isSymbioteNode, SymbioteSurface } from '@symbiote-native/engine';
14
- import reconciler from './host-config';
14
+ import reconciler from './host-config.js';
15
15
  export function createPortal(children, container, key) {
16
16
  if (!(container instanceof SymbioteSurface) && !isSymbioteNode(container)) {
17
17
  throw new Error('createPortal target must be an already-mounted host node (e.g. a ref to a rendered <View>) — got something else. Did you forget `.current`/`.value`, or pass a CSS-selector-style string?');
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- // createTunnel — the cross-surface answer to createPortal's same-surface-only v1 scope
3
- // (react-adapter-portal skill). Prior art: pmndrs/tunnel-rat exists precisely because a real
2
+ // createTunnel — the cross-surface answer to createPortal's same-surface-only scope.
3
+ // Prior art: pmndrs/tunnel-rat exists precisely because a real
4
4
  // createPortal cannot reach across two genuinely separate reconciler roots — see
5
5
  // github.com/facebook/react/issues/17147 ("react-reconciler & portals: missing root
6
6
  // instance"). The fix is the one the ecosystem already settled on: don't reach into a
@@ -2,7 +2,7 @@
2
2
  // framework-agnostic `Descriptor` tree; this maps it onto React elements. The resulting
3
3
  // host element (`symbiote-view`, `symbiote-activity-indicator`, …) flows on through the
4
4
  // react-reconciler host config → engine → Fabric, exactly like a hand-written JSX host
5
- // element. The wolf-tui twin is `packages/react/src/wnode/wnode-to-react.tsx`.
5
+ // element.
6
6
  import { createElement } from 'react';
7
7
  export function descriptorToReact(node, index) {
8
8
  const children = node.children.map(toChild);
@@ -2,7 +2,7 @@
2
2
  // on change. Mirrors RN's Libraries/Utilities/useColorScheme.js: a thin
3
3
  // useSyncExternalStore over Appearance's change event + current scheme read.
4
4
  import { useSyncExternalStore } from 'react';
5
- import { Appearance } from '../modules/appearance';
5
+ import { Appearance } from '../modules/appearance.js';
6
6
  const subscribe = (onStoreChange) => {
7
7
  const subscription = Appearance.addChangeListener(onStoreChange);
8
8
  return () => subscription.remove();
@@ -4,7 +4,7 @@
4
4
  // subscribing to close the gap between the render-time get and the effect-time
5
5
  // listener. Only the window metrics changing triggers a re-render.
6
6
  import { useEffect, useState } from 'react';
7
- import { Dimensions } from '../modules/dimensions';
7
+ import { Dimensions } from '../modules/dimensions.js';
8
8
  export function useWindowDimensions() {
9
9
  const [dimensions, setDimensions] = useState(() => Dimensions.get('window'));
10
10
  useEffect(() => {
@@ -5,12 +5,12 @@
5
5
  import createReconciler from 'react-reconciler';
6
6
  import { createContext } from 'react';
7
7
  import { appendChild, createElement, createRawText, insertBefore, removeChild, routeProp, setText, SymbioteSurface, } from '@symbiote-native/engine';
8
- import { DefaultEventPriority, DiscreteEventPriority, NoEventPriority, } from './reconciler-constants';
9
- import { toPublicInstance } from './host-instance';
8
+ import { DefaultEventPriority, DiscreteEventPriority, NoEventPriority, } from './reconciler-constants.js';
9
+ import { toPublicInstance } from './host-instance.js';
10
10
  // Intrinsic JSX type -> Fabric component name. The name table + resolver live once in
11
11
  // @symbiote-native/components, shared by every adapter so the names can't drift (one engine, one
12
- // Fabric). The table is Metro-split (.ios/.android, filename selects, no Platform.OS read,
13
- // per ADR 0020). Adding a primitive is one entry in each name table there, plus its thin
12
+ // Fabric). The table is Metro-split (.ios/.android, filename selects, no Platform.OS read).
13
+ // Adding a primitive is one entry in each name table there, plus its thin
14
14
  // component in components.ts: no host-config logic per primitive.
15
15
  import { descriptorFor } from '@symbiote-native/components';
16
16
  // React-reserved prop keys that must never reach Fabric. `children` is the element
package/build/index.js CHANGED
@@ -1,47 +1,49 @@
1
1
  // @symbiote-native/react: a react-reconciler host config (mutation mode) over
2
2
  // @symbiote-native/engine. React is a known-good driver: it proves the native pipe
3
- // (R1) and shared's clone-on-write engine (R2) before any non-React adapter.
4
- export { View, Text } from './components';
5
- export { Image, setImageSourceResolver } from './components/image';
6
- export { ImageBackground } from './components/image-background';
7
- export { ScrollView } from './components/scroll-view';
8
- export { TextInput } from './components/text-input';
9
- export { InputAccessoryView } from './components/input-accessory-view';
10
- export { Keyboard, KEYBOARD_EVENT } from './modules/keyboard';
11
- export { KeyboardAvoidingView } from './components/keyboard-avoiding-view';
12
- export { StatusBar } from './modules/status-bar';
13
- export { Switch } from './components/switch';
14
- export { ActivityIndicator } from './components/activity-indicator';
15
- export { SafeAreaView } from './components/safe-area-view';
16
- export { RefreshControl } from './components/refresh-control';
17
- export { Modal } from './components/modal';
18
- export { Pressable } from './components/pressable';
19
- export { TouchableOpacity, TouchableHighlight, TouchableWithoutFeedback, } from './components/touchable';
20
- export { Button } from './components/button';
21
- export { FlatList } from './components/flat-list';
22
- export { SectionList } from './components/section-list';
23
- export { VirtualizedSectionList } from './components/virtualized-section-list';
24
- export { VirtualizedList } from './components/virtualized-list';
25
- export { mount, unmount } from './render';
3
+ // and the shared clone-on-write engine before any non-React adapter has to.
4
+ export { View, Text } from './components.js';
5
+ export { Image, setImageSourceResolver } from './components/image/index.js';
6
+ export { ImageBackground } from './components/image-background/index.js';
7
+ export { ScrollView } from './components/scroll-view/index.js';
8
+ export { TextInput } from './components/text-input/index.js';
9
+ export { InputAccessoryView } from './components/input-accessory-view/index.js';
10
+ export { Keyboard, KEYBOARD_EVENT } from './modules/keyboard.js';
11
+ export { KeyboardAvoidingView } from './components/keyboard-avoiding-view/index.js';
12
+ export { StatusBar } from './modules/status-bar/index.js';
13
+ export { Switch } from './components/switch/index.js';
14
+ export { ActivityIndicator } from './components/activity-indicator/index.js';
15
+ export { SafeAreaView } from './components/safe-area-view/index.js';
16
+ export { RefreshControl } from './components/refresh-control/index.js';
17
+ export { Modal } from './components/modal/index.js';
18
+ export { Pressable } from './components/pressable/index.js';
19
+ export { TouchableOpacity, TouchableHighlight, TouchableWithoutFeedback, } from './components/touchable/index.js';
20
+ export { Button } from './components/button.js';
21
+ export { FlatList } from './components/flat-list/index.js';
22
+ export { SectionList } from './components/section-list/index.js';
23
+ export { VirtualizedSectionList } from './components/virtualized-section-list/index.js';
24
+ export { VirtualizedList } from './components/virtualized-list/index.js';
25
+ export { mount, unmount } from './render.js';
26
26
  // createPortal: react-reconciler's Fiber-level portal, working here because @symbiote-native/react is
27
27
  // mutation-mode (unlike stock RN's persistent-mode Fabric renderer, which doesn't support it —
28
28
  // see create-portal.ts). v1 scope: target must be an already-mounted node in the SAME surface.
29
- export { createPortal } from './create-portal';
30
- // createTunnel: cross-surface content sharing (createPortal/Teleport stay same-surface-only
31
- // by design — see create-tunnel.tsx and the react-adapter-portal skill for why).
32
- export { createTunnel } from './create-tunnel';
29
+ export { createPortal } from './create-portal.js';
30
+ // createTunnel: cross-surface content sharing. createPortal/Teleport stay same-surface-only
31
+ // by design — a real React portal can't reach across two separate reconciler roots either
32
+ // (see github.com/facebook/react/issues/17147), so reaching a different surface means letting
33
+ // that surface commit its own content by reading from a shared store instead.
34
+ export { createTunnel } from './create-tunnel.js';
33
35
  // descriptorToReact: the @symbiote-native/components Descriptor → React.createElement bridge. Exported so
34
36
  // an external wrapper package (e.g. @symbiote-native/slider/react over a third-party native view) can map
35
37
  // a shared render fn's Descriptor onto React elements through the SAME bridge the adapter uses.
36
- export { descriptorToReact } from './descriptor-to-react';
37
- export { findNodeHandle } from './host-instance';
38
+ export { descriptorToReact } from './descriptor-to-react/index.js';
39
+ export { findNodeHandle } from './host-instance.js';
38
40
  // AppRegistry: RN's app entry point over `mount`. setHostRegistrar wires RN's own
39
41
  // registrar so the native Fabric host finds our runnable by app key.
40
- export { AppRegistry, setHostRegistrar } from './modules/app-registry';
42
+ export { AppRegistry, setHostRegistrar } from './modules/app-registry/index.js';
41
43
  // Animated bridge: createAnimatedComponent + Animated.View/Text/Image, driving the
42
- // shared JS Animated engine (ADR 0016). Imperative timing/spring drivers merge into
43
- // this namespace once they land in shared.
44
- export { Animated, createAnimatedComponent } from './modules/animated';
44
+ // shared JS Animated engine. Imperative timing/spring drivers merge into this
45
+ // namespace once they land in shared.
46
+ export { Animated, createAnimatedComponent } from './modules/animated/index.js';
45
47
  // Framework-agnostic runtime utilities live in shared; the adapter re-exports them
46
48
  // so app code names only @symbiote-native/react (RN's surface, one import root).
47
49
  export { Platform, StyleSheet } from '@symbiote-native/engine';
@@ -55,31 +57,31 @@ export { PlatformColor, DynamicColorIOS, processColor } from '@symbiote-native/e
55
57
  export { setNativeViewConfigSource } from '@symbiote-native/engine';
56
58
  // Runtime modules: native-bridge consumers, same shape as Keyboard/StatusBar:
57
59
  // thin JS over getNativeModule + device events, no Fabric component of their own.
58
- export { Dimensions } from './modules/dimensions';
60
+ export { Dimensions } from './modules/dimensions.js';
59
61
  export { PixelRatio } from '@symbiote-native/engine';
60
- export { useWindowDimensions } from './hooks/use-window-dimensions';
61
- export { Appearance } from './modules/appearance';
62
- export { useColorScheme } from './hooks/use-color-scheme';
63
- export { AppState } from './modules/app-state';
64
- export { Alert } from './modules/alert';
65
- export { ActionSheetIOS } from './modules/action-sheet-ios';
66
- export { Linking } from './modules/linking';
67
- export { Vibration } from './modules/vibration';
68
- export { Share } from './modules/share';
69
- export { AccessibilityInfo } from './modules/accessibility-info';
70
- export { I18nManager } from './modules/i18n-manager';
71
- export { Settings } from './modules/settings';
62
+ export { useWindowDimensions } from './hooks/use-window-dimensions.js';
63
+ export { Appearance } from './modules/appearance.js';
64
+ export { useColorScheme } from './hooks/use-color-scheme.js';
65
+ export { AppState } from './modules/app-state.js';
66
+ export { Alert } from './modules/alert.js';
67
+ export { ActionSheetIOS } from './modules/action-sheet-ios.js';
68
+ export { Linking } from './modules/linking.js';
69
+ export { Vibration } from './modules/vibration.js';
70
+ export { Share } from './modules/share.js';
71
+ export { AccessibilityInfo } from './modules/accessibility-info/index.js';
72
+ export { I18nManager } from './modules/i18n-manager.js';
73
+ export { Settings } from './modules/settings.js';
72
74
  // Interaction subsystems: gestures, deferred work, and layout transitions.
73
75
  export { PanResponder } from '@symbiote-native/engine';
74
- export { LayoutAnimation } from './modules/layout-animation';
76
+ export { LayoutAnimation } from './modules/layout-animation.js';
75
77
  // InteractionManager is pure JS, so it lives in shared; re-exported here so app code
76
78
  // names only @symbiote-native/react (RN's single import root).
77
79
  export { InteractionManager } from '@symbiote-native/engine';
78
80
  // Android-only surface (the second-platform pass). Each is a thin JS shim over an
79
81
  // Android native module / Fabric view, inert on iOS (no module → graceful no-op,
80
- // no native view → degrade to a plain container). Native module names are
81
- // device-verify-pending; see .docs/native-module-platform-routing.md.
82
- export { BackHandler } from './modules/back-handler';
83
- export { ToastAndroid } from './modules/toast-android';
84
- export { PermissionsAndroid, PERMISSIONS, RESULTS } from './modules/permissions-android';
85
- export { TouchableNativeFeedback } from './components/touchable-native-feedback';
82
+ // no native view → degrade to a plain container). Native module name correctness
83
+ // can only be confirmed on a real device/simulator, not headless tests.
84
+ export { BackHandler } from './modules/back-handler.js';
85
+ export { ToastAndroid } from './modules/toast-android.js';
86
+ export { PermissionsAndroid, PERMISSIONS, RESULTS } from './modules/permissions-android.js';
87
+ export { TouchableNativeFeedback } from './components/touchable-native-feedback/index.js';
@@ -1,5 +1,5 @@
1
1
  // Base / default AccessibilityInfo: re-exports the iOS build. Metro overrides this with
2
2
  // accessibility-info.ios.ts / .android.ts on a real host; under tsx / tsc / web the host
3
3
  // config resolves here. Filename is the selector, no Platform.OS read. See
4
- // accessibility-info-shared.ts.
5
- export * from './index.ios';
4
+ // shared.ts.
5
+ export * from './index.ios.js';
@@ -1,4 +1,4 @@
1
- // ActionSheetIOS now lives framework-agnostic in @symbiote-native/engine (imperative
1
+ // ActionSheetIOS lives framework-agnostic in @symbiote-native/engine (imperative
2
2
  // native-bridge module, no visual, no lifecycle). The React adapter re-exports it
3
- // verbatim so the public surface is unchanged. See ADR 0019.
3
+ // verbatim so the public surface is unchanged.
4
4
  export { ActionSheetIOS } from '@symbiote-native/engine';
@@ -1,5 +1,5 @@
1
- // Alert now lives framework-agnostic in @symbiote-native/engine (imperative native-bridge
1
+ // Alert lives framework-agnostic in @symbiote-native/engine (imperative native-bridge
2
2
  // module, no visual, no lifecycle). The React adapter re-exports it verbatim so the
3
3
  // public surface is unchanged; the platform split (alert.ios/alert.android) lives
4
- // inside engine. See ADR 0019 + the engine relocation.
4
+ // inside engine.
5
5
  export { Alert } from '@symbiote-native/engine';
@@ -1,7 +1,7 @@
1
1
  // createAnimatedComponent wraps a base component (View / Text / Image / any) so
2
2
  // it can take AnimatedNodes in its props. Reimplemented thin against symbiote's
3
3
  // shared primitive: NO native driver, NO scheduleUpdate fallback. A frame is the
4
- // scoped commit setNativeProps drives from the AnimatedProps leaf (ADR 0016). RN's
4
+ // scoped commit setNativeProps drives from the AnimatedProps leaf. RN's
5
5
  // createAnimatedComponent + useAnimatedProps + createAnimatedPropsHook are the
6
6
  // structural reference, but their native helpers are deliberately not imported.
7
7
  //
@@ -58,7 +58,7 @@ export function createAnimatedComponent(Component) {
58
58
  previous.__detach();
59
59
  }
60
60
  }, [animatedProps]);
61
- // Native-driver trigger (ADR 0017). Runs after attach: push the leaf -> style -> transform
61
+ // Native-driver trigger. Runs after attach: push the leaf -> style -> transform
62
62
  // -> interpolation -> value chain native so the props animate on the UI thread (no JS lag).
63
63
  // Cascades down to the source value; the scroll event attaches to that same value
64
64
  // (idempotent). __makeNative is idempotent, so re-firing on a leaf swap is safe.
@@ -1,17 +1,17 @@
1
1
  // The Animated namespace for @symbiote-native/react. createAnimatedComponent applied to
2
2
  // the adapter's primitives gives Animated.View / Text / Image; the value graph,
3
3
  // easing and imperative drivers come from @symbiote-native/engine (framework-agnostic,
4
- // JS-driven, ADR 0016). Both halves meet here in one `Animated` object so the
4
+ // JS-driven). Both halves meet here in one `Animated` object so the
5
5
  // familiar surface (`Animated.timing(new Animated.Value(0), …).start()`) works.
6
6
  import { AnimatedValue, AnimatedValueXY, AnimatedColor, Easing, Platform, timing, spring, decay, parallel, sequence, stagger, loop, delay, add, subtract, multiply, divide, modulo, diffClamp, event, forkEvent, unforkEvent, } from '@symbiote-native/engine';
7
- import { View, Text } from '../../components';
8
- import { Image } from '../../components/image';
9
- import { ScrollView } from '../../components/scroll-view';
10
- import { FlatList } from '../../components/flat-list';
11
- import { SectionList } from '../../components/section-list';
12
- import { createAnimatedComponent } from './create-animated-component';
7
+ import { View, Text } from '../../components.js';
8
+ import { Image } from '../../components/image/index.js';
9
+ import { ScrollView } from '../../components/scroll-view/index.js';
10
+ import { FlatList } from '../../components/flat-list/index.js';
11
+ import { SectionList } from '../../components/section-list/index.js';
12
+ import { createAnimatedComponent } from './create-animated-component.js';
13
13
  import { AnimatedMock } from '@symbiote-native/engine';
14
- export { createAnimatedComponent } from './create-animated-component';
14
+ export { createAnimatedComponent } from './create-animated-component.js';
15
15
  // The pure graph leaves now live in @symbiote-native/engine (they extend AnimatedWithChildren,
16
16
  // no React); re-exported here so @symbiote-native/react's Animated surface is unchanged.
17
17
  export { AnimatedProps, AnimatedStyle, AnimatedTransform } from '@symbiote-native/engine';
@@ -26,7 +26,7 @@ const AnimatedImage = createAnimatedComponent(Image);
26
26
  // back, and a static `createAnimatedComponent(ScrollView)` at init would read ScrollView
27
27
  // inside its own TDZ. A memoized getter defers the wrap past module init, so the
28
28
  // cycle never fires. The wrappers carry no per-component animation logic; they only
29
- // add animated-prop support, so the adapter stays thin (invariant adapters_stay_thin).
29
+ // add animated-prop support, keeping the adapter a thin layer over the engine.
30
30
  // The native scroll-event attach (Animated.event onto contentOffset) is owned by
31
31
  // ScrollView itself.
32
32
  let animatedScrollView;
@@ -6,7 +6,7 @@
6
6
  // createElement + mount — so existing RN app-entry code ports verbatim.
7
7
  import { createElement } from 'react';
8
8
  import { createAppRegistry, dlog, } from '@symbiote-native/engine';
9
- import { mount } from '../../render';
9
+ import { mount } from '../../render.js';
10
10
  function runnableFor(componentProvider, getWrapperComponentProvider) {
11
11
  return appParameters => {
12
12
  dlog(`AppRegistry: mounting on rootTag ${String(appParameters.rootTag)}`);
@@ -1,4 +1,4 @@
1
1
  // I18nManager now lives framework-agnostic in @symbiote-native/engine (imperative
2
2
  // native-bridge module, no visual, no lifecycle). The React adapter re-exports it
3
- // verbatim so the public surface is unchanged. See ADR 0019.
3
+ // verbatim so the public surface is unchanged.
4
4
  export { I18nManager } from '@symbiote-native/engine';
@@ -1,4 +1,4 @@
1
1
  // Linking now lives framework-agnostic in @symbiote-native/engine (imperative native-bridge
2
2
  // module, no visual, no lifecycle). The React adapter re-exports it verbatim; the
3
- // platform split (linking.ios/linking.android) lives inside engine. See ADR 0019.
3
+ // platform split (linking.ios/linking.android) lives inside engine.
4
4
  export { Linking } from '@symbiote-native/engine';
@@ -1,4 +1,4 @@
1
1
  // Settings now lives framework-agnostic in @symbiote-native/engine (imperative native-bridge
2
2
  // module, no visual, no lifecycle). The React adapter re-exports it verbatim so the
3
- // public surface is unchanged. See ADR 0019.
3
+ // public surface is unchanged.
4
4
  export { Settings } from '@symbiote-native/engine';
@@ -1,4 +1,4 @@
1
1
  // Share now lives framework-agnostic in @symbiote-native/engine (imperative native-bridge
2
2
  // module, no visual, no lifecycle). The React adapter re-exports it verbatim; the
3
- // platform split (share.ios/share.android) lives inside engine. See ADR 0019.
3
+ // platform split (share.ios/share.android) lives inside engine.
4
4
  export { Share } from '@symbiote-native/engine';
@@ -13,7 +13,7 @@
13
13
  // not installed" because RN installs global.RN$stopSurface from its own renderer, which this
14
14
  // renderer replaces. Now that render.ts installs RN$stopSurface and tears surfaces down cleanly, the
15
15
  // relayout survives and the bar updates without blanking (verified on device: show/hide +
16
- // light/dark text). See render.ts installStopSurfaceGlobal + native-module-platform-routing.
16
+ // light/dark text).
17
17
  import { useEffect } from 'react';
18
18
  import { dlog, getNativeModule, processColor, STATUS_BAR_MANAGER, } from '@symbiote-native/engine';
19
19
  // processColor returns `unknown` (its result is platform-dependent); narrow to the
@@ -1,6 +1,6 @@
1
1
  // StatusBar on iOS: drives the iOS `StatusBarManager` TurboModule from its props
2
- // (and from static methods). The native contract is RN's spec at
3
- // .vendors/react-native/.../src/private/specs_DEPRECATED/modules/NativeStatusBarManagerIOS.js:
2
+ // (and from static methods). The native contract matches React Native's own
3
+ // NativeStatusBarManagerIOS spec:
4
4
  // setStyle(statusBarStyle?: string, animated: boolean)
5
5
  // setHidden(hidden: boolean, withAnimation: 'none' | 'fade' | 'slide')
6
6
  // setNetworkActivityIndicatorVisible(visible: boolean)
@@ -1,4 +1,4 @@
1
1
  // Base / default StatusBar: re-exports the iOS build. Metro overrides this with
2
2
  // status-bar.ios.ts / .android.ts on a real host; under tsx / tsc / web the host config
3
3
  // resolves here. Filename is the selector, no Platform.OS read. See status-bar-shared.ts.
4
- export * from './index.ios';
4
+ export * from './index.ios.js';
@@ -1,4 +1,4 @@
1
- // ToastAndroid now lives framework-agnostic in @symbiote-native/engine (imperative
1
+ // ToastAndroid lives framework-agnostic in @symbiote-native/engine (imperative
2
2
  // native-bridge module, no visual, no lifecycle). The React adapter re-exports it
3
- // verbatim so the public surface is unchanged. See ADR 0019.
3
+ // verbatim so the public surface is unchanged.
4
4
  export { ToastAndroid } from '@symbiote-native/engine';
@@ -1,4 +1,4 @@
1
- // Vibration now lives framework-agnostic in @symbiote-native/engine (imperative native-bridge
1
+ // Vibration lives framework-agnostic in @symbiote-native/engine (imperative native-bridge
2
2
  // module, no visual, no lifecycle). The React adapter re-exports it verbatim; the
3
- // platform split (vibration.ios/vibration.android) lives inside engine. See ADR 0019.
3
+ // platform split (vibration.ios/vibration.android) lives inside the engine.
4
4
  export { Vibration } from '@symbiote-native/engine';
package/build/render.js CHANGED
@@ -2,8 +2,8 @@
2
2
  // rootTag (via AppRegistry.registerRunnable); we create a surface for it and let
3
3
  // the reconciler drive shared, which commits into nativeFabricUIManager.
4
4
  import { createSurface, disposeRoot, setEventDispatcher, dlog, } from '@symbiote-native/engine';
5
- import reconciler, { withDiscretePriority } from './host-config';
6
- import { LegacyRoot } from './reconciler-constants';
5
+ import reconciler, { withDiscretePriority } from './host-config.js';
6
+ import { LegacyRoot } from './reconciler-constants.js';
7
7
  const noop = () => { };
8
8
  // A native event runs the listener (which may call setState) outside React's
9
9
  // loop. Run it at discrete priority so the update takes the sync lane, then
@@ -6,8 +6,7 @@
6
6
  // requiring FILE's own location, so this indirection is what actually removes the extra install
7
7
  // step, not pnpm hoisting (which does not propagate this transitively across workspace packages
8
8
  // the way a flat classic node_modules would). .cjs, not .js: this package is "type": "module",
9
- // and Metro's babelTransformerPath loading expects a require()-able module. See the
10
- // symbiote-sfc-style-compiler skill.
9
+ // and Metro's babelTransformerPath loading expects a require()-able module.
11
10
  // createCssMetroTransformer is a factory, not a ready transformer — Metro's
12
11
  // babelTransformerPath needs the actual {transform, getCacheKey} object it returns,
13
12
  // not the css-parser package barrel.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbiote-native/react",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
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
  "repository": {
6
6
  "type": "git",
@@ -36,9 +36,9 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "react-reconciler": "^0.33.0",
39
- "@symbiote-native/components": "0.2.0",
40
- "@symbiote-native/css-parser": "0.2.0",
41
- "@symbiote-native/engine": "0.1.1"
39
+ "@symbiote-native/components": "0.2.2",
40
+ "@symbiote-native/css-parser": "0.2.1",
41
+ "@symbiote-native/engine": "0.1.3"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "react": ">=19.0.0",
@@ -48,7 +48,7 @@
48
48
  "@types/react": "^19.2.0",
49
49
  "@types/react-reconciler": "^0.32.2",
50
50
  "react": "19.2.3",
51
- "@symbiote-native/test-utils": "0.1.1"
51
+ "@symbiote-native/test-utils": "0.1.3"
52
52
  },
53
53
  "scripts": {
54
54
  "typecheck": "tsc --build",