@symbiote-native/solid 0.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -14
- package/build/components/activity-indicator-props.d.ts +5 -0
- package/build/components/activity-indicator-props.js +1 -0
- package/build/components/button-props.d.ts +5 -0
- package/build/components/button-props.js +1 -0
- package/build/components/flat-list/index.jsx +3 -3
- package/build/components/{image-background.d.ts → image-background-props.d.ts} +2 -3
- package/build/components/image-background-props.js +1 -0
- package/build/components/image-props.d.ts +5 -0
- package/build/components/image-props.js +6 -0
- package/build/components/{input-accessory-view.d.ts → input-accessory-view-props.d.ts} +1 -2
- package/build/components/input-accessory-view-props.js +5 -0
- package/build/components/keyboard-avoiding-view.jsx +9 -4
- package/build/components/modal.jsx +6 -6
- package/build/components/{pressable.d.ts → pressable-props.d.ts} +8 -6
- package/build/components/pressable-props.js +13 -0
- package/build/components/{refresh-control.d.ts → refresh-control-props.d.ts} +3 -3
- package/build/components/refresh-control-props.js +7 -0
- package/build/components/safe-area-view-props.d.ts +10 -0
- package/build/components/safe-area-view-props.js +5 -0
- package/build/components/{scroll-view/shared.d.ts → scroll-view-props.d.ts} +7 -13
- package/build/components/scroll-view-props.js +29 -0
- package/build/components/switch-props.d.ts +6 -0
- package/build/components/switch-props.js +5 -0
- package/build/components/text-input-props.d.ts +8 -0
- package/build/components/text-input-props.js +1 -0
- package/build/components/{text.d.ts → text-props.d.ts} +3 -3
- package/build/components/text-props.js +11 -0
- package/build/components/touchable-native-feedback/touchable-native-feedback-props.d.ts +8 -0
- package/build/components/touchable-native-feedback/touchable-native-feedback-props.js +1 -0
- package/build/components/touchable-props.d.ts +18 -0
- package/build/components/touchable-props.js +1 -0
- package/build/components/touchable-without-feedback/touchable-without-feedback-props.d.ts +6 -0
- package/build/components/touchable-without-feedback/touchable-without-feedback-props.js +1 -0
- package/build/components/{view.d.ts → view-props.d.ts} +2 -3
- package/build/components/view-props.js +11 -0
- package/build/components/virtualized-list/index.android.js +5 -4
- package/build/components/virtualized-list/index.ios.js +6 -6
- package/build/components/virtualized-list/shared.d.ts +1 -3
- package/build/components/virtualized-list/shared.jsx +87 -98
- package/build/components/virtualized-list/sticky-header.d.ts +6 -0
- package/build/components/{scroll-view → virtualized-list}/sticky-header.jsx +28 -36
- package/build/components.d.ts +20 -30
- package/build/components.js +6 -33
- package/build/create-portal/index.jsx +1 -1
- package/build/descriptor-to-solid.js +1 -1
- package/build/host-instance.js +3 -3
- package/build/index.d.ts +2 -0
- package/build/index.js +13 -3
- package/build/jsx-runtime.d.ts +39 -2
- package/build/modules/animated/create-animated-component.d.ts +1 -1
- package/build/modules/animated/create-animated-component.jsx +22 -0
- package/build/modules/animated/index.d.ts +0 -4
- package/build/modules/animated/index.js +16 -22
- package/build/modules/image.d.ts +3 -0
- package/build/modules/image.js +12 -0
- package/build/register.d.ts +1 -0
- package/build/register.js +15 -0
- package/build/renderer.d.ts +1 -0
- package/build/renderer.js +133 -6
- package/build/utils/stable-keys.d.ts +1 -1
- package/build/utils/stable-keys.js +6 -5
- package/metro-css-parser.cjs +2 -1
- package/package.json +18 -7
- package/build/components/activity-indicator/index.android.d.ts +0 -2
- package/build/components/activity-indicator/index.android.js +0 -11
- package/build/components/activity-indicator/index.d.ts +0 -1
- package/build/components/activity-indicator/index.ios.d.ts +0 -2
- package/build/components/activity-indicator/index.ios.js +0 -10
- package/build/components/activity-indicator/index.js +0 -4
- package/build/components/activity-indicator/shared.d.ts +0 -8
- package/build/components/activity-indicator/shared.js +0 -51
- package/build/components/button.d.ts +0 -7
- package/build/components/button.jsx +0 -45
- package/build/components/image-background.jsx +0 -74
- package/build/components/image.d.ts +0 -9
- package/build/components/image.js +0 -75
- package/build/components/input-accessory-view.jsx +0 -39
- package/build/components/pressable.jsx +0 -185
- package/build/components/refresh-control.jsx +0 -36
- package/build/components/safe-area-view.d.ts +0 -10
- package/build/components/safe-area-view.jsx +0 -24
- package/build/components/scroll-view/index.android.d.ts +0 -2
- package/build/components/scroll-view/index.android.js +0 -11
- package/build/components/scroll-view/index.d.ts +0 -2
- package/build/components/scroll-view/index.ios.d.ts +0 -2
- package/build/components/scroll-view/index.ios.js +0 -8
- package/build/components/scroll-view/index.js +0 -9
- package/build/components/scroll-view/shared.jsx +0 -334
- package/build/components/scroll-view/sticky-header.d.ts +0 -18
- package/build/components/switch/index.android.d.ts +0 -2
- package/build/components/switch/index.android.js +0 -12
- package/build/components/switch/index.d.ts +0 -1
- package/build/components/switch/index.ios.d.ts +0 -2
- package/build/components/switch/index.ios.js +0 -11
- package/build/components/switch/index.js +0 -4
- package/build/components/switch/shared.d.ts +0 -11
- package/build/components/switch/shared.js +0 -87
- package/build/components/text-input.d.ts +0 -10
- package/build/components/text-input.js +0 -268
- package/build/components/text.jsx +0 -27
- package/build/components/touchable/index.d.ts +0 -22
- package/build/components/touchable/index.jsx +0 -247
- package/build/components/touchable-native-feedback/index.d.ts +0 -16
- package/build/components/touchable-native-feedback/index.jsx +0 -68
- package/build/components/view.jsx +0 -49
package/build/jsx-runtime.d.ts
CHANGED
|
@@ -1,9 +1,46 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ICrossTypedIntrinsics } from '@symbiote-native/components';
|
|
2
2
|
import type { ISymbioteNode } from '@symbiote-native/engine';
|
|
3
|
+
import type { IViewProps } from './components/view-props';
|
|
4
|
+
import type { ITextProps } from './components/text-props';
|
|
5
|
+
import type { IPressableProps } from './components/pressable-props';
|
|
6
|
+
import type { IButtonProps } from './components/button-props';
|
|
7
|
+
import type { IImageProps } from './components/image-props';
|
|
8
|
+
import type { IImageBackgroundProps } from './components/image-background-props';
|
|
9
|
+
import type { IInputAccessoryViewProps } from './components/input-accessory-view-props';
|
|
10
|
+
import type { IRefreshControlProps } from './components/refresh-control-props';
|
|
11
|
+
import type { ISafeAreaViewProps } from './components/safe-area-view-props';
|
|
12
|
+
import type { ITouchableNativeFeedbackProps } from './components/touchable-native-feedback/touchable-native-feedback-props';
|
|
13
|
+
import type { ITouchableOpacityProps, ITouchableHighlightProps } from './components/touchable-props';
|
|
14
|
+
import type { ITouchableWithoutFeedbackProps } from './components/touchable-without-feedback/touchable-without-feedback-props';
|
|
15
|
+
import type { IScrollViewProps } from './components/scroll-view-props';
|
|
16
|
+
import type { ISwitchProps } from './components/switch-props';
|
|
17
|
+
import type { ITextInputProps } from './components/text-input-props';
|
|
18
|
+
import type { IModalProps } from './components/modal';
|
|
19
|
+
import type { IActivityIndicatorProps } from './components/activity-indicator-props';
|
|
3
20
|
type ISymbioteHostAttributes = {
|
|
4
21
|
readonly children?: JSX.Element;
|
|
5
22
|
readonly [attribute: string]: unknown;
|
|
6
23
|
};
|
|
24
|
+
interface ICrossedPrimitiveProps {
|
|
25
|
+
view: IViewProps;
|
|
26
|
+
text: ITextProps;
|
|
27
|
+
pressable: IPressableProps;
|
|
28
|
+
button: IButtonProps;
|
|
29
|
+
image: IImageProps;
|
|
30
|
+
'image-background': IImageBackgroundProps;
|
|
31
|
+
'input-accessory-view': IInputAccessoryViewProps;
|
|
32
|
+
'refresh-control': IRefreshControlProps;
|
|
33
|
+
'safe-area-view': ISafeAreaViewProps;
|
|
34
|
+
'touchable-native-feedback': ITouchableNativeFeedbackProps;
|
|
35
|
+
'touchable-opacity': ITouchableOpacityProps;
|
|
36
|
+
'touchable-highlight': ITouchableHighlightProps;
|
|
37
|
+
'touchable-without-feedback': ITouchableWithoutFeedbackProps;
|
|
38
|
+
'scroll-view': IScrollViewProps;
|
|
39
|
+
switch: ISwitchProps;
|
|
40
|
+
'text-input': ITextInputProps;
|
|
41
|
+
modal: IModalProps;
|
|
42
|
+
'activity-indicator': IActivityIndicatorProps;
|
|
43
|
+
}
|
|
7
44
|
export declare namespace JSX {
|
|
8
45
|
type Element = ISymbioteNode | IArrayElement | IFunctionElement | (string & {}) | number | boolean | null | undefined;
|
|
9
46
|
interface IArrayElement extends Array<Element> {
|
|
@@ -20,7 +57,7 @@ export declare namespace JSX {
|
|
|
20
57
|
}
|
|
21
58
|
interface IntrinsicAttributes {
|
|
22
59
|
}
|
|
23
|
-
interface IntrinsicElements extends
|
|
60
|
+
interface IntrinsicElements extends ICrossTypedIntrinsics<ISymbioteHostAttributes, ICrossedPrimitiveProps> {
|
|
24
61
|
}
|
|
25
62
|
}
|
|
26
63
|
export {};
|
|
@@ -7,4 +7,4 @@ export interface IAnimatedComponentProps {
|
|
|
7
7
|
children?: JSX.Element;
|
|
8
8
|
[key: string]: unknown;
|
|
9
9
|
}
|
|
10
|
-
export declare function createAnimatedComponent(Base: Component<any>): (props: IAnimatedComponentProps) => JSX.Element;
|
|
10
|
+
export declare function createAnimatedComponent(Base: Component<any> | string): (props: IAnimatedComponentProps) => JSX.Element;
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
// next reconcile drops.
|
|
24
24
|
import { createEffect, mergeProps, onCleanup, splitProps, } from 'solid-js';
|
|
25
25
|
import { createAnimatedLeafLifecycle, isNativeAnimatedAvailable, isSymbioteNode, readPassthroughStyle, reduceProps, resolveHostNode, whenCommitted, } from '@symbiote-native/engine';
|
|
26
|
+
import { createElement, spread } from '../../renderer.js';
|
|
26
27
|
import { withStableKeys } from '../../utils/stable-keys.js';
|
|
27
28
|
// RN's prop carrying already-rasterized values that OVERRIDE the animated prop in the committed
|
|
28
29
|
// props, so the ShadowTree (hit-testing) stays current while the native driver animates.
|
|
@@ -31,6 +32,15 @@ const PASSTHROUGH_PROP = 'passthroughAnimatedPropExplicitValues';
|
|
|
31
32
|
// from). A precise generic cannot work: the bag handed to the base is assembled at RUNTIME from a
|
|
32
33
|
// key set that grows, so no static prop type describes it. The RETURN type stays precise, so a
|
|
33
34
|
// caller of Animated.View still gets a real prop type.
|
|
35
|
+
// `Base` accepts a TAG as well as a component, and the string branch is not symmetry — it is the
|
|
36
|
+
// only shape that works once a primitive becomes a public intrinsic. `<Base {...props} />` on a
|
|
37
|
+
// capitalized identifier compiles to `createComponent(Base, …)`, which is `untrack(() => Comp(props))`
|
|
38
|
+
// in solid-js, so a string base is a `TypeError: Comp is not a function` at first paint. There is
|
|
39
|
+
// nothing to widen INTO either: `createRenderer()` from solid-js/universal returns twelve names and
|
|
40
|
+
// `Dynamic` is not among them (solid-js/web's Dynamic is DOM-only), so the element has to be built
|
|
41
|
+
// through this renderer's own createElement + spread — the same two calls solid's own Dynamic makes
|
|
42
|
+
// on its string branch. `spread` handles `ref` and `children` itself (universal's spreadExpression
|
|
43
|
+
// skips both in its prop loop and drives them separately), which is why nothing is threaded by hand.
|
|
34
44
|
export function createAnimatedComponent(Base) {
|
|
35
45
|
return function AnimatedComponent(props) {
|
|
36
46
|
// The passthrough is CONSUMED (it only overrides the committed style below); `children` and
|
|
@@ -100,6 +110,18 @@ export function createAnimatedComponent(Base) {
|
|
|
100
110
|
return local.children;
|
|
101
111
|
},
|
|
102
112
|
});
|
|
113
|
+
// Narrowed HERE and not around the whole factory: `Base` is a parameter captured by this inner
|
|
114
|
+
// function, so a check outside it does not reach the JSX below.
|
|
115
|
+
if (typeof Base === 'string') {
|
|
116
|
+
const element = createElement(Base);
|
|
117
|
+
spread(element, childProps, false);
|
|
118
|
+
// createElement's return type is the renderer's node union, which includes the SURFACE — a
|
|
119
|
+
// root the renderer is handed, never something a tag produces. Narrowed rather than cast, and
|
|
120
|
+
// thrown rather than defaulted: returning null here would paint nothing and stay green.
|
|
121
|
+
if (!isSymbioteNode(element))
|
|
122
|
+
throw new Error(`createAnimatedComponent: <${Base}> did not build a host node`);
|
|
123
|
+
return element;
|
|
124
|
+
}
|
|
103
125
|
return <Base {...childProps}/>;
|
|
104
126
|
};
|
|
105
127
|
}
|
|
@@ -44,10 +44,6 @@ export declare const Animated: {
|
|
|
44
44
|
event: typeof event;
|
|
45
45
|
forkEvent: typeof forkEvent;
|
|
46
46
|
unforkEvent: typeof unforkEvent;
|
|
47
|
-
View: (props: import("./create-animated-component").IAnimatedComponentProps) => import("@symbiote-native/solid/jsx-runtime").JSX.Element;
|
|
48
|
-
Text: (props: import("./create-animated-component").IAnimatedComponentProps) => import("@symbiote-native/solid/jsx-runtime").JSX.Element;
|
|
49
|
-
Image: (props: import("./create-animated-component").IAnimatedComponentProps) => import("@symbiote-native/solid/jsx-runtime").JSX.Element;
|
|
50
|
-
ScrollView: IAnimatedComponent;
|
|
51
47
|
FlatList: IAnimatedComponent;
|
|
52
48
|
SectionList: IAnimatedComponent;
|
|
53
49
|
createAnimatedComponent: typeof createAnimatedComponent;
|
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
// The Animated namespace for @symbiote-native/solid.
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
1
|
+
// The Animated namespace for @symbiote-native/solid. The value graph, easing and imperative drivers
|
|
2
|
+
// come from @symbiote-native/engine (framework-agnostic), so both halves meet here in one object and
|
|
3
|
+
// `Animated.timing(new Animated.Value(0), …).start()` reads as it does in RN.
|
|
4
|
+
//
|
|
5
|
+
// THERE IS NO `Animated.View` / `Animated.Text` / `Animated.Image` / `Animated.ScrollView`, and
|
|
6
|
+
// nothing replaced any of them: `<view style={{ opacity: someAnimatedValue }}>` is the whole API
|
|
7
|
+
// for style, and `<scroll-view onScroll={Animated.event(…)}>` is the whole API for a native-driven
|
|
8
|
+
// scroll listener. The engine resolves an AnimatedNode written into any prop of any host node
|
|
9
|
+
// (`core/engine/src/animated/host-binding.ts`) — it publishes the current value, subscribes the
|
|
10
|
+
// leaf, writes each frame through its own targeted setNativeProps commit, and releases at the
|
|
11
|
+
// commit sweep; `setEventListener` calls `bindAnimatedEvent` on any `on*` prop for EVERY host node,
|
|
12
|
+
// not just a scroll one. Those four were aliases of the wrappers, and a wrapper is a tag now, which
|
|
13
|
+
// is not a value `<Animated.X>` can call.
|
|
14
|
+
//
|
|
15
|
+
// The two below REMAIN because they are tier 3: a render prop decides the list family's output
|
|
16
|
+
// shape in JS, so there is no tag for `<Animated.X>` to be an alias of.
|
|
7
17
|
//
|
|
8
18
|
// The NATIVE DRIVER is not this module's doing and must not be re-derived here. A
|
|
9
19
|
// useNativeDriver animation promotes the value graph itself (animations/base.ts ->
|
|
10
20
|
// value.__startNativeAnimation -> graph.__makeNative), and the props leaf follows automatically
|
|
11
21
|
// through graph.__addChild. This file only assembles the surface.
|
|
12
22
|
import { AnimatedValue, AnimatedValueXY, AnimatedColor, AnimatedMock, Easing, Platform, timing, spring, decay, parallel, sequence, stagger, loop, delay, add, subtract, multiply, divide, modulo, diffClamp, event, forkEvent, unforkEvent, } from '@symbiote-native/engine';
|
|
13
|
-
import { View } from '../../components/view.jsx';
|
|
14
|
-
import { Text } from '../../components/text.jsx';
|
|
15
|
-
import { Image } from '../../components/image.js';
|
|
16
|
-
import { ScrollView } from '../../components/scroll-view';
|
|
17
23
|
import { FlatList } from '../../components/flat-list/index.jsx';
|
|
18
24
|
import { SectionList } from '../../components/section-list/index.jsx';
|
|
19
25
|
import { createAnimatedComponent } from './create-animated-component.jsx';
|
|
@@ -21,11 +27,6 @@ export { createAnimatedComponent } from './create-animated-component.jsx';
|
|
|
21
27
|
// The pure graph leaves live in the engine (they extend AnimatedWithChildren, no framework);
|
|
22
28
|
// re-exported so this adapter's Animated surface matches React's.
|
|
23
29
|
export { AnimatedProps, AnimatedStyle, AnimatedTransform, } from '@symbiote-native/engine';
|
|
24
|
-
// View/Text/Image are pure host primitives with no cycle back to here, so wrap them eagerly.
|
|
25
|
-
const AnimatedView = createAnimatedComponent(View);
|
|
26
|
-
const AnimatedText = createAnimatedComponent(Text);
|
|
27
|
-
const AnimatedImage = createAnimatedComponent(Image);
|
|
28
|
-
let animatedScrollView;
|
|
29
30
|
let animatedFlatList;
|
|
30
31
|
let animatedSectionList;
|
|
31
32
|
// The live, JS-driven driver half. RN's AnimatedImplementation.
|
|
@@ -58,13 +59,6 @@ const liveDrivers = {
|
|
|
58
59
|
// spreads `...Animated` over the same component getters.
|
|
59
60
|
const drivers = Platform.isDisableAnimations ? AnimatedMock : liveDrivers;
|
|
60
61
|
export const Animated = {
|
|
61
|
-
View: AnimatedView,
|
|
62
|
-
Text: AnimatedText,
|
|
63
|
-
Image: AnimatedImage,
|
|
64
|
-
get ScrollView() {
|
|
65
|
-
animatedScrollView ??= createAnimatedComponent(ScrollView);
|
|
66
|
-
return animatedScrollView;
|
|
67
|
-
},
|
|
68
62
|
get FlatList() {
|
|
69
63
|
animatedFlatList ??= createAnimatedComponent(FlatList);
|
|
70
64
|
return animatedFlatList;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// RN's Image STATICS — `getSize`, `prefetch`, `queryCache`, `abortPrefetch`, `resolveAssetSource`.
|
|
2
|
+
//
|
|
3
|
+
// IN `modules/`, NOT `components/`. The primitive is the `<image>` tag and its fold runs in the
|
|
4
|
+
// engine (`behaviors/image.ts`); what survives under the name `Image` is an imperative API with no
|
|
5
|
+
// view, which is what this bucket is for. Sitting in `components/` was what made a statics object
|
|
6
|
+
// read as a component.
|
|
7
|
+
//
|
|
8
|
+
// A NAMESPACE OBJECT rather than five bare functions, deliberately: `Alert`, `Share`, `Linking`
|
|
9
|
+
// and `Vibration` all take that shape, and an app porting from RN writes `Image.getSize(...)`
|
|
10
|
+
// verbatim. Shared verbatim via `imageStatics`, the same source every other adapter attaches.
|
|
11
|
+
import { imageStatics } from '@symbiote-native/components';
|
|
12
|
+
export const Image = imageStatics;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@symbiote-native/components/register';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Side-effect ONLY. Exports nothing, and must never be re-exported from the barrel.
|
|
2
|
+
//
|
|
3
|
+
// The fourteen calls live once, in `@symbiote-native/components/register` — they were identical in
|
|
4
|
+
// all five adapters, and each copy carried a migration ledger justifying a call against a wrapper
|
|
5
|
+
// that no longer exists. What is per-adapter is only the SPELLING of the import below: every
|
|
6
|
+
// `*-tag.test.*` here reaches the registry through `import './register';`, and this adapter's own
|
|
7
|
+
// barrel guard pins that line.
|
|
8
|
+
//
|
|
9
|
+
// WHY A SIDE-EFFECT SUBPATH AND NOT A BARREL EXPORT. Metro turns on `inlineRequires` for PRODUCTION
|
|
10
|
+
// only: it moves a `require` down to the first place its binding is used as a VALUE, and
|
|
11
|
+
// `export { X } from './x'` compiles to a lazy getter. A registration reached that way never
|
|
12
|
+
// evaluates in a Release build — invisible to tsc, to vitest, and to grepping the bundle. A bare
|
|
13
|
+
// `import` placed NEXT TO a re-export of the same specifier does not help either: Babel merges the
|
|
14
|
+
// two into one dependency and the merged dependency stays lazy.
|
|
15
|
+
import '@symbiote-native/components/register';
|
package/build/renderer.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { SymbioteSurface, type ISymbioteNode } from '@symbiote-native/engine';
|
|
|
2
2
|
type IHostNode = ISymbioteNode | SymbioteSurface;
|
|
3
3
|
export declare function setActiveSurface(surface: SymbioteSurface | undefined): void;
|
|
4
4
|
export declare function replaceText(textNode: IHostNode, value: string): void;
|
|
5
|
+
export declare function setHostPressed(node: IHostNode, pressed: boolean): void;
|
|
5
6
|
export declare function removeNode(parent: IHostNode, node: IHostNode): void;
|
|
6
7
|
export declare const render: (code: () => IHostNode, node: IHostNode) => () => void, effect: <T>(fn: (prev?: T) => T, init?: T) => void, memo: <T>(fn: () => T, equal: boolean) => () => T, createComponent: <T>(Comp: (props: T) => IHostNode, props: T) => IHostNode, createElement: (tag: string) => IHostNode, createTextNode: (value: string) => IHostNode, insertNode: (parent: IHostNode, node: IHostNode, anchor?: IHostNode | undefined) => void, insert: <T>(parent: any, accessor: T | (() => T), marker?: any | null, initial?: any) => IHostNode, spread: <T>(node: any, accessor: (() => T) | T, skipChildren?: boolean) => void, setProp: <T>(node: IHostNode, name: string, value: T, prev?: T | undefined) => T, mergeProps: (...sources: unknown[]) => unknown, use: <A, T>(fn: (element: IHostNode, arg: A) => T, element: IHostNode, arg: A) => T;
|
|
7
8
|
export {};
|
package/build/renderer.js
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
// babel.transformSync over representative JSX (elements, dynamic text, <Show>, <For>, spread,
|
|
18
18
|
// ref) rather than read off the docs.
|
|
19
19
|
import { createRenderer } from 'solid-js/universal';
|
|
20
|
-
import { appendChild, createAnchor, createElement as createEngineElement, createRawText, dlog, insertBefore, removeChild as removeEngineChild, routeProp, setText as setEngineText, toPublicInstance, RAW_TEXT_COMPONENT, SymbioteSurface, } from '@symbiote-native/engine';
|
|
21
|
-
import { descriptorFor } from '@symbiote-native/components';
|
|
20
|
+
import { appendChild, createAnchor, createElement as createEngineElement, createRawText, dlog, insertBefore, removeChild as removeEngineChild, routeProp, setNodePressed, setProp as setEngineProp, setText as setEngineText, toPublicInstance, RAW_TEXT_COMPONENT, SymbioteSurface, } from '@symbiote-native/engine';
|
|
21
|
+
import { descriptorFor, TEXT_INPUT_MULTILINE_TAG, } from '@symbiote-native/components';
|
|
22
22
|
function isSurface(node) {
|
|
23
23
|
return node instanceof SymbioteSurface;
|
|
24
24
|
}
|
|
@@ -84,6 +84,23 @@ function asText(value) {
|
|
|
84
84
|
// has to DETACH its anchor host from the portal target on cleanup. Going through here rather than
|
|
85
85
|
// calling the engine's removeChild directly is what keeps the mutation paired with requestCommit(),
|
|
86
86
|
// and keeps the surface-vs-node branch in one place.
|
|
87
|
+
// The REFUSED path's half of `:active`, and the reason a refusal costs the component instance
|
|
88
|
+
// rather than the pressed styling. A `<Pressable>` the lowering left as a component still owns its
|
|
89
|
+
// own press machine, and one call here puts the node into its pressed state so `.btn:active`
|
|
90
|
+
// applies exactly as it would on a lowered tag.
|
|
91
|
+
//
|
|
92
|
+
// Exported paired with requestCommit() for the same reason removeNode below is: the press arrives
|
|
93
|
+
// from a NATIVE EVENT, outside any renderer mutation, so nothing else schedules a commit. React's
|
|
94
|
+
// twin (`setNodeHidden` from hideInstance) needs none because its reconciler is already mid-commit
|
|
95
|
+
// when it calls; Solid's is not. Costs nothing when no `:active` rule is registered — the engine
|
|
96
|
+
// hands back the same style object and `isAlreadyPublished` turns the re-push away without dirtying
|
|
97
|
+
// the node.
|
|
98
|
+
export function setHostPressed(node, pressed) {
|
|
99
|
+
if (isSurface(node))
|
|
100
|
+
return;
|
|
101
|
+
setNodePressed(node, pressed);
|
|
102
|
+
requestCommit();
|
|
103
|
+
}
|
|
87
104
|
export function removeNode(parent, node) {
|
|
88
105
|
if (isSurface(node))
|
|
89
106
|
return;
|
|
@@ -93,10 +110,89 @@ export function removeNode(parent, node) {
|
|
|
93
110
|
removeEngineChild(parent, node);
|
|
94
111
|
requestCommit();
|
|
95
112
|
}
|
|
113
|
+
const TEXT_FOLDS = new Map([
|
|
114
|
+
['ellipsizeMode', value => value ?? 'tail'],
|
|
115
|
+
['allowFontScaling', value => value !== false],
|
|
116
|
+
]);
|
|
117
|
+
function seedTextDefaults(node) {
|
|
118
|
+
for (const [key, fold] of TEXT_FOLDS)
|
|
119
|
+
setEngineProp(node, key, fold(undefined));
|
|
120
|
+
}
|
|
121
|
+
// Seeding at CREATE is not enough, and the gap is device-only. A framework that clears a prop it
|
|
122
|
+
// set earlier hands us an explicit `undefined` at PATCH time, and the default has to come BACK
|
|
123
|
+
// rather than stay cleared — RN treats a missing prop and an explicit undefined alike, and only a
|
|
124
|
+
// literal `false` opts out of allowFontScaling. Two Map lookups on text nodes only, and none at
|
|
125
|
+
// all on a View, so it stays off the hot path.
|
|
126
|
+
function foldTextValue(node, key, value) {
|
|
127
|
+
if (!node.isText)
|
|
128
|
+
return value;
|
|
129
|
+
const fold = TEXT_FOLDS.get(key);
|
|
130
|
+
return fold === undefined ? value : fold(value);
|
|
131
|
+
}
|
|
132
|
+
// The alias fold, at the RENDERER — the only place it can live now that an app writes the tag
|
|
133
|
+
// itself. A bare `<view id="x">` has no wrapper to inherit the fold from, and `id` is a key Fabric
|
|
134
|
+
// does not know, so it committed nothing while the component committed `nativeID`. Measured by
|
|
135
|
+
// mounting both forms and diffing committed key NAMES; totals were identical and said nothing.
|
|
136
|
+
//
|
|
137
|
+
// One string comparison rather than a Map lookup, because this sits on the per-prop write path —
|
|
138
|
+
// 32 001 prop writes on a benchmark create, where a Map.get is the kind of cost the engine spent
|
|
139
|
+
// this month removing. That is only safe while every primitive shares ONE alias pair, which is a
|
|
140
|
+
// property of the shared spec and not of this file, so `renderer-alias-fold.test.ts` re-derives
|
|
141
|
+
// both constants from `HOST_PRIMITIVES` and fails the moment a second pair appears.
|
|
142
|
+
const ALIAS_FROM = 'id';
|
|
143
|
+
const ALIAS_TO = 'nativeID';
|
|
144
|
+
// `multiline` selects between TWO Fabric views, so the TAG decides and no prop write moves a node
|
|
145
|
+
// between them. Two of the three paths that can build the node resolve it earlier — the wrapper
|
|
146
|
+
// CONSUMES the prop to pick its intrinsic, a lowering transform reads a literal at compile time —
|
|
147
|
+
// and an author writing the tag by hand has neither, which leaves two silent divergences.
|
|
148
|
+
//
|
|
149
|
+
// The shared behavior (`core/components/src/behaviors/text-input.ts`) already makes the PAYLOAD
|
|
150
|
+
// follow the tag. The complaint has to live here instead of there: `foldPayload` runs inside the
|
|
151
|
+
// commit, so a throw from it lands a tick later as an uncaught exception with no frame naming the
|
|
152
|
+
// call site — measured, a test awaiting the mount sees `nothing committed` rather than the error.
|
|
153
|
+
const MULTILINE_PROP = 'multiline';
|
|
154
|
+
function assertMultilineMatchesTag(node, value) {
|
|
155
|
+
if ((value === true) === (node.props[MULTILINE_PROP] === true))
|
|
156
|
+
return;
|
|
157
|
+
throw new Error(`multiline={${String(value)}} contradicts the tag: <text-input> and ` +
|
|
158
|
+
`<text-input-multiline> are different Fabric views and no prop write moves a node ` +
|
|
159
|
+
`between them. Pick the tag (a runtime choice needs a <Show> around both).`);
|
|
160
|
+
}
|
|
161
|
+
// RN gives `id` UNCONDITIONAL priority when both are set (View.js:77-79,
|
|
162
|
+
// `processedProps.nativeID = id`), and `foldHostBag` reproduces that by deleting the source key out
|
|
163
|
+
// of a whole bag. This renderer never sees a bag — it folds one key at a time — so precedence would
|
|
164
|
+
// otherwise come out as source order, and `<view id nativeID>` would keep the stale legacy value
|
|
165
|
+
// while `<view nativeID id>` would not. The wrapper hid that; a bare tag does not.
|
|
166
|
+
//
|
|
167
|
+
// So the node remembers that its nativeID came from an `id`, and a later raw `nativeID` write loses
|
|
168
|
+
// to it. Off the hot path in every ordinary case: nothing is touched unless the prop being written
|
|
169
|
+
// is one of these two names.
|
|
170
|
+
const aliasedNodes = new WeakSet();
|
|
171
|
+
function foldAliasKey(node, name, value) {
|
|
172
|
+
if (name === ALIAS_FROM) {
|
|
173
|
+
if (value === undefined)
|
|
174
|
+
aliasedNodes.delete(node);
|
|
175
|
+
else
|
|
176
|
+
aliasedNodes.add(node);
|
|
177
|
+
return ALIAS_TO;
|
|
178
|
+
}
|
|
179
|
+
return name;
|
|
180
|
+
}
|
|
96
181
|
const nodeOps = {
|
|
97
182
|
createElement(tag) {
|
|
98
183
|
const descriptor = descriptorFor(tag);
|
|
99
|
-
|
|
184
|
+
// The TAG goes over as well, not just the resolved Fabric name. The host-behavior registry is
|
|
185
|
+
// keyed by intrinsic tag while a node only ever carries the resolved view name — `symbiote-
|
|
186
|
+
// pressable` resolves to `RCTView` — so without this the lookup asks for `RCTView` and finds
|
|
187
|
+
// nothing, and the press machine silently never attaches. Registering under the Fabric name
|
|
188
|
+
// instead would be worse: every plain `View` would get a press machine.
|
|
189
|
+
const node = createEngineElement(descriptor.component, descriptor.isText, tag);
|
|
190
|
+
if (descriptor.isText)
|
|
191
|
+
seedTextDefaults(node);
|
|
192
|
+
// Only the multiline tag is seeded: writing `multiline: false` on the single-line one would add
|
|
193
|
+
// a key the wrapper's payload does not carry, i.e. a divergence in the other direction.
|
|
194
|
+
if (tag === TEXT_INPUT_MULTILINE_TAG)
|
|
195
|
+
setEngineProp(node, MULTILINE_PROP, true);
|
|
100
196
|
// Graft the imperative public-instance API (measure / setNativeProps / focus / …) onto the raw
|
|
101
197
|
// node so a `ref` to a host element exposes it exactly like React's getPublicInstance.
|
|
102
198
|
// toPublicInstance mutates in place and returns the SAME node identity, so the engine's commit
|
|
@@ -132,11 +228,15 @@ const nodeOps = {
|
|
|
132
228
|
setProperty(node, name, value) {
|
|
133
229
|
if (isSurface(node))
|
|
134
230
|
return;
|
|
231
|
+
if (name === MULTILINE_PROP)
|
|
232
|
+
assertMultilineMatchesTag(node, value);
|
|
233
|
+
if (name === ALIAS_TO && aliasedNodes.has(node))
|
|
234
|
+
return;
|
|
135
235
|
// routeProp makes the prop-vs-event decision from the node's ViewConfig (onPress on a View
|
|
136
236
|
// becomes a listener; onTintColor on a Switch stays a prop), and centralizes the class+style
|
|
137
237
|
// merge. Shared with React and Vue — never re-implement an `onX` check here
|
|
138
238
|
// (symbiote-engine-core §2).
|
|
139
|
-
routeProp(node, name, value);
|
|
239
|
+
routeProp(node, foldAliasKey(node, name, value), foldTextValue(node, name, value));
|
|
140
240
|
requestCommit();
|
|
141
241
|
},
|
|
142
242
|
insertNode(parent, node, anchor) {
|
|
@@ -168,10 +268,27 @@ const nodeOps = {
|
|
|
168
268
|
requestCommit();
|
|
169
269
|
},
|
|
170
270
|
removeNode,
|
|
271
|
+
// Reverse of `getFirstChild`'s `childHost` redirect: a child under a composed primitive's slot
|
|
272
|
+
// has `node.parent` pointing at the SLOT, but `cleanChildren`'s `isParent = getParentNode(el)
|
|
273
|
+
// === parent` compares against the OWNER — the same reference the JSX-level `insert()` call was
|
|
274
|
+
// given. Left un-redirected, that comparison is false for every child of a bare `<scroll-view>`
|
|
275
|
+
// (or any other slotted primitive) with a following sibling, so `isParent` never fires,
|
|
276
|
+
// `removeNode` is never called on a full array clear, and the old children are orphaned: still
|
|
277
|
+
// committed to Fabric, still retained, and re-diffed against on the next reconciliation —
|
|
278
|
+
// reproduced as unbounded RAM growth and an increasingly slow "Clear" on the benchmark screen.
|
|
279
|
+
// One level up only: `childHost` is always a DIRECT child the owner built (see `buildStructure`),
|
|
280
|
+
// never a deeper descendant.
|
|
171
281
|
getParentNode(node) {
|
|
172
282
|
if (isSurface(node))
|
|
173
283
|
return undefined;
|
|
174
|
-
|
|
284
|
+
const parent = node.parent ?? activeSurface;
|
|
285
|
+
if (parent === undefined || isSurface(parent))
|
|
286
|
+
return parent;
|
|
287
|
+
const grandparent = parent.parent;
|
|
288
|
+
if (grandparent !== undefined && grandparent.childHost === parent) {
|
|
289
|
+
return grandparent;
|
|
290
|
+
}
|
|
291
|
+
return parent;
|
|
175
292
|
},
|
|
176
293
|
// Anchors are NOT filtered out of this or getNextSibling, deliberately. solid-js/universal keeps
|
|
177
294
|
// its own record of which nodes it put where and re-derives positions through these two lookups
|
|
@@ -179,8 +296,18 @@ const nodeOps = {
|
|
|
179
296
|
// getFirstChild(parent) to replace text in place). Hiding a node the runtime itself inserted
|
|
180
297
|
// desyncs that record from the real tree. Anchors are invisible to FABRIC — the commit walk skips
|
|
181
298
|
// them — not to tree traversal.
|
|
299
|
+
//
|
|
300
|
+
// `childHost` redirected, same as the engine's own `appendChild`/`insertBefore`/`removeChild`
|
|
301
|
+
// (`hostFor`, core/engine/src/node.ts): a composed primitive's real children live on the slot it
|
|
302
|
+
// built, not on the owner it was asked to insert into, and `insert()`'s reconciliation reads this
|
|
303
|
+
// to know what is ALREADY there before deciding what to insert/move/remove. Reading the owner's
|
|
304
|
+
// own (single-child) array here would have every dynamic child on a bare `<scroll-view>` diffed
|
|
305
|
+
// against the wrong node — invisible on VirtualizedList, which never calls `insert()` on the
|
|
306
|
+
// owner directly, and wrong for any app writing `<scroll-view>{dynamicChildren}</scroll-view>`.
|
|
182
307
|
getFirstChild(node) {
|
|
183
|
-
|
|
308
|
+
if (isSurface(node))
|
|
309
|
+
return node.children[0];
|
|
310
|
+
return (node.childHost ?? node).children[0];
|
|
184
311
|
},
|
|
185
312
|
getNextSibling(node) {
|
|
186
313
|
if (isSurface(node))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function withStableKeys(props: () =>
|
|
1
|
+
export declare function withStableKeys<TProps extends object>(props: () => TProps): () => Record<string, unknown>;
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
// the actual diffing. Never hand-roll that diff instead.
|
|
13
13
|
//
|
|
14
14
|
// Lives here rather than beside either caller because BOTH reach for it: descriptorToSolid wraps
|
|
15
|
-
// a render fn's Descriptor props, and
|
|
16
|
-
//
|
|
17
|
-
//
|
|
15
|
+
// a render fn's Descriptor props, and a component that spreads a folded bag onto a bare `<view>`
|
|
16
|
+
// (Pressable, KeyboardAvoidingView) wraps its own — the same function, the same two-branch key
|
|
17
|
+
// set. This is the one capability a bare tag does NOT inherit from the wrappers that used to own
|
|
18
|
+
// it, so any Solid component folding props through a whole-object transform belongs on it too.
|
|
18
19
|
export function withStableKeys(props) {
|
|
19
20
|
const seen = new Set();
|
|
20
21
|
return () => {
|
|
@@ -22,9 +23,9 @@ export function withStableKeys(props) {
|
|
|
22
23
|
const widened = {};
|
|
23
24
|
for (const key of seen)
|
|
24
25
|
widened[key] = undefined;
|
|
25
|
-
for (const key of Object.
|
|
26
|
+
for (const [key, value] of Object.entries(next)) {
|
|
26
27
|
seen.add(key);
|
|
27
|
-
widened[key] =
|
|
28
|
+
widened[key] = value;
|
|
28
29
|
}
|
|
29
30
|
return widened;
|
|
30
31
|
};
|
package/metro-css-parser.cjs
CHANGED
|
@@ -5,4 +5,5 @@
|
|
|
5
5
|
// .cjs, not .js: this package is "type": "module", but Metro's babelTransformerPath loading needs
|
|
6
6
|
// a require()-able file. createCssMetroTransformer() is a factory — Metro needs the actual
|
|
7
7
|
// {transform, getCacheKey} object it returns, not the css-parser package barrel.
|
|
8
|
-
module.exports =
|
|
8
|
+
module.exports =
|
|
9
|
+
require('@symbiote-native/css-parser').createCssMetroTransformer();
|
package/package.json
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/solid",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "SymbioteNative's Solid adapter — a solid-js/universal createRenderer driving real native iOS/Android views through the same engine as every other adapter.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react-native",
|
|
7
|
+
"symbiote-native",
|
|
8
|
+
"solid",
|
|
9
|
+
"solid-js",
|
|
10
|
+
"fabric",
|
|
11
|
+
"cross-platform",
|
|
12
|
+
"ios",
|
|
13
|
+
"android"
|
|
14
|
+
],
|
|
5
15
|
"license": "MIT",
|
|
6
16
|
"repository": {
|
|
7
17
|
"type": "git",
|
|
@@ -52,18 +62,19 @@
|
|
|
52
62
|
"dependencies": {
|
|
53
63
|
"babel-preset-solid": "^1.9.12",
|
|
54
64
|
"typescript": "~6.0.0",
|
|
55
|
-
"@symbiote-native/components": "0.
|
|
56
|
-
"@symbiote-native/css-parser": "0.
|
|
65
|
+
"@symbiote-native/components": "2.0.0",
|
|
66
|
+
"@symbiote-native/css-parser": "0.5.0"
|
|
57
67
|
},
|
|
58
68
|
"peerDependencies": {
|
|
59
|
-
"@symbiote-native/engine": ">=0.1.7",
|
|
60
69
|
"solid-js": ">=1.9.0",
|
|
61
|
-
"react-native": ">=0.86"
|
|
70
|
+
"react-native": ">=0.86",
|
|
71
|
+
"@symbiote-native/engine": "^0.5.0"
|
|
62
72
|
},
|
|
63
73
|
"devDependencies": {
|
|
74
|
+
"@babel/core": "^7.25.2",
|
|
64
75
|
"solid-js": "^1.9.14",
|
|
65
|
-
"@symbiote-native/engine": "0.
|
|
66
|
-
"@symbiote-native/test-utils": "0.
|
|
76
|
+
"@symbiote-native/engine": "0.5.0",
|
|
77
|
+
"@symbiote-native/test-utils": "0.3.0"
|
|
67
78
|
},
|
|
68
79
|
"scripts": {
|
|
69
80
|
"typecheck": "tsc --build",
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
// ActivityIndicator on Android: AndroidProgressBar needs `styleAttr` (it drives its setStyle();
|
|
2
|
-
// without it the view throws "setStyle() not called") plus `indeterminate: true`, and its default
|
|
3
|
-
// color is the theme (null), which the render fn turns into an OMITTED color prop — a literal null
|
|
4
|
-
// would be rejected by Fabric's color parser. Same facts the other adapters' Android bindings
|
|
5
|
-
// encode. Metro picks this on an Android host; no Platform.OS read.
|
|
6
|
-
import { createActivityIndicator } from './shared.js';
|
|
7
|
-
export const ActivityIndicator = createActivityIndicator({
|
|
8
|
-
// RN: `color = Platform.OS === 'ios' ? GRAY : null`; Android lets the theme color it.
|
|
9
|
-
defaultColor: null,
|
|
10
|
-
nativeExtras: { styleAttr: 'Normal', indeterminate: true },
|
|
11
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './index.ios';
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// ActivityIndicator on iOS: RCTActivityIndicatorView takes the size enum plus a GRAY default color
|
|
2
|
-
// and no extra native props — the same facts adapters/react's, adapters/vue's and adapters/svelte's
|
|
3
|
-
// iOS bindings encode. Metro selects this file on an iOS host, no Platform.OS read.
|
|
4
|
-
import { createActivityIndicator } from './shared.js';
|
|
5
|
-
// RN's iOS default spinner color (Libraries/.../ActivityIndicator.js GRAY).
|
|
6
|
-
const IOS_DEFAULT_COLOR = '#999999';
|
|
7
|
-
export const ActivityIndicator = createActivityIndicator({
|
|
8
|
-
defaultColor: IOS_DEFAULT_COLOR,
|
|
9
|
-
nativeExtras: {},
|
|
10
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { JSX } from '../../jsx-runtime';
|
|
2
|
-
import { type IActivityIndicatorPlatform, type IActivityIndicatorProps as IActivityIndicatorBaseProps } from '@symbiote-native/components';
|
|
3
|
-
import type { IClassNameValue } from '@symbiote-native/engine';
|
|
4
|
-
export type { IActivityIndicatorPlatform, IActivityIndicatorSize, } from '@symbiote-native/components';
|
|
5
|
-
export type IActivityIndicatorProps = IActivityIndicatorBaseProps & {
|
|
6
|
-
class?: IClassNameValue;
|
|
7
|
-
};
|
|
8
|
-
export declare function createActivityIndicator(platform: IActivityIndicatorPlatform): (props: IActivityIndicatorProps) => JSX.Element;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
// ActivityIndicator, the Solid lifecycle half. The render (the 'small'/'large' -> native size enum
|
|
2
|
-
// translation, the fixed size boxes, the centering wrapper, the color omission) lives in
|
|
3
|
-
// @symbiote-native/components/view and is shared verbatim with React, Vue and Svelte. There is no
|
|
4
|
-
// state machine: the spinner animates natively, so Solid supplies only prop resolution and the
|
|
5
|
-
// descriptor bridge.
|
|
6
|
-
//
|
|
7
|
-
// NOTHING here destructures `props`. Solid props are getters and a component body runs ONCE;
|
|
8
|
-
// destructuring reads them at setup and freezes the component at its mount-time values. Every read
|
|
9
|
-
// below happens inside the descriptor accessor, which descriptorToSolid re-runs as a render effect
|
|
10
|
-
// on the SAME host nodes.
|
|
11
|
-
//
|
|
12
|
-
// The per-platform bits (iOS's GRAY default and no extras; Android's theme/null default plus
|
|
13
|
-
// styleAttr + indeterminate) arrive via `platform` from index.ios.ts / index.android.ts.
|
|
14
|
-
import { renderActivityIndicator, resolveAccessibilityProps, } from '@symbiote-native/components';
|
|
15
|
-
import { descriptorToSolid } from '../../descriptor-to-solid.js';
|
|
16
|
-
// Read by the component itself; everything else (testID, nativeID, the accessibility surface,
|
|
17
|
-
// onLayout, class) forwards onto the centering wrapper View, which is where RN spreads `...props`.
|
|
18
|
-
const HANDLED_PROPS = [
|
|
19
|
-
'animating',
|
|
20
|
-
'color',
|
|
21
|
-
'hidesWhenStopped',
|
|
22
|
-
'size',
|
|
23
|
-
'style',
|
|
24
|
-
];
|
|
25
|
-
// The wrapper is a raw symbiote-view emitted by the render fn, not the View component, so it never
|
|
26
|
-
// runs resolveAccessibilityProps itself — the fold happens here, exactly like React's hook does.
|
|
27
|
-
// The two branches of that fold emit DIFFERENT key sets; descriptorToSolid runs the resulting bag
|
|
28
|
-
// through withStableKeys, so a vanished key still reaches routeProp as a delete
|
|
29
|
-
// (.claude/rules/solid-descriptor-bridge.md §1).
|
|
30
|
-
function forwardProps(props) {
|
|
31
|
-
const forwarded = {
|
|
32
|
-
...resolveAccessibilityProps(props),
|
|
33
|
-
};
|
|
34
|
-
for (const key of HANDLED_PROPS)
|
|
35
|
-
delete forwarded[key];
|
|
36
|
-
return forwarded;
|
|
37
|
-
}
|
|
38
|
-
export function createActivityIndicator(platform) {
|
|
39
|
-
return function ActivityIndicator(props) {
|
|
40
|
-
// `?? 'small'` / `?? true` rather than a `!== false` coercion: props are typed here, so this is
|
|
41
|
-
// the exact semantics of React's destructuring defaults (only `undefined` falls back).
|
|
42
|
-
return descriptorToSolid(() => renderActivityIndicator({
|
|
43
|
-
animating: props.animating ?? true,
|
|
44
|
-
hidesWhenStopped: props.hidesWhenStopped ?? true,
|
|
45
|
-
size: props.size ?? 'small',
|
|
46
|
-
color: props.color,
|
|
47
|
-
style: props.style,
|
|
48
|
-
passthrough: forwardProps(props),
|
|
49
|
-
}, platform));
|
|
50
|
-
};
|
|
51
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { JSX } from '../jsx-runtime';
|
|
2
|
-
import { type IButtonProps as IButtonBaseProps } from '@symbiote-native/components';
|
|
3
|
-
import type { IClassNameValue } from '@symbiote-native/engine';
|
|
4
|
-
export type IButtonProps = IButtonBaseProps & {
|
|
5
|
-
class?: IClassNameValue;
|
|
6
|
-
};
|
|
7
|
-
export declare function Button(props: IButtonProps): JSX.Element;
|