@symbiote-native/vue 0.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +28 -13
  2. package/babel-jsx.cjs +52 -0
  3. package/build/components/activity-indicator-props.d.ts +5 -0
  4. package/build/components/activity-indicator-props.js +1 -0
  5. package/build/components/button-props.d.ts +5 -0
  6. package/build/components/button-props.js +1 -0
  7. package/build/components/flat-list/index.d.ts +3 -3
  8. package/build/components/flat-list/index.js +2 -2
  9. package/build/components/image-background-props.d.ts +7 -0
  10. package/build/components/image-background-props.js +1 -0
  11. package/build/components/image-props.d.ts +5 -0
  12. package/build/components/image-props.js +5 -0
  13. package/build/components/{input-accessory-view.d.ts → input-accessory-view-props.d.ts} +1 -3
  14. package/build/components/input-accessory-view-props.js +5 -0
  15. package/build/components/keyboard-avoiding-view.js +3 -3
  16. package/build/components/modal/index.js +1 -1
  17. package/build/components/pressable-props.d.ts +29 -0
  18. package/build/components/pressable-props.js +12 -0
  19. package/build/components/refresh-control-props.d.ts +16 -0
  20. package/build/components/refresh-control-props.js +9 -0
  21. package/build/components/safe-area-view-props.d.ts +6 -0
  22. package/build/components/safe-area-view-props.js +5 -0
  23. package/build/components/scroll-view/{shared.d.ts → scroll-view-props.d.ts} +4 -27
  24. package/build/components/scroll-view/scroll-view-props.js +1 -0
  25. package/build/components/section-list/index.d.ts +3 -3
  26. package/build/components/switch/switch-props.d.ts +6 -0
  27. package/build/components/switch/switch-props.js +1 -0
  28. package/build/components/text-input/text-input-props.d.ts +5 -0
  29. package/build/components/text-input/text-input-props.js +1 -0
  30. package/build/components/text-props.d.ts +24 -0
  31. package/build/components/text-props.js +6 -0
  32. package/build/components/touchable-native-feedback-props.d.ts +6 -0
  33. package/build/components/touchable-native-feedback-props.js +1 -0
  34. package/build/components/touchable-props.d.ts +15 -0
  35. package/build/components/touchable-props.js +1 -0
  36. package/build/components/touchable-without-feedback-props.d.ts +3 -0
  37. package/build/components/touchable-without-feedback-props.js +1 -0
  38. package/build/components/view-props.d.ts +29 -0
  39. package/build/components/view-props.js +5 -0
  40. package/build/components/virtualized-list/index.d.ts +3 -3
  41. package/build/components/virtualized-list/index.js +42 -37
  42. package/build/components/virtualized-section-list/index.d.ts +3 -3
  43. package/build/composables/use-raw-attrs.d.ts +1 -0
  44. package/build/composables/use-raw-attrs.js +26 -0
  45. package/build/descriptor-to-vue.js +2 -2
  46. package/build/host-instance/index.js +4 -5
  47. package/build/index.d.ts +25 -27
  48. package/build/index.js +35 -15
  49. package/build/intrinsic-elements.d.ts +19 -0
  50. package/build/intrinsic-elements.js +1 -0
  51. package/build/jsx-runtime.d.ts +67 -0
  52. package/build/jsx-runtime.js +1 -0
  53. package/build/modules/animated/create-animated-component.d.ts +1 -1
  54. package/build/modules/animated/create-animated-component.js +18 -4
  55. package/build/modules/animated/index.d.ts +3 -1
  56. package/build/modules/animated/index.js +20 -19
  57. package/build/modules/image/index.d.ts +3 -0
  58. package/build/modules/image/index.js +13 -0
  59. package/build/register.d.ts +1 -0
  60. package/build/register.js +15 -0
  61. package/build/renderer/index.js +112 -12
  62. package/build/runtime-helpers/index.d.ts +14 -1
  63. package/build/runtime-helpers/index.js +250 -9
  64. package/build/utils/normalize-attrs.d.ts +1 -0
  65. package/build/utils/normalize-attrs.js +21 -15
  66. package/intrinsic-tags.cjs +52 -0
  67. package/metro-css-parser.cjs +2 -1
  68. package/metro-vue-transformer.cjs +83 -13
  69. package/package.json +33 -8
  70. package/build/components/activity-indicator/index.android.d.ts +0 -4
  71. package/build/components/activity-indicator/index.android.js +0 -10
  72. package/build/components/activity-indicator/index.d.ts +0 -1
  73. package/build/components/activity-indicator/index.ios.d.ts +0 -4
  74. package/build/components/activity-indicator/index.ios.js +0 -10
  75. package/build/components/activity-indicator/index.js +0 -4
  76. package/build/components/activity-indicator/shared.d.ts +0 -8
  77. package/build/components/activity-indicator/shared.js +0 -48
  78. package/build/components/button.d.ts +0 -14
  79. package/build/components/button.js +0 -59
  80. package/build/components/image-background.d.ts +0 -9
  81. package/build/components/image-background.js +0 -103
  82. package/build/components/image.d.ts +0 -9
  83. package/build/components/image.js +0 -90
  84. package/build/components/input-accessory-view.js +0 -41
  85. package/build/components/pressable.d.ts +0 -58
  86. package/build/components/pressable.js +0 -214
  87. package/build/components/refresh-control.d.ts +0 -20
  88. package/build/components/refresh-control.js +0 -47
  89. package/build/components/safe-area-view.d.ts +0 -8
  90. package/build/components/safe-area-view.js +0 -33
  91. package/build/components/scroll-view/index.android.d.ts +0 -4
  92. package/build/components/scroll-view/index.android.js +0 -64
  93. package/build/components/scroll-view/index.d.ts +0 -1
  94. package/build/components/scroll-view/index.ios.d.ts +0 -4
  95. package/build/components/scroll-view/index.ios.js +0 -17
  96. package/build/components/scroll-view/index.js +0 -4
  97. package/build/components/scroll-view/shared.js +0 -271
  98. package/build/components/scroll-view/sticky-header.d.ts +0 -7
  99. package/build/components/scroll-view/sticky-header.js +0 -208
  100. package/build/components/switch/index.android.d.ts +0 -12
  101. package/build/components/switch/index.android.js +0 -13
  102. package/build/components/switch/index.d.ts +0 -2
  103. package/build/components/switch/index.ios.d.ts +0 -12
  104. package/build/components/switch/index.ios.js +0 -11
  105. package/build/components/switch/index.js +0 -5
  106. package/build/components/switch/shared.d.ts +0 -23
  107. package/build/components/switch/shared.js +0 -126
  108. package/build/components/text-input/index.d.ts +0 -24
  109. package/build/components/text-input/index.js +0 -242
  110. package/build/components/touchable-native-feedback.d.ts +0 -24
  111. package/build/components/touchable-native-feedback.js +0 -77
  112. package/build/components/touchable.d.ts +0 -50
  113. package/build/components/touchable.js +0 -278
  114. package/build/components.d.ts +0 -51
  115. package/build/components.js +0 -29
