naive-ui
Version:
A Vue 3 Component Library. Fairly Complete, Theme Customizable, Uses TypeScript, Fast
351 lines • 11.6 kB
JavaScript
import { computed, ref } from 'vue';
import { useMemo, useMergedState } from 'vooks';
import { createTreeMate } from 'treemate';
import { call, warn } from "../../_utils/index.mjs";
import { getDefaultPageSize } from "../../pagination/src/utils.mjs";
import { createShallowClonedObject } from "./utils.mjs";
import { useSorter } from "./use-sorter.mjs";
// useTableData combines filter, sorter and pagination
export function useTableData(props, {
dataRelatedColsRef
}) {
const selectionColumnRef = computed(() => {
const getSelectionColumn = cols => {
for (let i = 0; i < cols.length; ++i) {
const col = cols[i];
if ('children' in col) {
return getSelectionColumn(col.children);
} else if (col.type === 'selection') {
return col;
}
}
return null;
};
return getSelectionColumn(props.columns);
});
const treeMateRef = computed(() => {
const {
childrenKey
} = props;
return createTreeMate(props.data, {
ignoreEmptyChildren: true,
getKey: props.rowKey,
getChildren: rowData => rowData[childrenKey],
getDisabled: rowData => {
var _a, _b;
if ((_b = (_a = selectionColumnRef.value) === null || _a === void 0 ? void 0 : _a.disabled) === null || _b === void 0 ? void 0 : _b.call(_a, rowData)) {
return true;
}
return false;
}
});
});
const childTriggerColIndexRef = useMemo(() => {
const {
columns
} = props;
const {
length
} = columns;
let firstContentfulColIndex = null;
for (let i = 0; i < length; ++i) {
const col = columns[i];
if (!col.type && firstContentfulColIndex === null) {
firstContentfulColIndex = i;
}
if ('tree' in col && col.tree) {
return i;
}
}
return firstContentfulColIndex || 0;
});
const uncontrolledFilterStateRef = ref({});
const {
pagination
} = props;
const uncontrolledCurrentPageRef = ref(pagination ? pagination.defaultPage || 1 : 1);
const uncontrolledPageSizeRef = ref(getDefaultPageSize(pagination));
const mergedFilterStateRef = computed(() => {
const columnsWithControlledFilter = dataRelatedColsRef.value.filter(column => {
return column.filterOptionValues !== undefined || column.filterOptionValue !== undefined;
});
const controlledFilterState = {};
columnsWithControlledFilter.forEach(column => {
var _a;
if (column.type === 'selection' || column.type === 'expand') return;
if (column.filterOptionValues === undefined) {
controlledFilterState[column.key] = (_a = column.filterOptionValue) !== null && _a !== void 0 ? _a : null;
} else {
controlledFilterState[column.key] = column.filterOptionValues;
}
});
const activeFilters = Object.assign(createShallowClonedObject(uncontrolledFilterStateRef.value), controlledFilterState);
return activeFilters;
});
const filteredDataRef = computed(() => {
const mergedFilterState = mergedFilterStateRef.value;
const {
columns
} = props;
function createDefaultFilter(columnKey) {
return (filterOptionValue, row) => !!~String(row[columnKey]).indexOf(String(filterOptionValue));
}
const {
value: {
treeNodes: data
}
} = treeMateRef;
const columnEntries = [];
columns.forEach(column => {
if (column.type === 'selection' || column.type === 'expand' || 'children' in column) {
return;
}
columnEntries.push([column.key, column]);
});
return data ? data.filter(tmNode => {
const {
rawNode: row
} = tmNode;
// traverse all filters
for (const [columnKey, column] of columnEntries) {
let activeFilterOptionValues = mergedFilterState[columnKey];
if (activeFilterOptionValues == null) continue;
if (!Array.isArray(activeFilterOptionValues)) {
activeFilterOptionValues = [activeFilterOptionValues];
}
if (!activeFilterOptionValues.length) continue;
// When async, filter won't be set, so data won't be filtered
const filter = column.filter === 'default' ? createDefaultFilter(columnKey) : column.filter;
if (column && typeof filter === 'function') {
if (column.filterMode === 'and') {
if (activeFilterOptionValues.some(filterOptionValue => !filter(filterOptionValue, row))) {
return false;
}
} else {
if (activeFilterOptionValues.some(filterOptionValue => filter(filterOptionValue, row))) {
continue;
} else {
return false;
}
}
}
}
return true;
}) : [];
});
const {
sortedDataRef,
deriveNextSorter,
mergedSortStateRef,
sort,
clearSorter
} = useSorter(props, {
dataRelatedColsRef,
filteredDataRef
});
// initialize
dataRelatedColsRef.value.forEach(column => {
var _a;
if (column.filter) {
const defaultFilterOptionValues = column.defaultFilterOptionValues;
if (column.filterMultiple) {
uncontrolledFilterStateRef.value[column.key] = defaultFilterOptionValues || [];
} else if (defaultFilterOptionValues !== undefined) {
// this branch is for compatibility, someone may use `values` in single filter mode
uncontrolledFilterStateRef.value[column.key] = defaultFilterOptionValues === null ? [] : defaultFilterOptionValues;
} else {
uncontrolledFilterStateRef.value[column.key] = (_a = column.defaultFilterOptionValue) !== null && _a !== void 0 ? _a : null;
}
}
});
const controlledCurrentPageRef = computed(() => {
const {
pagination
} = props;
if (pagination === false) return undefined;
return pagination.page;
});
const controlledPageSizeRef = computed(() => {
const {
pagination
} = props;
if (pagination === false) return undefined;
return pagination.pageSize;
});
const _mergedCurrentPageRef = useMergedState(controlledCurrentPageRef, uncontrolledCurrentPageRef);
const mergedPageSizeRef = useMergedState(controlledPageSizeRef, uncontrolledPageSizeRef);
const boundedMergedCurrentPageRef = useMemo(() => {
const page = _mergedCurrentPageRef.value;
return props.remote ? page : Math.max(1, Math.min(Math.ceil(filteredDataRef.value.length / mergedPageSizeRef.value), page));
});
const mergedPageCountRef = computed(() => {
const {
pagination
} = props;
if (pagination) {
const {
pageCount
} = pagination;
if (pageCount !== undefined) return pageCount;
}
return undefined;
});
const paginatedDataRef = computed(() => {
if (props.remote) return treeMateRef.value.treeNodes;
if (!props.pagination) return sortedDataRef.value;
const pageSize = mergedPageSizeRef.value;
const startIndex = (boundedMergedCurrentPageRef.value - 1) * pageSize;
return sortedDataRef.value.slice(startIndex, startIndex + pageSize);
});
const rawPaginatedDataRef = computed(() => {
return paginatedDataRef.value.map(tmNode => tmNode.rawNode);
});
function mergedOnUpdatePage(page) {
const {
pagination
} = props;
if (pagination) {
const {
onChange,
'onUpdate:page': _onUpdatePage,
onUpdatePage
} = pagination;
if (onChange) call(onChange, page);
if (onUpdatePage) call(onUpdatePage, page);
if (_onUpdatePage) call(_onUpdatePage, page);
doUpdatePage(page);
}
}
function mergedOnUpdatePageSize(pageSize) {
const {
pagination
} = props;
if (pagination) {
const {
onPageSizeChange,
'onUpdate:pageSize': _onUpdatePageSize,
onUpdatePageSize
} = pagination;
if (onPageSizeChange) call(onPageSizeChange, pageSize);
if (onUpdatePageSize) call(onUpdatePageSize, pageSize);
if (_onUpdatePageSize) call(_onUpdatePageSize, pageSize);
doUpdatePageSize(pageSize);
}
}
const mergedItemCountRef = computed(() => {
if (props.remote) {
const {
pagination
} = props;
if (pagination) {
const {
itemCount
} = pagination;
if (itemCount !== undefined) return itemCount;
}
return undefined;
}
return filteredDataRef.value.length;
});
const mergedPaginationRef = computed(() => {
return Object.assign(Object.assign({}, props.pagination), {
// reset deprecated methods
onChange: undefined,
onUpdatePage: undefined,
onUpdatePageSize: undefined,
onPageSizeChange: undefined,
'onUpdate:page': mergedOnUpdatePage,
'onUpdate:pageSize': mergedOnUpdatePageSize,
// writing merged props after pagination to avoid
// pagination[key] === undefined
// key still exists but value is undefined
page: boundedMergedCurrentPageRef.value,
pageSize: mergedPageSizeRef.value,
pageCount: mergedItemCountRef.value === undefined ? mergedPageCountRef.value : undefined,
itemCount: mergedItemCountRef.value
});
});
function doUpdatePage(page) {
const {
'onUpdate:page': _onUpdatePage,
onPageChange,
onUpdatePage
} = props;
if (onUpdatePage) call(onUpdatePage, page);
if (_onUpdatePage) call(_onUpdatePage, page);
if (onPageChange) call(onPageChange, page);
uncontrolledCurrentPageRef.value = page;
}
function doUpdatePageSize(pageSize) {
const {
'onUpdate:pageSize': _onUpdatePageSize,
onPageSizeChange,
onUpdatePageSize
} = props;
if (onPageSizeChange) call(onPageSizeChange, pageSize);
if (onUpdatePageSize) call(onUpdatePageSize, pageSize);
if (_onUpdatePageSize) call(_onUpdatePageSize, pageSize);
uncontrolledPageSizeRef.value = pageSize;
}
function doUpdateFilters(filters, sourceColumn) {
const {
onUpdateFilters,
'onUpdate:filters': _onUpdateFilters,
onFiltersChange
} = props;
if (onUpdateFilters) call(onUpdateFilters, filters, sourceColumn);
if (_onUpdateFilters) call(_onUpdateFilters, filters, sourceColumn);
if (onFiltersChange) call(onFiltersChange, filters, sourceColumn);
uncontrolledFilterStateRef.value = filters;
}
function onUnstableColumnResize(resizedWidth, limitedWidth, column, getColumnWidth) {
var _a;
(_a = props.onUnstableColumnResize) === null || _a === void 0 ? void 0 : _a.call(props, resizedWidth, limitedWidth, column, getColumnWidth);
}
function page(page) {
doUpdatePage(page);
}
function clearFilter() {
clearFilters();
}
function clearFilters() {
filters({});
}
function filters(filters) {
filter(filters);
}
function filter(filters) {
if (!filters) {
uncontrolledFilterStateRef.value = {};
} else if (filters) {
uncontrolledFilterStateRef.value = createShallowClonedObject(filters);
} else if (process.env.NODE_ENV !== 'production') {
warn('data-table', '`filters` is not an object');
}
}
return {
treeMateRef,
mergedCurrentPageRef: boundedMergedCurrentPageRef,
mergedPaginationRef,
paginatedDataRef,
rawPaginatedDataRef,
mergedFilterStateRef,
mergedSortStateRef,
hoverKeyRef: ref(null),
selectionColumnRef,
childTriggerColIndexRef,
doUpdateFilters,
deriveNextSorter,
doUpdatePageSize,
doUpdatePage,
onUnstableColumnResize,
// exported methods
filter,
filters,
clearFilter,
clearFilters,
clearSorter,
page,
sort
};
}