@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.
Files changed (219) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -0
  3. package/build/bootstrap.d.ts +7 -0
  4. package/build/bootstrap.js +17 -0
  5. package/build/class-value.d.ts +6 -0
  6. package/build/class-value.js +81 -0
  7. package/build/components/RefreshControl.svelte +38 -0
  8. package/build/components/RefreshControl.svelte.d.ts +5 -0
  9. package/build/components/SafeAreaView.svelte +34 -0
  10. package/build/components/SafeAreaView.svelte.d.ts +5 -0
  11. package/build/components/Text.svelte +25 -0
  12. package/build/components/Text.svelte.d.ts +5 -0
  13. package/build/components/View.svelte +41 -0
  14. package/build/components/View.svelte.d.ts +5 -0
  15. package/build/components/activity-indicator/activity-indicator-platform.android.d.ts +3 -0
  16. package/build/components/activity-indicator/activity-indicator-platform.android.js +5 -0
  17. package/build/components/activity-indicator/activity-indicator-platform.d.ts +1 -0
  18. package/build/components/activity-indicator/activity-indicator-platform.ios.d.ts +3 -0
  19. package/build/components/activity-indicator/activity-indicator-platform.ios.js +6 -0
  20. package/build/components/activity-indicator/activity-indicator-platform.js +5 -0
  21. package/build/components/activity-indicator/activity-indicator-props.d.ts +5 -0
  22. package/build/components/activity-indicator/activity-indicator-props.js +1 -0
  23. package/build/components/activity-indicator/index.svelte +57 -0
  24. package/build/components/activity-indicator/index.svelte.d.ts +5 -0
  25. package/build/components/button-props.d.ts +5 -0
  26. package/build/components/button-props.js +1 -0
  27. package/build/components/button.svelte +71 -0
  28. package/build/components/button.svelte.d.ts +5 -0
  29. package/build/components/flat-list/flat-list-props.d.ts +10 -0
  30. package/build/components/flat-list/flat-list-props.js +1 -0
  31. package/build/components/flat-list/index.svelte +254 -0
  32. package/build/components/flat-list/index.svelte.d.ts +79 -0
  33. package/build/components/image/image-logic.d.ts +2 -0
  34. package/build/components/image/image-logic.js +125 -0
  35. package/build/components/image/image-props.d.ts +5 -0
  36. package/build/components/image/image-props.js +1 -0
  37. package/build/components/image/index.d.ts +3 -0
  38. package/build/components/image/index.js +10 -0
  39. package/build/components/image/index.svelte +66 -0
  40. package/build/components/image/index.svelte.d.ts +5 -0
  41. package/build/components/image-background/image-background-props.d.ts +10 -0
  42. package/build/components/image-background/image-background-props.js +1 -0
  43. package/build/components/image-background/index.svelte +81 -0
  44. package/build/components/image-background/index.svelte.d.ts +5 -0
  45. package/build/components/index.d.ts +50 -0
  46. package/build/components/index.js +24 -0
  47. package/build/components/input-accessory-view/index.svelte +48 -0
  48. package/build/components/input-accessory-view/index.svelte.d.ts +5 -0
  49. package/build/components/input-accessory-view/input-accessory-view-props.d.ts +11 -0
  50. package/build/components/input-accessory-view/input-accessory-view-props.js +1 -0
  51. package/build/components/keyboard-avoiding-view/index.svelte +135 -0
  52. package/build/components/keyboard-avoiding-view/index.svelte.d.ts +5 -0
  53. package/build/components/keyboard-avoiding-view/keyboard-avoiding-view-props.d.ts +15 -0
  54. package/build/components/keyboard-avoiding-view/keyboard-avoiding-view-props.js +1 -0
  55. package/build/components/modal/index.svelte +126 -0
  56. package/build/components/modal/index.svelte.d.ts +5 -0
  57. package/build/components/modal/modal-props.d.ts +24 -0
  58. package/build/components/modal/modal-props.js +1 -0
  59. package/build/components/pressable/index.svelte +160 -0
  60. package/build/components/pressable/index.svelte.d.ts +5 -0
  61. package/build/components/pressable/pressable-props.d.ts +27 -0
  62. package/build/components/pressable/pressable-props.js +1 -0
  63. package/build/components/refresh-control-props.d.ts +19 -0
  64. package/build/components/refresh-control-props.js +1 -0
  65. package/build/components/safe-area-view-props.d.ts +10 -0
  66. package/build/components/safe-area-view-props.js +1 -0
  67. package/build/components/scroll-view/index.svelte +298 -0
  68. package/build/components/scroll-view/index.svelte.d.ts +18 -0
  69. package/build/components/scroll-view/scroll-view-platform-types.d.ts +3 -0
  70. package/build/components/scroll-view/scroll-view-platform-types.js +1 -0
  71. package/build/components/scroll-view/scroll-view-platform.android.d.ts +3 -0
  72. package/build/components/scroll-view/scroll-view-platform.android.js +3 -0
  73. package/build/components/scroll-view/scroll-view-platform.d.ts +1 -0
  74. package/build/components/scroll-view/scroll-view-platform.ios.d.ts +3 -0
  75. package/build/components/scroll-view/scroll-view-platform.ios.js +3 -0
  76. package/build/components/scroll-view/scroll-view-platform.js +4 -0
  77. package/build/components/scroll-view/scroll-view-props.d.ts +78 -0
  78. package/build/components/scroll-view/scroll-view-props.js +1 -0
  79. package/build/components/scroll-view/scroll-view-sticky-context.d.ts +7 -0
  80. package/build/components/scroll-view/scroll-view-sticky-context.js +1 -0
  81. package/build/components/scroll-view/sticky-header-props.d.ts +10 -0
  82. package/build/components/scroll-view/sticky-header-props.js +1 -0
  83. package/build/components/scroll-view/sticky-header.svelte +254 -0
  84. package/build/components/scroll-view/sticky-header.svelte.d.ts +5 -0
  85. package/build/components/section-list/index.svelte +107 -0
  86. package/build/components/section-list/index.svelte.d.ts +57 -0
  87. package/build/components/section-list/section-list-props.d.ts +1 -0
  88. package/build/components/section-list/section-list-props.js +1 -0
  89. package/build/components/switch/index.svelte +123 -0
  90. package/build/components/switch/index.svelte.d.ts +5 -0
  91. package/build/components/switch/switch-platform-types.d.ts +5 -0
  92. package/build/components/switch/switch-platform-types.js +1 -0
  93. package/build/components/switch/switch-platform.android.d.ts +3 -0
  94. package/build/components/switch/switch-platform.android.js +8 -0
  95. package/build/components/switch/switch-platform.d.ts +1 -0
  96. package/build/components/switch/switch-platform.ios.d.ts +3 -0
  97. package/build/components/switch/switch-platform.ios.js +7 -0
  98. package/build/components/switch/switch-platform.js +5 -0
  99. package/build/components/switch/switch-props.d.ts +5 -0
  100. package/build/components/switch/switch-props.js +1 -0
  101. package/build/components/text-input/index.svelte +300 -0
  102. package/build/components/text-input/index.svelte.d.ts +12 -0
  103. package/build/components/text-input/text-input-props.d.ts +5 -0
  104. package/build/components/text-input/text-input-props.js +1 -0
  105. package/build/components/text-props.d.ts +23 -0
  106. package/build/components/text-props.js +1 -0
  107. package/build/components/touchable-base-props.d.ts +10 -0
  108. package/build/components/touchable-base-props.js +1 -0
  109. package/build/components/touchable-highlight/index.svelte +39 -0
  110. package/build/components/touchable-highlight/index.svelte.d.ts +5 -0
  111. package/build/components/touchable-highlight/touchable-highlight-props.d.ts +5 -0
  112. package/build/components/touchable-highlight/touchable-highlight-props.js +1 -0
  113. package/build/components/touchable-native-feedback/index.d.ts +9 -0
  114. package/build/components/touchable-native-feedback/index.js +14 -0
  115. package/build/components/touchable-native-feedback/touchable-native-feedback-props.d.ts +8 -0
  116. package/build/components/touchable-native-feedback/touchable-native-feedback-props.js +1 -0
  117. package/build/components/touchable-native-feedback/touchable-native-feedback.svelte +44 -0
  118. package/build/components/touchable-native-feedback/touchable-native-feedback.svelte.d.ts +5 -0
  119. package/build/components/touchable-opacity/index.svelte +124 -0
  120. package/build/components/touchable-opacity/index.svelte.d.ts +5 -0
  121. package/build/components/touchable-opacity/touchable-opacity-props.d.ts +5 -0
  122. package/build/components/touchable-opacity/touchable-opacity-props.js +1 -0
  123. package/build/components/touchable-without-feedback/index.svelte +19 -0
  124. package/build/components/touchable-without-feedback/index.svelte.d.ts +5 -0
  125. package/build/components/touchable-without-feedback/touchable-without-feedback-props.d.ts +2 -0
  126. package/build/components/touchable-without-feedback/touchable-without-feedback-props.js +1 -0
  127. package/build/components/view-props.d.ts +29 -0
  128. package/build/components/view-props.js +1 -0
  129. package/build/components/virtualized-list/index.svelte +702 -0
  130. package/build/components/virtualized-list/index.svelte.d.ts +79 -0
  131. package/build/components/virtualized-list/virtualized-list-props.d.ts +70 -0
  132. package/build/components/virtualized-list/virtualized-list-props.js +73 -0
  133. package/build/components/virtualized-section-list/index.svelte +206 -0
  134. package/build/components/virtualized-section-list/index.svelte.d.ts +57 -0
  135. package/build/components/virtualized-section-list/virtualized-section-list-props.d.ts +62 -0
  136. package/build/components/virtualized-section-list/virtualized-section-list-props.js +1 -0
  137. package/build/create-tunnel/index.d.ts +3 -0
  138. package/build/create-tunnel/index.js +3 -0
  139. package/build/create-tunnel/tunnel-in.svelte +24 -0
  140. package/build/create-tunnel/tunnel-in.svelte.d.ts +9 -0
  141. package/build/create-tunnel/tunnel-out.svelte +14 -0
  142. package/build/create-tunnel/tunnel-out.svelte.d.ts +7 -0
  143. package/build/create-tunnel/tunnel.d.ts +9 -0
  144. package/build/create-tunnel/tunnel.js +9 -0
  145. package/build/descriptor-to-svelte.d.ts +7 -0
  146. package/build/descriptor-to-svelte.js +104 -0
  147. package/build/dom-shim/comment.d.ts +9 -0
  148. package/build/dom-shim/comment.js +24 -0
  149. package/build/dom-shim/document-fragment.d.ts +8 -0
  150. package/build/dom-shim/document-fragment.js +23 -0
  151. package/build/dom-shim/document.d.ts +23 -0
  152. package/build/dom-shim/document.js +61 -0
  153. package/build/dom-shim/element.d.ts +22 -0
  154. package/build/dom-shim/element.js +130 -0
  155. package/build/dom-shim/index.d.ts +5 -0
  156. package/build/dom-shim/index.js +7 -0
  157. package/build/dom-shim/patch-globals.d.ts +2 -0
  158. package/build/dom-shim/patch-globals.js +94 -0
  159. package/build/dom-shim/shim-node.d.ts +30 -0
  160. package/build/dom-shim/shim-node.js +207 -0
  161. package/build/dom-shim/text.d.ts +14 -0
  162. package/build/dom-shim/text.js +97 -0
  163. package/build/host-instance.d.ts +5 -0
  164. package/build/host-instance.js +48 -0
  165. package/build/index.d.ts +28 -0
  166. package/build/index.js +77 -0
  167. package/build/modules/accessibility-info/index.android.d.ts +2 -0
  168. package/build/modules/accessibility-info/index.android.js +4 -0
  169. package/build/modules/accessibility-info/index.d.ts +1 -0
  170. package/build/modules/accessibility-info/index.ios.d.ts +2 -0
  171. package/build/modules/accessibility-info/index.ios.js +3 -0
  172. package/build/modules/accessibility-info/index.js +5 -0
  173. package/build/modules/animated/AnimatedImage.svelte +115 -0
  174. package/build/modules/animated/AnimatedImage.svelte.d.ts +5 -0
  175. package/build/modules/animated/AnimatedScrollView.svelte +92 -0
  176. package/build/modules/animated/AnimatedScrollView.svelte.d.ts +17 -0
  177. package/build/modules/animated/AnimatedText.svelte +58 -0
  178. package/build/modules/animated/AnimatedText.svelte.d.ts +5 -0
  179. package/build/modules/animated/AnimatedView.svelte +95 -0
  180. package/build/modules/animated/AnimatedView.svelte.d.ts +5 -0
  181. package/build/modules/animated/animated-component-props.d.ts +7 -0
  182. package/build/modules/animated/animated-component-props.js +1 -0
  183. package/build/modules/animated/index.d.ts +58 -0
  184. package/build/modules/animated/index.js +69 -0
  185. package/build/modules/app-registry/index.d.ts +7 -0
  186. package/build/modules/app-registry/index.js +28 -0
  187. package/build/modules/status-bar/index.d.ts +5 -0
  188. package/build/modules/status-bar/index.js +21 -0
  189. package/build/modules/status-bar/index.svelte +20 -0
  190. package/build/modules/status-bar/index.svelte.d.ts +4 -0
  191. package/build/native-view-bridge.d.ts +4 -0
  192. package/build/native-view-bridge.js +27 -0
  193. package/build/preprocessor/forbid-web-only-constructs.d.ts +8 -0
  194. package/build/preprocessor/forbid-web-only-constructs.js +204 -0
  195. package/build/preprocessor/scoped-styles.d.ts +10 -0
  196. package/build/preprocessor/scoped-styles.js +399 -0
  197. package/build/render.d.ts +7 -0
  198. package/build/render.js +46 -0
  199. package/build/root-element.d.ts +3 -0
  200. package/build/root-element.js +27 -0
  201. package/build/runes/attachments.d.ts +5 -0
  202. package/build/runes/attachments.js +73 -0
  203. package/build/runes/dimensions-value.d.ts +4 -0
  204. package/build/runes/dimensions-value.js +30 -0
  205. package/build/runes/media-query.d.ts +8 -0
  206. package/build/runes/media-query.js +38 -0
  207. package/build/runes/use-color-scheme.svelte.d.ts +4 -0
  208. package/build/runes/use-color-scheme.svelte.js +25 -0
  209. package/build/runes/use-window-dimensions.svelte.d.ts +4 -0
  210. package/build/runes/use-window-dimensions.svelte.js +43 -0
  211. package/build/runes/window.d.ts +6 -0
  212. package/build/runes/window.js +28 -0
  213. package/build/scope-token.d.ts +2 -0
  214. package/build/scope-token.js +33 -0
  215. package/build/style-scope.d.ts +1 -0
  216. package/build/style-scope.js +29 -0
  217. package/metro-css-parser.cjs +9 -0
  218. package/metro-svelte-transformer.cjs +156 -0
  219. 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
+ }
@@ -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,3 @@
1
+ // AccessibilityInfo (iOS) moved to @symbiote-native/engine. This thin re-export keeps @symbiote-native/svelte's
2
+ // surface identical; Metro selects the engine's accessibility-info.ios.ts on an iOS host.
3
+ export { AccessibilityInfo } 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;