@symbiote-native/svelte 0.3.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 +8 -10
- package/build/components/{activity-indicator/activity-indicator-props.d.ts → activity-indicator-props.d.ts} +1 -1
- package/build/components/flat-list/index.svelte +4 -4
- package/build/components/{image-background/image-background-props.d.ts → image-background-props.d.ts} +1 -1
- package/build/components/index.d.ts +6 -24
- package/build/components/index.js +0 -18
- package/build/components/keyboard-avoiding-view/index.svelte +6 -6
- package/build/components/modal/index.svelte +7 -7
- package/build/components/pressable/pressable-props.d.ts +1 -0
- package/build/components/refresh-control-props.d.ts +1 -0
- package/build/components/safe-area-view-props.d.ts +1 -0
- package/build/components/text-props.d.ts +1 -0
- package/build/components/virtualized-list/index.svelte +71 -250
- package/build/dom-shim/canonical-prop-names.d.ts +2 -0
- package/build/dom-shim/canonical-prop-names.js +320 -0
- package/build/dom-shim/document.js +1 -1
- package/build/dom-shim/element.d.ts +17 -5
- package/build/dom-shim/element.js +258 -40
- package/build/dom-shim/fold-host-bag.d.ts +1 -0
- package/build/dom-shim/fold-host-bag.js +7 -0
- package/build/dom-shim/patch-globals.js +35 -7
- package/build/dom-shim/shim-node.js +11 -0
- package/build/dom-shim/style-cache.d.ts +1 -0
- package/build/dom-shim/style-cache.js +27 -0
- package/build/dom-shim/text.js +2 -2
- package/build/host-instance.d.ts +2 -3
- package/build/host-instance.js +9 -4
- package/build/index.d.ts +8 -4
- package/build/index.js +21 -5
- package/build/intrinsic-elements.d.ts +63 -0
- package/build/modules/animated/index.d.ts +7 -27
- package/build/modules/animated/index.js +24 -34
- package/build/modules/image/index.d.ts +3 -0
- package/build/modules/image/index.js +15 -0
- package/build/preprocessor/scoped-styles.js +1 -1
- package/build/register.d.ts +1 -0
- package/build/register.js +15 -0
- package/build/root-element.js +1 -1
- package/metro-css-parser.cjs +2 -1
- package/metro-svelte-transformer.cjs +30 -12
- package/package.json +19 -9
- package/build/components/RefreshControl.svelte +0 -40
- package/build/components/RefreshControl.svelte.d.ts +0 -5
- package/build/components/SafeAreaView.svelte +0 -34
- package/build/components/SafeAreaView.svelte.d.ts +0 -5
- package/build/components/Text.svelte +0 -34
- package/build/components/Text.svelte.d.ts +0 -5
- package/build/components/View.svelte +0 -43
- package/build/components/View.svelte.d.ts +0 -5
- package/build/components/activity-indicator/activity-indicator-platform.android.d.ts +0 -3
- package/build/components/activity-indicator/activity-indicator-platform.android.js +0 -5
- package/build/components/activity-indicator/activity-indicator-platform.d.ts +0 -1
- package/build/components/activity-indicator/activity-indicator-platform.ios.d.ts +0 -3
- package/build/components/activity-indicator/activity-indicator-platform.ios.js +0 -6
- package/build/components/activity-indicator/activity-indicator-platform.js +0 -5
- package/build/components/activity-indicator/index.svelte +0 -63
- package/build/components/activity-indicator/index.svelte.d.ts +0 -5
- package/build/components/button.svelte +0 -76
- package/build/components/button.svelte.d.ts +0 -5
- package/build/components/image/image-logic.d.ts +0 -2
- package/build/components/image/image-logic.js +0 -135
- package/build/components/image/index.d.ts +0 -3
- package/build/components/image/index.js +0 -10
- package/build/components/image/index.svelte +0 -66
- package/build/components/image/index.svelte.d.ts +0 -5
- package/build/components/image-background/index.svelte +0 -87
- package/build/components/image-background/index.svelte.d.ts +0 -5
- package/build/components/input-accessory-view/index.svelte +0 -51
- package/build/components/input-accessory-view/index.svelte.d.ts +0 -5
- package/build/components/pressable/index.svelte +0 -167
- package/build/components/pressable/index.svelte.d.ts +0 -5
- package/build/components/scroll-view/index.svelte +0 -331
- package/build/components/scroll-view/index.svelte.d.ts +0 -18
- package/build/components/scroll-view/scroll-view-platform-types.d.ts +0 -3
- package/build/components/scroll-view/scroll-view-platform.android.d.ts +0 -3
- package/build/components/scroll-view/scroll-view-platform.android.js +0 -3
- package/build/components/scroll-view/scroll-view-platform.d.ts +0 -1
- package/build/components/scroll-view/scroll-view-platform.ios.d.ts +0 -3
- package/build/components/scroll-view/scroll-view-platform.ios.js +0 -3
- package/build/components/scroll-view/scroll-view-platform.js +0 -4
- package/build/components/scroll-view/scroll-view-sticky-context.d.ts +0 -7
- package/build/components/scroll-view/scroll-view-sticky-context.js +0 -1
- package/build/components/scroll-view/sticky-header-props.d.ts +0 -10
- package/build/components/scroll-view/sticky-header-props.js +0 -1
- package/build/components/scroll-view/sticky-header.svelte +0 -287
- package/build/components/scroll-view/sticky-header.svelte.d.ts +0 -5
- package/build/components/switch/index.svelte +0 -134
- package/build/components/switch/index.svelte.d.ts +0 -5
- package/build/components/text-input/index.svelte +0 -316
- package/build/components/text-input/index.svelte.d.ts +0 -12
- package/build/components/touchable-highlight/index.svelte +0 -138
- package/build/components/touchable-highlight/index.svelte.d.ts +0 -5
- package/build/components/touchable-native-feedback/index.d.ts +0 -9
- package/build/components/touchable-native-feedback/index.js +0 -14
- package/build/components/touchable-native-feedback/touchable-native-feedback.svelte +0 -49
- package/build/components/touchable-native-feedback/touchable-native-feedback.svelte.d.ts +0 -5
- package/build/components/touchable-opacity/index.svelte +0 -180
- package/build/components/touchable-opacity/index.svelte.d.ts +0 -5
- package/build/components/touchable-without-feedback/index.svelte +0 -74
- package/build/components/touchable-without-feedback/index.svelte.d.ts +0 -5
- package/build/modules/animated/animated-component-props.d.ts +0 -7
- package/build/modules/animated/animated-component-props.js +0 -1
- package/build/modules/animated/create-animated-component.d.ts +0 -5
- package/build/modules/animated/create-animated-component.js +0 -131
- /package/build/components/{activity-indicator/activity-indicator-props.js → activity-indicator-props.js} +0 -0
- /package/build/components/{image-background/image-background-props.js → image-background-props.js} +0 -0
- /package/build/{components/scroll-view/scroll-view-platform-types.js → intrinsic-elements.js} +0 -0
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
// TouchableOpacity: built on Pressable, like the rest of the family. Ported against RN's own
|
|
3
|
-
// source (.vendors/react-native/.../Components/Touchable/TouchableOpacity.js) after the
|
|
4
|
-
// 2026-08-19 audit found ten divergences shared by every adapter; Solid migrated first, then
|
|
5
|
-
// React, Vue and Angular, and this is Svelte.
|
|
6
|
-
//
|
|
7
|
-
// Shared (framework-agnostic) half: the press-scheduling machine and the resting-opacity math
|
|
8
|
-
// (@symbiote-native/components). Svelte owns only the lifecycle — runes, the real timers, and
|
|
9
|
-
// the Animated wiring.
|
|
10
|
-
//
|
|
11
|
-
// The interim `tweenOpacity` stand-in this file used to carry is GONE. Its header claimed no
|
|
12
|
-
// Animated binding existed for this adapter; that stopped being true when
|
|
13
|
-
// modules/animated landed, and a setTimeout tween can never be native-driven — which is
|
|
14
|
-
// exactly what RN asks for here (useNativeDriver: true, TouchableOpacity.js:242).
|
|
15
|
-
import type { ITouchableOpacityProps } from './touchable-opacity-props';
|
|
16
|
-
import View from '../View.svelte';
|
|
17
|
-
import { createAnimatedComponent } from '../../modules/animated/create-animated-component';
|
|
18
|
-
|
|
19
|
-
export type { ITouchableOpacityProps };
|
|
20
|
-
|
|
21
|
-
// Wrapped here, not imported from modules/animated: that barrel pulls in six `.svelte`
|
|
22
|
-
// components (View/Text/Image/ScrollView/FlatList/SectionList), and this package's vitest has
|
|
23
|
-
// no `.svelte` loader — a smoke test would have to pre-compile the whole tree to reach one
|
|
24
|
-
// Animated.View. Same reasoning, different cause, as sticky-header.svelte's own local wrap.
|
|
25
|
-
// Module scope, so every TouchableOpacity instance shares one component identity.
|
|
26
|
-
const AnimatedView = createAnimatedComponent(View);
|
|
27
|
-
</script>
|
|
28
|
-
|
|
29
|
-
<script lang="ts">
|
|
30
|
-
import {
|
|
31
|
-
createTouchableFeedbackHandlers,
|
|
32
|
-
createTouchableFeedbackRuntime,
|
|
33
|
-
DEFAULT_ACTIVE_OPACITY,
|
|
34
|
-
OPACITY_ACTIVE_GRANT_DURATION_MS,
|
|
35
|
-
OPACITY_INACTIVE_DURATION_MS,
|
|
36
|
-
TOUCHABLE_MIN_PRESS_DURATION_MS,
|
|
37
|
-
restingOpacityFromStyle,
|
|
38
|
-
} from '@symbiote-native/components';
|
|
39
|
-
import {
|
|
40
|
-
AnimatedMock,
|
|
41
|
-
AnimatedValue,
|
|
42
|
-
Easing,
|
|
43
|
-
Platform,
|
|
44
|
-
dlog,
|
|
45
|
-
timing,
|
|
46
|
-
type ISymbioteEvent,
|
|
47
|
-
} from '@symbiote-native/engine';
|
|
48
|
-
import Pressable from '../pressable/index.svelte';
|
|
49
|
-
|
|
50
|
-
// modules/animated's barrel swaps the WHOLE driver namespace for the mock when the host
|
|
51
|
-
// reports reduced motion; reaching it here would close the import the module block above
|
|
52
|
-
// avoids, so the one driver this component uses is swapped locally on the same flag.
|
|
53
|
-
const startTiming = Platform.isDisableAnimations
|
|
54
|
-
? AnimatedMock.timing
|
|
55
|
-
: timing;
|
|
56
|
-
|
|
57
|
-
function scheduleTimeout(callback: () => void, ms: number): () => void {
|
|
58
|
-
const id = setTimeout(callback, ms);
|
|
59
|
-
return () => clearTimeout(id);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
let {
|
|
63
|
-
activeOpacity = DEFAULT_ACTIVE_OPACITY,
|
|
64
|
-
style,
|
|
65
|
-
class: className,
|
|
66
|
-
children: content,
|
|
67
|
-
onPressIn,
|
|
68
|
-
onPressOut,
|
|
69
|
-
delayPressIn = 0,
|
|
70
|
-
delayPressOut = 0,
|
|
71
|
-
// RN's Touchables override Pressability's own 130ms floor with 0 (TouchableOpacity.js:195);
|
|
72
|
-
// what holds the active visual is the fade's duration, not a press-duration floor.
|
|
73
|
-
minPressDuration = TOUCHABLE_MIN_PRESS_DURATION_MS,
|
|
74
|
-
...rest
|
|
75
|
-
}: ITouchableOpacityProps = $props();
|
|
76
|
-
|
|
77
|
-
// RN's _getChildStyleOpacityWithDefault: the fade settles at the opacity the CALLER's style
|
|
78
|
-
// asks for, not at a hard 1.
|
|
79
|
-
const restingOpacity = $derived(restingOpacityFromStyle(style));
|
|
80
|
-
|
|
81
|
-
// One Animated.Value per mount, held by IDENTITY in a plain `const` — never `$state`, which
|
|
82
|
-
// would deep-proxy an engine object whose graph bookkeeping is keyed on the raw instance
|
|
83
|
-
// (same concern as Pressable's `$state.raw` hostShim).
|
|
84
|
-
// svelte-ignore state_referenced_locally -- the SEED is a one-shot read of the initial style;
|
|
85
|
-
// later changes are re-settled by the update effect below, not by re-seeding.
|
|
86
|
-
const opacity = new AnimatedValue(restingOpacity);
|
|
87
|
-
|
|
88
|
-
// Setup-scope only, mutated by the machine — same as Pressable's own runtime, never `$state`.
|
|
89
|
-
const runtime = createTouchableFeedbackRuntime();
|
|
90
|
-
|
|
91
|
-
function setOpacityTo(toValue: number, duration: number): void {
|
|
92
|
-
dlog(`TouchableOpacity opacity -> ${toValue} over ${duration}ms`);
|
|
93
|
-
// useNativeDriver: true is RN's own (TouchableOpacity.js:242). opacity is natively drivable,
|
|
94
|
-
// so the fade survives a busy JS thread — the whole point of press feedback.
|
|
95
|
-
startTiming(opacity, {
|
|
96
|
-
toValue,
|
|
97
|
-
duration,
|
|
98
|
-
easing: Easing.inOut(Easing.quad),
|
|
99
|
-
useNativeDriver: true,
|
|
100
|
-
}).start();
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Rebuilt whenever the timing config changes (mirrors Vue's per-render rebuild); the runtime
|
|
104
|
-
// persists across rebuilds so an in-flight delayPressIn timer / activation clock survives.
|
|
105
|
-
const handlers = $derived(
|
|
106
|
-
createTouchableFeedbackHandlers(
|
|
107
|
-
{
|
|
108
|
-
delayPressIn,
|
|
109
|
-
delayPressOut,
|
|
110
|
-
minPressDuration,
|
|
111
|
-
schedule: scheduleTimeout,
|
|
112
|
-
now: Date.now,
|
|
113
|
-
},
|
|
114
|
-
runtime,
|
|
115
|
-
{
|
|
116
|
-
activate(event: ISymbioteEvent): void {
|
|
117
|
-
// 0, not 150 (TouchableOpacity.js:215-220): the duration is chosen by where the
|
|
118
|
-
// press-in came from, and Pressability re-dispatches the GRANT event as the delay
|
|
119
|
-
// signal when delayPressIn is 0 — so an ordinary tap darkens instantly in RN. The 150ms
|
|
120
|
-
// branch is a re-activation (finger returning inside after leaving the bounds), which
|
|
121
|
-
// our engine never emits — it sends pressIn from one place, on topTouchStart.
|
|
122
|
-
setOpacityTo(activeOpacity, OPACITY_ACTIVE_GRANT_DURATION_MS);
|
|
123
|
-
onPressIn?.(event);
|
|
124
|
-
},
|
|
125
|
-
deactivate(event: ISymbioteEvent): void {
|
|
126
|
-
setOpacityTo(restingOpacity, OPACITY_INACTIVE_DURATION_MS);
|
|
127
|
-
onPressOut?.(event);
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
),
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
// Two SEPARATE deriveds, not one object: each memoizes by value, so an unrelated prop change
|
|
134
|
-
// cannot re-settle the opacity — the Svelte form of Vue's deliberate two-getter watch source.
|
|
135
|
-
const disabledInput = $derived(rest.disabled);
|
|
136
|
-
|
|
137
|
-
// RN's componentDidUpdate: a changed `disabled` or a changed style opacity re-settles the view,
|
|
138
|
-
// so a Touchable disabled mid-press does not stay stuck at its active opacity. The first run is
|
|
139
|
-
// skipped — RN does this on UPDATE only, and firing at mount would animate over the value the
|
|
140
|
-
// Animated.Value was just seeded with.
|
|
141
|
-
let settled: { disabled: unknown; resting: number } | undefined;
|
|
142
|
-
$effect(() => {
|
|
143
|
-
const current = { disabled: disabledInput, resting: restingOpacity };
|
|
144
|
-
const previous = settled;
|
|
145
|
-
settled = current;
|
|
146
|
-
if (previous === undefined) return;
|
|
147
|
-
if (
|
|
148
|
-
previous.disabled === current.disabled &&
|
|
149
|
-
previous.resting === current.resting
|
|
150
|
-
) {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
setOpacityTo(current.resting, OPACITY_INACTIVE_DURATION_MS);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// RN's componentWillUnmount: stop the animation and drop the value back, so a teardown
|
|
157
|
-
// mid-fade leaves no driver running against a node that is gone.
|
|
158
|
-
$effect(() => {
|
|
159
|
-
return () => {
|
|
160
|
-
opacity.resetAnimation();
|
|
161
|
-
};
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// Depends on `style` alone. `opacity` is a stable graph node, so a press changes what the node
|
|
165
|
-
// HOLDS, never this array — the per-frame path is setValue -> AnimatedProps.update ->
|
|
166
|
-
// setNativeProps, which never re-renders this component.
|
|
167
|
-
const feedbackStyle = $derived([style, { opacity }]);
|
|
168
|
-
</script>
|
|
169
|
-
|
|
170
|
-
<Pressable
|
|
171
|
-
{...rest}
|
|
172
|
-
onPressIn={handlers.handlePressIn}
|
|
173
|
-
onPressOut={handlers.handlePressOut}
|
|
174
|
-
>
|
|
175
|
-
{#snippet children()}
|
|
176
|
-
<AnimatedView style={feedbackStyle} class={className}>
|
|
177
|
-
{@render content?.()}
|
|
178
|
-
</AnimatedView>
|
|
179
|
-
{/snippet}
|
|
180
|
-
</Pressable>
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
// TouchableWithoutFeedback: built on Pressable, no visual feedback of its own. Ported against
|
|
3
|
-
// RN's own source (.vendors/react-native/.../Components/Touchable/TouchableWithoutFeedback.js)
|
|
4
|
-
// after the 2026-08-19 audit.
|
|
5
|
-
//
|
|
6
|
-
// RN builds a FULL Pressability config here — delayPressIn / delayPressOut /
|
|
7
|
-
// minPressDuration: 0 — so "without feedback" means no VISUAL, not no TIMING. The previous port
|
|
8
|
-
// spread the delay props straight into Pressable, which both ignored them (Pressable owns no
|
|
9
|
-
// press-delay scheduling) and forwarded them to the host as unknown Fabric props. The same
|
|
10
|
-
// shared machine TouchableOpacity runs now runs here with the visual half left empty.
|
|
11
|
-
import type { ITouchableWithoutFeedbackProps } from './touchable-without-feedback-props';
|
|
12
|
-
|
|
13
|
-
export type { ITouchableWithoutFeedbackProps };
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<script lang="ts">
|
|
17
|
-
import {
|
|
18
|
-
createTouchableFeedbackHandlers,
|
|
19
|
-
createTouchableFeedbackRuntime,
|
|
20
|
-
TOUCHABLE_MIN_PRESS_DURATION_MS,
|
|
21
|
-
} from '@symbiote-native/components';
|
|
22
|
-
import type { ISymbioteEvent } from '@symbiote-native/engine';
|
|
23
|
-
import Pressable from '../pressable/index.svelte';
|
|
24
|
-
|
|
25
|
-
function scheduleTimeout(callback: () => void, ms: number): () => void {
|
|
26
|
-
const id = setTimeout(callback, ms);
|
|
27
|
-
return () => clearTimeout(id);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
let {
|
|
31
|
-
children: content,
|
|
32
|
-
onPressIn,
|
|
33
|
-
onPressOut,
|
|
34
|
-
delayPressIn = 0,
|
|
35
|
-
delayPressOut = 0,
|
|
36
|
-
// RN's Touchables override Pressability's own 130ms floor with 0.
|
|
37
|
-
minPressDuration = TOUCHABLE_MIN_PRESS_DURATION_MS,
|
|
38
|
-
...rest
|
|
39
|
-
}: ITouchableWithoutFeedbackProps = $props();
|
|
40
|
-
|
|
41
|
-
// Setup-scope only, mutated by the machine — never `$state`.
|
|
42
|
-
const runtime = createTouchableFeedbackRuntime();
|
|
43
|
-
|
|
44
|
-
const handlers = $derived(
|
|
45
|
-
createTouchableFeedbackHandlers(
|
|
46
|
-
{
|
|
47
|
-
delayPressIn,
|
|
48
|
-
delayPressOut,
|
|
49
|
-
minPressDuration,
|
|
50
|
-
schedule: scheduleTimeout,
|
|
51
|
-
now: Date.now,
|
|
52
|
-
},
|
|
53
|
-
runtime,
|
|
54
|
-
{
|
|
55
|
-
activate(event: ISymbioteEvent): void {
|
|
56
|
-
onPressIn?.(event);
|
|
57
|
-
},
|
|
58
|
-
deactivate(event: ISymbioteEvent): void {
|
|
59
|
-
onPressOut?.(event);
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
),
|
|
63
|
-
);
|
|
64
|
-
</script>
|
|
65
|
-
|
|
66
|
-
<Pressable
|
|
67
|
-
{...rest}
|
|
68
|
-
onPressIn={handlers.handlePressIn}
|
|
69
|
-
onPressOut={handlers.handlePressOut}
|
|
70
|
-
>
|
|
71
|
-
{#snippet children()}
|
|
72
|
-
{@render content?.()}
|
|
73
|
-
{/snippet}
|
|
74
|
-
</Pressable>
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { ITouchableWithoutFeedbackProps } from './touchable-without-feedback-props';
|
|
2
|
-
export type { ITouchableWithoutFeedbackProps };
|
|
3
|
-
declare const Index: import("svelte").Component<import("../touchable-base-props").ITouchableBaseProps, {}, "">;
|
|
4
|
-
type Index = ReturnType<typeof Index>;
|
|
5
|
-
export default Index;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { Component, ComponentInternals } from 'svelte';
|
|
2
|
-
import type { IAnimatedComponentProps } from './animated-component-props';
|
|
3
|
-
type IAnimatedBase<TExports extends Record<string, unknown>> = (internals: ComponentInternals, props: never) => TExports;
|
|
4
|
-
export declare function createAnimatedComponent<TExports extends Record<string, unknown>>(Base: IAnimatedBase<TExports>): Component<IAnimatedComponentProps, TExports>;
|
|
5
|
-
export {};
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
// createAnimatedComponent: the Svelte twin of the React/Vue/Solid wrapper. Wraps ANY base
|
|
2
|
-
// component so it accepts AnimatedNodes in its props. The framework-agnostic half
|
|
3
|
-
// (reduceProps / readPassthroughStyle / resolveHostNode / the AnimatedProps leaf lifecycle)
|
|
4
|
-
// comes from @symbiote-native/engine, shared verbatim with every other adapter; only the
|
|
5
|
-
// lifecycle below is Svelte's.
|
|
6
|
-
//
|
|
7
|
-
// WHY IT IS PLAIN TS AND NOT A PARAMETRIZED `.svelte` FILE. The generic wrap expresses fine in
|
|
8
|
-
// Svelte — `<Component {...reduced} bind:this={inner} />` over a `component` prop compiles clean
|
|
9
|
-
// — but a `.ts` module that imports a `.svelte` file is unparseable by any tool without the
|
|
10
|
-
// Svelte plugin, which includes this repo's vitest and every consumer smoke test that builds an
|
|
11
|
-
// Animated namespace by hand (packages/navigation's drawer suite). Writing the component body
|
|
12
|
-
// against `svelte/internal/client` keeps `createAnimatedComponent` importable from ordinary TS
|
|
13
|
-
// everywhere, and leaves `modules/animated/` with no `.svelte` file at all. The internals used
|
|
14
|
-
// here are the exact calls the compiler itself emits for the same source — see this package's
|
|
15
|
-
// `svelte-internal-client.d.ts`, and §8 of the svelte-adapter-dom-shim skill for the bump
|
|
16
|
-
// checklist that covers them.
|
|
17
|
-
//
|
|
18
|
-
// TWO WAYS TO THE HOST NODE, because Svelte has no ref fall-through. `bind:this` on a COMPONENT
|
|
19
|
-
// resolves to that component's exports, never to its element:
|
|
20
|
-
// * a scroll container (ScrollView / FlatList / SectionList) exports an imperative handle, so
|
|
21
|
-
// resolveHostNode() unwraps it through getScrollNode() — the same call React and Vue make.
|
|
22
|
-
// Binding the leaf to the handle itself type-checks and then silently animates nothing.
|
|
23
|
-
// * a plain host primitive (View / Text / Image) exports nothing, so the node arrives through
|
|
24
|
-
// an `{@attach}` of our own: every Symbiote component forwards attachments onto its host tag
|
|
25
|
-
// (runes/attachments.ts), which is the adapter's documented seam to a committed node.
|
|
26
|
-
// A base this adapter does not own works if it does either.
|
|
27
|
-
//
|
|
28
|
-
// EVERY OTHER PROP IS FORWARDED UNTOUCHED, including snippets. Svelte snippets — `children` and
|
|
29
|
-
// named scoped ones such as a list's `item` / `sectionHeader` — are ordinary props, so naming any
|
|
30
|
-
// of them here would drop the rest: Vue's wrapper forwarded only its default slot and
|
|
31
|
-
// Animated.FlatList committed empty cells with no error. The only prop this wrapper consumes is
|
|
32
|
-
// `passthroughAnimatedPropExplicitValues`.
|
|
33
|
-
import { createAttachmentKey } from 'svelte/attachments';
|
|
34
|
-
import { derived, get, pop, push, set, spread_props, state, user_effect, } from 'svelte/internal/client';
|
|
35
|
-
import { createAnimatedLeafLifecycle, isNativeAnimatedAvailable, isSymbioteNode, readPassthroughStyle, reduceProps, resolveHostNode, } from '@symbiote-native/engine';
|
|
36
|
-
import { ShimElement } from '../../dom-shim/index.js';
|
|
37
|
-
// RN's prop carrying explicit (already-rasterized) values that override the animated prop in the
|
|
38
|
-
// COMMITTED props (sticky-header passthrough). Named once so reduce and reconcile agree.
|
|
39
|
-
const PASSTHROUGH_PROP = 'passthroughAnimatedPropExplicitValues';
|
|
40
|
-
// The three keys Svelte's own compiled `rest_props` always drops, plus the prop we consume.
|
|
41
|
-
const BASE_EXCLUDES = new Set([
|
|
42
|
-
'$$slots',
|
|
43
|
-
'$$events',
|
|
44
|
-
'$$legacy',
|
|
45
|
-
PASSTHROUGH_PROP,
|
|
46
|
-
]);
|
|
47
|
-
// The leaf additionally never sees `children`: an AnimatedProps leaf rasterizes its props into
|
|
48
|
-
// setNativeProps on every frame, and a snippet is not a Fabric prop. It still reaches the BASE.
|
|
49
|
-
const LEAF_EXCLUDES = new Set([...BASE_EXCLUDES, 'children']);
|
|
50
|
-
// A fresh plain object each call, never the live props proxy: the leaf lifecycle stores its
|
|
51
|
-
// argument as the previous-props SNAPSHOT and compares the next call against it, so handing it
|
|
52
|
-
// one live object twice compares that object with itself and skips every reconcile forever.
|
|
53
|
-
function collect(props, excludes) {
|
|
54
|
-
const out = {};
|
|
55
|
-
for (const key of Object.keys(props)) {
|
|
56
|
-
if (excludes.has(key))
|
|
57
|
-
continue;
|
|
58
|
-
out[key] = Reflect.get(props, key);
|
|
59
|
-
}
|
|
60
|
-
return out;
|
|
61
|
-
}
|
|
62
|
-
// Reads the base's display name for the dlog label, without a cast, so a reconcile line in a log
|
|
63
|
-
// dump says which Animated.* it came from — the per-component labels the six hand-authored files
|
|
64
|
-
// used to hardcode.
|
|
65
|
-
function baseName(base) {
|
|
66
|
-
if (typeof base !== 'function' && typeof base !== 'object')
|
|
67
|
-
return 'Anonymous';
|
|
68
|
-
if (base === null)
|
|
69
|
-
return 'Anonymous';
|
|
70
|
-
const name = Reflect.get(base, 'name');
|
|
71
|
-
return typeof name === 'string' && name.length > 0 ? name : 'Anonymous';
|
|
72
|
-
}
|
|
73
|
-
function hostNode(instance, shim) {
|
|
74
|
-
const unwrapped = resolveHostNode(instance);
|
|
75
|
-
if (isSymbioteNode(unwrapped))
|
|
76
|
-
return unwrapped;
|
|
77
|
-
return shim?.engineNode ?? null;
|
|
78
|
-
}
|
|
79
|
-
export function createAnimatedComponent(Base) {
|
|
80
|
-
const label = `Animated(${baseName(Base)})`;
|
|
81
|
-
return function AnimatedComponent(internals, props) {
|
|
82
|
-
// The compiled twin of a component's own `$props()` scope: without it the `$effect`s below
|
|
83
|
-
// are created immediately instead of being deferred to mount, and would first run before
|
|
84
|
-
// the base has rendered anything.
|
|
85
|
-
push(props, true);
|
|
86
|
-
const lifecycle = createAnimatedLeafLifecycle(label);
|
|
87
|
-
// The `$state.raw` twin: the shim is held by IDENTITY (a deep proxy would miss the engine's
|
|
88
|
-
// WeakMap mirror) and read inside the reconcile effect, so the leaf rebinds when it lands.
|
|
89
|
-
const hostShim = state(null);
|
|
90
|
-
// Rasterized props for the declarative bag: every animated node replaced by its current
|
|
91
|
-
// value, so the first paint already carries concrete values. The per-FRAME path is separate
|
|
92
|
-
// (AnimatedProps.update -> setNativeProps) and never goes through this.
|
|
93
|
-
const reduced = derived(() => {
|
|
94
|
-
const out = reduceProps(collect(props, BASE_EXCLUDES));
|
|
95
|
-
const passthroughStyle = readPassthroughStyle(Reflect.get(props, PASSTHROUGH_PROP));
|
|
96
|
-
if (passthroughStyle !== undefined) {
|
|
97
|
-
out.style =
|
|
98
|
-
out.style === undefined
|
|
99
|
-
? passthroughStyle
|
|
100
|
-
: [out.style, passthroughStyle];
|
|
101
|
-
}
|
|
102
|
-
return out;
|
|
103
|
-
});
|
|
104
|
-
// `reduceProps` rebuilds a plain string-keyed Record, so `{@attach}`'s SYMBOL keys do not
|
|
105
|
-
// survive it. This one is ours and rides as a second spread source; a user's own attachments
|
|
106
|
-
// are re-collected the same way.
|
|
107
|
-
const attachments = {
|
|
108
|
-
[createAttachmentKey()]: (node) => {
|
|
109
|
-
set(hostShim, node instanceof ShimElement ? node : null);
|
|
110
|
-
return () => set(hostShim, null);
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
for (const key of Object.getOwnPropertySymbols(props)) {
|
|
114
|
-
attachments[key] = Reflect.get(props, key);
|
|
115
|
-
}
|
|
116
|
-
const instance = Base(internals, spread_props(() => get(reduced), attachments));
|
|
117
|
-
// `props` and the node are read unconditionally before any branch — a guarded read would
|
|
118
|
-
// drop that dependency from later re-runs. reconcile() itself tolerates a null node.
|
|
119
|
-
user_effect(() => {
|
|
120
|
-
const leafProps = collect(props, LEAF_EXCLUDES);
|
|
121
|
-
const node = hostNode(instance, get(hostShim));
|
|
122
|
-
const passthrough = Reflect.get(props, PASSTHROUGH_PROP);
|
|
123
|
-
lifecycle.reconcile(leafProps, node, passthrough != null && isNativeAnimatedAvailable());
|
|
124
|
-
});
|
|
125
|
-
user_effect(() => () => lifecycle.teardown());
|
|
126
|
-
// The base's own exports ARE the wrapper's: a parent's `bind:this` on Animated.FlatList gets
|
|
127
|
-
// the real scrollToOffset/scrollToIndex/getScrollNode surface, and a method added to the base
|
|
128
|
-
// later cannot go missing here the way a hand-listed delegation would.
|
|
129
|
-
return pop(instance);
|
|
130
|
-
};
|
|
131
|
-
}
|
|
File without changes
|
/package/build/components/{image-background/image-background-props.js → image-background-props.js}
RENAMED
|
File without changes
|
/package/build/{components/scroll-view/scroll-view-platform-types.js → intrinsic-elements.js}
RENAMED
|
File without changes
|