@symbiote-native/svelte 0.1.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/LICENSE +21 -0
- package/README.md +161 -0
- package/build/bootstrap.d.ts +7 -0
- package/build/bootstrap.js +17 -0
- package/build/class-value.d.ts +6 -0
- package/build/class-value.js +81 -0
- package/build/components/RefreshControl.svelte +38 -0
- package/build/components/RefreshControl.svelte.d.ts +5 -0
- package/build/components/SafeAreaView.svelte +34 -0
- package/build/components/SafeAreaView.svelte.d.ts +5 -0
- package/build/components/Text.svelte +25 -0
- package/build/components/Text.svelte.d.ts +5 -0
- package/build/components/View.svelte +41 -0
- package/build/components/View.svelte.d.ts +5 -0
- package/build/components/activity-indicator/activity-indicator-platform.android.d.ts +3 -0
- package/build/components/activity-indicator/activity-indicator-platform.android.js +5 -0
- package/build/components/activity-indicator/activity-indicator-platform.d.ts +1 -0
- package/build/components/activity-indicator/activity-indicator-platform.ios.d.ts +3 -0
- package/build/components/activity-indicator/activity-indicator-platform.ios.js +6 -0
- package/build/components/activity-indicator/activity-indicator-platform.js +5 -0
- package/build/components/activity-indicator/activity-indicator-props.d.ts +5 -0
- package/build/components/activity-indicator/activity-indicator-props.js +1 -0
- package/build/components/activity-indicator/index.svelte +57 -0
- package/build/components/activity-indicator/index.svelte.d.ts +5 -0
- package/build/components/button-props.d.ts +5 -0
- package/build/components/button-props.js +1 -0
- package/build/components/button.svelte +71 -0
- package/build/components/button.svelte.d.ts +5 -0
- package/build/components/flat-list/flat-list-props.d.ts +10 -0
- package/build/components/flat-list/flat-list-props.js +1 -0
- package/build/components/flat-list/index.svelte +254 -0
- package/build/components/flat-list/index.svelte.d.ts +79 -0
- package/build/components/image/image-logic.d.ts +2 -0
- package/build/components/image/image-logic.js +125 -0
- package/build/components/image/image-props.d.ts +5 -0
- package/build/components/image/image-props.js +1 -0
- package/build/components/image/index.d.ts +3 -0
- package/build/components/image/index.js +10 -0
- package/build/components/image/index.svelte +66 -0
- package/build/components/image/index.svelte.d.ts +5 -0
- package/build/components/image-background/image-background-props.d.ts +10 -0
- package/build/components/image-background/image-background-props.js +1 -0
- package/build/components/image-background/index.svelte +81 -0
- package/build/components/image-background/index.svelte.d.ts +5 -0
- package/build/components/index.d.ts +50 -0
- package/build/components/index.js +24 -0
- package/build/components/input-accessory-view/index.svelte +48 -0
- package/build/components/input-accessory-view/index.svelte.d.ts +5 -0
- package/build/components/input-accessory-view/input-accessory-view-props.d.ts +11 -0
- package/build/components/input-accessory-view/input-accessory-view-props.js +1 -0
- package/build/components/keyboard-avoiding-view/index.svelte +135 -0
- package/build/components/keyboard-avoiding-view/index.svelte.d.ts +5 -0
- package/build/components/keyboard-avoiding-view/keyboard-avoiding-view-props.d.ts +15 -0
- package/build/components/keyboard-avoiding-view/keyboard-avoiding-view-props.js +1 -0
- package/build/components/modal/index.svelte +126 -0
- package/build/components/modal/index.svelte.d.ts +5 -0
- package/build/components/modal/modal-props.d.ts +24 -0
- package/build/components/modal/modal-props.js +1 -0
- package/build/components/pressable/index.svelte +160 -0
- package/build/components/pressable/index.svelte.d.ts +5 -0
- package/build/components/pressable/pressable-props.d.ts +27 -0
- package/build/components/pressable/pressable-props.js +1 -0
- package/build/components/refresh-control-props.d.ts +19 -0
- package/build/components/refresh-control-props.js +1 -0
- package/build/components/safe-area-view-props.d.ts +10 -0
- package/build/components/safe-area-view-props.js +1 -0
- package/build/components/scroll-view/index.svelte +298 -0
- package/build/components/scroll-view/index.svelte.d.ts +18 -0
- package/build/components/scroll-view/scroll-view-platform-types.d.ts +3 -0
- package/build/components/scroll-view/scroll-view-platform-types.js +1 -0
- package/build/components/scroll-view/scroll-view-platform.android.d.ts +3 -0
- package/build/components/scroll-view/scroll-view-platform.android.js +3 -0
- package/build/components/scroll-view/scroll-view-platform.d.ts +1 -0
- package/build/components/scroll-view/scroll-view-platform.ios.d.ts +3 -0
- package/build/components/scroll-view/scroll-view-platform.ios.js +3 -0
- package/build/components/scroll-view/scroll-view-platform.js +4 -0
- package/build/components/scroll-view/scroll-view-props.d.ts +78 -0
- package/build/components/scroll-view/scroll-view-props.js +1 -0
- package/build/components/scroll-view/scroll-view-sticky-context.d.ts +7 -0
- package/build/components/scroll-view/scroll-view-sticky-context.js +1 -0
- package/build/components/scroll-view/sticky-header-props.d.ts +10 -0
- package/build/components/scroll-view/sticky-header-props.js +1 -0
- package/build/components/scroll-view/sticky-header.svelte +254 -0
- package/build/components/scroll-view/sticky-header.svelte.d.ts +5 -0
- package/build/components/section-list/index.svelte +107 -0
- package/build/components/section-list/index.svelte.d.ts +57 -0
- package/build/components/section-list/section-list-props.d.ts +1 -0
- package/build/components/section-list/section-list-props.js +1 -0
- package/build/components/switch/index.svelte +123 -0
- package/build/components/switch/index.svelte.d.ts +5 -0
- package/build/components/switch/switch-platform-types.d.ts +5 -0
- package/build/components/switch/switch-platform-types.js +1 -0
- package/build/components/switch/switch-platform.android.d.ts +3 -0
- package/build/components/switch/switch-platform.android.js +8 -0
- package/build/components/switch/switch-platform.d.ts +1 -0
- package/build/components/switch/switch-platform.ios.d.ts +3 -0
- package/build/components/switch/switch-platform.ios.js +7 -0
- package/build/components/switch/switch-platform.js +5 -0
- package/build/components/switch/switch-props.d.ts +5 -0
- package/build/components/switch/switch-props.js +1 -0
- package/build/components/text-input/index.svelte +300 -0
- package/build/components/text-input/index.svelte.d.ts +12 -0
- package/build/components/text-input/text-input-props.d.ts +5 -0
- package/build/components/text-input/text-input-props.js +1 -0
- package/build/components/text-props.d.ts +23 -0
- package/build/components/text-props.js +1 -0
- package/build/components/touchable-base-props.d.ts +10 -0
- package/build/components/touchable-base-props.js +1 -0
- package/build/components/touchable-highlight/index.svelte +39 -0
- package/build/components/touchable-highlight/index.svelte.d.ts +5 -0
- package/build/components/touchable-highlight/touchable-highlight-props.d.ts +5 -0
- package/build/components/touchable-highlight/touchable-highlight-props.js +1 -0
- package/build/components/touchable-native-feedback/index.d.ts +9 -0
- package/build/components/touchable-native-feedback/index.js +14 -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-native-feedback/touchable-native-feedback.svelte +44 -0
- package/build/components/touchable-native-feedback/touchable-native-feedback.svelte.d.ts +5 -0
- package/build/components/touchable-opacity/index.svelte +124 -0
- package/build/components/touchable-opacity/index.svelte.d.ts +5 -0
- package/build/components/touchable-opacity/touchable-opacity-props.d.ts +5 -0
- package/build/components/touchable-opacity/touchable-opacity-props.js +1 -0
- package/build/components/touchable-without-feedback/index.svelte +19 -0
- package/build/components/touchable-without-feedback/index.svelte.d.ts +5 -0
- package/build/components/touchable-without-feedback/touchable-without-feedback-props.d.ts +2 -0
- package/build/components/touchable-without-feedback/touchable-without-feedback-props.js +1 -0
- package/build/components/view-props.d.ts +29 -0
- package/build/components/view-props.js +1 -0
- package/build/components/virtualized-list/index.svelte +702 -0
- package/build/components/virtualized-list/index.svelte.d.ts +79 -0
- package/build/components/virtualized-list/virtualized-list-props.d.ts +70 -0
- package/build/components/virtualized-list/virtualized-list-props.js +73 -0
- package/build/components/virtualized-section-list/index.svelte +206 -0
- package/build/components/virtualized-section-list/index.svelte.d.ts +57 -0
- package/build/components/virtualized-section-list/virtualized-section-list-props.d.ts +62 -0
- package/build/components/virtualized-section-list/virtualized-section-list-props.js +1 -0
- package/build/create-tunnel/index.d.ts +3 -0
- package/build/create-tunnel/index.js +3 -0
- package/build/create-tunnel/tunnel-in.svelte +24 -0
- package/build/create-tunnel/tunnel-in.svelte.d.ts +9 -0
- package/build/create-tunnel/tunnel-out.svelte +14 -0
- package/build/create-tunnel/tunnel-out.svelte.d.ts +7 -0
- package/build/create-tunnel/tunnel.d.ts +9 -0
- package/build/create-tunnel/tunnel.js +9 -0
- package/build/descriptor-to-svelte.d.ts +7 -0
- package/build/descriptor-to-svelte.js +104 -0
- package/build/dom-shim/comment.d.ts +9 -0
- package/build/dom-shim/comment.js +24 -0
- package/build/dom-shim/document-fragment.d.ts +8 -0
- package/build/dom-shim/document-fragment.js +23 -0
- package/build/dom-shim/document.d.ts +23 -0
- package/build/dom-shim/document.js +61 -0
- package/build/dom-shim/element.d.ts +22 -0
- package/build/dom-shim/element.js +130 -0
- package/build/dom-shim/index.d.ts +5 -0
- package/build/dom-shim/index.js +7 -0
- package/build/dom-shim/patch-globals.d.ts +2 -0
- package/build/dom-shim/patch-globals.js +94 -0
- package/build/dom-shim/shim-node.d.ts +30 -0
- package/build/dom-shim/shim-node.js +207 -0
- package/build/dom-shim/text.d.ts +14 -0
- package/build/dom-shim/text.js +97 -0
- package/build/host-instance.d.ts +5 -0
- package/build/host-instance.js +48 -0
- package/build/index.d.ts +28 -0
- package/build/index.js +77 -0
- package/build/modules/accessibility-info/index.android.d.ts +2 -0
- package/build/modules/accessibility-info/index.android.js +4 -0
- package/build/modules/accessibility-info/index.d.ts +1 -0
- package/build/modules/accessibility-info/index.ios.d.ts +2 -0
- package/build/modules/accessibility-info/index.ios.js +3 -0
- package/build/modules/accessibility-info/index.js +5 -0
- package/build/modules/animated/AnimatedImage.svelte +115 -0
- package/build/modules/animated/AnimatedImage.svelte.d.ts +5 -0
- package/build/modules/animated/AnimatedScrollView.svelte +92 -0
- package/build/modules/animated/AnimatedScrollView.svelte.d.ts +17 -0
- package/build/modules/animated/AnimatedText.svelte +58 -0
- package/build/modules/animated/AnimatedText.svelte.d.ts +5 -0
- package/build/modules/animated/AnimatedView.svelte +95 -0
- package/build/modules/animated/AnimatedView.svelte.d.ts +5 -0
- package/build/modules/animated/animated-component-props.d.ts +7 -0
- package/build/modules/animated/animated-component-props.js +1 -0
- package/build/modules/animated/index.d.ts +58 -0
- package/build/modules/animated/index.js +69 -0
- package/build/modules/app-registry/index.d.ts +7 -0
- package/build/modules/app-registry/index.js +28 -0
- package/build/modules/status-bar/index.d.ts +5 -0
- package/build/modules/status-bar/index.js +21 -0
- package/build/modules/status-bar/index.svelte +20 -0
- package/build/modules/status-bar/index.svelte.d.ts +4 -0
- package/build/native-view-bridge.d.ts +4 -0
- package/build/native-view-bridge.js +27 -0
- package/build/preprocessor/forbid-web-only-constructs.d.ts +8 -0
- package/build/preprocessor/forbid-web-only-constructs.js +204 -0
- package/build/preprocessor/scoped-styles.d.ts +10 -0
- package/build/preprocessor/scoped-styles.js +399 -0
- package/build/render.d.ts +7 -0
- package/build/render.js +46 -0
- package/build/root-element.d.ts +3 -0
- package/build/root-element.js +27 -0
- package/build/runes/attachments.d.ts +5 -0
- package/build/runes/attachments.js +73 -0
- package/build/runes/dimensions-value.d.ts +4 -0
- package/build/runes/dimensions-value.js +30 -0
- package/build/runes/media-query.d.ts +8 -0
- package/build/runes/media-query.js +38 -0
- package/build/runes/use-color-scheme.svelte.d.ts +4 -0
- package/build/runes/use-color-scheme.svelte.js +25 -0
- package/build/runes/use-window-dimensions.svelte.d.ts +4 -0
- package/build/runes/use-window-dimensions.svelte.js +43 -0
- package/build/runes/window.d.ts +6 -0
- package/build/runes/window.js +28 -0
- package/build/scope-token.d.ts +2 -0
- package/build/scope-token.js +33 -0
- package/build/style-scope.d.ts +1 -0
- package/build/style-scope.js +29 -0
- package/metro-css-parser.cjs +9 -0
- package/metro-svelte-transformer.cjs +156 -0
- package/package.json +83 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// The retained shim tree Svelte's compiled output believes is the DOM. Every shim node
|
|
2
|
+
// (Element / Text / Comment / DocumentFragment) extends this. See the svelte-adapter-dom-shim
|
|
3
|
+
// skill (§2, §3, §9) for the measured Svelte-internal contract this satisfies.
|
|
4
|
+
//
|
|
5
|
+
// The engine binding is LAZY (§9): `from_tree` builds each template graph once and
|
|
6
|
+
// `cloneNode(true)`s it per instance, so a template's prototype nodes are never inserted
|
|
7
|
+
// into a live tree. Creating an ISymbioteNode for those would allocate engine nodes that
|
|
8
|
+
// never render. A shim node gets its ISymbioteNode only when it (or an ancestor) is
|
|
9
|
+
// actually inserted under the live root — `makeLive` does that, once, recursively.
|
|
10
|
+
//
|
|
11
|
+
// Fields below are plain public members, not TS `private`/`protected`: this whole
|
|
12
|
+
// `dom-shim/` directory is internal implementation, never reachable from the adapter's
|
|
13
|
+
// public barrel (see index.ts) or from app code, so per-field access control buys nothing
|
|
14
|
+
// here and would only get in the way of the module-level helpers (`detachFromParent`,
|
|
15
|
+
// `normalizeInsertable`) and the root's eager bind (root-element.ts) that all need to reach
|
|
16
|
+
// across sibling shim-node instances.
|
|
17
|
+
import { appendChild as engineAppendChild, insertBefore as engineInsertBefore, removeChild as engineRemoveChild, } from '@symbiote-native/engine';
|
|
18
|
+
let documentFactory;
|
|
19
|
+
export function registerShimDocumentFactory(factory) {
|
|
20
|
+
documentFactory = factory;
|
|
21
|
+
}
|
|
22
|
+
function shimDocument() {
|
|
23
|
+
if (documentFactory === undefined) {
|
|
24
|
+
throw new Error('svelte dom-shim: document accessed before its module finished loading');
|
|
25
|
+
}
|
|
26
|
+
return documentFactory();
|
|
27
|
+
}
|
|
28
|
+
export class ShimNode {
|
|
29
|
+
parent = null;
|
|
30
|
+
children = [];
|
|
31
|
+
engineNode = undefined;
|
|
32
|
+
surface = undefined;
|
|
33
|
+
// Overridden to `true` by ShimDocumentFragment's field initializer — a plain inherited-field
|
|
34
|
+
// check, not an `instanceof`, so this module never has to import that subclass (§ above).
|
|
35
|
+
isDocumentFragment = false;
|
|
36
|
+
onMadeLive() { }
|
|
37
|
+
get parentNode() {
|
|
38
|
+
return this.parent;
|
|
39
|
+
}
|
|
40
|
+
get lastChild() {
|
|
41
|
+
return this.children[this.children.length - 1] ?? null;
|
|
42
|
+
}
|
|
43
|
+
get nodeName() {
|
|
44
|
+
return '';
|
|
45
|
+
}
|
|
46
|
+
// We never emit `<template>` — always undefined, per §3c.
|
|
47
|
+
get content() {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
get ownerDocument() {
|
|
51
|
+
return shimDocument();
|
|
52
|
+
}
|
|
53
|
+
// Called once, when this node (or an ancestor) is first inserted under the live root.
|
|
54
|
+
// Idempotent: a node already live just hands back its existing engine node.
|
|
55
|
+
makeLive(surface) {
|
|
56
|
+
const existing = this.engineNode;
|
|
57
|
+
if (existing !== undefined)
|
|
58
|
+
return existing;
|
|
59
|
+
this.surface = surface;
|
|
60
|
+
const engineNode = this.createEngineNode();
|
|
61
|
+
this.engineNode = engineNode;
|
|
62
|
+
this.onMadeLive();
|
|
63
|
+
for (const child of this.children) {
|
|
64
|
+
engineAppendChild(engineNode, child.makeLive(surface));
|
|
65
|
+
}
|
|
66
|
+
return engineNode;
|
|
67
|
+
}
|
|
68
|
+
append(...nodes) {
|
|
69
|
+
for (const node of nodes)
|
|
70
|
+
this.appendChild(node);
|
|
71
|
+
}
|
|
72
|
+
appendChild(node) {
|
|
73
|
+
for (const single of normalizeInsertable(node))
|
|
74
|
+
this.insertOne(single, null);
|
|
75
|
+
return node;
|
|
76
|
+
}
|
|
77
|
+
insertBefore(node, ref) {
|
|
78
|
+
for (const single of normalizeInsertable(node))
|
|
79
|
+
this.insertOne(single, ref);
|
|
80
|
+
return node;
|
|
81
|
+
}
|
|
82
|
+
// Spec-compliant no-op when parentless (DOM's ChildNode.before() steps: "let parent be
|
|
83
|
+
// this's parent; if parent is null, then return" — NOT a throw). This is load-bearing, not
|
|
84
|
+
// pedantry: Svelte's own BranchManager (dom/blocks/branches.js, the machinery behind
|
|
85
|
+
// `{#each}`/`{#if}`/`{@render}` deferred/batched updates) races an offscreen fragment's
|
|
86
|
+
// placeholder anchor against the very effect that renders into it — the anchor can already
|
|
87
|
+
// be detached (via `offscreen.fragment.lastChild.remove()` during a batch commit) by the
|
|
88
|
+
// time that effect's own `anchor.before(realContent)` call fires. In a real DOM this is
|
|
89
|
+
// harmless (the spec no-op just drops the stale insertion); a throw here crashed any
|
|
90
|
+
// component populating a reactive list via a POST-MOUNT effect (proven via a minimal
|
|
91
|
+
// {#each}-over-a-SvelteMap-populated-in-$effect repro — see svelte-adapter-dom-shim skill).
|
|
92
|
+
before(node) {
|
|
93
|
+
if (this.parent === null)
|
|
94
|
+
return;
|
|
95
|
+
this.parent.insertBefore(node, this);
|
|
96
|
+
}
|
|
97
|
+
// A REAL DOM method (`Node.prototype.remove()`, not our own `removeChild`), called by
|
|
98
|
+
// Svelte's own effect-teardown and anchor-management paths (svelte's `effects.js`,
|
|
99
|
+
// `operations.js`) directly on the node being torn down, not on its parent. Missing this
|
|
100
|
+
// surfaced only at actual runtime (mount-pipeline.smoke.test.ts) — `tsc --build` has no way
|
|
101
|
+
// to catch a missing DOM method a compiled Svelte bundle calls.
|
|
102
|
+
remove() {
|
|
103
|
+
this.parent?.removeChild(this);
|
|
104
|
+
}
|
|
105
|
+
removeChild(child) {
|
|
106
|
+
const index = this.children.indexOf(child);
|
|
107
|
+
if (index >= 0)
|
|
108
|
+
this.children.splice(index, 1);
|
|
109
|
+
child.parent = null;
|
|
110
|
+
if (this.engineNode !== undefined && child.engineNode !== undefined) {
|
|
111
|
+
engineRemoveChild(this.engineNode, child.engineNode);
|
|
112
|
+
this.surface?.requestCommit();
|
|
113
|
+
}
|
|
114
|
+
return child;
|
|
115
|
+
}
|
|
116
|
+
set textContent(value) {
|
|
117
|
+
for (const child of this.children.slice())
|
|
118
|
+
this.removeChild(child);
|
|
119
|
+
if (value !== '') {
|
|
120
|
+
this.appendChild(shimDocument().createTextNode(value));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
insertOne(node, ref) {
|
|
124
|
+
detachFromParent(node);
|
|
125
|
+
node.parent = this;
|
|
126
|
+
if (ref === null) {
|
|
127
|
+
this.children.push(node);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const index = this.children.indexOf(ref);
|
|
131
|
+
this.children.splice(index < 0 ? this.children.length : index, 0, node);
|
|
132
|
+
}
|
|
133
|
+
if (this.engineNode !== undefined && this.surface !== undefined) {
|
|
134
|
+
const engineNode = node.makeLive(this.surface);
|
|
135
|
+
const refEngineNode = ref?.engineNode;
|
|
136
|
+
if (ref !== null && refEngineNode !== undefined) {
|
|
137
|
+
engineInsertBefore(this.engineNode, engineNode, refEngineNode);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
engineAppendChild(this.engineNode, engineNode);
|
|
141
|
+
}
|
|
142
|
+
this.surface.requestCommit();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// `Node.prototype.firstChild` / `nextSibling` MUST be real prototype getters, not
|
|
147
|
+
// instance own-properties — `init_operations()` extracts their descriptors once and calls
|
|
148
|
+
// `getter.call(node)` for every node afterward (svelte-adapter-dom-shim skill §3a/§3c).
|
|
149
|
+
Object.defineProperty(ShimNode.prototype, 'firstChild', {
|
|
150
|
+
configurable: true,
|
|
151
|
+
get() {
|
|
152
|
+
return this.children[0] ?? null;
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
Object.defineProperty(ShimNode.prototype, 'nextSibling', {
|
|
156
|
+
configurable: true,
|
|
157
|
+
get() {
|
|
158
|
+
if (this.parent === null)
|
|
159
|
+
return null;
|
|
160
|
+
const siblings = this.parent.children;
|
|
161
|
+
const index = siblings.indexOf(this);
|
|
162
|
+
return index < 0 ? null : (siblings[index + 1] ?? null);
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
// Unlinking a node from its parent must unlink the ENGINE node too, or the shim tree and the
|
|
166
|
+
// native tree disagree: the shim thinks the node is gone while Fabric keeps painting it.
|
|
167
|
+
//
|
|
168
|
+
// The case that makes this load-bearing is a LIVE node moved into an OFFSCREEN
|
|
169
|
+
// `DocumentFragment`. In real DOM, `fragment.append(liveNode)` takes the node out of the
|
|
170
|
+
// document; here the fragment has no engine node of its own, so `insertOne`'s engine half is
|
|
171
|
+
// skipped entirely and this is the only chance to detach. Svelte does exactly that move in
|
|
172
|
+
// three places (§17): `dom/blocks/branches.js` (an onscreen branch parked for a later batch),
|
|
173
|
+
// `dom/blocks/each.js` (`destroy_effects` preserving an item a pending batch still needs), and
|
|
174
|
+
// `dom/blocks/boundary.js`'s `#render` (`move_effect` while a `pending` snippet shows). Without
|
|
175
|
+
// this the parked subtree stays committed underneath whatever replaced it — silent, since
|
|
176
|
+
// nothing throws and a smoke that only checks "is my new content there" still passes.
|
|
177
|
+
//
|
|
178
|
+
// A live->live move (a keyed `{#each}` reorder) reaches this too and is unaffected in outcome:
|
|
179
|
+
// the engine's own `appendChild`/`insertBefore` already detach first, so removing here just
|
|
180
|
+
// makes the same unlink explicit and earlier.
|
|
181
|
+
function detachFromParent(node) {
|
|
182
|
+
const parent = node.parent;
|
|
183
|
+
if (parent === null)
|
|
184
|
+
return;
|
|
185
|
+
const index = parent.children.indexOf(node);
|
|
186
|
+
if (index >= 0)
|
|
187
|
+
parent.children.splice(index, 1);
|
|
188
|
+
node.parent = null;
|
|
189
|
+
const parentEngineNode = parent.engineNode;
|
|
190
|
+
const engineNode = node.engineNode;
|
|
191
|
+
if (parentEngineNode === undefined || engineNode === undefined)
|
|
192
|
+
return;
|
|
193
|
+
engineRemoveChild(parentEngineNode, engineNode);
|
|
194
|
+
parent.surface?.requestCommit();
|
|
195
|
+
}
|
|
196
|
+
// A DOM fragment inserts its CHILDREN, not itself, and ends up empty — the rule every
|
|
197
|
+
// mandatory block path (`{#each}`/`{#if}`/`<svelte:boundary>`, §3e) depends on.
|
|
198
|
+
function normalizeInsertable(node) {
|
|
199
|
+
if (node.isDocumentFragment) {
|
|
200
|
+
const children = node.children.slice();
|
|
201
|
+
for (const child of children)
|
|
202
|
+
detachFromParent(child);
|
|
203
|
+
node.children.length = 0;
|
|
204
|
+
return children;
|
|
205
|
+
}
|
|
206
|
+
return [node];
|
|
207
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ISymbioteNode } from '@symbiote-native/engine';
|
|
2
|
+
import { ShimNode } from './shim-node';
|
|
3
|
+
export declare class ShimText extends ShimNode {
|
|
4
|
+
private value;
|
|
5
|
+
constructor(value: string);
|
|
6
|
+
get nodeName(): string;
|
|
7
|
+
get data(): string;
|
|
8
|
+
set data(next: string);
|
|
9
|
+
private promoteAnchorToRawText;
|
|
10
|
+
get nodeValue(): string;
|
|
11
|
+
set nodeValue(next: string);
|
|
12
|
+
cloneNode(deep?: boolean): ShimText;
|
|
13
|
+
createEngineNode(): ISymbioteNode;
|
|
14
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// A text node. Svelte's own rule (not ours to relax): raw text is only valid inside an
|
|
2
|
+
// `RCTText`; content outside one throws at commit time (same restriction the Vue adapter
|
|
3
|
+
// enforces in insert()). See svelte-adapter-dom-shim skill §3b (createTextNode).
|
|
4
|
+
//
|
|
5
|
+
// An EMPTY text node is not text at all — it is one of Svelte's positional ANCHORS, and it must
|
|
6
|
+
// map to an engine anchor, never to a raw text. Svelte's runtime builds every block/component
|
|
7
|
+
// boundary anchor with `create_text()` i.e. `document.createTextNode('')`, while template text
|
|
8
|
+
// always carries at least one character (a dynamic interpolation compiles to `' '` in the
|
|
9
|
+
// from_tree template, then `set_text` overwrites it — verified against the compiled output of
|
|
10
|
+
// `{#each}` + `{...}`), so "empty means anchor" is a sound discriminator, not a heuristic.
|
|
11
|
+
// This mirrors what the Vue adapter's renderer has always done in `createText`
|
|
12
|
+
// (`text === '' ? createAnchor() : createRawText(text)`) — the shim was simply missing it.
|
|
13
|
+
//
|
|
14
|
+
// It matters for three reasons, in ascending order: an anchor-as-raw-text is a REAL extra
|
|
15
|
+
// Fabric shadow node per block/component instance; an empty RCTRawText actually PAINTS in
|
|
16
|
+
// Fabric (the reason Vue's renderer maps it to an anchor rather than an empty text); and a raw
|
|
17
|
+
// text child of a non-Text parent is the invalid "text outside <Text>" shape. Found by
|
|
18
|
+
// native-node-parity.test.ts, which diffs committed native trees against the Vue adapter.
|
|
19
|
+
import { appendChild as engineAppendChild, createAnchor, createRawText, insertBefore as engineInsertBefore, isAnchor, removeChild as engineRemoveChild, setText, } from '@symbiote-native/engine';
|
|
20
|
+
import { ShimNode } from './shim-node.js';
|
|
21
|
+
export class ShimText extends ShimNode {
|
|
22
|
+
value;
|
|
23
|
+
constructor(value) {
|
|
24
|
+
super();
|
|
25
|
+
this.value = value;
|
|
26
|
+
}
|
|
27
|
+
get nodeName() {
|
|
28
|
+
return '#text';
|
|
29
|
+
}
|
|
30
|
+
get data() {
|
|
31
|
+
return this.value;
|
|
32
|
+
}
|
|
33
|
+
set data(next) {
|
|
34
|
+
this.value = next;
|
|
35
|
+
const node = this.engineNode;
|
|
36
|
+
if (node === undefined)
|
|
37
|
+
return; // not live yet — createEngineNode() reads `value` when it is
|
|
38
|
+
if (!isAnchor(node)) {
|
|
39
|
+
// Deliberately NOT demoted back to an anchor when `next` is '': a node that once carried
|
|
40
|
+
// content and is now empty is genuine empty text content, which is what React renders
|
|
41
|
+
// there too. Demoting would also churn the engine tree on every edit that empties a
|
|
42
|
+
// binding. Only the promotion direction is special-cased.
|
|
43
|
+
setText(node, next);
|
|
44
|
+
this.surface?.requestCommit();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (next === '')
|
|
48
|
+
return; // an anchor that stays empty stays an anchor
|
|
49
|
+
this.promoteAnchorToRawText(node, next);
|
|
50
|
+
}
|
|
51
|
+
// A node that mounted empty (so became an anchor) has just been given real content. The engine
|
|
52
|
+
// has no anchor->text conversion — an anchor is a distinct component — so swap the node in
|
|
53
|
+
// place, keeping sibling order: remove the anchor, insert a raw text at the same position.
|
|
54
|
+
promoteAnchorToRawText(anchor, value) {
|
|
55
|
+
const rawText = createRawText(value);
|
|
56
|
+
const parent = this.parent;
|
|
57
|
+
const parentEngineNode = parent?.engineNode;
|
|
58
|
+
if (parent === null || parentEngineNode === undefined) {
|
|
59
|
+
// Live node under a parent that is not itself live — nothing is committed from here yet,
|
|
60
|
+
// so swapping the binding is enough; insertion places it when the parent goes live.
|
|
61
|
+
this.engineNode = rawText;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// Anchor before the FIRST live following sibling, mirroring ShimNode.insertOne's own rule:
|
|
65
|
+
// a not-yet-live sibling contributes no engine node to order against.
|
|
66
|
+
const index = parent.children.indexOf(this);
|
|
67
|
+
let reference;
|
|
68
|
+
for (let i = index + 1; i < parent.children.length; i += 1) {
|
|
69
|
+
const candidate = parent.children[i]?.engineNode;
|
|
70
|
+
if (candidate !== undefined) {
|
|
71
|
+
reference = candidate;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
engineRemoveChild(parentEngineNode, anchor);
|
|
76
|
+
if (reference !== undefined)
|
|
77
|
+
engineInsertBefore(parentEngineNode, rawText, reference);
|
|
78
|
+
else
|
|
79
|
+
engineAppendChild(parentEngineNode, rawText);
|
|
80
|
+
this.engineNode = rawText;
|
|
81
|
+
this.surface?.requestCommit();
|
|
82
|
+
}
|
|
83
|
+
// Svelte reads/writes both names for a text node depending on the code path.
|
|
84
|
+
get nodeValue() {
|
|
85
|
+
return this.value;
|
|
86
|
+
}
|
|
87
|
+
set nodeValue(next) {
|
|
88
|
+
this.data = next;
|
|
89
|
+
}
|
|
90
|
+
cloneNode(deep) {
|
|
91
|
+
void deep; // DOM signature parity only — a text node has no children to deep-clone
|
|
92
|
+
return new ShimText(this.value);
|
|
93
|
+
}
|
|
94
|
+
createEngineNode() {
|
|
95
|
+
return this.value === '' ? createAnchor() : createRawText(this.value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type IHostInstance } from '@symbiote-native/engine';
|
|
2
|
+
import type { ShimElement } from './dom-shim';
|
|
3
|
+
export type { IHostInstance } from '@symbiote-native/engine';
|
|
4
|
+
export declare function hostInstance(shim: ShimElement | null | undefined): IHostInstance | undefined;
|
|
5
|
+
export declare function findNodeHandle(componentOrHandle: ShimElement | number | null | undefined): number | null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// findNodeHandle, the Svelte adapter twin of adapters/react/src/host-instance.ts and
|
|
2
|
+
// adapters/vue/src/host-instance/index.ts. RN's "ref/instance -> native reactTag" lookup, the
|
|
3
|
+
// seam imperative-interop libraries (reanimated, gesture-handler, react-navigation) reach
|
|
4
|
+
// through.
|
|
5
|
+
//
|
|
6
|
+
// A Svelte `bind:this={hostShim}` gives back a ShimElement (dom-shim/element.ts), not the raw
|
|
7
|
+
// engine node directly — its `.engineNode` field IS the raw ISymbioteNode once the shim has
|
|
8
|
+
// gone live (undefined before the first commit, same "uncommitted -> null" idempotent shape
|
|
9
|
+
// RN's own findNodeHandle has). The node -> tag resolution itself belongs to the engine
|
|
10
|
+
// (getNativeTag, keyed on the raw node in the commit mirror); this only adapts the
|
|
11
|
+
// Svelte-shaped input (a ShimElement) onto it.
|
|
12
|
+
import { getNativeTag, isSymbioteNode, toPublicInstance, dlog, } from '@symbiote-native/engine';
|
|
13
|
+
// `engineNode` alone does NOT identify a ShimElement: it is declared on the shared ShimNode base
|
|
14
|
+
// (dom-shim/shim-node.ts), so a ShimText / ShimComment / ShimDocumentFragment satisfies it too,
|
|
15
|
+
// and none of those is a host ref an interop library can hand back. `tagName` is ShimElement's
|
|
16
|
+
// own field, so checking it makes the predicate mean what its name says.
|
|
17
|
+
function isShimElement(value) {
|
|
18
|
+
return typeof value === 'object' && value !== null && 'engineNode' in value && 'tagName' in value;
|
|
19
|
+
}
|
|
20
|
+
// The typed imperative handle (measure/measureInWindow/measureLayout/setNativeProps/focus/blur)
|
|
21
|
+
// a `bind:this` host ref carries — the Svelte twin of a React `ref.current`/Vue template ref
|
|
22
|
+
// already being an `IHostInstance`. `dom-shim/element.ts`'s `createEngineNode()` grafts
|
|
23
|
+
// toPublicInstance onto every host node AT CREATION, so this call is idempotent (its own
|
|
24
|
+
// isHostInstance guard short-circuits); this helper exists only to give app code a correctly
|
|
25
|
+
// TYPED accessor off the SHIM value (`ShimElement`) instead of the bare `.engineNode` field,
|
|
26
|
+
// with no `as` cast at the call site.
|
|
27
|
+
export function hostInstance(shim) {
|
|
28
|
+
if (shim === null || shim === undefined)
|
|
29
|
+
return undefined;
|
|
30
|
+
const node = shim.engineNode;
|
|
31
|
+
return node !== undefined && isSymbioteNode(node) ? toPublicInstance(node) : undefined;
|
|
32
|
+
}
|
|
33
|
+
export function findNodeHandle(componentOrHandle) {
|
|
34
|
+
if (componentOrHandle === null || componentOrHandle === undefined)
|
|
35
|
+
return null;
|
|
36
|
+
if (typeof componentOrHandle === 'number')
|
|
37
|
+
return componentOrHandle;
|
|
38
|
+
if (!isShimElement(componentOrHandle))
|
|
39
|
+
return null;
|
|
40
|
+
const node = componentOrHandle.engineNode;
|
|
41
|
+
if (node !== undefined && isSymbioteNode(node)) {
|
|
42
|
+
const tag = getNativeTag(node) ?? null;
|
|
43
|
+
dlog(`findNodeHandle: component=${node.component} tag=${tag}`);
|
|
44
|
+
return tag;
|
|
45
|
+
}
|
|
46
|
+
dlog('findNodeHandle: hostShim not live yet (engineNode undefined)');
|
|
47
|
+
return null;
|
|
48
|
+
}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export { mount, unmount } from './render';
|
|
2
|
+
export { AppRegistry, setHostRegistrar } from './modules/app-registry';
|
|
3
|
+
export type { IComponentProvider, IWrapperComponentProvider, IAppParameters, IRunnable, IHostRegistrar, IRegistry, IHeadlessTask, ITaskProvider, ITaskCanceller, ITaskCancelProvider, } from './modules/app-registry';
|
|
4
|
+
export { View, Text, ActivityIndicator, Image, ImageBackground, InputAccessoryView, KeyboardAvoidingView, Switch, TextInput, Modal, SafeAreaView, RefreshControl, Pressable, TouchableOpacity, TouchableHighlight, TouchableWithoutFeedback, TouchableNativeFeedback, Button, ScrollView, ScrollViewStickyHeader, VirtualizedList, FlatList, VirtualizedSectionList, SectionList, } from './components';
|
|
5
|
+
export type { IViewProps, ITextProps, IActivityIndicatorProps, IImageProps, IImageStatics, IImageBackgroundProps, IInputAccessoryViewProps, IKeyboardAvoidingViewProps, IKeyboardAvoidingBehavior, ISwitchProps, ITextInputProps, ITextInputHandle, IModalProps, ISafeAreaViewProps, IRefreshControlProps, IPressableProps, ITouchableOpacityProps, ITouchableHighlightProps, ITouchableWithoutFeedbackProps, ITouchableNativeFeedbackProps, IButtonProps, IScrollViewProps, IScrollViewHandle, IStickyHeaderComponentProps, IVirtualizedListProps, IVirtualizedListHandle, IFlatListProps, IFlatListHandle, IVirtualizedSectionListProps, ISectionListProps, ISection, } from './components';
|
|
6
|
+
export type { IAccessibilityProps, IAriaProps, IAccessibilityRole, IRole, IAccessibilityStateValue, IAccessibilityValue, IAccessibilityActionInfo, IResponderProps, } from '@symbiote-native/components';
|
|
7
|
+
export { setImageSourceResolver } from '@symbiote-native/components';
|
|
8
|
+
export type { IImageSource, IImageSourceProp, IResizeMode, IImageSize, IImageCacheStatus, IModalAnimationType, IModalPresentationStyle, IModalOrientation, IViewToken, IViewableItemsChangedInfo, IViewabilityConfig, IViewabilityConfigCallbackPair, IPressState, ISwitchTrackColor, INativeFeedbackBackground, IThemeAttrBackground, IRippleBackground, IVirtualizedSectionListHandle, IVirtualizedSectionListHandle as ISectionListHandle, ICellLayout, ISeparatorProps, ISeparators, IModalOrientationChangeEvent, IPressableAndroidRippleConfig, IEnterKeyHint, IInputMode, ISubmitBehavior, ITextInputSelection, } from '@symbiote-native/components';
|
|
9
|
+
export { Platform, StyleSheet, PlatformColor, DynamicColorIOS, processColor, setNativeViewConfigSource, setColorProcessor, setDeviceEventSource, PixelRatio, PanResponder, dlog, isDebug, } from '@symbiote-native/engine';
|
|
10
|
+
export type { INativeViewConfig, INativeViewConfigSource, IPixelRatioStatic, ISymbioteEvent, ISymbioteNode, IRootTag, IPanResponderGestureState, IPanResponderCallbacks, IGestureResponderHandlers, IPanResponderInstance, IViewStyle, ITextStyle, IFlexAlign, IFlexJustify, IPlatformStatic, IPlatformOSType, IPlatformConstantsIOS, IPlatformConstantsAndroid, IPlatformSelectSpec, IColorValue, IOpaqueColorValue, IDynamicColorIOSTuple, } from '@symbiote-native/engine';
|
|
11
|
+
export { Alert, Share, ActionSheetIOS, Linking, Vibration, ToastAndroid, Settings, I18nManager, Dimensions, Appearance, AppState, Keyboard, KEYBOARD_EVENT, BackHandler, PermissionsAndroid, PERMISSIONS, RESULTS, LayoutAnimation, InteractionManager, } from '@symbiote-native/engine';
|
|
12
|
+
export type { IAlertType, IAlertButtonStyle, IAlertButton, IAlertButtons, IAlertOptions, IShareContent, IShareOptions, IShareAction, IActionSheetIOSOptions, IShareActionSheetIOSOptions, IShareActionSheetError, IUrlEvent, II18nManagerConstants, IDisplayMetrics, IDisplayMetricsAndroid, IDimensionsPayload, IDimensionsSet, IDimensionsKey, IDimensionsChangeListener, IDimensionsStatic, IColorSchemeName, IColorSchemePreference, IAppStateStatus, IAppStateEvent, IKeyboardEventName, IKeyboardEvent, IKeyboardMetrics, IBackPressEventName, IBackPressHandler, IPermission, IPermissionStatus, IRationale, ILayoutAnimationType, ILayoutAnimationProperty, ILayoutAnimationConfig, ILayoutAnimationAnim, IInteractionEvent, ISimpleTask, IPromiseTask, ITask, IHandle, } from '@symbiote-native/engine';
|
|
13
|
+
export { StatusBar } from './modules/status-bar';
|
|
14
|
+
export type { IStatusBarProps, IStatusBarStyle } from './modules/status-bar';
|
|
15
|
+
export { AccessibilityInfo } from './modules/accessibility-info';
|
|
16
|
+
export type { IAccessibilityChangeEvent, IAccessibilityChangeEventName, IAccessibilityChangeEventHandler, IAccessibilityAnnouncementFinishedEvent, IAnnounceForAccessibilityOptions, IAccessibilityEventType, } from './modules/accessibility-info';
|
|
17
|
+
export { findNodeHandle, hostInstance } from './host-instance';
|
|
18
|
+
export type { IHostInstance } from './host-instance';
|
|
19
|
+
export type { ShimElement } from './dom-shim';
|
|
20
|
+
export { createTunnel, TunnelIn, TunnelOut, type ITunnel } from './create-tunnel';
|
|
21
|
+
export { useWindowDimensions } from './runes/use-window-dimensions.svelte';
|
|
22
|
+
export { useColorScheme } from './runes/use-color-scheme.svelte';
|
|
23
|
+
export { innerWidth, innerHeight, outerWidth, outerHeight, devicePixelRatio } from './runes/window';
|
|
24
|
+
export { orientation, createWidthQuery } from './runes/media-query';
|
|
25
|
+
export type { IOrientation, IWidthQueryBounds } from './runes/media-query';
|
|
26
|
+
export type { IReactiveValue } from './runes/dimensions-value';
|
|
27
|
+
export { normalizeSvelteClass, resolveSvelteClass, type ISvelteClassValue, type IClassMap, type IClassEntry, } from './class-value';
|
|
28
|
+
export { Animated } from './modules/animated';
|
package/build/index.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// @symbiote-native/svelte: a DOM-shim adapter over @symbiote-native/engine. Stock compiled
|
|
2
|
+
// Svelte output believes it is talking to the real DOM (svelte-adapter-dom-shim skill);
|
|
3
|
+
// underneath, every DOM call routes into the same mutation API every other adapter drives.
|
|
4
|
+
// All Fabric clone-on-write lives in the engine, shared cross-adapter. App code names only
|
|
5
|
+
// @symbiote-native/svelte.
|
|
6
|
+
//
|
|
7
|
+
// Full component parity with React/Vue/Angular landed 2026-08-11 (svelte-adapter-dom-shim
|
|
8
|
+
// skill §15): every `core/components` render function has a fixed tree shape, so no
|
|
9
|
+
// `descriptorToSvelte` bridge was ever needed — each component below is hand-authored Svelte
|
|
10
|
+
// markup mirroring its render-*.ts, reusing only the pure state/render logic. See skill §17/§18
|
|
11
|
+
// for the one open async-exception repro and the honest cross-cutting gap list.
|
|
12
|
+
export { mount, unmount } from './render.js';
|
|
13
|
+
export { AppRegistry, setHostRegistrar } from './modules/app-registry/index.js';
|
|
14
|
+
export { View, Text, ActivityIndicator, Image, ImageBackground, InputAccessoryView, KeyboardAvoidingView, Switch, TextInput, Modal, SafeAreaView, RefreshControl, Pressable, TouchableOpacity, TouchableHighlight, TouchableWithoutFeedback, TouchableNativeFeedback, Button, ScrollView, ScrollViewStickyHeader, VirtualizedList, FlatList, VirtualizedSectionList, SectionList, } from './components/index.js';
|
|
15
|
+
// Component-scoped agnostic types that live in @symbiote-native/components but weren't yet
|
|
16
|
+
// threaded through this barrel (parity fix, see React's index.ts lines 55-58, 89, 245-250).
|
|
17
|
+
export { setImageSourceResolver } from '@symbiote-native/components';
|
|
18
|
+
// Pure, framework-agnostic runtime modules — same re-export every other adapter does per
|
|
19
|
+
// CLAUDE.md's <runtime_modules_layering>. PanResponder was missing here (present on
|
|
20
|
+
// React/Vue's own barrels) until 2026-08-12 — a pure engine re-export, no framework glue, so
|
|
21
|
+
// adding it is a one-line parity fix, not new adapter work.
|
|
22
|
+
export { Platform, StyleSheet, PlatformColor, DynamicColorIOS, processColor, setNativeViewConfigSource, setColorProcessor, setDeviceEventSource, PixelRatio, PanResponder, dlog, isDebug, } from '@symbiote-native/engine';
|
|
23
|
+
// Imperative runtime modules: the SAME module every adapter shares, re-exported straight from
|
|
24
|
+
// @symbiote-native/engine so app code names only @symbiote-native/svelte (RN's single import
|
|
25
|
+
// root). Nothing here has a visual or a lifecycle, so there is no Svelte half to write.
|
|
26
|
+
export { Alert, Share, ActionSheetIOS, Linking, Vibration, ToastAndroid, Settings, I18nManager, Dimensions, Appearance, AppState, Keyboard, KEYBOARD_EVENT, BackHandler, PermissionsAndroid, PERMISSIONS, RESULTS, LayoutAnimation, InteractionManager, } from '@symbiote-native/engine';
|
|
27
|
+
// StatusBar is the one imperative-looking module with a real declarative half: it renders
|
|
28
|
+
// nothing but applies its props via an `$effect` (modules/status-bar/index.svelte).
|
|
29
|
+
export { StatusBar } from './modules/status-bar/index.js';
|
|
30
|
+
export { AccessibilityInfo } from './modules/accessibility-info';
|
|
31
|
+
// findNodeHandle: RN's ref -> native reactTag lookup, the Svelte twin of the React/Vue
|
|
32
|
+
// adapters' own (host-instance.ts / host-instance/index.ts). hostInstance: the typed
|
|
33
|
+
// measure/setNativeProps/focus/blur accessor off a `bind:this` ShimElement ref (see
|
|
34
|
+
// host-instance.ts's header — React/Vue get this for free off a plain ref value; Svelte's ref is
|
|
35
|
+
// a ShimElement wrapper, so it needs its own typed unwrap).
|
|
36
|
+
export { findNodeHandle, hostInstance } from './host-instance.js';
|
|
37
|
+
// The generic Descriptor -> shim-tree bridge (svelte-adapter-dom-shim skill §19) — the Svelte
|
|
38
|
+
// twin of Vue's `descriptorToVue` / React's `descriptorToReact`, which a downstream package
|
|
39
|
+
// wrapping a THIRD-PARTY native view (@symbiote-native/slider, packages/slider/src/svelte) needs
|
|
40
|
+
// to mount a Descriptor whose `type` is a raw, non-`symbiote-`-prefixed Fabric name (e.g.
|
|
41
|
+
// 'RNCSlider'). Deliberately NOT re-exported from THIS barrel: `./index.ts` also re-exports
|
|
42
|
+
// `./components`, real `.svelte` sources, so importing even one unrelated name from here forces
|
|
43
|
+
// the whole `.svelte` module graph to load — fatal under vitest's plain (svelte-plugin-free)
|
|
44
|
+
// transform. Import `@symbiote-native/svelte/native-view-bridge` instead — see that file's
|
|
45
|
+
// header for the full reasoning and native-view-bridge.ts for what else it carries
|
|
46
|
+
// (mount/unmount, for a downstream package's own tests).
|
|
47
|
+
// createTunnel: the Svelte twin of adapters/vue/src/create-tunnel (see create-tunnel/tunnel.ts's
|
|
48
|
+
// header for why the API shape — an explicit `tunnel` prop on TunnelIn/TunnelOut, rather than
|
|
49
|
+
// `tunnel.In`/`tunnel.Out` — deliberately differs from React/Vue). NOTE: React's createPortal has
|
|
50
|
+
// no Svelte (or even Vue) twin — it is react-reconciler's own Fiber-level HostPortal primitive,
|
|
51
|
+
// with no equivalent in a framework with no reconciler; createTunnel is the achievable analog,
|
|
52
|
+
// same scope Vue itself settled on.
|
|
53
|
+
export { createTunnel, TunnelIn, TunnelOut } from './create-tunnel/index.js';
|
|
54
|
+
// useWindowDimensions / useColorScheme: the Svelte twins of React's hooks / Vue's composables —
|
|
55
|
+
// see runes/use-window-dimensions.svelte.ts's header for why this adapter's lifecycle-helper
|
|
56
|
+
// bucket is named `runes/`, not `hooks/`/`composables/`.
|
|
57
|
+
export { useWindowDimensions } from './runes/use-window-dimensions.svelte';
|
|
58
|
+
export { useColorScheme } from './runes/use-color-scheme.svelte';
|
|
59
|
+
// The React Native twins of `svelte/reactivity/window`, which is browser-only and would read
|
|
60
|
+
// `undefined` forever here. Same names, same `.current` shape, engine Dimensions/PixelRatio
|
|
61
|
+
// underneath — see runes/window.ts's header for the two deliberate differences from upstream, and
|
|
62
|
+
// for why `scrollX`/`scrollY`/`screenLeft`/`screenTop` are absent rather than faked.
|
|
63
|
+
export { innerWidth, innerHeight, outerWidth, outerHeight, devicePixelRatio } from './runes/window.js';
|
|
64
|
+
// What replaces `MediaQuery` from `svelte/reactivity`: named exports for the media features RN can
|
|
65
|
+
// actually answer, instead of a class taking a CSS query string it would mostly have to answer
|
|
66
|
+
// `false` to. `(prefers-color-scheme)`'s twin is `useColorScheme()` above. See
|
|
67
|
+
// runes/media-query.ts's header for the argument.
|
|
68
|
+
export { orientation, createWidthQuery } from './runes/media-query.js';
|
|
69
|
+
// The `class` prop's Svelte-flavoured union — a clsx map / array on top of the engine's
|
|
70
|
+
// IClassNameValue — plus the normalizer, for a consumer building a class value in its own
|
|
71
|
+
// helper. See class-value.ts's header for the object-is-a-style vs object-is-a-clsx-map rule.
|
|
72
|
+
export { normalizeSvelteClass, resolveSvelteClass, } from './class-value.js';
|
|
73
|
+
// Animated: the Svelte twin of adapters/vue/src/modules/animated (see modules/animated/index.ts's
|
|
74
|
+
// header for why Animated.View/Text/Image/ScrollView are each their own hand-authored .svelte
|
|
75
|
+
// file rather than a generic createAnimatedComponent() wrap — Svelte has no runtime h()/
|
|
76
|
+
// createElement equivalent a factory could target).
|
|
77
|
+
export { Animated } from './modules/animated/index.js';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { AccessibilityInfo } from '@symbiote-native/engine';
|
|
2
|
+
export type { IAccessibilityChangeEvent, IAccessibilityChangeEventName, IAccessibilityChangeEventHandler, IAccessibilityAnnouncementFinishedEvent, IAnnounceForAccessibilityOptions, IAccessibilityEventType, } from '@symbiote-native/engine';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// AccessibilityInfo (Android) moved to @symbiote-native/engine. This thin re-export keeps
|
|
2
|
+
// @symbiote-native/svelte's surface identical; Metro selects the engine's accessibility-info.android.ts
|
|
3
|
+
// on an Android host.
|
|
4
|
+
export { AccessibilityInfo } from '@symbiote-native/engine';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.ios';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { AccessibilityInfo } from '@symbiote-native/engine';
|
|
2
|
+
export type { IAccessibilityChangeEvent, IAccessibilityChangeEventName, IAccessibilityChangeEventHandler, IAccessibilityAnnouncementFinishedEvent, IAnnounceForAccessibilityOptions, IAccessibilityEventType, } from '@symbiote-native/engine';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Base / default AccessibilityInfo: re-exports the iOS build. Metro overrides this with
|
|
2
|
+
// accessibility-info.ios.ts / .android.ts on a real host; under tsx / tsc / web the host
|
|
3
|
+
// config resolves here. Filename is the selector, no Platform.OS read. See
|
|
4
|
+
// shared.ts.
|
|
5
|
+
export * from './index.ios.js';
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
// Animated.Image — unlike View/Text, Image.svelte does REAL prop transformation
|
|
3
|
+
// (buildImageBag: source resolution, resizeMode/tintColor read off style, width/height fold,
|
|
4
|
+
// alt->accessibility). Hand-authoring a bare pass-through bag here (like AnimatedView/Text)
|
|
5
|
+
// would silently drop all of that — the exact copy-paste-instead-of-calling bug class the
|
|
6
|
+
// svelte-adapter-dom-shim skill's §15/§19 already caught on Switch/ActivityIndicator/
|
|
7
|
+
// TextInput/ImageBackground. So this component calls buildImageBag itself (same as
|
|
8
|
+
// image/index.svelte), fed with rasterized (reduceProps'd) field values.
|
|
9
|
+
//
|
|
10
|
+
// Known, inherited (not Svelte-specific) limitation: the PER-FRAME animated path
|
|
11
|
+
// (AnimatedProps.update -> setNativeProps) pushes the raw `rest` fields directly, bypassing
|
|
12
|
+
// buildImageBag's mapping — same as Vue's/React's Animated.Image, since AnimatedProps is
|
|
13
|
+
// framework-agnostic and has no notion of a component's own prop transform. In practice this
|
|
14
|
+
// only matters if a non-`style` field (e.g. `source`) is itself animated, which is not a
|
|
15
|
+
// supported use — animating Image is expected to go through `style` (opacity/transform),
|
|
16
|
+
// which round-trips correctly since buildImageBag keeps `style` under the same key name.
|
|
17
|
+
import type { IAnimatedComponentProps } from './animated-component-props';
|
|
18
|
+
|
|
19
|
+
export type { IAnimatedComponentProps };
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<script lang="ts">
|
|
23
|
+
import {
|
|
24
|
+
createAnimatedLeafLifecycle,
|
|
25
|
+
isNativeAnimatedAvailable,
|
|
26
|
+
reduceProps,
|
|
27
|
+
readPassthroughStyle,
|
|
28
|
+
} from '@symbiote-native/engine';
|
|
29
|
+
import { resolveAccessibilityProps } from '@symbiote-native/components';
|
|
30
|
+
import type { IAccessibilityProps, IAriaProps, IImageViewProps } from '@symbiote-native/components';
|
|
31
|
+
import { buildImageBag } from '../../components/image/image-logic';
|
|
32
|
+
import { createAttachmentsSync } from '../../runes/attachments';
|
|
33
|
+
import type { ShimElement } from '../../dom-shim';
|
|
34
|
+
|
|
35
|
+
let { passthroughAnimatedPropExplicitValues: passthrough, ...rest }: IAnimatedComponentProps =
|
|
36
|
+
$props();
|
|
37
|
+
|
|
38
|
+
let hostShim = $state.raw<ShimElement | null>(null);
|
|
39
|
+
|
|
40
|
+
const wantsNative = $derived(passthrough != null && isNativeAnimatedAvailable());
|
|
41
|
+
|
|
42
|
+
// Rasterize every field (style's animated entries resolved to plain numbers, any other
|
|
43
|
+
// animated field to its current value), then re-run Image's own field split + buildImageBag
|
|
44
|
+
// over the resolved values — the same shape image/index.svelte builds, just fed reduced
|
|
45
|
+
// values instead of raw $props().
|
|
46
|
+
const reduced = $derived.by(() => {
|
|
47
|
+
const resolved = reduceProps(rest);
|
|
48
|
+
const {
|
|
49
|
+
source,
|
|
50
|
+
defaultSource,
|
|
51
|
+
loadingIndicatorSource,
|
|
52
|
+
style,
|
|
53
|
+
resizeMode,
|
|
54
|
+
tintColor,
|
|
55
|
+
src,
|
|
56
|
+
srcSet,
|
|
57
|
+
alt,
|
|
58
|
+
width,
|
|
59
|
+
height,
|
|
60
|
+
crossOrigin,
|
|
61
|
+
referrerPolicy,
|
|
62
|
+
...imagePassthrough
|
|
63
|
+
} = resolved;
|
|
64
|
+
// reduceProps returns a flat Record<string, unknown> — every field above is `unknown`
|
|
65
|
+
// even though it is, at runtime, exactly the shape IImageViewProps/IAccessibilityProps
|
|
66
|
+
// declare. Bridging that back into a typed shape without an `as` cast uses the same
|
|
67
|
+
// `Object.assign(Object.create(null), …)` pattern React's create-animated-component.tsx
|
|
68
|
+
// already establishes: Object.create(null) types as `any`, so Object.assign's result does
|
|
69
|
+
// too, and TS allows assigning `any` into a specifically-typed binding.
|
|
70
|
+
const accessibility: IAccessibilityProps & IAriaProps = Object.assign(
|
|
71
|
+
Object.create(null),
|
|
72
|
+
imagePassthrough,
|
|
73
|
+
);
|
|
74
|
+
const view: IImageViewProps = Object.assign(Object.create(null), {
|
|
75
|
+
source,
|
|
76
|
+
defaultSource,
|
|
77
|
+
loadingIndicatorSource,
|
|
78
|
+
style,
|
|
79
|
+
resizeMode,
|
|
80
|
+
tintColor,
|
|
81
|
+
src,
|
|
82
|
+
srcSet,
|
|
83
|
+
alt,
|
|
84
|
+
width,
|
|
85
|
+
height,
|
|
86
|
+
crossOrigin,
|
|
87
|
+
referrerPolicy,
|
|
88
|
+
passthrough: resolveAccessibilityProps(accessibility),
|
|
89
|
+
});
|
|
90
|
+
const bag = buildImageBag(view);
|
|
91
|
+
const passthroughStyle = readPassthroughStyle(passthrough);
|
|
92
|
+
if (passthroughStyle !== undefined) {
|
|
93
|
+
bag.style = bag.style === undefined ? passthroughStyle : [bag.style, passthroughStyle];
|
|
94
|
+
}
|
|
95
|
+
return bag;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const runtime = createAnimatedLeafLifecycle('AnimatedImage');
|
|
99
|
+
|
|
100
|
+
$effect(() => {
|
|
101
|
+
const currentRest = rest;
|
|
102
|
+
const node = hostShim?.engineNode ?? null;
|
|
103
|
+
runtime.reconcile(currentRest, node, wantsNative);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
$effect(() => () => runtime.teardown());
|
|
107
|
+
|
|
108
|
+
// See View.svelte's note on `{@attach}`.
|
|
109
|
+
const syncAttachments = createAttachmentsSync();
|
|
110
|
+
$effect(() => {
|
|
111
|
+
syncAttachments(hostShim, rest);
|
|
112
|
+
});
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<symbiote-image p={reduced} bind:this={hostShim} />
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IAnimatedComponentProps } from './animated-component-props';
|
|
2
|
+
export type { IAnimatedComponentProps };
|
|
3
|
+
declare const AnimatedImage: import("svelte").Component<IAnimatedComponentProps, {}, "">;
|
|
4
|
+
type AnimatedImage = ReturnType<typeof AnimatedImage>;
|
|
5
|
+
export default AnimatedImage;
|