@@ -1 +1,2 @@
1
+ export declare function normalizeVueAttrKey(key: string): string;
1
2
  export declare function normalizeVueAttrs(attrs: Record<string, unknown>): Record<string, unknown>;
@@ -12,21 +12,27 @@ const KEBAB_SEGMENT = /-([a-z])/g;
12
12
  function toCamel(key) {
13
13
  return key.replace(KEBAB_SEGMENT, (_match, char) => char.toUpperCase());
14
14
  }
15
+ // The per-KEY half, for the path that never sees a whole attrs bag: a host primitive lowered to
16
+ // its intrinsic tag by the SFC transformer reaches the renderer one patchProp call at a time,
17
+ // with no component in between to fold the bag. Returns the key unchanged (same string identity)
18
+ // whenever there is nothing to convert, which is every key on the hot path.
19
+ export function normalizeVueAttrKey(key) {
20
+ if (!key.includes('-'))
21
+ return key;
22
+ if (key.startsWith('aria-') || key.startsWith('data-'))
23
+ return key;
24
+ return toCamel(key);
25
+ }
26
+ // Always returns a PLAIN copy, never the input. An earlier version handed the input back when no
27
+ // key needed converting - which is every SFC/TSX bag, since `@press` / `:style` already arrive
28
+ // camel - and that gave callers Vue's attrs PROXY to read from. In production, not just dev, that
29
+ // proxy's get trap is `track(target, "get", "")` before every value
30
+ // (runtime-core.esm-bundler.js:8357), so each of Pressable's ~16 per-render attr reads paid two
31
+ // map lookups it did not need. The copy loop reads every key through the trap once regardless, so
32
+ // the only thing the early return ever saved was this one object.
15
33
  export function normalizeVueAttrs(attrs) {
16
- let changed = false;
17
34
  const out = {};
18
- for (const key of Object.keys(attrs)) {
19
- if (key.includes('-') &&
20
- !key.startsWith('aria-') &&
21
- !key.startsWith('data-')) {
22
- out[toCamel(key)] = attrs[key];
23
- changed = true;
24
- }
25
- else {
26
- out[key] = attrs[key];
27
- }
28
- }
29
- // Return the original object when nothing converted (the already-camel / TSX path): avoids a
30
- // per-render allocation and keeps attrs identity stable.
31
- return changed ? out : attrs;
35
+ for (const key of Object.keys(attrs))
36
+ out[normalizeVueAttrKey(key)] = attrs[key];
37
+ return out;
32
38
  }
