@nstudio/ui-collectionview
Version:
Customized NativeScript CollectionView for high performance lists. Supports vertical and horizontal modes, templating, and more.
98 lines • 3.85 kB
JavaScript
import { Observable } from '@nativescript/core';
import { NSVRoot, defineComponent, getCurrentInstance, h, ref, render, toRaw, watch } from 'nativescript-vue';
const LIST_CELL_ID = Symbol('list_cell_id');
const LIST_CELL_CONTAINER = Symbol('list_cell_container');
function getItemCtx(item, index, itemAlias, indexAlias) {
return {
[itemAlias]: item,
[indexAlias]: index,
index,
even: index % 2 === 0,
odd: index % 2 !== 0,
};
}
function propagateAppContext(vnode, appContext) {
if (!vnode || !appContext)
return;
vnode.appContext = appContext;
if (Array.isArray(vnode.children)) {
vnode.children.forEach((child) => propagateAppContext(child, appContext));
}
}
export const CollectionView = defineComponent({
props: {
items: {
type: Object,
required: true,
},
alias: {
type: String,
default: 'item',
},
itemIdGenerator: {
type: String,
default: '$index',
},
itemTemplateSelector: Function,
},
setup(props, ctx) {
// const itemsCtx = computed(() => (props.items as []).map((item, index) => getItemCtx(item, index, props.alias, props.itemIdGenerator)));
const itemTemplates = Object.keys(ctx.slots).map((slotName) => ({
key: slotName,
createView() {
// no need to return anything here
},
}));
const getSlotName = (item, index, items) => props.itemTemplateSelector?.(item, index, items) ?? 'default';
const collectionView = ref(null);
const vm = getCurrentInstance();
watch(() => props.items, (oldVal, newVal) => {
if (!(oldVal instanceof Observable)) {
collectionView.value.setAttribute('items', newVal);
}
});
let cellId = 0;
const cells = ref({});
function onItemLoading(event) {
const index = event.index;
const id = event.view?.[LIST_CELL_ID] ?? `${cellId++}`;
const item = defineComponent(event.bindingContext);
const itemCtx = getItemCtx(item, index, props.alias, props.itemIdGenerator);
// const itemCtx: ListItem = getItemCtx(props.items instanceof ObservableArray ? props.items.getItem(index) : props.items[index], index, props.alias, props.itemIdGenerator);
// update the cell data with the current row
const slotName = getSlotName(item, index, event.object.items);
cells.value[id] = {
itemCtx,
slotName,
};
// trigger an update!
// vm?.update();
// find the vnode rendering this cell
const container = event.view?.[LIST_CELL_CONTAINER] ?? new NSVRoot();
const vnode = ctx.slots[slotName]?.(itemCtx)[0];
propagateAppContext(vnode, vm?.appContext);
if (event.view) {
event.view._batchUpdate(() => {
// todo: handle the case where the slot is not found
render(vnode, container);
});
}
else {
// todo: handle the case where the slot is not found
render(vnode, container);
}
const cellEl = toRaw(vnode?.el?.nativeView);
cellEl[LIST_CELL_ID] = id;
cellEl[LIST_CELL_CONTAINER] = container;
event.view = cellEl;
}
return () => h('NativeCollectionView', {
ref: collectionView,
items: props.items,
itemTemplates,
onItemLoading,
itemTemplateSelector: (item, index, items) => getSlotName(item, index, items),
});
},
});
//# sourceMappingURL=component.js.map