@symbiote-native/components 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,9 +7,9 @@ and pure render functions for every visual component (`Switch`, `Modal`, `Scroll
7
7
  exists so that "add component X to a new adapter" means writing a thin lifecycle + descriptor
8
8
  bridge, not re-implementing X's logic per framework.
9
9
 
10
- > New to SymbioteNative? The [root README](../../README.md) has the architecture. This package is
11
- > "Workstream B" — the piece that makes cross-adapter feature parity **structural** instead of a
12
- > promise kept by hand.
10
+ > New to SymbioteNative? The [root README](../../README.md) has the architecture. This package
11
+ > is the piece that makes cross-adapter feature parity **structural** instead of a promise kept
12
+ > by hand.
13
13
 
14
14
  ---
15
15
 
@@ -7,7 +7,7 @@
7
7
  // own View.js transform. Types are kept in sync with RN's ViewAccessibility.js.
8
8
  //
9
9
  // Framework-agnostic (imports only @symbiote-native/engine), so every adapter (React,
10
- // Vue, and the next) folds aria/role into accessibility* identically (ADR 0024).
10
+ // Vue, and the next) folds aria/role into accessibility* identically.
11
11
  import { dlog } from '@symbiote-native/engine';
12
12
  // RN's web `role` → native `accessibilityRole`. Where the web role has no native
13
13
  // counterpart it is forwarded unchanged (the AccessibilityRole union stays open),
@@ -6,7 +6,7 @@
6
6
  // importing it directly must stay unreachable from the tested main index.ts.
7
7
  import { processColor, DeviceEventEmitter, Image } from 'react-native';
8
8
  import { setColorProcessor, setDeviceEventSource, setNativeViewConfigSource, } from '@symbiote-native/engine';
9
- import { setImageSourceResolver } from './view/render-image';
9
+ import { setImageSourceResolver } from './view/render-image.js';
10
10
  // @ts-expect-error react-native ships no types for this internal path (plain .js) — the
11
11
  // try/catch below is what actually proves the shape, not TS.
12
12
  import * as ReactNativeViewConfigRegistry from 'react-native/Libraries/Renderer/shims/ReactNativeViewConfigRegistry';
@@ -1,8 +1,8 @@
1
- // Android Fabric component names. Metro picks this file on an Android host. See ADR 0020.
1
+ // Android Fabric component names. Metro picks this file on an Android host.
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 { buildDescriptors, makeDescriptorFor } from './shared';
5
+ import { buildDescriptors, makeDescriptorFor } from './shared.js';
6
6
  const ANDROID_NAMES = {
7
7
  'symbiote-view': 'RCTView',
8
8
  'symbiote-text': 'RCTText',
@@ -1,8 +1,8 @@
1
1
  // iOS Fabric component names. Metro picks this file on an iOS host; it is also the base
2
- // (component-names.ts re-exports it) for headless tsx / tsc / web fallback. See ADR 0020.
2
+ // (component-names.ts re-exports it) for headless tsx / tsc / web fallback.
3
3
  // Fabric names are the codegen spec's registered name (the new-arch name), not the legacy
4
4
  // paperComponentName (RCTSwitch, …).
5
- import { buildDescriptors, makeDescriptorFor } from './shared';
5
+ import { buildDescriptors, makeDescriptorFor } from './shared.js';
6
6
  const IOS_NAMES = {
7
7
  'symbiote-view': 'RCTView',
8
8
  'symbiote-text': 'RCTText',
@@ -1,5 +1,5 @@
1
1
  // Base / default component-name table: re-exports the iOS table. Metro overrides this
2
2
  // with component-names.ios.ts / component-names.android.ts on a real host; under tsx /
3
3
  // tsc / web (no Metro) the host config resolves here. Filename is the selector, no
4
- // Platform.OS read. See ADR 0020.
5
- export * from './index.ios';
4
+ // Platform.OS read.
5
+ export * from './index.ios.js';
@@ -1,6 +1,6 @@
1
1
  // The intrinsic JSX types symbiote's host config maps to Fabric components, plus the
2
2
  // machinery to turn a platform name table into the descriptors the host config reads.
3
- // Per ADR 0020 the Fabric NAME of a primitive is platform-specific (iOS 'Switch' vs
3
+ // The Fabric NAME of a primitive is platform-specific (iOS 'Switch' vs
4
4
  // Android 'AndroidSwitch'), so the name tables live in component-names.ios.ts /
5
5
  // .android.ts and the filename selects, no Platform.OS read. The isText flag is
6
6
  // platform-invariant, so it lives here once and both tables share it.
@@ -3,12 +3,10 @@
3
3
  // element (`descriptorToReact` → React.createElement, `descriptorToVue` → h()). The
4
4
  // adapter's host element then flows on through its reconciler → engine → Fabric.
5
5
  //
6
- // The wolf-tui twin is `internal/shared/src/wnode/types.ts` (`WNode` + `wbox`/`wtext`).
7
- // We diverge in one way: `type` is an open host-component string, not a closed two-member
8
- // union, because symbiote paints one host element PER native component
9
- // (`symbiote-activity-indicator`, `symbiote-switch`, …), not just box/text.
6
+ // `type` is an open host-component string, not a closed two-member union, because
7
+ // symbiote paints one host element PER native component (`symbiote-activity-indicator`,
8
+ // `symbiote-switch`, …), not just a generic box/text pair.
10
9
  // el(): a host element of any type. txt(): shorthand for the `symbiote-text` primitive.
11
- // Mirror wolf-tui's `wbox` / `wtext`.
12
10
  export function el(type, props = {}, children = [], key) {
13
11
  return { type, props, children, key };
14
12
  }
package/build/index.js CHANGED
@@ -1,63 +1,63 @@
1
1
  // @symbiote-native/components: the framework-agnostic component layer. Pure state machines
2
2
  // (`state/`) and render functions (`view/`) that paint `Descriptor` trees; every adapter
3
3
  // wires state→render with ITS lifecycle (React hooks / Vue reactivity) and maps the
4
- // Descriptor onto its own element. See CLAUDE.md <components_split_logic_view_lifecycle>.
5
- export { el, txt } from './descriptor';
4
+ // Descriptor onto its own element.
5
+ export { el, txt } from './descriptor.js';
6
6
  // Accessibility folding: the web-alias (aria-*/role) → canonical accessibility* transform
7
- // and its types. Framework-agnostic (ADR 0024), so React, Vue, and the next adapter all fold
7
+ // and its types. Framework-agnostic, so React, Vue, and the next adapter all fold
8
8
  // identically; moved here from @symbiote-native/react. RefreshControl/SafeAreaView/ScrollView consume it.
9
- export { resolveAccessibilityProps } from './accessibility-props';
9
+ export { resolveAccessibilityProps } from './accessibility-props.js';
10
10
  // Intrinsic (`symbiote-*`) → Fabric view-name resolution. Shared by every adapter so the
11
11
  // names CANNOT drift between them (one engine, one Fabric). The name tables are
12
- // Metro-split (.ios/.android, filename selects, no Platform.OS read, ADR 0020); the base
12
+ // Metro-split (.ios/.android, filename selects, no Platform.OS read); the base
13
13
  // re-exports iOS for headless. descriptorFor is the per-platform-bound resolver.
14
- export { descriptorFor, COMPONENT_DESCRIPTORS } from './component-names';
15
- export { buildDescriptors, makeDescriptorFor } from './component-names/shared';
16
- export { renderActivityIndicator } from './view/render-activity-indicator';
17
- export { renderSwitch } from './view/render-switch';
14
+ export { descriptorFor, COMPONENT_DESCRIPTORS } from './component-names/index.js';
15
+ export { buildDescriptors, makeDescriptorFor } from './component-names/shared.js';
16
+ export { renderActivityIndicator } from './view/render-activity-indicator.js';
17
+ export { renderSwitch } from './view/render-switch.js';
18
18
  // Switch is the first STATE machine off this layer (ActivityIndicator was render-only):
19
19
  // the reducer + the two pure predicates are the logic half, the adapter supplies the hook.
20
- export { switchReducer, createInitialSwitchState, shouldSnapBack, valueFromChange, } from './state/switch';
20
+ export { switchReducer, createInitialSwitchState, shouldSnapBack, valueFromChange, } from './state/switch.js';
21
21
  // ScrollView: pure render/command helpers (no state machine, no 3-layer split). The adapter
22
22
  // owns the refs/effects/element assembly and the sticky-header component; these supply the
23
- // platform-invariant math and plumbing every adapter shares (ADR 0024).
24
- export { resolveDecelerationRate, selectScrollIntrinsics, readLayoutDimension, didContentSizeChange, SCROLL_VIEW_BASE_HORIZONTAL, SCROLL_VIEW_BASE_VERTICAL, } from './view/render-scroll-view';
25
- export { buildScrollViewHandle, splitLayoutProps, attachStickyScroll, isSymbioteEvent, forwardScrollEvent, } from './scroll-view-commands';
26
- export { computeStickyInterpolation, nextStickyHeaderY, stickyDebounceMs, readLayoutNumber, STICKY_HEADER_Z_INDEX, } from './view/render-scroll-sticky';
27
- export { renderImage, imageStatics, setImageSourceResolver } from './view/render-image';
23
+ // platform-invariant math and plumbing every adapter shares.
24
+ export { resolveDecelerationRate, selectScrollIntrinsics, readLayoutDimension, didContentSizeChange, SCROLL_VIEW_BASE_HORIZONTAL, SCROLL_VIEW_BASE_VERTICAL, } from './view/render-scroll-view.js';
25
+ export { buildScrollViewHandle, splitLayoutProps, attachStickyScroll, isSymbioteEvent, forwardScrollEvent, } from './scroll-view-commands.js';
26
+ export { computeStickyInterpolation, nextStickyHeaderY, stickyDebounceMs, readLayoutNumber, STICKY_HEADER_Z_INDEX, } from './view/render-scroll-sticky.js';
27
+ export { renderImage, imageStatics, setImageSourceResolver } from './view/render-image.js';
28
28
  // ImageBackground: render-only composition (absolute-fill image behind, children on top).
29
- export { renderImageBackground } from './view/render-image-background';
29
+ export { renderImageBackground } from './view/render-image-background.js';
30
30
  // InputAccessoryView: render-only host assembly (nativeID/backgroundColor).
31
- export { renderInputAccessoryView } from './view/render-input-accessory-view';
31
+ export { renderInputAccessoryView } from './view/render-input-accessory-view.js';
32
32
  // Modal: full 3-layer split (state machine gates the iOS keep-alive frame).
33
- export { renderModal } from './view/render-modal';
34
- export { modalReducer, createInitialModalState, shouldRenderModal } from './state/modal';
33
+ export { renderModal } from './view/render-modal.js';
34
+ export { modalReducer, createInitialModalState, shouldRenderModal } from './state/modal.js';
35
35
  // KeyboardAvoidingView: pure inset/behavior math; the adapter owns the Keyboard subscription.
36
- export { computeInset, readKeyboardFrame, readLayoutFrame, resolveKeyboardAvoidingLayout, DEFAULT_VERTICAL_OFFSET, } from './view/render-keyboard-avoiding-view';
36
+ export { computeInset, readKeyboardFrame, readLayoutFrame, resolveKeyboardAvoidingLayout, DEFAULT_VERTICAL_OFFSET, } from './view/render-keyboard-avoiding-view.js';
37
37
  // Pressable: the press state machine (logic) + render decisions. The pure lifecycle (timers,
38
38
  // geometry, drift test, suppression flags) lives in state/pressable; the responder-listener +
39
39
  // accessibilityState + ripple render decisions in view/render-pressable. Every adapter supplies
40
40
  // only its reactive `pressed` cell + the View's measure handle (see the 3-layer split).
41
- export { createPressHandlers, createPressRuntime, normalizeRect, maxEdge, isTouchWithinRegion, readPoint, computeRegion, rippleProps, DEFAULT_DELAY_LONG_PRESS_MS, DEFAULT_PRESS_RECT_OFFSETS, } from './state/pressable';
42
- export { buildPressableListeners, resolveDisabledAccessibilityState, noteHoverNoop, } from './view/render-pressable';
41
+ export { createPressHandlers, createPressRuntime, normalizeRect, maxEdge, isTouchWithinRegion, readPoint, computeRegion, rippleProps, DEFAULT_DELAY_LONG_PRESS_MS, DEFAULT_PRESS_RECT_OFFSETS, } from './state/pressable.js';
42
+ export { buildPressableListeners, resolveDisabledAccessibilityState, noteHoverNoop, } from './view/render-pressable.js';
43
43
  // Touchable*: shared press-timing constants + the deactivation-floor math (the Animated feedback
44
44
  // itself stays per-adapter), and TouchableNativeFeedback's pure static factories + background map.
45
- export { computePressOutWait, DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, DEFAULT_HIGHLIGHT_CHILD_OPACITY, DEFAULT_UNDERLAY_COLOR, DEFAULT_MIN_PRESS_DURATION_MS, } from './state/touchable';
46
- export { backgroundProps, canUseNativeForeground, selectableBackground, selectableBackgroundBorderless, rippleBackground, } from './view/render-touchable-native-feedback';
45
+ export { computePressOutWait, DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, DEFAULT_HIGHLIGHT_CHILD_OPACITY, DEFAULT_UNDERLAY_COLOR, DEFAULT_MIN_PRESS_DURATION_MS, } from './state/touchable.js';
46
+ export { backgroundProps, canUseNativeForeground, selectableBackground, selectableBackgroundBorderless, rippleBackground, } from './view/render-touchable-native-feedback.js';
47
47
  // Button: shared base text style, role constant, and color fold (the adapter composes its own
48
48
  // TouchableOpacity + Text).
49
- export { BUTTON_ACCESSIBILITY_ROLE, buttonTextStyle, resolveButtonTextStyle, } from './view/render-button';
49
+ export { BUTTON_ACCESSIBILITY_ROLE, buttonTextStyle, resolveButtonTextStyle, } from './view/render-button.js';
50
50
  // TextInput: the controlled-value / event-count handshake. The logic half is the pure
51
51
  // folds/maps + the controlled-write predicate (not a single reducer: count must re-render the
52
52
  // imperative handle, lastNativeText must not); the view half picks the intrinsic and maps the
53
53
  // resolved native props. Both shared verbatim across React and Vue; the adapter owns only the
54
54
  // hooks/reactivity + the imperative handle.
55
- export { resolveTextInputProps, foldText, foldAutoComplete, foldSubmitBehavior, mapAutoComplete, textFromChange, eventCountFromChange, shouldCommandText, INITIAL_EVENT_COUNT, SELECTION_NONE, } from './state/text-input';
56
- export { renderTextInput } from './view/render-text-input';
55
+ export { resolveTextInputProps, foldText, foldAutoComplete, foldSubmitBehavior, mapAutoComplete, textFromChange, eventCountFromChange, shouldCommandText, INITIAL_EVENT_COUNT, SELECTION_NONE, } from './state/text-input.js';
56
+ export { renderTextInput } from './view/render-text-input.js';
57
57
  // VirtualizedList family: the framework-agnostic windowing engine + data shapes. Lists
58
58
  // have NO view/render-*.ts (the cell content is the framework's own children, so there is
59
59
  // no Descriptor render fn) — the shared layer for lists is this STATE/logic, reused
60
- // verbatim by React and Vue. See core/components/.docs-note-lists.md.
61
- 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, buildOffsets, computeWindow, throttleWindow, visiblePercent, isCellViewable, offsetForIndex, averageMeasuredLength, highestMeasuredIndex, computeEndReached, computeStartReached, buildViewabilityPairs, computeViewableSet, diffViewable, maxMinimumViewTime, buildListPlan, } from './state/virtualized-list';
62
- export { SINGLE_COLUMN, chunkIntoRows, rowKeyExtractor, expandRowToken, expandRowViewability, lastItemOfRow, firstItemOfRow, } from './state/flat-list';
63
- export { flattenSections, unwrapEntryItem, sectionEntryKey, scrollLocationToFlatIndex, } from './state/section-list';
60
+ // verbatim by React and Vue.
61
+ 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, buildOffsets, computeWindow, throttleWindow, visiblePercent, isCellViewable, offsetForIndex, averageMeasuredLength, highestMeasuredIndex, computeEndReached, computeStartReached, buildViewabilityPairs, computeViewableSet, diffViewable, maxMinimumViewTime, buildListPlan, } from './state/virtualized-list.js';
62
+ export { SINGLE_COLUMN, chunkIntoRows, rowKeyExtractor, expandRowToken, expandRowViewability, lastItemOfRow, firstItemOfRow, } from './state/flat-list.js';
63
+ export { flattenSections, unwrapEntryItem, sectionEntryKey, scrollLocationToFlatIndex, } from './state/section-list.js';
@@ -1,9 +1,9 @@
1
1
  // VirtualizedList logic: the framework-agnostic windowing engine. Every adapter
2
2
  // (React hooks, Vue reactivity) drives the SAME math from here, so a windowing /
3
- // viewability / edge-reached bug is fixed once for all adapters
4
- // (<adapters_reach_full_feature_parity>). The adapter supplies only its lifecycle
5
- // (refs/state/effects), the imperative handle wiring, and the per-cell element
6
- // creation (createElement / h) — never the geometry.
3
+ // viewability / edge-reached bug is fixed once for all adapters. The adapter
4
+ // supplies only its lifecycle (refs/state/effects), the imperative handle
5
+ // wiring, and the per-cell element creation (createElement / h) — never the
6
+ // geometry.
7
7
  //
8
8
  // What lives here:
9
9
  // - the RN-matching defaults + sentinels,
@@ -18,7 +18,7 @@
18
18
  // What stays in the adapter (genuinely framework-bound): the cell CONTENT is the
19
19
  // framework's own children (renderItem -> ReactNode / VNode), so there is no
20
20
  // Descriptor render fn for a list — the shared layer for lists is this STATE/logic
21
- // module, not a view/render-*.ts. See core/components/.docs-note-lists.md.
21
+ // module, not a view/render-*.ts.
22
22
  // Defaults match RN. windowSize is measured in viewport-lengths (21 => ten screens
23
23
  // of buffer on each side of the visible region). onEndReachedThreshold is a multiple
24
24
  // of the visible length (RN's onEndReachedThresholdOrDefault returns `?? 2`).
@@ -3,13 +3,13 @@
3
3
  // enum AND a fixed box style; a numeric size never reaches native (it sizes the spinner
4
4
  // via style only). That translation is platform-invariant and lives here.
5
5
  //
6
- // What IS platform-specific (ADR 0020, prop-level): Android's AndroidProgressBar needs
6
+ // What IS platform-specific: Android's AndroidProgressBar needs
7
7
  // `styleAttr` (which triggers its setStyle(), without it the view throws "setStyle() not
8
8
  // called") plus `indeterminate: true`, and its default color is the theme (null), whereas
9
9
  // iOS's ActivityIndicatorView takes neither and defaults to GRAY. The adapter's per-host
10
10
  // file supplies those bits via `platform`.
11
11
  import { dlog } from '@symbiote-native/engine';
12
- import { el } from '../descriptor';
12
+ import { el } from '../descriptor.js';
13
13
  // Fixed pixel boxes RN gives the two named sizes (styles.sizeSmall/sizeLarge).
14
14
  const SIZE_SMALL_PX = 20;
15
15
  const SIZE_LARGE_PX = 36;
@@ -9,8 +9,8 @@
9
9
  // fight the wrapper's explicit dimensions, so we proxy them back onto the Image so it fills
10
10
  // the box. `imageStyle` wins last.
11
11
  import { dlog, flattenStyle, } from '@symbiote-native/engine';
12
- import { el } from '../descriptor';
13
- import { renderImage } from './render-image';
12
+ import { el } from '../descriptor.js';
13
+ import { renderImage } from './render-image.js';
14
14
  // The inner Image's positioning: absolute-fill behind the wrapper's children.
15
15
  const IMAGE_BACKGROUND_ABSOLUTE_FILL = {
16
16
  position: 'absolute',
@@ -1,5 +1,5 @@
1
1
  import { dlog, flattenStyle, getNativeModule, Platform, } from '@symbiote-native/engine';
2
- import { el } from '../descriptor';
2
+ import { el } from '../descriptor.js';
3
3
  // Default resolver: identity. RN's resolveAssetSource (which turns a require()
4
4
  // number into {uri, scale, width, height}) is wired in by the app at startup.
5
5
  let resolveSource = source => source;
@@ -109,10 +109,9 @@ function readSourceUri(source) {
109
109
  return undefined;
110
110
  }
111
111
  // The iOS native module name RN registers this under (NativeImageLoaderIOS.js
112
- // resolves `TurboModuleRegistry.getEnforcing<Spec>('ImageLoader')`). Per the
113
- // symbiote invariant, a module name is only provable on a real host (a headless
114
- // fake answers to any name); this iOS name is device-verify-pending. See
115
- // .docs/native-module-platform-routing.md.
112
+ // resolves `TurboModuleRegistry.getEnforcing<Spec>('ImageLoader')`). A module
113
+ // name like this is only provable on a real host — a headless fake answers to
114
+ // any name — so this iOS name is device-verify-pending.
116
115
  const IMAGE_LOADER_MODULE = 'ImageLoader';
117
116
  let imageLoaderModule;
118
117
  function getImageLoader() {
@@ -5,7 +5,7 @@
5
5
  // onto the intrinsic and the user children (injected by the adapter) nest under it. Shared
6
6
  // verbatim across adapters: React and Vue both bridge this Descriptor.
7
7
  import { dlog } from '@symbiote-native/engine';
8
- import { el } from '../descriptor';
8
+ import { el } from '../descriptor.js';
9
9
  export function renderInputAccessoryView(view) {
10
10
  const props = { ...view.passthrough, style: view.style };
11
11
  if (view.nativeID !== undefined)
@@ -6,7 +6,7 @@
6
6
  // full-screen container View that holds the user children (injected by the adapter). Shared
7
7
  // verbatim: React and Vue both bridge this Descriptor; the keep-alive state lives in state/modal.ts.
8
8
  import { dlog } from '@symbiote-native/engine';
9
- import { el } from '../descriptor';
9
+ import { el } from '../descriptor.js';
10
10
  // The full-screen box RN anchors the modal content in (Modal.js styles.container: [side]:0,
11
11
  // top:0, flex:1, backgroundColor:'white'). It is NOT position:absolute, it is a flex child that
12
12
  // fills the ModalHostView, whose shadow node self-sizes to the screen
@@ -3,7 +3,7 @@
3
3
  // decelerationRate, picking the per-axis intrinsics/base style, reading layout dimensions, and
4
4
  // the content-size dedupe are all platform- and framework-invariant, so they live here. The
5
5
  // adapter owns the lifecycle (refs/state/effects) and the element assembly; it calls these pure
6
- // helpers from prepareScrollView. What diverges per platform (ADR 0020), how a RefreshControl
6
+ // helpers from prepareScrollView. What diverges per platform, and how a RefreshControl
7
7
  // integrates, stays in the adapter's .ios/.android files.
8
8
  import { Platform } from '@symbiote-native/engine';
9
9
  // Pull a numeric field out of an onLayout event's nativeEvent.layout without a cast:
@@ -5,7 +5,7 @@
5
5
  // ios_backgroundColor folds into the style as the pill that shows through the shrunken track.
6
6
  // Pure and prop-driven; no hooks, no events. The adapter owns those.
7
7
  import { dlog } from '@symbiote-native/engine';
8
- import { el } from '../descriptor';
8
+ import { el } from '../descriptor.js';
9
9
  // RN rounds the iOS background pill to this radius when ios_backgroundColor is set.
10
10
  const IOS_BACKGROUND_BORDER_RADIUS = 16;
11
11
  // Fold ios_backgroundColor into the style, matching RN's iOS branch: it paints the
@@ -5,7 +5,7 @@
5
5
  // remaining native events) arrive folded into `passthrough` and land on the host untouched.
6
6
  // Pure and prop-driven; no hooks, no events. The adapter owns those.
7
7
  import { dlog } from '@symbiote-native/engine';
8
- import { el } from '../descriptor';
8
+ import { el } from '../descriptor.js';
9
9
  // One host element per native input class. Text carries the only non-trivial nesting elsewhere;
10
10
  // here the choice is binary and runtime (the `multiline` prop), so the module stays flat.
11
11
  const SINGLELINE_INTRINSIC = 'symbiote-text-input';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbiote-native/components",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Framework-agnostic component logic (state machines + render functions) for SymbioteNative — written once, inherited by every adapter (React, Vue, Angular, ...).",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@symbiote-native/engine": "0.1.1"
36
+ "@symbiote-native/engine": "0.1.3"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "react-native": ">=0.86"