@@ -0,0 +1,52 @@
1
+ // Every tag both Vue compilers must treat as an ELEMENT rather than as a component to resolve.
2
+ //
3
+ // Vue decides element-vs-component in two unrelated places — `@vue/compiler-sfc`'s
4
+ // `isCustomElement` and `@vue/babel-plugin-jsx`'s option of the same name — so the answer has to
5
+ // come from one set or the two paths drift. That drift is not loud: a tag Vue takes for a component
6
+ // compiles to `resolveComponent("text-input")` with its children as a slot the element path never
7
+ // reads, which renders a blank subtree with no error.
8
+ //
9
+ // DERIVED, never enumerated. Until 2026-09-07 this was the prefix test `tag.startsWith('symbiote-')`
10
+ // in ./babel-jsx.cjs — correct while every intrinsic carried that marker, and answering FALSE for
11
+ // every tag since the prefix was dropped (`core/components/src/component-names/shared.ts` says why
12
+ // it went). What hid it is the tag alphabet: `view` / `text` / `image` / `switch` are real SVG
13
+ // element names, so both compilers resolve those four as elements with no configuration at all, and
14
+ // only the hyphenated half degraded.
15
+ //
16
+ // SCOPE, stated because it is smaller than `ISymbioteIntrinsic`. That union also holds
17
+ // `scroll-view`, `modal`, `activity-indicator` and the rest, but it is a TypeScript type and these
18
+ // consumers are Babel/Metro plugins that run before TS exists. `HOST_PRIMITIVES` is the only
19
+ // runtime-readable table reachable from here, so a hand-written `<scroll-view>` still resolves as a
20
+ // component. Closing that needs a CJS intrinsic table in `core/components`.
21
+ //
22
+ // WHAT THAT GAP COSTS, measured 2026-09-11 rather than reasoned, because the first guess was that
23
+ // the tag simply would not work. It works: `resolveComponent` falls back to the tag STRING, and
24
+ // `normalizeChildren` then unwraps the `withCtx` default slot for an element shapeFlag, so
25
+ // `<scroll-view><text>hi</text></scroll-view>` committed `RCTView > RCTScrollView > RCTText >
26
+ // RCTRawText`. What it costs is a dev-mode `[Vue warn]: Failed to resolve component: scroll-view`
27
+ // on every such element plus the component codegen path (a slot closure per element) instead of
28
+ // `_createElementBlock`. That is a divergence from every other tag, so `ScrollView`,
29
+ // `TouchableOpacity` and `TouchableHighlight` stay COMPONENTS on Vue until their
30
+ // `HOST_PRIMITIVES` entries land — and `intrinsic-elements.ts` already types all three as valid
31
+ // markup off `ISymbioteIntrinsic`, so vue-tsc accepts what the runtime compiler warns about.
32
+ //
33
+ // The tell that the three are still wrapped rather than merely unlisted: `src/register.ts` does
34
+ // NOT call their behaviors, because a registered behavior plus a surviving wrapper is two owners
35
+ // on one node. Those two facts move together or not at all.
36
+ //
37
+ // .cjs, and its own file rather than a copy in each consumer: two transforms carrying one
38
+ // derivation is the drift the shared spec exists to prevent.
39
+
40
+ const {
41
+ HOST_PRIMITIVES,
42
+ } = require('@symbiote-native/components/host-primitives');
43
+
44
+ // BOTH tags a spec entry can emit. A primitive with an `intrinsicWhen` selects between two native
45
+ // views by one prop, so its second intrinsic is as hand-writable as its first.
46
+ module.exports = new Set(
47
+ Object.values(HOST_PRIMITIVES).flatMap(entry =>
48
+ entry.intrinsicWhen === undefined
49
+ ? [entry.intrinsic]
50
+ : [entry.intrinsic, entry.intrinsicWhen.intrinsic],
51
+ ),
52
+ );
@@ -9,4 +9,5 @@
9
9
  // directly instead, since it needs the individual parse/compile functions, not a Metro transformer
10
10
  // object. createCssMetroTransformer is a factory — babelTransformerPath needs the actual
11
11
  // {transform, getCacheKey} object it returns, not the css-parser package barrel.
12
- module.exports = require('@symbiote-native/css-parser').createCssMetroTransformer();
12
+ module.exports =
13
+ require('@symbiote-native/css-parser').createCssMetroTransformer();
@@ -11,7 +11,12 @@
11
11
  // babelTransformerPath at it.
12
12
 
13
13
  const nodeFs = require('fs');
14
- const { parse, compileScript, registerTS } = require('@vue/compiler-sfc');
14
+ const {
15
+ parse,
16
+ parseCache,
17
+ compileScript,
18
+ registerTS,
19
+ } = require('@vue/compiler-sfc');
15
20
  const { createCompoundExpression } = require('@vue/compiler-core');
16
21
 
17
22
  // A bare-specifier type import (`import type { X } from '@symbiote-native/navigation/vue'`) needs
@@ -109,6 +114,39 @@ function createScopeClassNodeTransform(renames) {
109
114
  };
110
115
  }
111
116
 
