@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,278 +0,0 @@
1
- // The Touchable* family for Vue, all built on Pressable. Ported against RN's own sources
2
- // (.vendors/react-native/.../Components/Touchable/*.js) after the 2026-08-19 audit found ten
3
- // divergences shared by the React/Vue/Svelte/Angular ports; Solid migrated first, this is Vue.
4
- //
5
- // Shared (framework-agnostic) half: the press-scheduling machine, the underlay machine, the
6
- // resting-opacity math, the press-handler gate, the extra-style split. Vue owns only the
7
- // lifecycle — refs, the real timers, the Animated wiring, and the emit bridge:
8
- // TouchableOpacity: an Animated.Value fading toward activeOpacity on press-in and back to the
9
- // style's own opacity on press-out.
10
- // TouchableHighlight: the underlay machine flipping a `shown` ref; underlayColor lands on the
11
- // container, the lowered opacity on the cloned child.
12
- // TouchableWithoutFeedback: the same press-scheduling machine with the visual half empty.
13
- //
14
- // Inputs arrive as attrs (untyped), narrowed with runtime guards. The handlers read attrs LIVE
15
- // (they fire on events, not render) so a re-supplied callback / timing is always honored.
16
- import { cloneVNode, defineComponent, getCurrentInstance, h, onUnmounted, ref, watch, } from '@vue/runtime-core';
17
- import { createHighlightUnderlayHandlers, createHighlightUnderlayRuntime, createTouchableFeedbackHandlers, createTouchableFeedbackRuntime, hasTouchablePressHandler, resolveHighlightExtraStyles, restingOpacityFromStyle, DEFAULT_ACTIVE_OPACITY, OPACITY_ACTIVE_GRANT_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, TOUCHABLE_MIN_PRESS_DURATION_MS, } from '@symbiote-native/components';
18
- import { dlog, } from '@symbiote-native/engine';
19
- import { Pressable, emitPressableEvents, PRESSABLE_EMITS, } from './pressable.js';
20
- import { Animated } from '../modules/animated/index.js';
21
- import { normalizeVueAttrs } from '../utils/normalize-attrs.js';
22
- const TOUCHABLE_HIGHLIGHT_EMITS = {
23
- ...PRESSABLE_EMITS,
24
- showUnderlay: () => true,
25
- hideUnderlay: () => true,
26
- };
27
- function numberOr(value, fallback) {
28
- return typeof value === 'number' ? value : fallback;
29
- }
30
- // The real setTimeout the shared machines schedule their deferred activation/deactivation/underlay
31
- // hide on (core/components has no timer globals). Returns a canceller so an early release flushes
32
- // the timer.
33
- function scheduleTimeout(callback, ms) {
34
- const id = setTimeout(callback, ms);
35
- return () => clearTimeout(id);
36
- }
37
- function forwardExcept(attrs, handled) {
38
- const result = {};
39
- for (const key of Object.keys(attrs)) {
40
- if (!handled.includes(key))
41
- result[key] = attrs[key];
42
- }
43
- return result;
44
- }
45
- const TOUCHABLE_OPACITY_HANDLED = [
46
- 'activeOpacity',
47
- 'style',
48
- 'class',
49
- 'onPressIn',
50
- 'onPressOut',
51
- 'delayPressIn',
52
- 'delayPressOut',
53
- 'minPressDuration',
54
- ];
55
- export const TouchableOpacity = defineComponent((_props, { slots, attrs: rawAttrs, emit }) => {
56
- // RN's _getChildStyleOpacityWithDefault: the fade settles at the opacity the CALLER's style
57
- // asks for, not at a hard 1 — and the Animated.Value is SEEDED there, or the first paint jumps
58
- // to fully opaque on a Touchable styled `opacity: 0.6`.
59
- const restingOpacity = () => restingOpacityFromStyle(normalizeVueAttrs(rawAttrs).style);
60
- // One Animated.Value per mount. Held by identity in setup scope (an engine object, never a
61
- // reactive ref — a Proxy would miss the graph's bookkeeping). The Animated.View leaf commits
62
- // it every frame.
63
- const opacity = new Animated.Value(restingOpacity());
64
- // The shared press-scheduling cell (delayPressIn timer + activation clock), persisted across
65
- // renders in setup scope; the handlers are rebuilt each render over live attrs.
66
- const runtime = createTouchableFeedbackRuntime();
67
- function setOpacityTo(toValue, duration) {
68
- dlog(`TouchableOpacity opacity -> ${toValue} over ${duration}ms`);
69
- // useNativeDriver: true is RN's own (TouchableOpacity.js:242). opacity is natively drivable,
70
- // so the fade survives a busy JS thread — the whole point of press feedback.
71
- Animated.timing(opacity, {
72
- toValue,
73
- duration,
74
- easing: Animated.Easing.inOut(Animated.Easing.quad),
75
- useNativeDriver: true,
76
- }).start();
77
- }
78
- // RN's componentDidUpdate: a changed `disabled` or a changed style opacity re-settles the view,
79
- // so a Touchable disabled mid-press does not stay stuck at its active opacity. NO `immediate` —
80
- // RN does this on UPDATE only, and firing at mount would animate over the value the
81
- // Animated.Value was just seeded with. Two getter sources, not one object: Vue compares an
82
- // array source element-wise, so an unrelated attr change does not re-settle the opacity.
83
- watch([() => normalizeVueAttrs(rawAttrs).disabled, restingOpacity], ([, resting]) => {
84
- setOpacityTo(resting, OPACITY_INACTIVE_DURATION_MS);
85
- });
86
- // RN's componentWillUnmount: stop the animation and drop the value back, so a teardown
87
- // mid-fade leaves no driver running against a node that is gone.
88
- onUnmounted(() => {
89
- opacity.resetAnimation();
90
- });
91
- return () => {
92
- const attrs = normalizeVueAttrs(rawAttrs);
93
- const style = attrs.style;
94
- // Rebuilt each render so a re-supplied delay/opacity is honored (Vue's live-attr idiom); the
95
- // shared machine owns the scheduling, the adapter supplies the Animated fade + emit.
96
- const { handlePressIn, handlePressOut } = createTouchableFeedbackHandlers({
97
- delayPressIn: numberOr(attrs.delayPressIn, 0),
98
- delayPressOut: numberOr(attrs.delayPressOut, 0),
99
- // RN's Touchables override Pressability's 130ms floor with 0; what holds the active
100
- // visual is the fade's own duration, not a press-duration floor.
101
- minPressDuration: numberOr(attrs.minPressDuration, TOUCHABLE_MIN_PRESS_DURATION_MS),
102
- schedule: scheduleTimeout,
103
- now: Date.now,
104
- }, runtime, {
105
- activate(event) {
106
- setOpacityTo(numberOr(attrs.activeOpacity, DEFAULT_ACTIVE_OPACITY), OPACITY_ACTIVE_GRANT_DURATION_MS);
107
- emit('pressIn', event);
108
- },
109
- deactivate(event) {
110
- setOpacityTo(restingOpacity(), OPACITY_INACTIVE_DURATION_MS);
111
- emit('pressOut', event);
112
- },
113
- });
114
- const pressableProps = {
115
- ...forwardExcept(attrs, TOUCHABLE_OPACITY_HANDLED),
116
- ...emitPressableEvents(emit),
117
- onPressIn: handlePressIn,
118
- onPressOut: handlePressOut,
119
- };
120
- const children = slots.default !== undefined ? slots.default() : [];
121
- const feedback = h(Animated.View, { style: [style, { opacity }], class: attrs.class }, () => children);
122
- return h(Pressable, pressableProps, { default: () => [feedback] });
123
- };
124
- }, {
125
- name: 'TouchableOpacity',
126
- inheritAttrs: false,
127
- emits: PRESSABLE_EMITS,
128
- });
129
- // delayPressOut is CONSUMED here (the underlay hold), so it must not also forward to the host.
130
- // onPress/onPressIn/onPressOut/onShowUnderlay/onHideUnderlay never appear in attrs at all — they
131
- // are declared emits, which Vue strips from $attrs.
132
- const TOUCHABLE_HIGHLIGHT_HANDLED = [
133
- 'activeOpacity',
134
- 'underlayColor',
135
- 'style',
136
- 'delayPressOut',
137
- ];
138
- // A vnode that can carry a style prop: a host tag (string) or a component (object/function).
139
- // Fragment / Text / Comment / Static are Symbols and fail all three — cloning one with a style
140
- // would silently drop it.
141
- function isStylableVNode(vnode) {
142
- const type = vnode.type;
143
- return (typeof type === 'string' ||
144
- typeof type === 'function' ||
145
- (typeof type === 'object' && type !== null));
146
- }
147
- export const TouchableHighlight = defineComponent((_props, { slots, attrs: rawAttrs, emit }) => {
148
- // `shown` is NOT `pressed`: RN holds the underlay for delayPressOut past the tap so a fast tap
149
- // still flashes, and the pressed flag is already false by then.
150
- const shown = ref(false);
151
- // The mutable underlay cell (the in-flight hide canceller). A plain setup-scope object, never
152
- // a ref: the machine mutates it on every event and nothing reads it reactively.
153
- const runtime = createHighlightUnderlayRuntime();
154
- // The press callbacks are declared emits, so Vue has stripped their onX listeners from $attrs.
155
- // RN's _hasPressHandler gate therefore reads what the PARENT actually passed, off the
156
- // instance's own vnode props — the same shape FlatList/VirtualizedList use for this.
157
- const instance = getCurrentInstance();
158
- const listener = (onName) => {
159
- const vnodeProps = instance?.vnode.props;
160
- return vnodeProps == null ? undefined : vnodeProps[onName];
161
- };
162
- return () => {
163
- const attrs = normalizeVueAttrs(rawAttrs);
164
- const hasPressHandler = hasTouchablePressHandler({
165
- onPress: listener('onPress'),
166
- onPressIn: listener('onPressIn'),
167
- onPressOut: listener('onPressOut'),
168
- onLongPress: listener('onLongPress'),
169
- });
170
- // Rebuilt each render over live attrs; the runtime persists, so an in-flight hide timer
171
- // survives a rebuild.
172
- const underlay = createHighlightUnderlayHandlers({
173
- delayPressOut: numberOr(attrs.delayPressOut, 0),
174
- hasPressHandler,
175
- schedule: scheduleTimeout,
176
- }, runtime, {
177
- setShown: next => {
178
- shown.value = next;
179
- },
180
- onShowUnderlay: () => emit('showUnderlay'),
181
- onHideUnderlay: () => emit('hideUnderlay'),
182
- });
183
- const extra = resolveHighlightExtraStyles({
184
- shown: shown.value,
185
- hasPressHandler,
186
- underlayColor: typeof attrs.underlayColor === 'string'
187
- ? attrs.underlayColor
188
- : undefined,
189
- activeOpacity: typeof attrs.activeOpacity === 'number'
190
- ? attrs.activeOpacity
191
- : undefined,
192
- });
193
- const children = slots.default !== undefined ? slots.default() : [];
194
- // RN's _createExtraStyles split: the backgroundColor on the CONTAINER, the lowered opacity
195
- // on the CHILD (TouchableHighlight.js clones its single child). Vue can reach the child
196
- // without a wrapper node — cloneVNode merges the style onto exactly one existing vnode, so
197
- // nothing is inserted into the flex chain. It needs RN's own single-element-child shape
198
- // though (React.Children.only): a fragment, a raw text node or several roots have no one
199
- // child to clone, and there both styles fold onto the container — the pre-audit
200
- // approximation, where the opacity fades the very underlay it should reveal.
201
- const onlyChild = children.length === 1 && children[0] !== undefined
202
- ? children[0]
203
- : undefined;
204
- const canStyleChild = onlyChild !== undefined && isStylableVNode(onlyChild);
205
- const styledChildren = extra !== undefined && canStyleChild && onlyChild !== undefined
206
- ? [cloneVNode(onlyChild, { style: extra.child })]
207
- : children;
208
- const containerStyle = extra === undefined
209
- ? attrs.style
210
- : canStyleChild
211
- ? [attrs.style, extra.underlay]
212
- : [attrs.style, extra.underlay, extra.child];
213
- const pressableProps = {
214
- ...forwardExcept(attrs, TOUCHABLE_HIGHLIGHT_HANDLED),
215
- ...emitPressableEvents(emit),
216
- style: containerStyle,
217
- // Visual first, then the caller's callback — RN's order in _createPressabilityConfig.
218
- onPress: (event) => {
219
- underlay.handlePress(event);
220
- emit('press', event);
221
- },
222
- onPressIn: (event) => {
223
- underlay.handlePressIn(event);
224
- emit('pressIn', event);
225
- },
226
- onPressOut: (event) => {
227
- underlay.handlePressOut(event);
228
- emit('pressOut', event);
229
- },
230
- };
231
- return h(Pressable, pressableProps, { default: () => styledChildren });
232
- };
233
- }, {
234
- name: 'TouchableHighlight',
235
- inheritAttrs: false,
236
- emits: TOUCHABLE_HIGHLIGHT_EMITS,
237
- });
238
- // RN's TouchableWithoutFeedback builds a FULL Pressability config — "without feedback" means no
239
- // VISUAL, not no timing — so the delay props are consumed by the shared machine here instead of
240
- // forwarding to the host as unknown Fabric props.
241
- const TOUCHABLE_WITHOUT_FEEDBACK_HANDLED = [
242
- 'delayPressIn',
243
- 'delayPressOut',
244
- 'minPressDuration',
245
- ];
246
- export const TouchableWithoutFeedback = defineComponent((_props, { slots, attrs: rawAttrs, emit }) => {
247
- const runtime = createTouchableFeedbackRuntime();
248
- return () => {
249
- const attrs = normalizeVueAttrs(rawAttrs);
250
- // The same machine TouchableOpacity runs, with the visual half left empty.
251
- const { handlePressIn, handlePressOut } = createTouchableFeedbackHandlers({
252
- delayPressIn: numberOr(attrs.delayPressIn, 0),
253
- delayPressOut: numberOr(attrs.delayPressOut, 0),
254
- minPressDuration: numberOr(attrs.minPressDuration, TOUCHABLE_MIN_PRESS_DURATION_MS),
255
- schedule: scheduleTimeout,
256
- now: Date.now,
257
- }, runtime, {
258
- activate(event) {
259
- emit('pressIn', event);
260
- },
261
- deactivate(event) {
262
- emit('pressOut', event);
263
- },
264
- });
265
- const pressableProps = {
266
- ...forwardExcept(attrs, TOUCHABLE_WITHOUT_FEEDBACK_HANDLED),
267
- ...emitPressableEvents(emit),
268
- onPressIn: handlePressIn,
269
- onPressOut: handlePressOut,
270
- };
271
- const children = slots.default !== undefined ? slots.default() : [];
272
- return h(Pressable, pressableProps, { default: () => children });
273
- };
274
- }, {
275
- name: 'TouchableWithoutFeedback',
276
- inheritAttrs: false,
277
- emits: PRESSABLE_EMITS,
278
- });
@@ -1,51 +0,0 @@
1
- import { type FunctionalComponent, type VNodeRef } from '@vue/runtime-core';
2
- import type { ISymbioteEvent, IClassNameValue, IStyleProp, ITextStyle, IViewStyle } from '@symbiote-native/engine';
3
- import type { IAccessibilityProps, IAriaProps, IResponderProps } from '@symbiote-native/components';
4
- export interface IViewProps extends IAccessibilityProps, IAriaProps, IResponderProps {
5
- style?: IStyleProp<IViewStyle>;
6
- class?: IClassNameValue;
7
- onPress?: (event: ISymbioteEvent) => void;
8
- onPressIn?: (event: ISymbioteEvent) => void;
9
- onPressOut?: (event: ISymbioteEvent) => void;
10
- onLayout?: (event: ISymbioteEvent) => void;
11
- onFocus?: (event: ISymbioteEvent) => void;
12
- onBlur?: (event: ISymbioteEvent) => void;
13
- pointerEvents?: 'auto' | 'none' | 'box-none' | 'box-only';
14
- hitSlop?: number | {
15
- top?: number;
16
- left?: number;
17
- bottom?: number;
18
- right?: number;
19
- };
20
- id?: string;
21
- focusable?: boolean;
22
- collapsable?: boolean;
23
- removeClippedSubviews?: boolean;
24
- renderToHardwareTextureAndroid?: boolean;
25
- shouldRasterizeIOS?: boolean;
26
- needsOffscreenAlphaCompositing?: boolean;
27
- ref?: VNodeRef;
28
- key?: string | number | symbol;
29
- }
30
- export interface ITextProps extends IAccessibilityProps, IAriaProps {
31
- style?: IStyleProp<ITextStyle>;
32
- class?: IClassNameValue;
33
- onPress?: (event: ISymbioteEvent) => void;
34
- onLongPress?: (event: ISymbioteEvent) => void;
35
- onPressIn?: (event: ISymbioteEvent) => void;
36
- onPressOut?: (event: ISymbioteEvent) => void;
37
- onLayout?: (event: ISymbioteEvent) => void;
38
- onTextLayout?: (event: ISymbioteEvent) => void;
39
- numberOfLines?: number;
40
- ellipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
41
- selectable?: boolean;
42
- adjustsFontSizeToFit?: boolean;
43
- minimumFontScale?: number;
44
- allowFontScaling?: boolean;
45
- maxFontSizeMultiplier?: number | null;
46
- selectionColor?: string;
47
- ref?: VNodeRef;
48
- key?: string | number | symbol;
49
- }
50
- export declare const View: FunctionalComponent<IViewProps, {}, any, {}>;
51
- export declare const Text: FunctionalComponent<ITextProps, {}, any, {}>;
@@ -1,29 +0,0 @@
1
- // Host primitives for app code. Thin FUNCTIONAL components over the intrinsic tags the
2
- // renderer maps to Fabric: `inheritAttrs: false` + a manual attr spread passes every
3
- // prop and `@event` (onX) straight through to patchProp -> routeProp. The full prop
4
- // surface (typed ViewProps/TextProps, a11y folding) arrives with @symbiote-native/components.
5
- //
6
- // FUNCTIONAL, not a stateful defineComponent: a functional component has no instance, so
7
- // a template/function ref on it falls through to its single root host element (the raw
8
- // SymbioteNode), exactly like React's functional View hands back its host instance. A
9
- // stateful component's ref would resolve to a useless component proxy, which is why
10
- // createAnimatedComponent (which captures the host node via that ref) needs the fall-through.
11
- import { h } from '@vue/runtime-core';
12
- import { resolveTextProps } from '@symbiote-native/components';
13
- import { normalizeVueAttrs } from './utils/normalize-attrs.js';
14
- function hostComponent(intrinsic, name,
15
- // An optional last fold over the normalized attrs. Text needs one (RN's ellipsizeMode /
16
- // allowFontScaling defaults); View does not, so it stays a straight pass-through.
17
- fold = attrs => attrs) {
18
- // normalizeVueAttrs folds kebab template props (:accessibility-label) to the RN camelCase contract.
19
- const component = (_props, { slots, attrs }) => h(intrinsic, fold(normalizeVueAttrs(attrs)), slots.default !== undefined ? slots.default() : undefined);
20
- component.displayName = name;
21
- component.inheritAttrs = false;
22
- return component;
23
- }
24
- export const View = hostComponent('symbiote-view', 'View');
25
- export const Text = hostComponent('symbiote-text', 'Text', resolveTextProps);
26
- // Text is no longer bare either — it carries RN's Text.js defaults through resolveTextProps.
27
- // Image is NOT a bare host primitive: it needs the shared fold (source/src/srcSet resolution,
28
- // width/height -> style, alt -> accessibility) + the Image statics, so it lives in ./image as a
29
- // functional component over renderImage. View/Text stay bare; they forward attrs verbatim.