@symbiote-native/vue 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +142 -0
- package/build/components/activity-indicator/index.android.d.ts +4 -0
- package/build/components/activity-indicator/index.android.js +10 -0
- package/build/components/activity-indicator/index.d.ts +1 -0
- package/build/components/activity-indicator/index.ios.d.ts +4 -0
- package/build/components/activity-indicator/index.ios.js +10 -0
- package/build/components/activity-indicator/index.js +4 -0
- package/build/components/activity-indicator/shared.d.ts +8 -0
- package/build/components/activity-indicator/shared.js +48 -0
- package/build/components/button.d.ts +14 -0
- package/build/components/button.js +59 -0
- package/build/components/drawer-layout-android/index.android.d.ts +8 -0
- package/build/components/drawer-layout-android/index.android.js +144 -0
- package/build/components/drawer-layout-android/index.d.ts +8 -0
- package/build/components/drawer-layout-android/index.js +36 -0
- package/build/components/drawer-layout-android/shared.d.ts +18 -0
- package/build/components/drawer-layout-android/shared.js +6 -0
- package/build/components/flat-list/index.d.ts +88 -0
- package/build/components/flat-list/index.js +189 -0
- package/build/components/image-background.d.ts +9 -0
- package/build/components/image-background.js +114 -0
- package/build/components/image.d.ts +9 -0
- package/build/components/image.js +99 -0
- package/build/components/input-accessory-view.d.ts +10 -0
- package/build/components/input-accessory-view.js +41 -0
- package/build/components/keyboard-avoiding-view.d.ts +18 -0
- package/build/components/keyboard-avoiding-view.js +121 -0
- package/build/components/modal.d.ts +29 -0
- package/build/components/modal.js +134 -0
- package/build/components/pressable.d.ts +58 -0
- package/build/components/pressable.js +221 -0
- package/build/components/refresh-control.d.ts +20 -0
- package/build/components/refresh-control.js +53 -0
- package/build/components/safe-area-view.d.ts +8 -0
- package/build/components/safe-area-view.js +33 -0
- package/build/components/scroll-view/index.android.d.ts +4 -0
- package/build/components/scroll-view/index.android.js +74 -0
- package/build/components/scroll-view/index.d.ts +1 -0
- package/build/components/scroll-view/index.ios.d.ts +4 -0
- package/build/components/scroll-view/index.ios.js +15 -0
- package/build/components/scroll-view/index.js +4 -0
- package/build/components/scroll-view/shared.d.ts +96 -0
- package/build/components/scroll-view/shared.js +297 -0
- package/build/components/scroll-view/sticky-header.d.ts +7 -0
- package/build/components/scroll-view/sticky-header.js +195 -0
- package/build/components/section-list/index.d.ts +39 -0
- package/build/components/section-list/index.js +77 -0
- package/build/components/switch/index.android.d.ts +12 -0
- package/build/components/switch/index.android.js +13 -0
- package/build/components/switch/index.d.ts +2 -0
- package/build/components/switch/index.ios.d.ts +12 -0
- package/build/components/switch/index.ios.js +11 -0
- package/build/components/switch/index.js +5 -0
- package/build/components/switch/shared.d.ts +23 -0
- package/build/components/switch/shared.js +129 -0
- package/build/components/text-input/index.d.ts +24 -0
- package/build/components/text-input/index.js +257 -0
- package/build/components/touchable-native-feedback.d.ts +24 -0
- package/build/components/touchable-native-feedback.js +75 -0
- package/build/components/touchable.d.ts +44 -0
- package/build/components/touchable.js +150 -0
- package/build/components/virtualized-list/index.d.ts +121 -0
- package/build/components/virtualized-list/index.js +687 -0
- package/build/components/virtualized-section-list/index.d.ts +96 -0
- package/build/components/virtualized-section-list/index.js +160 -0
- package/build/components.d.ts +51 -0
- package/build/components.js +26 -0
- package/build/composables/use-color-scheme.d.ts +3 -0
- package/build/composables/use-color-scheme.js +24 -0
- package/build/composables/use-window-dimensions.d.ts +3 -0
- package/build/composables/use-window-dimensions.js +34 -0
- package/build/create-tunnel.d.ts +9 -0
- package/build/create-tunnel.js +37 -0
- package/build/descriptor-to-vue.d.ts +3 -0
- package/build/descriptor-to-vue.js +14 -0
- package/build/host-instance/index.d.ts +2 -0
- package/build/host-instance/index.js +34 -0
- package/build/index.d.ts +67 -0
- package/build/index.js +90 -0
- package/build/modules/animated/create-animated-component.d.ts +4 -0
- package/build/modules/animated/create-animated-component.js +169 -0
- package/build/modules/animated/index.d.ts +55 -0
- package/build/modules/animated/index.js +66 -0
- package/build/modules/app-registry/index.d.ts +7 -0
- package/build/modules/app-registry/index.js +32 -0
- package/build/modules/status-bar.d.ts +17 -0
- package/build/modules/status-bar.js +65 -0
- package/build/render.d.ts +7 -0
- package/build/render.js +43 -0
- package/build/renderer.d.ts +4 -0
- package/build/renderer.js +129 -0
- package/build/runtime-helpers.d.ts +28 -0
- package/build/runtime-helpers.js +68 -0
- package/build/utils/component-helpers.d.ts +2 -0
- package/build/utils/component-helpers.js +13 -0
- package/build/utils/model-binding.d.ts +4 -0
- package/build/utils/model-binding.js +17 -0
- package/build/utils/normalize-attrs.d.ts +1 -0
- package/build/utils/normalize-attrs.js +30 -0
- package/build/utils/slots-to-render-props.d.ts +4 -0
- package/build/utils/slots-to-render-props.js +18 -0
- package/metro-css-parser.cjs +12 -0
- package/package.json +54 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// TextInput, the Vue lifecycle half. The folds/maps (value->text, the W3C/alias resolution)
|
|
2
|
+
// and the controlled-write predicate live in @symbiote-native/components/state, the render (intrinsic
|
|
3
|
+
// + native-prop mapping) in @symbiote-native/components/view, both shared verbatim with the React
|
|
4
|
+
// adapter. Here Vue supplies only the reactivity: a shallowRef holds the host node, a ref holds
|
|
5
|
+
// the acknowledged event count (so the exposed handle echoes the latest), setup-scope `let`s
|
|
6
|
+
// hold the last native text + focus flag, a post-flush watch runs the controlled-write command,
|
|
7
|
+
// and expose() wires the imperative handle. The Vue twin of the React useState/useRef +
|
|
8
|
+
// useLayoutEffect + useImperativeHandle.
|
|
9
|
+
//
|
|
10
|
+
// Inputs arrive as attrs (untyped), so each is narrowed with a runtime guard rather than a cast.
|
|
11
|
+
// onValueChange MUST be stripped from the forwarded attrs: it is not a ViewConfig event (it's
|
|
12
|
+
// derived from the native onChange), so leaking it would reach Fabric as a function prop and
|
|
13
|
+
// crash Android's folly::dynamic. The imperative module (blurTextInput / setInput*) is imported
|
|
14
|
+
// from @symbiote-native/engine, the same framework-agnostic singleton both adapters share.
|
|
15
|
+
import { defineComponent, onBeforeUnmount, ref, shallowRef, watch } from '@vue/runtime-core';
|
|
16
|
+
import { resolveAccessibilityProps, resolveTextInputProps, renderTextInput, foldText, textFromChange, eventCountFromChange, shouldCommandText, INITIAL_EVENT_COUNT, SELECTION_NONE, } from '@symbiote-native/components';
|
|
17
|
+
import { dispatchViewCommand, isSymbioteNode, dlog, blurTextInput, setInputFocused, setInputBlurred, whenCommitted, } from '@symbiote-native/engine';
|
|
18
|
+
import { descriptorToVue } from '../../descriptor-to-vue';
|
|
19
|
+
import { normalizeVueAttrs } from '../../utils/normalize-attrs';
|
|
20
|
+
import { resolveModelValue, emitModelUpdate } from '../../utils/model-binding';
|
|
21
|
+
function isRecord(value) {
|
|
22
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
23
|
+
}
|
|
24
|
+
function asString(value) {
|
|
25
|
+
return typeof value === 'string' ? value : undefined;
|
|
26
|
+
}
|
|
27
|
+
function isString(value) {
|
|
28
|
+
return typeof value === 'string';
|
|
29
|
+
}
|
|
30
|
+
function asBoolean(value) {
|
|
31
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
32
|
+
}
|
|
33
|
+
// selection arrives untyped; keep only the numeric start/end the render fn + controlled write read.
|
|
34
|
+
function normalizeSelection(value) {
|
|
35
|
+
if (!isRecord(value))
|
|
36
|
+
return undefined;
|
|
37
|
+
if (typeof value.start !== 'number')
|
|
38
|
+
return undefined;
|
|
39
|
+
const selection = { start: value.start };
|
|
40
|
+
if (typeof value.end === 'number')
|
|
41
|
+
selection.end = value.end;
|
|
42
|
+
return selection;
|
|
43
|
+
}
|
|
44
|
+
// The prop/handler keys the lifecycle consumes itself (mirrors the React adapter's destructure);
|
|
45
|
+
// everything else (placeholder, secureTextEntry, the remaining native events, accessibility,
|
|
46
|
+
// testID, style…) forwards onto the host node. onFocus/onBlur are re-supplied as our wrapped
|
|
47
|
+
// handlers; onValueChange is pure JS and must never reach Fabric.
|
|
48
|
+
const HANDLED_ATTRS = [
|
|
49
|
+
'value',
|
|
50
|
+
'modelValue',
|
|
51
|
+
'defaultValue',
|
|
52
|
+
'multiline',
|
|
53
|
+
'selection',
|
|
54
|
+
'inputMode',
|
|
55
|
+
'enterKeyHint',
|
|
56
|
+
'readOnly',
|
|
57
|
+
'submitBehavior',
|
|
58
|
+
'blurOnSubmit',
|
|
59
|
+
'cursorColor',
|
|
60
|
+
'selectionColor',
|
|
61
|
+
'selectionHandleColor',
|
|
62
|
+
'keyboardType',
|
|
63
|
+
'returnKeyType',
|
|
64
|
+
'editable',
|
|
65
|
+
'autoComplete',
|
|
66
|
+
'textContentType',
|
|
67
|
+
'autoFocus',
|
|
68
|
+
'showSoftInputOnFocus',
|
|
69
|
+
'underlineColorAndroid',
|
|
70
|
+
'onValueChange',
|
|
71
|
+
'onFocus',
|
|
72
|
+
'onBlur',
|
|
73
|
+
];
|
|
74
|
+
function forwardAttrs(attrs) {
|
|
75
|
+
const result = {};
|
|
76
|
+
for (const key of Object.keys(attrs)) {
|
|
77
|
+
if (!HANDLED_ATTRS.includes(key))
|
|
78
|
+
result[key] = attrs[key];
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
export const TextInput = defineComponent((_props, { attrs: rawAttrs, emit, expose }) => {
|
|
83
|
+
// shallowRef, NOT ref: the engine node must be held by IDENTITY. A plain ref() runs the node
|
|
84
|
+
// through Vue's toReactive(), handing back a reactive Proxy, a different object than the raw
|
|
85
|
+
// node the engine's WeakMap mirror is keyed on, so every imperative command
|
|
86
|
+
// (dispatchViewCommand / focus / blur / setTextAndSelection) would miss and silently no-op.
|
|
87
|
+
// See .claude/skills/vue-adapter-reactivity. Same rule as the Switch / ScrollView host node.
|
|
88
|
+
const nodeRef = shallowRef(null);
|
|
89
|
+
const setNodeRef = (el) => {
|
|
90
|
+
nodeRef.value = isSymbioteNode(el) ? el : null;
|
|
91
|
+
};
|
|
92
|
+
// The count native last acknowledged. A ref so the render echoes it back as
|
|
93
|
+
// mostRecentEventCount and the exposed handle reads the latest; the controlled write commands
|
|
94
|
+
// it so native's eventLag lands on 0.
|
|
95
|
+
const mostRecentEventCount = ref(INITIAL_EVENT_COUNT);
|
|
96
|
+
// The last text native holds, as far as JS knows. Seeded from the mount-time value (the `text`
|
|
97
|
+
// prop already carries it down via createNode, so the FIRST controlled value is not a
|
|
98
|
+
// divergence and must NOT re-command). A setup-scope `let`: no render needed when it changes.
|
|
99
|
+
let lastNativeText = foldText(resolveModelValue(rawAttrs, isString), asString(rawAttrs.defaultValue));
|
|
100
|
+
// JS-side focus state, mirrored from the focus/blur events for isFocused(): native exposes no
|
|
101
|
+
// synchronous focus getter (RN's TextInputState holds the same).
|
|
102
|
+
let focused = false;
|
|
103
|
+
// autoFocus fires once when the node first commits; guard so a later node identity change does
|
|
104
|
+
// not re-focus.
|
|
105
|
+
let autoFocused = false;
|
|
106
|
+
const handleChange = (event) => {
|
|
107
|
+
// Event seam: the controlled handshake hinges on the change payload carrying `text`
|
|
108
|
+
// (+ `eventCount`). iOS and Android Fabric can key these differently, so log the actual shape.
|
|
109
|
+
dlog(`TextInput change keys=[${Object.keys(event.nativeEvent).join(',')}] ` +
|
|
110
|
+
`text=${JSON.stringify(event.nativeEvent.text)} count=${JSON.stringify(event.nativeEvent.eventCount)}`);
|
|
111
|
+
const text = textFromChange(event);
|
|
112
|
+
if (text !== undefined) {
|
|
113
|
+
// Record the text first, then the count, so the count never runs ahead of the text it
|
|
114
|
+
// stands for.
|
|
115
|
+
lastNativeText = text;
|
|
116
|
+
emit('valueChange', text, event);
|
|
117
|
+
emitModelUpdate(emit, text);
|
|
118
|
+
}
|
|
119
|
+
const count = eventCountFromChange(event);
|
|
120
|
+
if (count !== undefined)
|
|
121
|
+
mostRecentEventCount.value = count;
|
|
122
|
+
};
|
|
123
|
+
const handleFocus = (event) => {
|
|
124
|
+
focused = true;
|
|
125
|
+
// Track focus app-wide so Keyboard.dismiss can blur this input without a ref.
|
|
126
|
+
const node = nodeRef.value;
|
|
127
|
+
if (node !== null)
|
|
128
|
+
setInputFocused(node);
|
|
129
|
+
emit('focus', event);
|
|
130
|
+
};
|
|
131
|
+
const handleBlur = (event) => {
|
|
132
|
+
focused = false;
|
|
133
|
+
const node = nodeRef.value;
|
|
134
|
+
if (node !== null)
|
|
135
|
+
setInputBlurred(node);
|
|
136
|
+
emit('blur', event);
|
|
137
|
+
};
|
|
138
|
+
// Controlled write: when JS-side `value` diverges from what native reported, command the new
|
|
139
|
+
// text down with the acknowledged count; a plain prop re-push would race the user's
|
|
140
|
+
// keystrokes. Watching `value` covers every divergence (the parent only rewrites `value` after
|
|
141
|
+
// a change). flush:'post' so the engine has committed the node before the command reads its
|
|
142
|
+
// Fabric handle; the predicate makes it a no-op on mount (value === the seed).
|
|
143
|
+
watch(() => resolveModelValue(rawAttrs, isString), value => {
|
|
144
|
+
const node = nodeRef.value;
|
|
145
|
+
if (node === null)
|
|
146
|
+
return;
|
|
147
|
+
if (!shouldCommandText(lastNativeText, value))
|
|
148
|
+
return;
|
|
149
|
+
const selection = normalizeSelection(rawAttrs.selection);
|
|
150
|
+
const selStart = selection?.start ?? SELECTION_NONE;
|
|
151
|
+
const selEnd = selection?.end ?? selection?.start ?? SELECTION_NONE;
|
|
152
|
+
dlog(`TextInput setTextAndSelection count=${mostRecentEventCount.value} text=${JSON.stringify(value)}`);
|
|
153
|
+
dispatchViewCommand(node, 'setTextAndSelection', [
|
|
154
|
+
mostRecentEventCount.value,
|
|
155
|
+
value,
|
|
156
|
+
selStart,
|
|
157
|
+
selEnd,
|
|
158
|
+
]);
|
|
159
|
+
lastNativeText = value;
|
|
160
|
+
}, { flush: 'post' });
|
|
161
|
+
// autoFocus is driven in JS, not as a native prop: once the node first commits, command `focus`
|
|
162
|
+
// down once (RN does the same via TextInputState.focusInput). The watch fires when nodeRef is
|
|
163
|
+
// set (mount), but under Vue's async-batched commit the node has no Fabric tag yet at post-flush,
|
|
164
|
+
// so the focus command would be skipped with no retry. whenCommitted defers it to the commit that
|
|
165
|
+
// assigns the tag. Cancelled on unmount so an un-committed pending focus can't leak.
|
|
166
|
+
let cancelAutoFocus;
|
|
167
|
+
watch(nodeRef, node => {
|
|
168
|
+
if (autoFocused || node === null || rawAttrs.autoFocus !== true)
|
|
169
|
+
return;
|
|
170
|
+
autoFocused = true;
|
|
171
|
+
dlog('TextInput autoFocus -> focus command');
|
|
172
|
+
cancelAutoFocus = whenCommitted(node, () => dispatchViewCommand(node, 'focus', []));
|
|
173
|
+
}, { flush: 'post' });
|
|
174
|
+
onBeforeUnmount(() => cancelAutoFocus?.());
|
|
175
|
+
// The imperative API RN exposes on the ref. The methods read nodeRef.value / the count LIVE,
|
|
176
|
+
// so no stale capture: the Vue twin of React's useImperativeHandle. focus/blur drive native
|
|
177
|
+
// view commands; clear and setSelection reuse setTextAndSelection (the same stale-safe path as
|
|
178
|
+
// a controlled write) echoing the acknowledged event count.
|
|
179
|
+
expose({
|
|
180
|
+
focus: () => {
|
|
181
|
+
const node = nodeRef.value;
|
|
182
|
+
if (node !== null)
|
|
183
|
+
dispatchViewCommand(node, 'focus', []);
|
|
184
|
+
},
|
|
185
|
+
blur: () => {
|
|
186
|
+
// Routes through TextInputState so the app-wide focus tracking clears too.
|
|
187
|
+
blurTextInput(nodeRef.value);
|
|
188
|
+
},
|
|
189
|
+
clear: () => {
|
|
190
|
+
const node = nodeRef.value;
|
|
191
|
+
if (node === null)
|
|
192
|
+
return;
|
|
193
|
+
dispatchViewCommand(node, 'setTextAndSelection', [mostRecentEventCount.value, '', 0, 0]);
|
|
194
|
+
lastNativeText = '';
|
|
195
|
+
},
|
|
196
|
+
isFocused: () => focused,
|
|
197
|
+
setSelection: (start, end) => {
|
|
198
|
+
const node = nodeRef.value;
|
|
199
|
+
if (node === null)
|
|
200
|
+
return;
|
|
201
|
+
const current = lastNativeText ?? '';
|
|
202
|
+
dispatchViewCommand(node, 'setTextAndSelection', [
|
|
203
|
+
mostRecentEventCount.value,
|
|
204
|
+
current,
|
|
205
|
+
start,
|
|
206
|
+
end,
|
|
207
|
+
]);
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
return () => {
|
|
211
|
+
const attrs = normalizeVueAttrs(rawAttrs);
|
|
212
|
+
const multiline = attrs.multiline === true;
|
|
213
|
+
const folded = resolveTextInputProps({
|
|
214
|
+
inputMode: asString(attrs.inputMode),
|
|
215
|
+
keyboardType: asString(attrs.keyboardType),
|
|
216
|
+
enterKeyHint: asString(attrs.enterKeyHint),
|
|
217
|
+
returnKeyType: asString(attrs.returnKeyType),
|
|
218
|
+
readOnly: asBoolean(attrs.readOnly),
|
|
219
|
+
editable: asBoolean(attrs.editable),
|
|
220
|
+
submitBehavior: asString(attrs.submitBehavior),
|
|
221
|
+
blurOnSubmit: asBoolean(attrs.blurOnSubmit),
|
|
222
|
+
multiline,
|
|
223
|
+
cursorColor: asString(attrs.cursorColor),
|
|
224
|
+
selectionColor: asString(attrs.selectionColor),
|
|
225
|
+
selectionHandleColor: asString(attrs.selectionHandleColor),
|
|
226
|
+
autoComplete: asString(attrs.autoComplete),
|
|
227
|
+
textContentType: asString(attrs.textContentType),
|
|
228
|
+
showSoftInputOnFocus: asBoolean(attrs.showSoftInputOnFocus),
|
|
229
|
+
underlineColorAndroid: asString(attrs.underlineColorAndroid),
|
|
230
|
+
});
|
|
231
|
+
const text = foldText(resolveModelValue(attrs, isString), asString(attrs.defaultValue));
|
|
232
|
+
return descriptorToVue(renderTextInput({
|
|
233
|
+
multiline,
|
|
234
|
+
text,
|
|
235
|
+
mostRecentEventCount: mostRecentEventCount.value,
|
|
236
|
+
selection: normalizeSelection(attrs.selection),
|
|
237
|
+
folded,
|
|
238
|
+
passthrough: {
|
|
239
|
+
...resolveAccessibilityProps(forwardAttrs(attrs)),
|
|
240
|
+
ref: setNodeRef,
|
|
241
|
+
onChange: handleChange,
|
|
242
|
+
onFocus: handleFocus,
|
|
243
|
+
onBlur: handleBlur,
|
|
244
|
+
},
|
|
245
|
+
}));
|
|
246
|
+
};
|
|
247
|
+
}, {
|
|
248
|
+
name: 'TextInput',
|
|
249
|
+
inheritAttrs: false,
|
|
250
|
+
emits: {
|
|
251
|
+
valueChange: (_text, _event) => true,
|
|
252
|
+
focus: (_event) => true,
|
|
253
|
+
blur: (_event) => true,
|
|
254
|
+
'update:modelValue': (_text) => true,
|
|
255
|
+
'update:value': (_text) => true,
|
|
256
|
+
},
|
|
257
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { canUseNativeForeground, rippleBackground, selectableBackground, selectableBackgroundBorderless, type INativeFeedbackBackground } from '@symbiote-native/components';
|
|
2
|
+
import { type IPressableEmits, type IPressableProps } from './pressable';
|
|
3
|
+
export type { INativeFeedbackBackground, IThemeAttrBackground, IRippleBackground, } from '@symbiote-native/components';
|
|
4
|
+
export type ITouchableNativeFeedbackProps = Omit<IPressableProps, 'style'> & {
|
|
5
|
+
background?: INativeFeedbackBackground;
|
|
6
|
+
useForeground?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare const TouchableNativeFeedback: import("vue").DefineSetupFnComponent<ITouchableNativeFeedbackProps, IPressableEmits, {}, Omit<IPressableProps, "style"> & {
|
|
9
|
+
background?: INativeFeedbackBackground;
|
|
10
|
+
useForeground?: boolean;
|
|
11
|
+
} & {
|
|
12
|
+
onPress?: ((event: import("@symbiote-native/engine").ISymbioteEvent) => any) | undefined;
|
|
13
|
+
onPressIn?: ((event: import("@symbiote-native/engine").ISymbioteEvent) => any) | undefined;
|
|
14
|
+
onPressOut?: ((event: import("@symbiote-native/engine").ISymbioteEvent) => any) | undefined;
|
|
15
|
+
onPressMove?: ((event: import("@symbiote-native/engine").ISymbioteEvent) => any) | undefined;
|
|
16
|
+
onLongPress?: ((event: import("@symbiote-native/engine").ISymbioteEvent) => any) | undefined;
|
|
17
|
+
onHoverIn?: ((event: import("@symbiote-native/engine").ISymbioteEvent) => any) | undefined;
|
|
18
|
+
onHoverOut?: ((event: import("@symbiote-native/engine").ISymbioteEvent) => any) | undefined;
|
|
19
|
+
}, import("vue").PublicProps> & {
|
|
20
|
+
SelectableBackground: typeof selectableBackground;
|
|
21
|
+
SelectableBackgroundBorderless: typeof selectableBackgroundBorderless;
|
|
22
|
+
Ripple: typeof rippleBackground;
|
|
23
|
+
canUseNativeForeground: typeof canUseNativeForeground;
|
|
24
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// TouchableNativeFeedback for Vue: Android's ripple/state-drawable touchable, built on Pressable
|
|
2
|
+
// like the rest of the family (the Vue twin of the React adapter). The native ripple props
|
|
3
|
+
// (nativeBackgroundAndroid / nativeForegroundAndroid) ride a dedicated feedback View nested under
|
|
4
|
+
// the Pressable; on iOS they are inert. The static factories + background mapping are shared in
|
|
5
|
+
// @symbiote-native/components/view; Vue only attaches them onto the component value and nests the View.
|
|
6
|
+
import { defineComponent, h } from '@vue/runtime-core';
|
|
7
|
+
import { backgroundProps, canUseNativeForeground, rippleBackground, selectableBackground, selectableBackgroundBorderless, } from '@symbiote-native/components';
|
|
8
|
+
import { dlog } from '@symbiote-native/engine';
|
|
9
|
+
import { View } from '../components';
|
|
10
|
+
import { Pressable, emitPressableEvents, PRESSABLE_EMITS, } from './pressable';
|
|
11
|
+
import { normalizeVueAttrs } from '../utils/normalize-attrs';
|
|
12
|
+
const HANDLED = ['background', 'useForeground'];
|
|
13
|
+
function forwardAttrs(attrs) {
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const key of Object.keys(attrs)) {
|
|
16
|
+
if (!HANDLED.includes(key))
|
|
17
|
+
result[key] = attrs[key];
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
function isRecord(value) {
|
|
22
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
23
|
+
}
|
|
24
|
+
// `background` arrives untyped; narrow it to the discriminated union the mapping reads, else
|
|
25
|
+
// undefined (the impl then defaults to SelectableBackground, like RN).
|
|
26
|
+
function asBackground(value) {
|
|
27
|
+
if (!isRecord(value))
|
|
28
|
+
return undefined;
|
|
29
|
+
if (value.type === 'ThemeAttrAndroid') {
|
|
30
|
+
if (value.attribute === 'selectableItemBackground' ||
|
|
31
|
+
value.attribute === 'selectableItemBackgroundBorderless') {
|
|
32
|
+
return {
|
|
33
|
+
type: 'ThemeAttrAndroid',
|
|
34
|
+
attribute: value.attribute,
|
|
35
|
+
rippleRadius: typeof value.rippleRadius === 'number' ? value.rippleRadius : undefined,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
if (value.type === 'RippleAndroid') {
|
|
41
|
+
return {
|
|
42
|
+
type: 'RippleAndroid',
|
|
43
|
+
color: typeof value.color === 'string' ? value.color : null,
|
|
44
|
+
borderless: value.borderless === true,
|
|
45
|
+
rippleRadius: typeof value.rippleRadius === 'number' ? value.rippleRadius : undefined,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const TouchableNativeFeedbackImpl = defineComponent((_props, { slots, attrs: rawAttrs, emit }) => {
|
|
51
|
+
return () => {
|
|
52
|
+
const attrs = normalizeVueAttrs(rawAttrs);
|
|
53
|
+
const useForeground = attrs.useForeground === true;
|
|
54
|
+
// RN defaults a missing background to SelectableBackground() so the touchable always shows
|
|
55
|
+
// feedback; mirror that here.
|
|
56
|
+
const resolved = asBackground(attrs.background) ?? selectableBackground();
|
|
57
|
+
dlog(`TouchableNativeFeedback render ${resolved.type} useForeground ${useForeground}`);
|
|
58
|
+
const nativeProps = backgroundProps(resolved, useForeground);
|
|
59
|
+
const children = slots.default !== undefined ? slots.default() : [];
|
|
60
|
+
const feedback = h(View, nativeProps, () => children);
|
|
61
|
+
return h(Pressable, { ...forwardAttrs(attrs), ...emitPressableEvents(emit) }, { default: () => [feedback] });
|
|
62
|
+
};
|
|
63
|
+
}, {
|
|
64
|
+
name: 'TouchableNativeFeedback',
|
|
65
|
+
inheritAttrs: false,
|
|
66
|
+
emits: PRESSABLE_EMITS,
|
|
67
|
+
});
|
|
68
|
+
// The static factories live on the component value so callers reach TouchableNativeFeedback.Ripple(…)
|
|
69
|
+
// exactly like RN. Object.assign onto the defineComponent return (a plain object) keeps the typing.
|
|
70
|
+
export const TouchableNativeFeedback = Object.assign(TouchableNativeFeedbackImpl, {
|
|
71
|
+
SelectableBackground: selectableBackground,
|
|
72
|
+
SelectableBackgroundBorderless: selectableBackgroundBorderless,
|
|
73
|
+
Ripple: rippleBackground,
|
|
74
|
+
canUseNativeForeground,
|
|
75
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type IPressTimingProps } from '@symbiote-native/components';
|
|
2
|
+
import { type ISymbioteEvent, type IStyleProp, type IViewStyle } from '@symbiote-native/engine';
|
|
3
|
+
import { type IPressableEmits, type IPressableProps } from './pressable';
|
|
4
|
+
type ITouchableBaseProps = Omit<IPressableProps, 'style'> & IPressTimingProps & {
|
|
5
|
+
style?: IStyleProp<IViewStyle>;
|
|
6
|
+
};
|
|
7
|
+
export interface ITouchableOpacityProps extends ITouchableBaseProps {
|
|
8
|
+
activeOpacity?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ITouchableHighlightProps extends ITouchableBaseProps {
|
|
11
|
+
activeOpacity?: number;
|
|
12
|
+
underlayColor?: string;
|
|
13
|
+
}
|
|
14
|
+
export type ITouchableWithoutFeedbackProps = ITouchableBaseProps;
|
|
15
|
+
export declare const TouchableOpacity: import("vue").DefineSetupFnComponent<ITouchableOpacityProps, IPressableEmits, {}, ITouchableOpacityProps & {
|
|
16
|
+
onPress?: ((event: ISymbioteEvent) => any) | undefined;
|
|
17
|
+
onPressIn?: ((event: ISymbioteEvent) => any) | undefined;
|
|
18
|
+
onPressOut?: ((event: ISymbioteEvent) => any) | undefined;
|
|
19
|
+
onPressMove?: ((event: ISymbioteEvent) => any) | undefined;
|
|
20
|
+
onLongPress?: ((event: ISymbioteEvent) => any) | undefined;
|
|
21
|
+
onHoverIn?: ((event: ISymbioteEvent) => any) | undefined;
|
|
22
|
+
onHoverOut?: ((event: ISymbioteEvent) => any) | undefined;
|
|
23
|
+
}, import("vue").PublicProps>;
|
|
24
|
+
export declare const TouchableHighlight: import("vue").DefineSetupFnComponent<ITouchableHighlightProps, IPressableEmits, {}, ITouchableHighlightProps & {
|
|
25
|
+
onPress?: ((event: ISymbioteEvent) => any) | undefined;
|
|
26
|
+
onPressIn?: ((event: ISymbioteEvent) => any) | undefined;
|
|
27
|
+
onPressOut?: ((event: ISymbioteEvent) => any) | undefined;
|
|
28
|
+
onPressMove?: ((event: ISymbioteEvent) => any) | undefined;
|
|
29
|
+
onLongPress?: ((event: ISymbioteEvent) => any) | undefined;
|
|
30
|
+
onHoverIn?: ((event: ISymbioteEvent) => any) | undefined;
|
|
31
|
+
onHoverOut?: ((event: ISymbioteEvent) => any) | undefined;
|
|
32
|
+
}, import("vue").PublicProps>;
|
|
33
|
+
export declare const TouchableWithoutFeedback: import("vue").DefineSetupFnComponent<ITouchableBaseProps, IPressableEmits, {}, Omit<IPressableProps, "style"> & IPressTimingProps & {
|
|
34
|
+
style?: IStyleProp<IViewStyle>;
|
|
35
|
+
} & {
|
|
36
|
+
onPress?: ((event: ISymbioteEvent) => any) | undefined;
|
|
37
|
+
onPressIn?: ((event: ISymbioteEvent) => any) | undefined;
|
|
38
|
+
onPressOut?: ((event: ISymbioteEvent) => any) | undefined;
|
|
39
|
+
onPressMove?: ((event: ISymbioteEvent) => any) | undefined;
|
|
40
|
+
onLongPress?: ((event: ISymbioteEvent) => any) | undefined;
|
|
41
|
+
onHoverIn?: ((event: ISymbioteEvent) => any) | undefined;
|
|
42
|
+
onHoverOut?: ((event: ISymbioteEvent) => any) | undefined;
|
|
43
|
+
}, import("vue").PublicProps>;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// The Touchable* family for Vue, all built on Pressable, the Vue twin of the React adapter. The
|
|
2
|
+
// press-timing constants and the deactivation-floor math are shared with React
|
|
3
|
+
// (@symbiote-native/components/state/touchable); here Vue owns only the Animated wiring + the press
|
|
4
|
+
// scheduling state:
|
|
5
|
+
// TouchableOpacity: animate an Animated.Value opacity toward activeOpacity on press-in, back
|
|
6
|
+
// to 1 on press-out, driven from Pressable's onPressIn/onPressOut.
|
|
7
|
+
// TouchableHighlight: paint underlayColor + lower child opacity while pressed, via Pressable's
|
|
8
|
+
// style-as-function (the pressed state RN drives with setState).
|
|
9
|
+
// TouchableWithoutFeedback: no visual change, just the press wiring.
|
|
10
|
+
//
|
|
11
|
+
// Inputs arrive as attrs (untyped), narrowed with runtime guards. The handlers read attrs LIVE
|
|
12
|
+
// (they fire on events, not render) so a re-supplied callback / timing is always honored.
|
|
13
|
+
import { defineComponent, h } from '@vue/runtime-core';
|
|
14
|
+
import { computePressOutWait, DEFAULT_ACTIVE_OPACITY, DEFAULT_HIGHLIGHT_CHILD_OPACITY, DEFAULT_MIN_PRESS_DURATION_MS, DEFAULT_UNDERLAY_COLOR, OPACITY_ACTIVE_DURATION_MS, OPACITY_INACTIVE_DURATION_MS, RESTING_OPACITY, } from '@symbiote-native/components';
|
|
15
|
+
import { dlog, } from '@symbiote-native/engine';
|
|
16
|
+
import { Pressable, emitPressableEvents, PRESSABLE_EMITS, } from './pressable';
|
|
17
|
+
import { Animated } from '../modules/animated';
|
|
18
|
+
import { normalizeVueAttrs } from '../utils/normalize-attrs';
|
|
19
|
+
function numberOr(value, fallback) {
|
|
20
|
+
return typeof value === 'number' ? value : fallback;
|
|
21
|
+
}
|
|
22
|
+
function forwardExcept(attrs, handled) {
|
|
23
|
+
const result = {};
|
|
24
|
+
for (const key of Object.keys(attrs)) {
|
|
25
|
+
if (!handled.includes(key))
|
|
26
|
+
result[key] = attrs[key];
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
const TOUCHABLE_OPACITY_HANDLED = [
|
|
31
|
+
'activeOpacity',
|
|
32
|
+
'style',
|
|
33
|
+
'class',
|
|
34
|
+
'onPressIn',
|
|
35
|
+
'onPressOut',
|
|
36
|
+
'delayPressIn',
|
|
37
|
+
'delayPressOut',
|
|
38
|
+
'minPressDuration',
|
|
39
|
+
];
|
|
40
|
+
export const TouchableOpacity = defineComponent((_props, { slots, attrs: rawAttrs, emit }) => {
|
|
41
|
+
// One Animated.Value per mount, resting at full opacity. Held by identity in setup scope (an
|
|
42
|
+
// engine object, never a reactive ref). The Animated.View leaf commits it every frame.
|
|
43
|
+
const opacity = new Animated.Value(RESTING_OPACITY);
|
|
44
|
+
let pressInTimer;
|
|
45
|
+
let activatedAt;
|
|
46
|
+
function setOpacityTo(toValue, duration) {
|
|
47
|
+
Animated.timing(opacity, {
|
|
48
|
+
toValue,
|
|
49
|
+
duration,
|
|
50
|
+
easing: Animated.Easing.inOut(Animated.Easing.quad),
|
|
51
|
+
useNativeDriver: false,
|
|
52
|
+
}).start();
|
|
53
|
+
}
|
|
54
|
+
function clearPressInTimer() {
|
|
55
|
+
if (pressInTimer !== undefined) {
|
|
56
|
+
clearTimeout(pressInTimer);
|
|
57
|
+
pressInTimer = undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function activate(event) {
|
|
61
|
+
activatedAt = Date.now();
|
|
62
|
+
setOpacityTo(numberOr(rawAttrs.activeOpacity, DEFAULT_ACTIVE_OPACITY), OPACITY_ACTIVE_DURATION_MS);
|
|
63
|
+
emit('pressIn', event);
|
|
64
|
+
}
|
|
65
|
+
function deactivate(event) {
|
|
66
|
+
activatedAt = undefined;
|
|
67
|
+
setOpacityTo(RESTING_OPACITY, OPACITY_INACTIVE_DURATION_MS);
|
|
68
|
+
emit('pressOut', event);
|
|
69
|
+
}
|
|
70
|
+
function handlePressIn(event) {
|
|
71
|
+
const delayPressIn = numberOr(rawAttrs.delayPressIn, 0);
|
|
72
|
+
if (delayPressIn > 0) {
|
|
73
|
+
dlog(`TouchableOpacity pressIn deferred ${delayPressIn}ms`);
|
|
74
|
+
pressInTimer = setTimeout(() => {
|
|
75
|
+
pressInTimer = undefined;
|
|
76
|
+
activate(event);
|
|
77
|
+
}, delayPressIn);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
activate(event);
|
|
81
|
+
}
|
|
82
|
+
function handlePressOut(event) {
|
|
83
|
+
if (pressInTimer !== undefined) {
|
|
84
|
+
clearPressInTimer();
|
|
85
|
+
activate(event);
|
|
86
|
+
}
|
|
87
|
+
const heldFor = activatedAt === undefined ? 0 : Date.now() - activatedAt;
|
|
88
|
+
const wait = computePressOutWait(heldFor, numberOr(rawAttrs.minPressDuration, DEFAULT_MIN_PRESS_DURATION_MS), numberOr(rawAttrs.delayPressOut, 0));
|
|
89
|
+
if (wait > 0) {
|
|
90
|
+
dlog(`TouchableOpacity pressOut deferred ${wait}ms`);
|
|
91
|
+
setTimeout(() => deactivate(event), wait);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
deactivate(event);
|
|
95
|
+
}
|
|
96
|
+
return () => {
|
|
97
|
+
const attrs = normalizeVueAttrs(rawAttrs);
|
|
98
|
+
const style = attrs.style;
|
|
99
|
+
const pressableProps = {
|
|
100
|
+
...forwardExcept(attrs, TOUCHABLE_OPACITY_HANDLED),
|
|
101
|
+
...emitPressableEvents(emit),
|
|
102
|
+
onPressIn: handlePressIn,
|
|
103
|
+
onPressOut: handlePressOut,
|
|
104
|
+
};
|
|
105
|
+
const children = slots.default !== undefined ? slots.default() : [];
|
|
106
|
+
const feedback = h(Animated.View, { style: [style, { opacity }], class: attrs.class }, () => children);
|
|
107
|
+
return h(Pressable, pressableProps, { default: () => [feedback] });
|
|
108
|
+
};
|
|
109
|
+
}, {
|
|
110
|
+
name: 'TouchableOpacity',
|
|
111
|
+
inheritAttrs: false,
|
|
112
|
+
emits: PRESSABLE_EMITS,
|
|
113
|
+
});
|
|
114
|
+
const TOUCHABLE_HIGHLIGHT_HANDLED = ['activeOpacity', 'underlayColor', 'style'];
|
|
115
|
+
export const TouchableHighlight = defineComponent((_props, { slots, attrs: rawAttrs, emit }) => {
|
|
116
|
+
return () => {
|
|
117
|
+
const attrs = normalizeVueAttrs(rawAttrs);
|
|
118
|
+
const activeOpacity = numberOr(attrs.activeOpacity, DEFAULT_HIGHLIGHT_CHILD_OPACITY);
|
|
119
|
+
const underlayColor = typeof attrs.underlayColor === 'string' ? attrs.underlayColor : DEFAULT_UNDERLAY_COLOR;
|
|
120
|
+
const style = attrs.style;
|
|
121
|
+
function pressedStyle({ pressed }) {
|
|
122
|
+
if (!pressed)
|
|
123
|
+
return style;
|
|
124
|
+
const overlay = { backgroundColor: underlayColor, opacity: activeOpacity };
|
|
125
|
+
return [style, overlay];
|
|
126
|
+
}
|
|
127
|
+
const pressableProps = {
|
|
128
|
+
...forwardExcept(attrs, TOUCHABLE_HIGHLIGHT_HANDLED),
|
|
129
|
+
...emitPressableEvents(emit),
|
|
130
|
+
style: pressedStyle,
|
|
131
|
+
};
|
|
132
|
+
const children = slots.default !== undefined ? slots.default() : [];
|
|
133
|
+
return h(Pressable, pressableProps, { default: () => children });
|
|
134
|
+
};
|
|
135
|
+
}, {
|
|
136
|
+
name: 'TouchableHighlight',
|
|
137
|
+
inheritAttrs: false,
|
|
138
|
+
emits: PRESSABLE_EMITS,
|
|
139
|
+
});
|
|
140
|
+
export const TouchableWithoutFeedback = defineComponent((_props, { slots, attrs: rawAttrs, emit }) => {
|
|
141
|
+
return () => {
|
|
142
|
+
const attrs = normalizeVueAttrs(rawAttrs);
|
|
143
|
+
const children = slots.default !== undefined ? slots.default() : [];
|
|
144
|
+
return h(Pressable, { ...attrs, ...emitPressableEvents(emit) }, { default: () => children });
|
|
145
|
+
};
|
|
146
|
+
}, {
|
|
147
|
+
name: 'TouchableWithoutFeedback',
|
|
148
|
+
inheritAttrs: false,
|
|
149
|
+
emits: PRESSABLE_EMITS,
|
|
150
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { type VNode } from '@vue/runtime-core';
|
|
2
|
+
import { type ISeparatorProps, type ISeparators, type IViewabilityConfig, type IViewabilityConfigCallbackPair, type IViewableItemsChangedInfo } from '@symbiote-native/components';
|
|
3
|
+
import { type IStyleProp, type ISymbioteEvent, type IViewStyle } from '@symbiote-native/engine';
|
|
4
|
+
export type { ICellLayout, ISeparators, ISeparatorProps, IViewToken, IViewableItemsChangedInfo, IViewabilityConfig, IViewabilityConfigCallbackPair, IVirtualizedListHandle, } from '@symbiote-native/components';
|
|
5
|
+
export interface IVirtualizedListProps<ItemT> {
|
|
6
|
+
data: unknown;
|
|
7
|
+
getItem: (data: unknown, index: number) => ItemT;
|
|
8
|
+
getItemCount: (data: unknown) => number;
|
|
9
|
+
keyExtractor?: (item: ItemT, index: number) => string;
|
|
10
|
+
getItemLayout?: (data: unknown, index: number) => {
|
|
11
|
+
length: number;
|
|
12
|
+
offset: number;
|
|
13
|
+
index: number;
|
|
14
|
+
};
|
|
15
|
+
horizontal?: boolean;
|
|
16
|
+
inverted?: boolean;
|
|
17
|
+
extraData?: unknown;
|
|
18
|
+
onEndReachedThreshold?: number;
|
|
19
|
+
onStartReachedThreshold?: number;
|
|
20
|
+
refreshing?: boolean | null;
|
|
21
|
+
progressViewOffset?: number;
|
|
22
|
+
viewabilityConfig?: IViewabilityConfig;
|
|
23
|
+
viewabilityConfigCallbackPairs?: IViewabilityConfigCallbackPair<ItemT>[];
|
|
24
|
+
initialNumToRender?: number;
|
|
25
|
+
initialScrollIndex?: number;
|
|
26
|
+
maxToRenderPerBatch?: number;
|
|
27
|
+
updateCellsBatchingPeriod?: number;
|
|
28
|
+
windowSize?: number;
|
|
29
|
+
stickyHeaderIndices?: number[];
|
|
30
|
+
maintainVisibleContentPosition?: {
|
|
31
|
+
minIndexForVisible: number;
|
|
32
|
+
autoscrollToTopThreshold?: number;
|
|
33
|
+
};
|
|
34
|
+
onScroll?: (event: ISymbioteEvent) => void;
|
|
35
|
+
onScrollBeginDrag?: (event: ISymbioteEvent) => void;
|
|
36
|
+
onScrollEndDrag?: (event: ISymbioteEvent) => void;
|
|
37
|
+
onMomentumScrollBegin?: (event: ISymbioteEvent) => void;
|
|
38
|
+
onMomentumScrollEnd?: (event: ISymbioteEvent) => void;
|
|
39
|
+
scrollEventThrottle?: number;
|
|
40
|
+
keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
|
|
41
|
+
keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
|
|
42
|
+
style?: IStyleProp<IViewStyle>;
|
|
43
|
+
contentContainerStyle?: IStyleProp<IViewStyle>;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
export type IVirtualizedListSlots<ItemT> = {
|
|
47
|
+
item: (info: {
|
|
48
|
+
item: ItemT;
|
|
49
|
+
index: number;
|
|
50
|
+
separators: ISeparators;
|
|
51
|
+
}) => VNode[] | VNode;
|
|
52
|
+
separator?: (props: ISeparatorProps<ItemT>) => VNode[] | VNode;
|
|
53
|
+
header?: () => VNode[] | VNode;
|
|
54
|
+
footer?: () => VNode[] | VNode;
|
|
55
|
+
empty?: () => VNode[] | VNode;
|
|
56
|
+
};
|
|
57
|
+
export type IVirtualizedListEmits<ItemT> = {
|
|
58
|
+
viewableItemsChanged: (info: IViewableItemsChangedInfo<ItemT>) => void;
|
|
59
|
+
endReached: (info: {
|
|
60
|
+
distanceFromEnd: number;
|
|
61
|
+
}) => void;
|
|
62
|
+
startReached: (info: {
|
|
63
|
+
distanceFromStart: number;
|
|
64
|
+
}) => void;
|
|
65
|
+
refresh: () => void;
|
|
66
|
+
scrollToIndexFailed: (info: {
|
|
67
|
+
index: number;
|
|
68
|
+
highestMeasuredFrameIndex: number;
|
|
69
|
+
averageItemLength: number;
|
|
70
|
+
}) => void;
|
|
71
|
+
};
|
|
72
|
+
export declare const VirtualizedList: new <ItemT>(props: (IVirtualizedListProps<ItemT> & ({} | {
|
|
73
|
+
onRefresh?: (() => any) | undefined;
|
|
74
|
+
onViewableItemsChanged?: ((info: IViewableItemsChangedInfo<ItemT>) => any) | undefined;
|
|
75
|
+
onEndReached?: ((info: {
|
|
76
|
+
distanceFromEnd: number;
|
|
77
|
+
}) => any) | undefined;
|
|
78
|
+
onStartReached?: ((info: {
|
|
79
|
+
distanceFromStart: number;
|
|
80
|
+
}) => any) | undefined;
|
|
81
|
+
onScrollToIndexFailed?: ((info: {
|
|
82
|
+
index: number;
|
|
83
|
+
highestMeasuredFrameIndex: number;
|
|
84
|
+
averageItemLength: number;
|
|
85
|
+
}) => any) | undefined;
|
|
86
|
+
})) & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps) => import("vue").CreateComponentPublicInstanceWithMixins<IVirtualizedListProps<ItemT> & ({} | {
|
|
87
|
+
onRefresh?: (() => any) | undefined;
|
|
88
|
+
onViewableItemsChanged?: ((info: IViewableItemsChangedInfo<ItemT>) => any) | undefined;
|
|
89
|
+
onEndReached?: ((info: {
|
|
90
|
+
distanceFromEnd: number;
|
|
91
|
+
}) => any) | undefined;
|
|
92
|
+
onStartReached?: ((info: {
|
|
93
|
+
distanceFromStart: number;
|
|
94
|
+
}) => any) | undefined;
|
|
95
|
+
onScrollToIndexFailed?: ((info: {
|
|
96
|
+
index: number;
|
|
97
|
+
highestMeasuredFrameIndex: number;
|
|
98
|
+
averageItemLength: number;
|
|
99
|
+
}) => any) | undefined;
|
|
100
|
+
}), {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} | IVirtualizedListEmits<ItemT>, import("vue").PublicProps, {}, false, {}, import("vue").SlotsType<IVirtualizedListSlots<ItemT>>, {}, {}, string, {}, any, import("vue").ComponentProvideOptions, {
|
|
101
|
+
P: {};
|
|
102
|
+
B: {};
|
|
103
|
+
D: {};
|
|
104
|
+
C: {};
|
|
105
|
+
M: {};
|
|
106
|
+
Defaults: {};
|
|
107
|
+
}, (IVirtualizedListProps<ItemT> & {}) | (IVirtualizedListProps<ItemT> & {
|
|
108
|
+
onRefresh?: (() => any) | undefined;
|
|
109
|
+
onViewableItemsChanged?: ((info: IViewableItemsChangedInfo<ItemT>) => any) | undefined;
|
|
110
|
+
onEndReached?: ((info: {
|
|
111
|
+
distanceFromEnd: number;
|
|
112
|
+
}) => any) | undefined;
|
|
113
|
+
onStartReached?: ((info: {
|
|
114
|
+
distanceFromStart: number;
|
|
115
|
+
}) => any) | undefined;
|
|
116
|
+
onScrollToIndexFailed?: ((info: {
|
|
117
|
+
index: number;
|
|
118
|
+
highestMeasuredFrameIndex: number;
|
|
119
|
+
averageItemLength: number;
|
|
120
|
+
}) => any) | undefined;
|
|
121
|
+
}), {}, {}, {}, {}, {}>;
|