117
+ // The parser's own condense() collapses a text node's multi-line whitespace to a single boundary
118
+ // space but never trims it: `<text>\n plain\n</text>` compiles to " plain " instead of "plain" -
119
+ // a real leading/trailing space on the rendered RN Text. Babel's JSX whitespace cleaner
120
+ // (cleanJSXElementLiteralChild, used by every other adapter) DOES trim this; Vue's does not, so we
121
+ // do it here, once, for every template. Matches Babel's own rule: only a text node whose SOURCE
122
+ // crosses a line break is touched, so a genuinely single-line `<text>Score: {{ x }}</text>` keeps
123
+ // its intentional trailing space untouched (see examples/vue-sfc's CompoundClassDemo.vue for the
124
+ // device-measured bug this closes).
125
+ function trimReflowedTextNodeTransform(node) {
126
+ if (node.type !== 1 /* NodeTypes.ELEMENT */ || node.children.length === 0)
127
+ return;
128
+ const first = node.children[0];
129
+ if (
130
+ first.type === 2 /* NodeTypes.TEXT */ &&
131
+ first.loc.source.includes('\n') &&
132
+ first.content.startsWith(' ')
133
+ ) {
134
+ first.content = first.content.slice(1);
135
+ }
136
+ const last = node.children[node.children.length - 1];
137
+ if (
138
+ last.type === 2 /* NodeTypes.TEXT */ &&
139
+ last.loc.source.includes('\n') &&
140
+ last.content.endsWith(' ')
141
+ ) {
142
+ last.content = last.content.slice(0, -1);
143
+ }
144
+ }
145
+
146
+ // Shared with ./babel-jsx.cjs: Vue's two compilers must give one answer to element-vs-component.
147
+ const INTRINSIC_TAGS = require('./intrinsic-tags.cjs');
148
+
149
+
112
150
  // A short, stable id per file, used as the SFC scope id regardless of whether the file has
113
151
  // scoped styles - built on css-parser's shared hashFilePath so the algorithm isn't duplicated
114
152
  // against the standalone .module.css compiler's identical need.
@@ -177,7 +215,31 @@ async function compileStyleBlockContent(style, filename) {
177
215
  }
178
216
 
