@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.
- package/README.md +28 -13
- package/babel-jsx.cjs +52 -0
- package/build/components/activity-indicator-props.d.ts +5 -0
- package/build/components/activity-indicator-props.js +1 -0
- package/build/components/button-props.d.ts +5 -0
- package/build/components/button-props.js +1 -0
- package/build/components/flat-list/index.d.ts +3 -3
- package/build/components/flat-list/index.js +2 -2
- package/build/components/image-background-props.d.ts +7 -0
- package/build/components/image-background-props.js +1 -0
- package/build/components/image-props.d.ts +5 -0
- package/build/components/image-props.js +5 -0
- package/build/components/{input-accessory-view.d.ts → input-accessory-view-props.d.ts} +1 -3
- package/build/components/input-accessory-view-props.js +5 -0
- package/build/components/keyboard-avoiding-view.js +3 -3
- package/build/components/modal/index.js +1 -1
- package/build/components/pressable-props.d.ts +29 -0
- package/build/components/pressable-props.js +12 -0
- package/build/components/refresh-control-props.d.ts +16 -0
- package/build/components/refresh-control-props.js +9 -0
- package/build/components/safe-area-view-props.d.ts +6 -0
- package/build/components/safe-area-view-props.js +5 -0
- package/build/components/scroll-view/{shared.d.ts → scroll-view-props.d.ts} +4 -27
- package/build/components/scroll-view/scroll-view-props.js +1 -0
- package/build/components/section-list/index.d.ts +3 -3
- package/build/components/switch/switch-props.d.ts +6 -0
- package/build/components/switch/switch-props.js +1 -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 +24 -0
- package/build/components/text-props.js +6 -0
- package/build/components/touchable-native-feedback-props.d.ts +6 -0
- package/build/components/touchable-native-feedback-props.js +1 -0
- package/build/components/touchable-props.d.ts +15 -0
- package/build/components/touchable-props.js +1 -0
- package/build/components/touchable-without-feedback-props.d.ts +3 -0
- package/build/components/touchable-without-feedback-props.js +1 -0
- package/build/components/view-props.d.ts +29 -0
- package/build/components/view-props.js +5 -0
- package/build/components/virtualized-list/index.d.ts +3 -3
- package/build/components/virtualized-list/index.js +42 -37
- package/build/components/virtualized-section-list/index.d.ts +3 -3
- package/build/composables/use-raw-attrs.d.ts +1 -0
- package/build/composables/use-raw-attrs.js +26 -0
- package/build/descriptor-to-vue.js +2 -2
- package/build/host-instance/index.js +4 -5
- package/build/index.d.ts +25 -27
- package/build/index.js +35 -15
- package/build/intrinsic-elements.d.ts +19 -0
- package/build/intrinsic-elements.js +1 -0
- package/build/jsx-runtime.d.ts +67 -0
- package/build/jsx-runtime.js +1 -0
- package/build/modules/animated/create-animated-component.d.ts +1 -1
- package/build/modules/animated/create-animated-component.js +18 -4
- package/build/modules/animated/index.d.ts +3 -1
- package/build/modules/animated/index.js +20 -19
- package/build/modules/image/index.d.ts +3 -0
- package/build/modules/image/index.js +13 -0
- package/build/register.d.ts +1 -0
- package/build/register.js +15 -0
- package/build/renderer/index.js +112 -12
- package/build/runtime-helpers/index.d.ts +14 -1
- package/build/runtime-helpers/index.js +250 -9
- package/build/utils/normalize-attrs.d.ts +1 -0
- package/build/utils/normalize-attrs.js +21 -15
- package/intrinsic-tags.cjs +52 -0
- package/metro-css-parser.cjs +2 -1
- package/metro-vue-transformer.cjs +83 -13
- package/package.json +33 -8
- package/build/components/activity-indicator/index.android.d.ts +0 -4
- package/build/components/activity-indicator/index.android.js +0 -10
- package/build/components/activity-indicator/index.d.ts +0 -1
- package/build/components/activity-indicator/index.ios.d.ts +0 -4
- package/build/components/activity-indicator/index.ios.js +0 -10
- package/build/components/activity-indicator/index.js +0 -4
- package/build/components/activity-indicator/shared.d.ts +0 -8
- package/build/components/activity-indicator/shared.js +0 -48
- package/build/components/button.d.ts +0 -14
- package/build/components/button.js +0 -59
- package/build/components/image-background.d.ts +0 -9
- package/build/components/image-background.js +0 -103
- package/build/components/image.d.ts +0 -9
- package/build/components/image.js +0 -90
- package/build/components/input-accessory-view.js +0 -41
- package/build/components/pressable.d.ts +0 -58
- package/build/components/pressable.js +0 -214
- package/build/components/refresh-control.d.ts +0 -20
- package/build/components/refresh-control.js +0 -47
- package/build/components/safe-area-view.d.ts +0 -8
- package/build/components/safe-area-view.js +0 -33
- package/build/components/scroll-view/index.android.d.ts +0 -4
- package/build/components/scroll-view/index.android.js +0 -64
- package/build/components/scroll-view/index.d.ts +0 -1
- package/build/components/scroll-view/index.ios.d.ts +0 -4
- package/build/components/scroll-view/index.ios.js +0 -17
- package/build/components/scroll-view/index.js +0 -4
- package/build/components/scroll-view/shared.js +0 -271
- package/build/components/scroll-view/sticky-header.d.ts +0 -7
- package/build/components/scroll-view/sticky-header.js +0 -208
- package/build/components/switch/index.android.d.ts +0 -12
- package/build/components/switch/index.android.js +0 -13
- package/build/components/switch/index.d.ts +0 -2
- package/build/components/switch/index.ios.d.ts +0 -12
- package/build/components/switch/index.ios.js +0 -11
- package/build/components/switch/index.js +0 -5
- package/build/components/switch/shared.d.ts +0 -23
- package/build/components/switch/shared.js +0 -126
- package/build/components/text-input/index.d.ts +0 -24
- package/build/components/text-input/index.js +0 -242
- package/build/components/touchable-native-feedback.d.ts +0 -24
- package/build/components/touchable-native-feedback.js +0 -77
- package/build/components/touchable.d.ts +0 -50
- package/build/components/touchable.js +0 -278
- package/build/components.d.ts +0 -51
- package/build/components.js +0 -29
|
@@ -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
|
-
|
|
20
|
-
|
|
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
|
+
);
|
package/metro-css-parser.cjs
CHANGED
|
@@ -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 =
|
|
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 {
|
|
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
|
-
|
|
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
|
-
//
|
|
247
|
-
// a .vue with only unscoped/no styles
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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 = [
|
|
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.
|
|
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.
|
|
50
|
-
"@symbiote-native/css-parser": "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
|
-
"@
|
|
59
|
-
"@symbiote-native/
|
|
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;
|