@symbiote-native/vue 3.3.0 → 3.5.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/build/components/flat-list/index.d.ts +4 -3
- package/build/components/flat-list/index.js +18 -21
- package/build/components/input-accessory-view-props.d.ts +4 -4
- package/build/components/keyboard-avoiding-view.d.ts +11 -3
- package/build/components/keyboard-avoiding-view.js +38 -69
- package/build/components/layout-conformance-props.d.ts +4 -0
- package/build/components/layout-conformance-props.js +1 -0
- package/build/components/modal/index.d.ts +18 -5
- package/build/components/modal/index.js +53 -24
- package/build/components/refresh-control-props.d.ts +7 -7
- package/build/components/scroll-view/scroll-view-props.d.ts +8 -5
- package/build/components/section-list/index.d.ts +1 -1
- package/build/components/section-list/index.js +2 -6
- package/build/components/text-props.d.ts +3 -3
- package/build/components/touchable-props.d.ts +6 -6
- package/build/components/virtualized-list/index.d.ts +5 -75
- package/build/components/virtualized-list/index.js +130 -558
- package/build/components/virtualized-list/list-children.d.ts +18 -0
- package/build/components/virtualized-list/list-children.js +81 -0
- package/build/components/virtualized-list/list-elements.d.ts +7 -0
- package/build/components/virtualized-list/list-elements.js +29 -0
- package/build/components/virtualized-list/list-scroll-props.d.ts +20 -0
- package/build/components/virtualized-list/list-scroll-props.js +9 -0
- package/build/components/virtualized-list/narrow-props.d.ts +79 -0
- package/build/components/virtualized-list/narrow-props.js +89 -0
- package/build/components/virtualized-list/nested-scope.d.ts +3 -0
- package/build/components/virtualized-list/nested-scope.js +12 -0
- package/build/components/virtualized-list/user-handlers.d.ts +3 -0
- package/build/components/virtualized-list/user-handlers.js +24 -0
- package/build/components/virtualized-list/virtualized-list-props.d.ts +82 -0
- package/build/components/virtualized-list/virtualized-list-props.js +41 -0
- package/build/components/virtualized-section-list/index.d.ts +20 -5
- package/build/components/virtualized-section-list/index.js +81 -95
- package/build/components/virtualized-section-list/section-item-cell.d.ts +18 -0
- package/build/components/virtualized-section-list/section-item-cell.js +52 -0
- package/build/composables/use-animated-value.d.ts +7 -0
- package/build/composables/use-animated-value.js +14 -0
- package/build/composables/use-color-scheme.d.ts +1 -1
- package/build/create-transition/index.d.ts +2 -2
- package/build/create-transition/index.js +1 -1
- package/build/index.d.ts +13 -4
- package/build/index.js +16 -31
- package/build/modules/animated/index.d.ts +54 -41
- package/build/modules/animated/index.js +2 -26
- package/build/modules/app-registry/index.d.ts +3 -3
- package/build/modules/app-registry/index.js +2 -2
- package/build/modules/status-bar.js +22 -24
- package/metro-vue-transformer.cjs +177 -229
- package/package.json +6 -6
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type VNode } from '@vue/runtime-core';
|
|
2
|
+
import { type IListMetrics, type ISeparatorProps, type ISeparators } from '@symbiote-native/components';
|
|
3
|
+
import type { ISymbioteEvent } from '@symbiote-native/engine';
|
|
4
|
+
import type { INarrowedProps } from './narrow-props';
|
|
5
|
+
export type IChildrenArgs<ItemT> = {
|
|
6
|
+
props: INarrowedProps<ItemT>;
|
|
7
|
+
metrics: IListMetrics;
|
|
8
|
+
keyFor: (index: number) => string;
|
|
9
|
+
separatorOverrides: Map<number, Partial<ISeparatorProps<unknown>>>;
|
|
10
|
+
makeSeparators: (index: number) => ISeparators;
|
|
11
|
+
makeCellMeasure: (index: number) => (event: ISymbioteEvent) => void;
|
|
12
|
+
makeCellFocus: (index: number) => () => void;
|
|
13
|
+
};
|
|
14
|
+
export type IListChildren = {
|
|
15
|
+
children: VNode[];
|
|
16
|
+
hasHeader: boolean;
|
|
17
|
+
};
|
|
18
|
+
export declare function buildListChildren<ItemT>(args: IChildrenArgs<ItemT>): IListChildren;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// The list's child VNodes: header, the windowed cells with their spacers, footer
|
|
2
|
+
import { h } from '@vue/runtime-core';
|
|
3
|
+
import { FIRST_INDEX, LIST_SEGMENT_KIND, buildSeparatorProps, cellStyleOf, listStyleOf, planFromMetrics, spacerStyleOf, } from '@symbiote-native/components';
|
|
4
|
+
import { renderCellContent, resolveElement } from './list-elements.js';
|
|
5
|
+
// The separator lives INSIDE the cell's measuring wrapper, a sibling would be an extra flex child
|
|
6
|
+
// that lands every cell below a collapsed spacer short by the separator plus the gap
|
|
7
|
+
// It gates on the last index of the DATA, or a cell's measured height would change with the window
|
|
8
|
+
function separatorOf(args, index) {
|
|
9
|
+
const { props, metrics } = args;
|
|
10
|
+
if (props.itemSeparatorComponent === undefined)
|
|
11
|
+
return undefined;
|
|
12
|
+
if (index >= metrics.count - 1)
|
|
13
|
+
return undefined;
|
|
14
|
+
return h(props.itemSeparatorComponent, buildSeparatorProps(props.getItem(props.data, index), props.getItem(props.data, index + 1), args.separatorOverrides.get(index)));
|
|
15
|
+
}
|
|
16
|
+
// A cell the app flagged sticky IS the `sticky-header` tag, which pins by document order and so
|
|
17
|
+
// survives windowing, `stickyHeaderIndices` numbers paint children and does not
|
|
18
|
+
function cellVNode(args, segment, stickySet) {
|
|
19
|
+
const { props } = args;
|
|
20
|
+
const content = renderCellContent(props, {
|
|
21
|
+
item: props.getItem(props.data, segment.index),
|
|
22
|
+
index: segment.index,
|
|
23
|
+
separators: args.makeSeparators(segment.index),
|
|
24
|
+
});
|
|
25
|
+
const separator = separatorOf(args, segment.index);
|
|
26
|
+
const isSticky = stickySet?.has(segment.index) === true;
|
|
27
|
+
const key = `cell-${segment.key}`;
|
|
28
|
+
const cellProps = {
|
|
29
|
+
onLayout: args.makeCellMeasure(segment.index),
|
|
30
|
+
onFocus: args.makeCellFocus(segment.index),
|
|
31
|
+
style: cellStyleOf(props),
|
|
32
|
+
};
|
|
33
|
+
const children = separator === undefined ? [content] : [content, separator];
|
|
34
|
+
if (props.cellRendererComponent === undefined) {
|
|
35
|
+
return h(isSticky ? 'sticky-header' : 'view', { key, ...cellProps }, children);
|
|
36
|
+
}
|
|
37
|
+
const custom = h(props.cellRendererComponent, {
|
|
38
|
+
key,
|
|
39
|
+
...cellProps,
|
|
40
|
+
cellKey: segment.key,
|
|
41
|
+
index: segment.index,
|
|
42
|
+
item: props.getItem(props.data, segment.index),
|
|
43
|
+
}, { default: () => children });
|
|
44
|
+
// RN pins the custom component itself, the sticky wrapper only holds it
|
|
45
|
+
return isSticky ? h('sticky-header', { key }, [custom]) : custom;
|
|
46
|
+
}
|
|
47
|
+
function windowChildren(args) {
|
|
48
|
+
const { props, metrics } = args;
|
|
49
|
+
if (metrics.count === FIRST_INDEX) {
|
|
50
|
+
const empty = resolveElement(props.listEmptyComponent);
|
|
51
|
+
return empty === undefined
|
|
52
|
+
? []
|
|
53
|
+
: [
|
|
54
|
+
h('view', { key: 'list-empty', style: listStyleOf(props, undefined) }, [empty]),
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
const { plan, stickySet } = planFromMetrics(metrics, args.keyFor, props.stickyHeaderIndices);
|
|
58
|
+
return plan.segments.map(segment => segment.kind === LIST_SEGMENT_KIND.spacer
|
|
59
|
+
? h('view', {
|
|
60
|
+
key: segment.key,
|
|
61
|
+
style: spacerStyleOf(segment.extent, props.horizontal),
|
|
62
|
+
})
|
|
63
|
+
: cellVNode(args, segment, stickySet));
|
|
64
|
+
}
|
|
65
|
+
function slotVNodes(props, slot, slotStyle, key) {
|
|
66
|
+
return slot === undefined
|
|
67
|
+
? []
|
|
68
|
+
: [h('view', { key, style: listStyleOf(props, slotStyle) }, [slot])];
|
|
69
|
+
}
|
|
70
|
+
export function buildListChildren(args) {
|
|
71
|
+
const header = resolveElement(args.props.listHeaderComponent);
|
|
72
|
+
const footer = resolveElement(args.props.listFooterComponent);
|
|
73
|
+
return {
|
|
74
|
+
hasHeader: header !== undefined,
|
|
75
|
+
children: [
|
|
76
|
+
...slotVNodes(args.props, header, args.props.listHeaderComponentStyle, 'list-header'),
|
|
77
|
+
...windowChildren(args),
|
|
78
|
+
...slotVNodes(args.props, footer, args.props.listFooterComponentStyle, 'list-footer'),
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Component, type VNode } from '@vue/runtime-core';
|
|
2
|
+
import type { IListItemInfo, IRenderItem } from './narrow-props';
|
|
3
|
+
export declare function renderCellContent<ItemT>(renderers: {
|
|
4
|
+
renderItem?: IRenderItem<ItemT>;
|
|
5
|
+
listItemComponent?: Component;
|
|
6
|
+
}, info: IListItemInfo<ItemT>): VNode | VNode[] | undefined;
|
|
7
|
+
export declare function resolveElement(value: unknown): VNode | undefined;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Turning a header, footer or empty slot value into a VNode
|
|
2
|
+
import { h, isVNode } from '@vue/runtime-core';
|
|
3
|
+
import { pickItemRenderer } from '@symbiote-native/components';
|
|
4
|
+
// RN's `_renderElement`: the component wins over the `#item` slot. A list with neither keeps
|
|
5
|
+
// rendering empty cells here (the list logs it), RN would throw
|
|
6
|
+
export function renderCellContent(renderers, info) {
|
|
7
|
+
const { renderItem, listItemComponent } = renderers;
|
|
8
|
+
if (listItemComponent === undefined)
|
|
9
|
+
return renderItem?.(info);
|
|
10
|
+
pickItemRenderer({
|
|
11
|
+
hasRenderItem: renderItem !== undefined,
|
|
12
|
+
hasComponent: true,
|
|
13
|
+
});
|
|
14
|
+
return h(listItemComponent, info);
|
|
15
|
+
}
|
|
16
|
+
function isComponent(value) {
|
|
17
|
+
return (typeof value === 'function' || (typeof value === 'object' && value !== null));
|
|
18
|
+
}
|
|
19
|
+
// A list component element is either a Vue component (invoked via `h`) or a ready VNode, narrowed
|
|
20
|
+
// with `isVNode` first because a VNode is an object too
|
|
21
|
+
export function resolveElement(value) {
|
|
22
|
+
if (value === undefined || value === null)
|
|
23
|
+
return undefined;
|
|
24
|
+
if (isVNode(value))
|
|
25
|
+
return value;
|
|
26
|
+
if (isComponent(value))
|
|
27
|
+
return h(value);
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ISymbioteEvent } from '@symbiote-native/engine';
|
|
2
|
+
import type { INarrowedProps } from './narrow-props';
|
|
3
|
+
export type IScrollTagInputs<ItemT> = {
|
|
4
|
+
props: INarrowedProps<ItemT>;
|
|
5
|
+
total: number;
|
|
6
|
+
hasHeader: boolean;
|
|
7
|
+
onScroll: (event: ISymbioteEvent) => void;
|
|
8
|
+
onScrollBeginDrag: (event: ISymbioteEvent) => void;
|
|
9
|
+
onScrollEndDrag: (event: ISymbioteEvent) => void;
|
|
10
|
+
onMomentumScrollBegin: (event: ISymbioteEvent) => void;
|
|
11
|
+
onMomentumScrollEnd: (event: ISymbioteEvent) => void;
|
|
12
|
+
onContentSizeChange: (width: number, height: number) => void;
|
|
13
|
+
onLayout: (event: ISymbioteEvent) => void;
|
|
14
|
+
setRef: (el: unknown) => void;
|
|
15
|
+
commandedOffset: {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
} | undefined;
|
|
19
|
+
};
|
|
20
|
+
export declare function buildScrollProps<ItemT>(inputs: IScrollTagInputs<ItemT>): Record<string, unknown>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// The props handed to the scroll tag: the shared list set over the attrs the consumer passed
|
|
2
|
+
import { buildListScrollProps } from '@symbiote-native/components';
|
|
3
|
+
export function buildScrollProps(inputs) {
|
|
4
|
+
const { props, setRef, ...tagInputs } = inputs;
|
|
5
|
+
return {
|
|
6
|
+
...buildListScrollProps({ ...props, ...tagInputs }, props.forwarded),
|
|
7
|
+
ref: setRef,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Component, VNode } from '@vue/runtime-core';
|
|
2
|
+
import { type IViewableItemsChangedInfo, type IViewabilityConfig, type IViewabilityConfigCallbackPair, type ISeparators } from '@symbiote-native/components';
|
|
3
|
+
import type { IStyleProp, ISymbioteEvent, IViewStyle } from '@symbiote-native/engine';
|
|
4
|
+
import type { IVirtualizedListEmits, IVirtualizedListProps, IVirtualizedListSlots } from './virtualized-list-props';
|
|
5
|
+
export type IListItemInfo<ItemT> = {
|
|
6
|
+
item: ItemT;
|
|
7
|
+
index: number;
|
|
8
|
+
separators: ISeparators;
|
|
9
|
+
};
|
|
10
|
+
export type IRenderItem<ItemT> = (info: IListItemInfo<ItemT>) => VNode | VNode[] | undefined;
|
|
11
|
+
type IScrollHandler = (event: ISymbioteEvent) => void;
|
|
12
|
+
type IScrollToIndexFailedInfo = {
|
|
13
|
+
index: number;
|
|
14
|
+
highestMeasuredFrameIndex: number;
|
|
15
|
+
averageItemLength: number;
|
|
16
|
+
};
|
|
17
|
+
export type INarrowedProps<ItemT> = {
|
|
18
|
+
data: unknown;
|
|
19
|
+
getItem: (data: unknown, index: number) => ItemT;
|
|
20
|
+
getItemCount: (data: unknown) => number;
|
|
21
|
+
renderItem?: IRenderItem<ItemT>;
|
|
22
|
+
listItemComponent?: Component;
|
|
23
|
+
keyExtractor?: (item: ItemT, index: number) => string;
|
|
24
|
+
getItemLayout?: (data: unknown, index: number) => {
|
|
25
|
+
length: number;
|
|
26
|
+
offset: number;
|
|
27
|
+
index: number;
|
|
28
|
+
};
|
|
29
|
+
itemSeparatorComponent?: Component;
|
|
30
|
+
cellRendererComponent?: Component;
|
|
31
|
+
listHeaderComponent?: unknown;
|
|
32
|
+
listFooterComponent?: unknown;
|
|
33
|
+
listEmptyComponent?: unknown;
|
|
34
|
+
horizontal: boolean;
|
|
35
|
+
inverted: boolean;
|
|
36
|
+
onEndReached?: (info: {
|
|
37
|
+
distanceFromEnd: number;
|
|
38
|
+
}) => void;
|
|
39
|
+
onEndReachedThreshold?: number;
|
|
40
|
+
onStartReached?: (info: {
|
|
41
|
+
distanceFromStart: number;
|
|
42
|
+
}) => void;
|
|
43
|
+
onStartReachedThreshold?: number;
|
|
44
|
+
onRefresh?: () => void;
|
|
45
|
+
refreshing: boolean;
|
|
46
|
+
progressViewOffset?: number;
|
|
47
|
+
onViewableItemsChanged?: (info: IViewableItemsChangedInfo<ItemT>) => void;
|
|
48
|
+
viewabilityConfig?: IViewabilityConfig;
|
|
49
|
+
viewabilityConfigCallbackPairs?: IViewabilityConfigCallbackPair<ItemT>[];
|
|
50
|
+
onScrollToIndexFailed?: (info: IScrollToIndexFailedInfo) => void;
|
|
51
|
+
initialNumToRender: number;
|
|
52
|
+
initialScrollIndex?: number;
|
|
53
|
+
maxToRenderPerBatch: number;
|
|
54
|
+
updateCellsBatchingPeriod: number;
|
|
55
|
+
windowSize: number;
|
|
56
|
+
disableVirtualization: boolean;
|
|
57
|
+
stickyHeaderIndices?: number[];
|
|
58
|
+
maintainVisibleContentPosition?: {
|
|
59
|
+
minIndexForVisible: number;
|
|
60
|
+
autoscrollToTopThreshold?: number;
|
|
61
|
+
};
|
|
62
|
+
userOnScroll?: IScrollHandler;
|
|
63
|
+
style?: IStyleProp<IViewStyle>;
|
|
64
|
+
contentContainerStyle?: IStyleProp<IViewStyle>;
|
|
65
|
+
listHeaderComponentStyle?: IStyleProp<IViewStyle>;
|
|
66
|
+
listFooterComponentStyle?: IStyleProp<IViewStyle>;
|
|
67
|
+
keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
|
|
68
|
+
keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
|
|
69
|
+
forwarded: Record<string, unknown>;
|
|
70
|
+
};
|
|
71
|
+
export type INarrowSource<ItemT> = {
|
|
72
|
+
props: IVirtualizedListProps<ItemT>;
|
|
73
|
+
attrs: Record<string, unknown>;
|
|
74
|
+
slots: IVirtualizedListSlots<ItemT>;
|
|
75
|
+
emit: <K extends keyof IVirtualizedListEmits<ItemT>>(event: K, ...args: Parameters<IVirtualizedListEmits<ItemT>[K]>) => void;
|
|
76
|
+
listens: (onName: string) => boolean;
|
|
77
|
+
};
|
|
78
|
+
export declare function narrowProps<ItemT>(source: INarrowSource<ItemT>): INarrowedProps<ItemT>;
|
|
79
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// The props snapshot the list lifecycle works against: defaults applied, slots resolved, native
|
|
2
|
+
// listeners turned into emit bridges
|
|
3
|
+
import { DEFAULT_INITIAL_NUM_TO_RENDER, DEFAULT_MAX_TO_RENDER_PER_BATCH, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD, DEFAULT_WINDOW_SIZE, } from '@symbiote-native/components';
|
|
4
|
+
import { normalizeVueAttrs } from '../../utils/normalize-attrs.js';
|
|
5
|
+
import { componentFromSlot } from '../../utils/slots-to-render-props.js';
|
|
6
|
+
function isHandler(value) {
|
|
7
|
+
return typeof value === 'function';
|
|
8
|
+
}
|
|
9
|
+
function asNumber(value, fallback) {
|
|
10
|
+
return typeof value === 'number' ? value : fallback;
|
|
11
|
+
}
|
|
12
|
+
// The list composes `onScroll` and `onLayout` itself, a consumer-passed one is re-set there
|
|
13
|
+
function forwardAttrs(attrs) {
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const key of Object.keys(attrs)) {
|
|
16
|
+
if (key !== 'onScroll' && key !== 'onLayout')
|
|
17
|
+
result[key] = attrs[key];
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
// Each bridge exists only when the consumer listens, so a list builds RefreshControl and computes
|
|
22
|
+
// viewability strictly on demand
|
|
23
|
+
function emitBridges(source) {
|
|
24
|
+
const { emit, listens } = source;
|
|
25
|
+
return {
|
|
26
|
+
onEndReached: listens('onEndReached')
|
|
27
|
+
? info => emit('endReached', info)
|
|
28
|
+
: undefined,
|
|
29
|
+
onStartReached: listens('onStartReached')
|
|
30
|
+
? info => emit('startReached', info)
|
|
31
|
+
: undefined,
|
|
32
|
+
onRefresh: listens('onRefresh') ? () => emit('refresh') : undefined,
|
|
33
|
+
onViewableItemsChanged: listens('onViewableItemsChanged')
|
|
34
|
+
? info => emit('viewableItemsChanged', info)
|
|
35
|
+
: undefined,
|
|
36
|
+
onScrollToIndexFailed: listens('onScrollToIndexFailed')
|
|
37
|
+
? info => emit('scrollToIndexFailed', info)
|
|
38
|
+
: undefined,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function narrowProps(source) {
|
|
42
|
+
const { props, slots } = source;
|
|
43
|
+
const folded = normalizeVueAttrs(source.attrs);
|
|
44
|
+
return {
|
|
45
|
+
...emitBridges(source),
|
|
46
|
+
data: props.data,
|
|
47
|
+
getItem: props.getItem,
|
|
48
|
+
getItemCount: props.getItemCount,
|
|
49
|
+
// `#item` IS the render fn, `#separator` carries scope props so it becomes a component, the
|
|
50
|
+
// scopeless header, footer and empty slots are handed over bare
|
|
51
|
+
renderItem: slots.item,
|
|
52
|
+
listItemComponent: props.listItemComponent,
|
|
53
|
+
keyExtractor: props.keyExtractor,
|
|
54
|
+
getItemLayout: props.getItemLayout,
|
|
55
|
+
itemSeparatorComponent: componentFromSlot(slots.separator),
|
|
56
|
+
cellRendererComponent: props.cellRendererComponent,
|
|
57
|
+
listHeaderComponent: slots.header,
|
|
58
|
+
listFooterComponent: slots.footer,
|
|
59
|
+
listEmptyComponent: slots.empty,
|
|
60
|
+
horizontal: props.horizontal === true,
|
|
61
|
+
inverted: props.inverted === true,
|
|
62
|
+
onEndReachedThreshold: typeof props.onEndReachedThreshold === 'number'
|
|
63
|
+
? props.onEndReachedThreshold
|
|
64
|
+
: undefined,
|
|
65
|
+
onStartReachedThreshold: typeof props.onStartReachedThreshold === 'number'
|
|
66
|
+
? props.onStartReachedThreshold
|
|
67
|
+
: undefined,
|
|
68
|
+
refreshing: props.refreshing === true,
|
|
69
|
+
progressViewOffset: props.progressViewOffset,
|
|
70
|
+
viewabilityConfig: props.viewabilityConfig,
|
|
71
|
+
viewabilityConfigCallbackPairs: props.viewabilityConfigCallbackPairs,
|
|
72
|
+
initialNumToRender: asNumber(props.initialNumToRender, DEFAULT_INITIAL_NUM_TO_RENDER),
|
|
73
|
+
initialScrollIndex: props.initialScrollIndex,
|
|
74
|
+
maxToRenderPerBatch: asNumber(props.maxToRenderPerBatch, DEFAULT_MAX_TO_RENDER_PER_BATCH),
|
|
75
|
+
updateCellsBatchingPeriod: asNumber(props.updateCellsBatchingPeriod, DEFAULT_UPDATE_CELLS_BATCHING_PERIOD),
|
|
76
|
+
windowSize: asNumber(props.windowSize, DEFAULT_WINDOW_SIZE),
|
|
77
|
+
disableVirtualization: props.disableVirtualization === true,
|
|
78
|
+
stickyHeaderIndices: props.stickyHeaderIndices,
|
|
79
|
+
maintainVisibleContentPosition: props.maintainVisibleContentPosition,
|
|
80
|
+
userOnScroll: isHandler(folded.onScroll) ? folded.onScroll : undefined,
|
|
81
|
+
style: props.style,
|
|
82
|
+
contentContainerStyle: props.contentContainerStyle,
|
|
83
|
+
listHeaderComponentStyle: props.listHeaderComponentStyle,
|
|
84
|
+
listFooterComponentStyle: props.listFooterComponentStyle,
|
|
85
|
+
keyboardShouldPersistTaps: props.keyboardShouldPersistTaps,
|
|
86
|
+
keyboardDismissMode: props.keyboardDismissMode,
|
|
87
|
+
forwarded: forwardAttrs(folded),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// The scope a list hands down to the lists nested in its cells, Vue's way to carry it
|
|
2
|
+
// What it holds and how it behaves is `createListNesting` in the shared components package
|
|
3
|
+
import { inject, provide } from '@vue/runtime-core';
|
|
4
|
+
const SCOPE_KEY = Symbol('virtualizedListScope');
|
|
5
|
+
// Null outside every list, the scope of the nearest list above otherwise
|
|
6
|
+
export function useVirtualizedListScope() {
|
|
7
|
+
return inject(SCOPE_KEY, null);
|
|
8
|
+
}
|
|
9
|
+
// A portal-like component (Modal) passes null, its content sits outside the list's scroll
|
|
10
|
+
export function provideVirtualizedListScope(scope) {
|
|
11
|
+
provide(SCOPE_KEY, scope);
|
|
12
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// The app's own scroll listeners, read off the narrowed props and the attrs forwarded with them
|
|
2
|
+
function listenerOf(forwarded, name) {
|
|
3
|
+
const listener = forwarded[name];
|
|
4
|
+
return typeof listener === 'function'
|
|
5
|
+
? (event) => void listener(event)
|
|
6
|
+
: undefined;
|
|
7
|
+
}
|
|
8
|
+
function sizeListenerOf(forwarded) {
|
|
9
|
+
const listener = forwarded.onContentSizeChange;
|
|
10
|
+
return typeof listener === 'function'
|
|
11
|
+
? (width, height) => void listener(width, height)
|
|
12
|
+
: undefined;
|
|
13
|
+
}
|
|
14
|
+
export function userHandlersOf(props) {
|
|
15
|
+
const { forwarded } = props;
|
|
16
|
+
return {
|
|
17
|
+
onContentSizeChange: sizeListenerOf(forwarded),
|
|
18
|
+
onScroll: props.userOnScroll,
|
|
19
|
+
onScrollBeginDrag: listenerOf(forwarded, 'onScrollBeginDrag'),
|
|
20
|
+
onScrollEndDrag: listenerOf(forwarded, 'onScrollEndDrag'),
|
|
21
|
+
onMomentumScrollBegin: listenerOf(forwarded, 'onMomentumScrollBegin'),
|
|
22
|
+
onMomentumScrollEnd: listenerOf(forwarded, 'onMomentumScrollEnd'),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Component, VNode } from '@vue/runtime-core';
|
|
2
|
+
import type { IInnerViewRef, IViewabilityConfig, IViewabilityConfigCallbackPair, IViewableItemsChangedInfo, ISeparatorProps, ISeparators } from '@symbiote-native/components';
|
|
3
|
+
import type { IStyleProp, ISymbioteEvent, IViewStyle } from '@symbiote-native/engine';
|
|
4
|
+
export type IVirtualizedListProps<ItemT> = {
|
|
5
|
+
data: unknown;
|
|
6
|
+
getItem: (data: unknown, index: number) => ItemT;
|
|
7
|
+
getItemCount: (data: unknown) => number;
|
|
8
|
+
keyExtractor?: (item: ItemT, index: number) => string;
|
|
9
|
+
getItemLayout?: (data: unknown, index: number) => {
|
|
10
|
+
length: number;
|
|
11
|
+
offset: number;
|
|
12
|
+
index: number;
|
|
13
|
+
};
|
|
14
|
+
horizontal?: boolean;
|
|
15
|
+
inverted?: boolean;
|
|
16
|
+
extraData?: unknown;
|
|
17
|
+
onEndReachedThreshold?: number;
|
|
18
|
+
onStartReachedThreshold?: number;
|
|
19
|
+
refreshing?: boolean | null;
|
|
20
|
+
progressViewOffset?: number;
|
|
21
|
+
viewabilityConfig?: IViewabilityConfig;
|
|
22
|
+
viewabilityConfigCallbackPairs?: IViewabilityConfigCallbackPair<ItemT>[];
|
|
23
|
+
initialNumToRender?: number;
|
|
24
|
+
initialScrollIndex?: number;
|
|
25
|
+
maxToRenderPerBatch?: number;
|
|
26
|
+
updateCellsBatchingPeriod?: number;
|
|
27
|
+
windowSize?: number;
|
|
28
|
+
cellRendererComponent?: Component;
|
|
29
|
+
listItemComponent?: Component;
|
|
30
|
+
disableVirtualization?: boolean;
|
|
31
|
+
stickyHeaderIndices?: number[];
|
|
32
|
+
maintainVisibleContentPosition?: {
|
|
33
|
+
minIndexForVisible: number;
|
|
34
|
+
autoscrollToTopThreshold?: number;
|
|
35
|
+
};
|
|
36
|
+
onScroll?: (event: ISymbioteEvent) => void;
|
|
37
|
+
onScrollBeginDrag?: (event: ISymbioteEvent) => void;
|
|
38
|
+
onScrollEndDrag?: (event: ISymbioteEvent) => void;
|
|
39
|
+
onMomentumScrollBegin?: (event: ISymbioteEvent) => void;
|
|
40
|
+
onMomentumScrollEnd?: (event: ISymbioteEvent) => void;
|
|
41
|
+
onContentSizeChange?: (width: number, height: number) => void;
|
|
42
|
+
scrollEventThrottle?: number;
|
|
43
|
+
keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
|
|
44
|
+
keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
|
|
45
|
+
removeClippedSubviews?: boolean;
|
|
46
|
+
nestedScrollEnabled?: boolean;
|
|
47
|
+
stickyHeaderHiddenOnScroll?: boolean;
|
|
48
|
+
innerViewRef?: IInnerViewRef;
|
|
49
|
+
style?: IStyleProp<IViewStyle>;
|
|
50
|
+
contentContainerStyle?: IStyleProp<IViewStyle>;
|
|
51
|
+
listHeaderComponentStyle?: IStyleProp<IViewStyle>;
|
|
52
|
+
listFooterComponentStyle?: IStyleProp<IViewStyle>;
|
|
53
|
+
[key: string]: unknown;
|
|
54
|
+
};
|
|
55
|
+
export type IVirtualizedListSlots<ItemT> = {
|
|
56
|
+
item: (info: {
|
|
57
|
+
item: ItemT;
|
|
58
|
+
index: number;
|
|
59
|
+
separators: ISeparators;
|
|
60
|
+
}) => VNode[] | VNode;
|
|
61
|
+
separator?: (props: ISeparatorProps<ItemT>) => VNode[] | VNode;
|
|
62
|
+
header?: () => VNode[] | VNode;
|
|
63
|
+
footer?: () => VNode[] | VNode;
|
|
64
|
+
empty?: () => VNode[] | VNode;
|
|
65
|
+
};
|
|
66
|
+
export type IVirtualizedListEmits<ItemT> = {
|
|
67
|
+
viewableItemsChanged: (info: IViewableItemsChangedInfo<ItemT>) => void;
|
|
68
|
+
endReached: (info: {
|
|
69
|
+
distanceFromEnd: number;
|
|
70
|
+
}) => void;
|
|
71
|
+
startReached: (info: {
|
|
72
|
+
distanceFromStart: number;
|
|
73
|
+
}) => void;
|
|
74
|
+
refresh: () => void;
|
|
75
|
+
scrollToIndexFailed: (info: {
|
|
76
|
+
index: number;
|
|
77
|
+
highestMeasuredFrameIndex: number;
|
|
78
|
+
averageItemLength: number;
|
|
79
|
+
}) => void;
|
|
80
|
+
};
|
|
81
|
+
export declare const PROP_KEYS: readonly ["data", "getItem", "getItemCount", "keyExtractor", "getItemLayout", "viewabilityConfig", "viewabilityConfigCallbackPairs", "extraData", "horizontal", "inverted", "onEndReachedThreshold", "onStartReachedThreshold", "refreshing", "progressViewOffset", "initialNumToRender", "initialScrollIndex", "maxToRenderPerBatch", "updateCellsBatchingPeriod", "windowSize", "cellRendererComponent", "listItemComponent", "disableVirtualization", "stickyHeaderIndices", "maintainVisibleContentPosition", "style", "contentContainerStyle", "listHeaderComponentStyle", "listFooterComponentStyle", "keyboardShouldPersistTaps", "keyboardDismissMode"];
|
|
82
|
+
export declare const EMIT_KEYS: readonly ["viewableItemsChanged", "endReached", "startReached", "refresh", "scrollToIndexFailed"];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// The public prop, slot and emit contract of the Vue VirtualizedList
|
|
2
|
+
// The runtime `props` declaration, the raw scroll events and the emit events are absent on purpose
|
|
3
|
+
export const PROP_KEYS = [
|
|
4
|
+
'data',
|
|
5
|
+
'getItem',
|
|
6
|
+
'getItemCount',
|
|
7
|
+
'keyExtractor',
|
|
8
|
+
'getItemLayout',
|
|
9
|
+
'viewabilityConfig',
|
|
10
|
+
'viewabilityConfigCallbackPairs',
|
|
11
|
+
'extraData',
|
|
12
|
+
'horizontal',
|
|
13
|
+
'inverted',
|
|
14
|
+
'onEndReachedThreshold',
|
|
15
|
+
'onStartReachedThreshold',
|
|
16
|
+
'refreshing',
|
|
17
|
+
'progressViewOffset',
|
|
18
|
+
'initialNumToRender',
|
|
19
|
+
'initialScrollIndex',
|
|
20
|
+
'maxToRenderPerBatch',
|
|
21
|
+
'updateCellsBatchingPeriod',
|
|
22
|
+
'windowSize',
|
|
23
|
+
'cellRendererComponent',
|
|
24
|
+
'listItemComponent',
|
|
25
|
+
'disableVirtualization',
|
|
26
|
+
'stickyHeaderIndices',
|
|
27
|
+
'maintainVisibleContentPosition',
|
|
28
|
+
'style',
|
|
29
|
+
'contentContainerStyle',
|
|
30
|
+
'listHeaderComponentStyle',
|
|
31
|
+
'listFooterComponentStyle',
|
|
32
|
+
'keyboardShouldPersistTaps',
|
|
33
|
+
'keyboardDismissMode',
|
|
34
|
+
];
|
|
35
|
+
export const EMIT_KEYS = [
|
|
36
|
+
'viewableItemsChanged',
|
|
37
|
+
'endReached',
|
|
38
|
+
'startReached',
|
|
39
|
+
'refresh',
|
|
40
|
+
'scrollToIndexFailed',
|
|
41
|
+
];
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { type VNode } from '@vue/runtime-core';
|
|
2
|
-
import { type ISection, type ISeparatorProps, type ISeparators, type IVirtualizedSectionListHandle } from '@symbiote-native/components';
|
|
2
|
+
import { type IInnerViewRef, type ISection as ICoreSection, type ISeparatorProps, type ISeparators, type IVirtualizedSectionListHandle } from '@symbiote-native/components';
|
|
3
3
|
import { type IStyleProp, type ISymbioteEvent, type IViewStyle } from '@symbiote-native/engine';
|
|
4
|
-
export type { ISection } from '@symbiote-native/components';
|
|
5
4
|
export type { IVirtualizedSectionListHandle };
|
|
6
|
-
export
|
|
5
|
+
export type ISection<ItemT> = ICoreSection<ItemT> & {
|
|
6
|
+
renderItem?: (info: {
|
|
7
|
+
item: ItemT;
|
|
8
|
+
index: number;
|
|
9
|
+
section: ISection<ItemT>;
|
|
10
|
+
separators: ISeparators;
|
|
11
|
+
}) => VNode[] | VNode;
|
|
12
|
+
ItemSeparatorComponent?: (props: ISeparatorProps<ItemT>) => VNode[] | VNode;
|
|
13
|
+
};
|
|
14
|
+
export type IVirtualizedSectionListProps<ItemT> = {
|
|
7
15
|
sections: ReadonlyArray<ISection<ItemT>>;
|
|
8
16
|
keyExtractor?: (item: ItemT, index: number) => string;
|
|
9
17
|
getItemLayout?: (data: ReadonlyArray<ISection<ItemT>> | null, index: number) => {
|
|
@@ -22,7 +30,9 @@ export interface IVirtualizedSectionListProps<ItemT> {
|
|
|
22
30
|
maxToRenderPerBatch?: number;
|
|
23
31
|
updateCellsBatchingPeriod?: number;
|
|
24
32
|
windowSize?: number;
|
|
33
|
+
disableVirtualization?: boolean;
|
|
25
34
|
inverted?: boolean;
|
|
35
|
+
horizontal?: boolean;
|
|
26
36
|
maintainVisibleContentPosition?: {
|
|
27
37
|
minIndexForVisible: number;
|
|
28
38
|
autoscrollToTopThreshold?: number;
|
|
@@ -32,15 +42,20 @@ export interface IVirtualizedSectionListProps<ItemT> {
|
|
|
32
42
|
onScrollEndDrag?: (event: ISymbioteEvent) => void;
|
|
33
43
|
onMomentumScrollBegin?: (event: ISymbioteEvent) => void;
|
|
34
44
|
onMomentumScrollEnd?: (event: ISymbioteEvent) => void;
|
|
45
|
+
onContentSizeChange?: (width: number, height: number) => void;
|
|
35
46
|
scrollEventThrottle?: number;
|
|
36
47
|
keyboardShouldPersistTaps?: boolean | 'always' | 'never' | 'handled';
|
|
37
48
|
keyboardDismissMode?: 'none' | 'on-drag' | 'interactive';
|
|
38
49
|
removeClippedSubviews?: boolean;
|
|
39
50
|
nestedScrollEnabled?: boolean;
|
|
51
|
+
stickyHeaderHiddenOnScroll?: boolean;
|
|
52
|
+
innerViewRef?: IInnerViewRef;
|
|
40
53
|
style?: IStyleProp<IViewStyle>;
|
|
41
54
|
contentContainerStyle?: IStyleProp<IViewStyle>;
|
|
55
|
+
listHeaderComponentStyle?: IStyleProp<IViewStyle>;
|
|
56
|
+
listFooterComponentStyle?: IStyleProp<IViewStyle>;
|
|
42
57
|
[key: string]: unknown;
|
|
43
|
-
}
|
|
58
|
+
};
|
|
44
59
|
export type IVirtualizedSectionListSlots<ItemT> = {
|
|
45
60
|
item: (info: {
|
|
46
61
|
item: ItemT;
|
|
@@ -54,7 +69,7 @@ export type IVirtualizedSectionListSlots<ItemT> = {
|
|
|
54
69
|
sectionFooter?: (info: {
|
|
55
70
|
section: ISection<ItemT>;
|
|
56
71
|
}) => VNode[] | VNode;
|
|
57
|
-
sectionSeparator?: () => VNode[] | VNode;
|
|
72
|
+
sectionSeparator?: (props: ISeparatorProps<ItemT>) => VNode[] | VNode;
|
|
58
73
|
separator?: (props: ISeparatorProps<ItemT>) => VNode[] | VNode;
|
|
59
74
|
header?: () => VNode[] | VNode;
|
|
60
75
|
footer?: () => VNode[] | VNode;
|