179
217
  async function compileSfc(src, filename) {
180
- const { descriptor, errors } = parse(src, { filename });
218
+ // `parse` memoizes its descriptor on (source, filename) in a module-global LRU, and the node
219
+ // scope-class transform below MUTATES that descriptor's template AST in place, replacing
220
+ // `prop.exp`. Handing the same object to a second compile therefore walks a half-transformed
221
+ // tree and generation dies with `Codegen node is missing for element/if/for node`.
222
+ //
223
+ // Metro compiles each file once per build, so the cache buys this caller nothing; the only place
224
+ // it was ever exercised is css-parser's golden-corpus determinism check, which compiles one
225
+ // source twice on purpose. That is the ONLY test anywhere that can see this, which is why a
226
+ // transform bug surfaced as a failure in another package's corpus.
227
+ //
228
+ // `clear()` rather than deleting our one key: the key is `source + JSON.stringify(options)`
229
+ // (`@vue/shared`'s genCacheKey), so reproducing it here would couple this file to an internal
230
+ // format across every Vue bump. Clearing a pure memo is always safe — the only cost is a
231
+ // re-parse, which is what we need anyway.
232
+
233
+ parseCache.clear();
234
+ // element-vs-component is decided by the PARSER, not by the later `isCustomElement` in
235
+ // templateOptions — `compileScript` reuses this descriptor's already-parsed AST, where `tagType`
236
+ // is already fixed. So a hand-written `<pressable>` needs the answer here or it stays a component
237
+ // whatever templateOptions says, which is how it read until 2026-09-07:
238
+ // `resolveComponent("pressable")`, a blank subtree with no error.
239
+ const { descriptor, errors } = parse(src, {
240
+ filename,
241
+ templateParseOptions: { isCustomElement: tag => INTRINSIC_TAGS.has(tag) },
242
+ });
181
243
  if (errors && errors.length > 0) {
182
244
  throw new Error(
183
245
  `Vue SFC parse error in ${filename}:\n${errors.map(String).join('\n')}`,
@@ -243,16 +305,24 @@ async function compileSfc(src, filename) {
243
305
  }
244
306
  }
245
307
 
246
- // Skipped entirely (not even passed to the compiler) when nothing in this file is scoped, so
247
- // a .vue with only unscoped/no styles compiles with zero added runtime cost.
248
- const templateOptions =
249
- scopedClassNames.size > 0
250
- ? {
251
- compilerOptions: {
252
- nodeTransforms: [createScopeClassNodeTransform(scopedClassNames)],
253
- },
254
- }
255
- : undefined;
308
+ // Scoped-class rewriting is skipped entirely (not even passed to the compiler) when nothing in
309
+ // this file is scoped, so a .vue with only unscoped/no styles adds no runtime cost.
310
+ const nodeTransforms = [trimReflowedTextNodeTransform];
311
+ if (scopedClassNames.size > 0)
312
+ nodeTransforms.push(createScopeClassNodeTransform(scopedClassNames));
313
+ // UNCONDITIONAL, and covering EVERY intrinsic rather than the ones this file happens to import.
314
+ // Both narrowings were live until 2026-09-07 and both broke a hand-written tag: a file importing
315
+ // no wrapper got no `isCustomElement` at all, and a file importing one got an answer scoped to
316
+ // that import, so `<pressable>` written by hand compiled to `resolveComponent("pressable")` —
317
+ // a blank subtree with no error — whichever way the file was written. `<switch v-model>` failed
318
+ // louder: `@vue/compiler-dom`'s transformModel rejects v-model on an element that is neither
319
+ // input/textarea/select nor a custom element, so it was a hard compile error.
320
+ const templateOptions = {
321
+ compilerOptions: {
322
+ ...(nodeTransforms.length > 0 ? { nodeTransforms } : {}),
323
+ isCustomElement: tag => INTRINSIC_TAGS.has(tag),
324
+ },
325
+ };
256
326
 
257
327
  // inlineTemplate folds the <template> render fn into setup(): one module, one `export
258
328
  // default`. Only valid with <script setup>, which the canary uses.
@@ -303,7 +373,7 @@ async function compileSfc(src, filename) {
303
373
  preamble.push(`const ${bindingName} = ${JSON.stringify(classMap)};`);
304
374
  }
305
375
 
306
- const parts = [...preamble, code];
376
+ const parts = [preamble.join('\n'), code];
307
377
  if (hasCssModules) {
308
378
  const bindings = [...cssModuleBindings.keys()]
309
379
  .map(name => `${JSON.stringify(name)}: ${name}`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbiote-native/vue",
3
- "version": "0.5.0",
3
+ "version": "2.0.0",
4
4
  "description": "SymbioteNative's Vue adapter — a @vue/runtime-core createRenderer driving real native iOS/Android views through the same engine as the React adapter.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -13,6 +13,18 @@
13
13
  "url": "https://github.com/OneEyed1366/symbiote-native/issues"
14
14
  },
15
15
  "author": "Andrey Prokopenko <psevdoproger@gmail.com>",
16
+ "keywords": [
17
+ "react-native",
18
+ "symbiote-native",
19
+ "vue",
20
+ "vue3",
21
+ "fabric",
22
+ "renderer",
23
+ "cross-platform",
24
+ "mobile",
25
+ "ios",
26
+ "android"
27
+ ],
16
28
  "type": "module",
17
29
  "main": "./build/index.js",
18
30
  "module": "./build/index.js",
@@ -31,10 +43,21 @@
31
43
  "default": "./build/runtime-helpers/index.js"
32
44
  },
33
45
  "./metro-css-parser": "./metro-css-parser.cjs",
34
- "./metro-vue-transformer": "./metro-vue-transformer.cjs"
46
+ "./metro-vue-transformer": "./metro-vue-transformer.cjs",
47
+ "./babel-jsx": "./babel-jsx.cjs",
48
+ "./jsx-runtime": {
49
+ "types": "./build/jsx-runtime.d.ts",
50
+ "default": "./build/jsx-runtime.js"
51
+ },
52
+ "./jsx-dev-runtime": {
53
+ "types": "./build/jsx-runtime.d.ts",
54
+ "default": "./build/jsx-runtime.js"
55
+ }
35
56
  },
36
57
  "files": [
58
+ "babel-jsx.cjs",
37
59
  "build",
60
+ "intrinsic-tags.cjs",
38
61
  "metro-css-parser.cjs",
39
62
  "metro-vue-transformer.cjs"
40
63
  ],
@@ -42,21 +65,23 @@
42
65
  "access": "public"
43
66
  },
44
67
  "dependencies": {
68
+ "@vue/babel-plugin-jsx": "^1.5.0",
45
69
  "@vue/compiler-core": "^3.5.13",
46
70
  "@vue/compiler-sfc": "^3.5.13",
47
71
  "@vue/runtime-core": "^3.5.13",
48
72
  "typescript": "~6.0.0",
49
- "@symbiote-native/components": "0.5.0",
50
- "@symbiote-native/css-parser": "0.4.0"
73
+ "@symbiote-native/components": "2.0.0",
74
+ "@symbiote-native/css-parser": "0.5.0"
51
75
  },
52
76
  "peerDependencies": {
53
- "@symbiote-native/engine": ">=0.1.7",
54
77
  "vue": ">=3.5.0",
55
- "react-native": ">=0.86"
78
+ "react-native": ">=0.86",
79
+ "@symbiote-native/engine": "^0.5.0"
56
80
  },
57
81
  "devDependencies": {
58
- "@symbiote-native/engine": "0.3.0",
59
- "@symbiote-native/test-utils": "0.2.0"
82
+ "@babel/core": "^7.25.2",
83
+ "@symbiote-native/engine": "0.5.0",
84
+ "@symbiote-native/test-utils": "0.3.0"
60
85
  },
