@symbiote-native/vue 1.0.0 → 3.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 +13 -12
- package/babel-jsx.cjs +26 -18
- 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 +3 -3
- 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 +9 -5
- package/build/components/modal/index.js +1 -1
- package/build/components/pressable-props.d.ts +31 -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 +7 -0
- package/build/components/touchable-native-feedback-props.js +1 -0
- package/build/components/touchable-props.d.ts +17 -0
- package/build/components/touchable-props.js +1 -0
- package/build/components/touchable-without-feedback-props.d.ts +5 -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 +64 -46
- package/build/components/virtualized-section-list/index.d.ts +3 -3
- package/build/descriptor-to-vue.js +2 -2
- package/build/host-instance/index.js +2 -2
- package/build/index.d.ts +24 -27
- package/build/index.js +31 -16
- 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/index.d.ts +41 -20
- 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 -1
- package/build/register.js +13 -33
- package/build/renderer/index.js +108 -54
- package/build/runtime-helpers/index.d.ts +10 -1
- package/build/runtime-helpers/index.js +56 -22
- package/build/utils/normalize-attrs.js +3 -3
- package/intrinsic-tags.cjs +52 -0
- package/metro-vue-transformer.cjs +55 -345
- package/package.json +13 -9
- package/babel-lower-host-primitives.cjs +0 -225
- 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 -61
- 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 -233
- 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 -9
- 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 -260
- package/build/components/touchable-native-feedback.d.ts +0 -24
- package/build/components/touchable-native-feedback.js +0 -82
- package/build/components/touchable.d.ts +0 -50
- package/build/components/touchable.js +0 -281
- package/build/components.d.ts +0 -53
- package/build/components.js +0 -45
- package/build/composables/use-raw-attrs.d.ts +0 -1
- package/build/composables/use-raw-attrs.js +0 -26
- package/build/state-style.d.ts +0 -1
- package/build/state-style.js +0 -13
|
@@ -6,17 +6,27 @@
|
|
|
6
6
|
// real HTMLElement - we have no DOM, so this module supplies our OWN implementation under the
|
|
7
7
|
// same export name instead of leaving `v-show` a silent no-op.
|
|
8
8
|
//
|
|
9
|
-
// Scope: Vue's own template directives (v-show, Teleport) and
|
|
10
|
-
//
|
|
9
|
+
// Scope: Vue's own template directives (v-show, Teleport) and `v-model` on an ELEMENT — see
|
|
10
|
+
// vModelText below for why that is in scope.
|
|
11
11
|
export * from '@vue/runtime-core';
|
|
12
12
|
import { getCurrentInstance, mergeProps as baseMergeProps, normalizeClass, normalizeStyle as baseNormalizeStyle, warn, } from '@vue/runtime-core';
|
|
13
|
-
import { requestCommitFor, setNativeProps, setProp, whenCommitted, } from '@symbiote-native/engine';
|
|
13
|
+
import { componentOf, propOf, requestCommitFor, setNativeProps, setProp, whenCommitted, } from '@symbiote-native/engine';
|
|
14
14
|
import { descriptorFor, SWITCH_TAG } from '@symbiote-native/components';
|
|
15
|
-
//
|
|
16
|
-
// same
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
|
|
15
|
+
// Do NOT shadow runtime-core's own Teleport here, however tempting the guarded ../create-portal
|
|
16
|
+
// wrapper looks (same reasoning that shadowed it in the first place, and it is wrong for this
|
|
17
|
+
// file specifically). @vue/compiler-sfc recognises the literal tag name "Teleport" as one of
|
|
18
|
+
// Vue's CORE built-ins at compile time — regardless of which value the name resolves to at
|
|
19
|
+
// runtime — and compiles its children as a raw array with a PROPS-only patchFlag (`dynamicProps:
|
|
20
|
+
// ["to"]`), never the DYNAMIC_SLOTS-flagged shape a real user component gets. Substituting a real
|
|
21
|
+
// `defineComponent` under that name makes it go through Vue's ordinary component update path
|
|
22
|
+
// (shouldUpdateComponent), which — for a PROPS-only patchFlag — checks ONLY the props named in
|
|
23
|
+
// `dynamicProps` and never re-renders on a children/slot change at all. Confirmed by reproducing
|
|
24
|
+
// through the real compiler (compileSfc) + a live mount: the wrapper's render() fires once at
|
|
25
|
+
// mount and never again, so a Teleport whose content is gated by v-if (the ordinary "toast"/
|
|
26
|
+
// "modal" shape) silently stops updating the moment `to` itself stays the same. `export *` above
|
|
27
|
+
// already re-exports the real, unwrapped Teleport for this path — leave it there. The guarded
|
|
28
|
+
// wrapper (../create-portal) is still exported from the adapter's main barrel for anyone who
|
|
29
|
+
// constructs the vnode by hand (`h(Teleport, ...)`, e.g. in TSX), where no such codegen applies.
|
|
20
30
|
// Shadows @vue/shared's own `normalizeProps` for every compiled `from 'vue'` import, for ONE
|
|
21
31
|
// divergence: a FUNCTION-valued `style` survives it.
|
|
22
32
|
//
|
|
@@ -71,12 +81,10 @@ export function normalizeProps(props) {
|
|
|
71
81
|
// contract reads it (`Pressable.js`: `ViewStyleProp | ((state) => ViewStyleProp)` — the callback is
|
|
72
82
|
// top-level, never an array element, so `:style="[a, fn]"` is out of contract here exactly as it is
|
|
73
83
|
// there, and is deliberately NOT rescued).
|
|
74
|
-
// The THIRD door
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
// here, and today nothing notices because the lowering transform rewrites that attribute into a
|
|
79
|
-
// resting/active pair before Vue ever emits the helper.
|
|
84
|
+
// The THIRD door. A `:style` binding compiles to `_normalizeStyle(expr)` whenever the compiler
|
|
85
|
+
// cannot keep it on the cheap patch-flag path — an inline arrow and a call expression both do, a
|
|
86
|
+
// bare identifier does not. So `<pressable :style="({pressed}) => …">` would lose its callback here
|
|
87
|
+
// without the rescue below.
|
|
80
88
|
//
|
|
81
89
|
// A TOP-LEVEL function is preserved; one nested inside an array is not, and that asymmetry is the
|
|
82
90
|
// contract rather than an omission. React Native types the prop
|
|
@@ -117,6 +125,14 @@ export const vShow = {
|
|
|
117
125
|
// Drop a still-pending first-commit wait if the element unmounts before it ever lands.
|
|
118
126
|
unmounted: el => pendingShowCommits.get(el)?.(),
|
|
119
127
|
};
|
|
128
|
+
function textFromChangeEvent(event) {
|
|
129
|
+
const text = Reflect.get(event, 'text');
|
|
130
|
+
return typeof text === 'string' ? text : undefined;
|
|
131
|
+
}
|
|
132
|
+
function valueFromChangeEvent(event) {
|
|
133
|
+
const value = Reflect.get(event, 'value');
|
|
134
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
135
|
+
}
|
|
120
136
|
const modelStates = new WeakMap();
|
|
121
137
|
// Runtime guards, not casts: both slots are read out of untyped bags — `vnode.props` and
|
|
122
138
|
// `node.props` are `Record<string, unknown>` — and `typeof x === 'function'` alone narrows to the
|
|
@@ -163,9 +179,16 @@ function modelStateFor(el) {
|
|
|
163
179
|
appListener: undefined,
|
|
164
180
|
trim: false,
|
|
165
181
|
number: false,
|
|
166
|
-
listener:
|
|
167
|
-
state.appListener?.(
|
|
168
|
-
|
|
182
|
+
listener: event => {
|
|
183
|
+
state.appListener?.(event);
|
|
184
|
+
const text = textFromChangeEvent(event);
|
|
185
|
+
if (text !== undefined) {
|
|
186
|
+
state.assign?.(applyModelModifiers(state, text));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const value = valueFromChangeEvent(event);
|
|
190
|
+
if (value !== undefined)
|
|
191
|
+
state.assign?.(value);
|
|
169
192
|
},
|
|
170
193
|
};
|
|
171
194
|
modelStates.set(el, state);
|
|
@@ -175,14 +198,14 @@ function modelStateFor(el) {
|
|
|
175
198
|
// by `patchProp` during the same patch, so anything captured earlier is either missing or stale. A
|
|
176
199
|
// prop that is already OUR listener means nothing overwrote it and the app half is unchanged.
|
|
177
200
|
function syncModelListener(el, state) {
|
|
178
|
-
const current = el
|
|
201
|
+
const current = propOf(el, 'onValueChange');
|
|
179
202
|
if (current === state.listener)
|
|
180
203
|
return;
|
|
181
204
|
state.appListener = isValueChangeListener(current) ? current : undefined;
|
|
182
205
|
setProp(el, 'onValueChange', state.listener);
|
|
183
206
|
}
|
|
184
207
|
// Vue's compiler picks the directive by ELEMENT, and for anything it does not recognise as a DOM
|
|
185
|
-
// input it emits `vModelText` —
|
|
208
|
+
// input it emits `vModelText` — `<switch>` included. Stringifying there is what
|
|
186
209
|
// upstream must do (a DOM input's value IS a string) and what we must not: the Switch behavior
|
|
187
210
|
// reads `props.value === true`, so `String(true)` pins the control OFF and no tap can move it.
|
|
188
211
|
// Device-confirmed on `examples/vue-sfc` 2026-09-02, both switches on `CanaryScreen`.
|
|
@@ -192,11 +215,12 @@ function syncModelListener(el, state) {
|
|
|
192
215
|
// of carrying a copy of both.
|
|
193
216
|
const SWITCH_COMPONENT = descriptorFor(SWITCH_TAG).component;
|
|
194
217
|
function isSwitchNode(el) {
|
|
195
|
-
return el
|
|
218
|
+
return componentOf(el) === SWITCH_COMPONENT;
|
|
196
219
|
}
|
|
197
220
|
function syncModelValue(el, value) {
|
|
198
|
-
// The READ half needs no branch: the behavior calls `onValueChange(
|
|
199
|
-
//
|
|
221
|
+
// The READ half needs no branch: the behavior calls `onValueChange(event)` for both primitives
|
|
222
|
+
// with `text`/`value` carried on the event, and `applyModelModifiers` passes a non-string through
|
|
223
|
+
// untouched.
|
|
200
224
|
if (isSwitchNode(el)) {
|
|
201
225
|
setProp(el, 'value', value === true);
|
|
202
226
|
requestCommitFor(el);
|
|
@@ -268,6 +292,16 @@ const MODIFIER_GUARDS = {
|
|
|
268
292
|
* typed as required, matching upstream Vue's own declaration — its runtime-only `!fn` guard below
|
|
269
293
|
* (for a compiler-generated call site that could pass a falsy handler) isn't reflected in the
|
|
270
294
|
* type there either.
|
|
295
|
+
*
|
|
296
|
+
* `@press.self` on an element reaches this, and both halves were measured 2026-09-11 rather
|
|
297
|
+
* than assumed — the question arose because a modifier on a COMPONENT takes Vue's own event path
|
|
298
|
+
* and only an element emits the helper. `<pressable @press.self>` compiles to
|
|
299
|
+
* `_withModifiers(fn, ["self"])` imported `from "@symbiote-native/vue/runtime-helpers"` (the Metro
|
|
300
|
+
* transformer retargets every compiled `from 'vue'`), so the compiler-emitted call lands here and
|
|
301
|
+
* not on @vue/runtime-dom's. And `ISymbioteEvent` (`core/engine/src/node.ts`) declares `target`,
|
|
302
|
+
* `currentTarget` and `stopPropagation` as REQUIRED fields with the DOM semantics these guards
|
|
303
|
+
* read, so `.self` genuinely filters a bubbled press instead of degenerating to
|
|
304
|
+
* `undefined !== undefined`.
|
|
271
305
|
*/
|
|
272
306
|
export function withModifiers(fn, modifiers) {
|
|
273
307
|
if (!fn)
|
|
@@ -12,9 +12,9 @@ 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:
|
|
16
|
-
//
|
|
17
|
-
//
|
|
15
|
+
// The per-KEY half, for the path that never sees a whole attrs bag: an intrinsic tag reaches the
|
|
16
|
+
// renderer one patchProp call at a time, with no component in between to fold the bag. Returns the
|
|
17
|
+
// key unchanged (same string identity)
|
|
18
18
|
// whenever there is nothing to convert, which is every key on the hot path.
|
|
19
19
|
export function normalizeVueAttrKey(key) {
|
|
20
20
|
if (!key.includes('-'))
|
|
@@ -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
|
+
);
|