61
86
  "scripts": {
62
87
  "typecheck": "tsc --build",
@@ -1,4 +0,0 @@
1
- export type { IActivityIndicatorProps } from './shared';
2
- export declare const ActivityIndicator: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
3
- [key: string]: any;
4
- }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -1,10 +0,0 @@
1
- // ActivityIndicator on Android: AndroidProgressBar needs `styleAttr` (it drives the
2
- // ProgressBar's setStyle(); without it the view throws "setStyle() not called") and
3
- // `indeterminate: true`, and its default color is the theme (null). Metro picks this on an
4
- // Android host; no Platform.OS read. Mirrors the React adapter's Android binding.
5
- import { createActivityIndicator } from './shared.js';
6
- export const ActivityIndicator = createActivityIndicator({
7
- // RN: `color = Platform.OS === 'ios' ? GRAY : null`. Android lets the theme color it.
8
- defaultColor: null,
9
- nativeExtras: { styleAttr: 'Normal', indeterminate: true },
10
- });
@@ -1 +0,0 @@
1
- export * from './index.ios';
@@ -1,4 +0,0 @@
1
- export type { IActivityIndicatorProps } from './shared';
2
- export declare const ActivityIndicator: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
3
- [key: string]: any;
4
- }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -1,10 +0,0 @@
1
- // ActivityIndicator on iOS: RCTActivityIndicatorView takes the size enum + a GRAY default
2
- // color and no extra native props. Also the base (activity-indicator.ts re-exports it) for
3
- // headless / web. Mirrors the React adapter's iOS binding.
4
- import { createActivityIndicator } from './shared.js';
5
- // RN's iOS default spinner color (Libraries/.../ActivityIndicator.js GRAY).
6
- const IOS_DEFAULT_COLOR = '#999999';
7
- export const ActivityIndicator = createActivityIndicator({
8
- defaultColor: IOS_DEFAULT_COLOR,
9
- nativeExtras: {},
10
- });
@@ -1,4 +0,0 @@
1
- // Base / default ActivityIndicator. Re-exports the iOS build. Metro overrides this with
2
- // activity-indicator.ios.ts / .android.ts on a real host; under tsx / tsc / web the host
3
- // resolves here. Filename is the selector, no Platform.OS read.
4
- export * from './index.ios.js';
@@ -1,8 +0,0 @@
1
- import type { IActivityIndicatorPlatform, IActivityIndicatorProps as IActivityIndicatorBaseProps } from '@symbiote-native/components';
2
- import type { IClassNameValue } from '@symbiote-native/engine';
3
- export type IActivityIndicatorProps = IActivityIndicatorBaseProps & {
4
- class?: IClassNameValue;
5
- };
6
- export declare function createActivityIndicator(platform: IActivityIndicatorPlatform): import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
7
- [key: string]: any;
8
- }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -1,48 +0,0 @@
1
- // ActivityIndicator, the Vue lifecycle half. The render (size translation, wrapper +
2
- // spinner, color omission) lives framework-agnostic in @symbiote-native/components and is shared
3
- // verbatim with the React adapter; here Vue only normalizes inputs, calls the render fn,
4
- // and bridges the Descriptor to a vnode. No reactivity of its own; this component is
5
- // render-only (the spinner animates natively).
6
- //
7
- // Inputs arrive as attrs, not a typed props block, the same passthrough shape as
8
- // components.ts. RN's per-platform bits (iOS GRAY default; Android theme/null + styleAttr +
9
- // indeterminate) are supplied by the .ios/.android files via `IActivityIndicatorPlatform`.
10
- import { defineComponent } from '@vue/runtime-core';
11
- import { renderActivityIndicator } from '@symbiote-native/components';
12
- import { descriptorToVue } from '../../descriptor-to-vue.js';
13
- import { normalizeVueAttrs } from '../../utils/normalize-attrs.js';
14
- function normalizeSize(size) {
15
- if (size === 'large')
16
- return 'large';
17
- if (typeof size === 'number')
18
- return size;
19
- return 'small';
20
- }
21
- // Narrow attrs.style to a plain ViewStyle object (assignable to the render fn's StyleProp
22
- // param) without a cast. Array/registered styles degrade to undefined; the engine's own
23
- // flatten handles those when an app passes them; the wrapper only needs the object form.
24
- function isViewStyleObject(value) {
25
- return typeof value === 'object' && value !== null && !Array.isArray(value);
26
- }
27
- export function createActivityIndicator(platform) {
28
- return defineComponent({
29
- name: 'ActivityIndicator',
30
- inheritAttrs: false,
31
- setup(_props, { attrs: rawAttrs }) {
32
- return () => {
33
- // Defaults match RN (animating / hidesWhenStopped true, size 'small'); the rest of
34
- // attrs (testID, accessibility, onLayout) forwards onto the wrapper via passthrough.
35
- const attrs = normalizeVueAttrs(rawAttrs);
36
- const { animating, color, hidesWhenStopped, size, style, ...passthrough } = attrs;
37
- return descriptorToVue(renderActivityIndicator({
38
- animating: animating !== false,
39
- hidesWhenStopped: hidesWhenStopped !== false,
40
- size: normalizeSize(size),
41
- color: typeof color === 'string' ? color : undefined,
42
- style: isViewStyleObject(style) ? style : undefined,
43
- passthrough,
44
- }, platform));
45
- };
46
- },
47
- });
48
- }
@@ -1,14 +0,0 @@
1
- import { type IButtonProps as ICoreButtonProps } from '@symbiote-native/components';
2
- import type { IClassNameValue, ISymbioteEvent } from '@symbiote-native/engine';
3
- export type IButtonProps = Omit<ICoreButtonProps, 'onPress'> & {
4
- class?: IClassNameValue;
5
- };
6
- type IButtonEmits = {
7
- press: (event: ISymbioteEvent) => boolean;
8
- };
9
- export declare const Button: import("vue").DefineSetupFnComponent<IButtonProps, IButtonEmits, {}, Omit<ICoreButtonProps, "onPress"> & {
10
- class?: IClassNameValue;
11
- } & {
12
- onPress?: ((event: ISymbioteEvent) => any) | undefined;
13
- }, import("vue").PublicProps>;
14
- export {};
@@ -1,59 +0,0 @@
1
- // Button for Vue. The minimal cross-platform button in RN's iOS shape (Button.js): a
2
- // TouchableOpacity wrapping a Text. The base text style, the role constant, and the color fold are
3
- // shared in @symbiote-native/components/view; here Vue only composes its TouchableOpacity + Text and
4
- // forwards the native-only props. The Vue twin of the React adapter's Button.
5
- import { defineComponent, h } from '@vue/runtime-core';
6
- import { BUTTON_ACCESSIBILITY_ROLE, resolveButtonTextStyle, } from '@symbiote-native/components';
7
- import { Text } from '../components.js';
8
- import { TouchableOpacity } from './touchable.js';
9
- import { normalizeVueAttrs } from '../utils/normalize-attrs.js';
10
- // The props Button consumes / re-maps itself; everything else (accessibility, aria, TV-focus,
11
- // testID, nativeID) forwards to the TouchableOpacity. `title` becomes the Text child; onPress and
12
- // disabled re-map; touchSoundDisabled maps to the pressable's android_disableSound.
13
- const HANDLED = [
14
- 'title',
15
- 'color',
16
- 'touchSoundDisabled',
17
- 'accessibilityRole',
18
- 'accessible',
19
- 'accessibilityState',
20
- ];
21
- function forwardAttrs(attrs) {
22
- const result = {};
23
- for (const key of Object.keys(attrs)) {
24
- if (!HANDLED.includes(key))
25
- result[key] = attrs[key];
26
- }
27
- return result;
28
- }
29
- export const Button = defineComponent((_props, { attrs: rawAttrs, emit }) => {
30
- return () => {
31
- const attrs = normalizeVueAttrs(rawAttrs);
32
- const title = typeof attrs.title === 'string' ? attrs.title : '';
33
- const color = typeof attrs.color === 'string' ? attrs.color : undefined;
34
- const disabled = attrs.disabled === true ? true : undefined;
35
- const touchSoundDisabled = attrs.touchSoundDisabled === true ? true : undefined;
36
- const textStyle = resolveButtonTextStyle(color, disabled);
37
- // RN's Button sets role=button, is accessible, and propagates the disabled accessibility
38
- // state. The caller's props pass through, but Button's fixed role / accessible / disabled-
39
- // state win, applied after the forwarded spread. touchSoundDisabled → android_disableSound.
40
- const touchableProps = {
41
- ...forwardAttrs(attrs),
42
- disabled,
43
- android_disableSound: touchSoundDisabled,
44
- accessibilityRole: BUTTON_ACCESSIBILITY_ROLE,
45
- accessible: true,
46
- accessibilityState: { disabled },
47
- onPress: (event) => emit('press', event),
48
- };
49
- return h(TouchableOpacity, touchableProps, {
50
- default: () => [h(Text, { style: textStyle }, () => title)],
51
- });
52
- };
53
- }, {
54
- name: 'Button',
55
- inheritAttrs: false,
56
- emits: {
57
- press: (_event) => true,
58
- },
59
- });
@@ -1,9 +0,0 @@
1
- import { type FunctionalComponent } from '@vue/runtime-core';
2
- import { type IImageProps } from '@symbiote-native/components';
3
- import { type IClassNameValue, type IStyleProp, type IViewStyle } from '@symbiote-native/engine';
4
- export interface IImageBackgroundProps extends Omit<IImageProps, 'style'> {
5
- style?: IStyleProp<IViewStyle>;
6
- imageStyle?: IStyleProp<IViewStyle> | string;
7
- class?: IClassNameValue;
8
- }
9
- export declare const ImageBackground: FunctionalComponent<{}, {}, any, {}>;
@@ -1,103 +0,0 @@
1
- // ImageBackground: the Vue lifecycle half. The composition (the absolute-fill Image behind the
2
- // children, the dimension-proxy + style-merge math) lives framework-agnostic in
3
- // @symbiote-native/components/renderImageBackground, shared verbatim with React; Vue narrows the
4
- // untyped attrs into the typed Image view, folds aria/role, bridges the Descriptor to vnodes, and
5
- // appends the slot children ON TOP of the inner image.
6
- //
7
- // FUNCTIONAL, not a stateful defineComponent: render-only, no state.
8
- import { h } from '@vue/runtime-core';
9
- import { renderImageBackground, resolveAccessibilityProps, } from '@symbiote-native/components';
10
- import { resolveClassName, } from '@symbiote-native/engine';
11
- import { descriptorToVue } from '../descriptor-to-vue.js';
12
- import { normalizeVueAttrs } from '../utils/normalize-attrs.js';
13
- function asString(value) {
14
- return typeof value === 'string' ? value : undefined;
15
- }
16
- function asNumber(value) {
17
- return typeof value === 'number' ? value : undefined;
18
- }
19
- function asSource(value) {
20
- if (typeof value === 'number')
21
- return value;
22
- if (typeof value === 'object' && value !== null)
23
- return value;
24
- return undefined;
25
- }
26
- function isResizeMode(value) {
27
- return (value === 'cover' ||
28
- value === 'contain' ||
29
- value === 'stretch' ||
30
- value === 'repeat' ||
31
- value === 'center');
32
- }
33
- function asResizeMode(value) {
34
- return isResizeMode(value) ? value : undefined;
35
- }
36
- function asCrossOrigin(value) {
37
- return value === 'anonymous' || value === 'use-credentials'
38
- ? value
39
- : undefined;
40
- }
41
- function isStyleProp(value) {
42
- return typeof value === 'object' && value !== null;
43
- }
44
- function toChildVNode(child) {
45
- return typeof child === 'string' ? child : descriptorToVue(child);
46
- }
47
- const HANDLED_ATTRS = [
48
- 'style',
49
- 'imageStyle',
50
- 'class',
51
- 'source',
52
- 'defaultSource',
53
- 'loadingIndicatorSource',
54
- 'resizeMode',
55
- 'tintColor',
56
- 'src',
57
- 'srcSet',
58
- 'alt',
59
- 'width',
60
- 'height',
61
- 'crossOrigin',
62
- 'referrerPolicy',
63
- ];
64
- function forwardAttrs(attrs) {
65
- const result = {};
66
- for (const key of Object.keys(attrs)) {
67
- if (!HANDLED_ATTRS.includes(key))
68
- result[key] = attrs[key];
69
- }
70
- return result;
71
- }
72
- const ImageBackgroundComponent = (_props, { attrs: rawAttrs, slots }) => {
73
- const attrs = normalizeVueAttrs(rawAttrs);
74
- const wrapper = renderImageBackground({
75
- style: isStyleProp(attrs.style) ? attrs.style : undefined,
76
- imageStyle: typeof attrs.imageStyle === 'string'
77
- ? resolveClassName(attrs.imageStyle)
78
- : isStyleProp(attrs.imageStyle)
79
- ? attrs.imageStyle
80
- : undefined,
81
- image: {
82
- source: asSource(attrs.source),
83
- defaultSource: asSource(attrs.defaultSource),
84
- loadingIndicatorSource: asSource(attrs.loadingIndicatorSource),
85
- resizeMode: asResizeMode(attrs.resizeMode),
86
- tintColor: asString(attrs.tintColor),
87
- src: asString(attrs.src),
88
- srcSet: asString(attrs.srcSet),
89
- alt: asString(attrs.alt),
90
- width: asNumber(attrs.width),
91
- height: asNumber(attrs.height),
92
- crossOrigin: asCrossOrigin(attrs.crossOrigin),
93
- referrerPolicy: asString(attrs.referrerPolicy),
94
- passthrough: resolveAccessibilityProps(forwardAttrs(attrs)),
95
- },
96
- });
97
- // wrapper = symbiote-view > [imageDescriptor]; the slot children paint AFTER the image (on top).
98
- const slotChildren = slots.default !== undefined ? slots.default() : [];
99
- return h(wrapper.type, { ...wrapper.props, key: wrapper.key, class: attrs.class }, [...wrapper.children.map(toChildVNode), ...slotChildren]);
100
- };
101
- ImageBackgroundComponent.displayName = 'ImageBackground';
102
- ImageBackgroundComponent.inheritAttrs = false;
103
- export const ImageBackground = ImageBackgroundComponent;
@@ -1,9 +0,0 @@
1
- import type { FunctionalComponent } from '@vue/runtime-core';
2
- import { type IImageProps as IImageBaseProps, type IImageStatics } from '@symbiote-native/components';
3
- import type { IClassNameValue } from '@symbiote-native/engine';
4
- export { setImageSourceResolver } from '@symbiote-native/components';
5
- export type { IImageSource, IImageSourceProp, IResizeMode, IImageSize, IImageCacheStatus, } from '@symbiote-native/components';
6
- export type IImageProps = IImageBaseProps & {
7
- class?: IClassNameValue;
8
- };
9
- export declare const Image: FunctionalComponent<IImageProps> & IImageStatics;