@aplus-frontend/antdv
Version:
Vue basic component library maintained based on ant-design-vue
474 lines • 18.9 kB
JavaScript
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import { createVNode as _createVNode } from "vue";
import _extends from "@babel/runtime/helpers/esm/extends";
import RcTable from '../vc-table';
import { INTERNAL_HOOKS } from '../vc-table/Table';
import Spin from '../spin';
import Pagination from '../pagination';
import usePagination, { DEFAULT_PAGE_SIZE, getPaginationParam } from './hooks/usePagination';
import useLazyKVMap from './hooks/useLazyKVMap';
import useSelection from './hooks/useSelection';
import useSorter, { getSortData } from './hooks/useSorter';
import useFilter, { getFilterData } from './hooks/useFilter';
import useTitleColumns from './hooks/useTitleColumns';
import renderExpandIcon from './ExpandIcon';
import scrollTo from '../_util/scrollTo';
import defaultLocale from '../locale/en_US';
import devWarning from '../vc-util/devWarning';
import { nextTick, reactive, ref, computed, defineComponent, toRef, watchEffect, watch } from 'vue';
import useBreakpoint from '../_util/hooks/useBreakpoint';
import useConfigInject from '../config-provider/hooks/useConfigInject';
import { useLocaleReceiver } from '../locale-provider/LocaleReceiver';
import classNames from '../_util/classNames';
import omit from '../_util/omit';
import { initDefaultProps } from '../_util/props-util';
import { useProvideSlots, useProvideTableContext } from './context';
import useColumns from './hooks/useColumns';
import { convertChildrenToColumns } from './util';
import { stringType, booleanType, arrayType, someType, functionType, objectType } from '../_util/type';
// CSSINJS
import useStyle from './style';
const EMPTY_LIST = [];
export const tableProps = () => {
return {
prefixCls: stringType(),
columns: arrayType(),
rowKey: someType([String, Function]),
tableLayout: stringType(),
rowClassName: someType([String, Function]),
title: functionType(),
footer: functionType(),
id: stringType(),
showHeader: booleanType(),
components: objectType(),
customRow: functionType(),
customHeaderRow: functionType(),
direction: stringType(),
expandFixed: someType([Boolean, String]),
expandColumnWidth: Number,
expandedRowKeys: arrayType(),
defaultExpandedRowKeys: arrayType(),
expandedRowRender: functionType(),
expandRowByClick: booleanType(),
expandIcon: functionType(),
onExpand: functionType(),
onExpandedRowsChange: functionType(),
'onUpdate:expandedRowKeys': functionType(),
defaultExpandAllRows: booleanType(),
indentSize: Number,
/** @deprecated Please use `EXPAND_COLUMN` in `columns` directly */
expandIconColumnIndex: Number,
showExpandColumn: booleanType(),
expandedRowClassName: functionType(),
childrenColumnName: stringType(),
rowExpandable: functionType(),
sticky: someType([Boolean, Object]),
dropdownPrefixCls: String,
dataSource: arrayType(),
pagination: someType([Boolean, Object]),
loading: someType([Boolean, Object]),
size: stringType(),
bordered: booleanType(),
locale: objectType(),
onChange: functionType(),
onResizeColumn: functionType(),
rowSelection: objectType(),
getPopupContainer: functionType(),
scroll: objectType(),
sortDirections: arrayType(),
showSorterTooltip: someType([Boolean, Object], true),
transformCellText: functionType()
};
};
const InternalTable = defineComponent({
name: 'InternalTable',
inheritAttrs: false,
props: initDefaultProps(_extends(_extends({}, tableProps()), {
contextSlots: objectType()
}), {
rowKey: 'key'
}),
setup(props, _ref) {
let {
attrs,
slots,
expose,
emit
} = _ref;
devWarning(!(typeof props.rowKey === 'function' && props.rowKey.length > 1), 'Table', '`index` parameter of `rowKey` function is deprecated. There is no guarantee that it will work as expected.');
useProvideSlots(computed(() => props.contextSlots));
useProvideTableContext({
onResizeColumn: (w, col) => {
emit('resizeColumn', w, col);
}
});
const screens = useBreakpoint();
const vcTableRef = ref();
const mergedColumns = computed(() => {
const matched = new Set(Object.keys(screens.value).filter(m => screens.value[m]));
return props.columns.filter(c => !c.responsive || c.responsive.some(r => matched.has(r)));
});
const {
size: mergedSize,
renderEmpty,
direction,
prefixCls,
configProvider
} = useConfigInject('table', props);
// Style
const [wrapSSR, hashId] = useStyle(prefixCls);
const transformCellText = computed(() => {
var _a;
return props.transformCellText || ((_a = configProvider.transformCellText) === null || _a === void 0 ? void 0 : _a.value);
});
const [tableLocale] = useLocaleReceiver('Table', defaultLocale.Table, toRef(props, 'locale'));
const rawData = computed(() => props.dataSource || EMPTY_LIST);
const dropdownPrefixCls = computed(() => configProvider.getPrefixCls('dropdown', props.dropdownPrefixCls));
const childrenColumnName = computed(() => props.childrenColumnName || 'children');
const expandType = computed(() => {
if (rawData.value.some(item => item === null || item === void 0 ? void 0 : item[childrenColumnName.value])) {
return 'nest';
}
if (props.expandedRowRender) {
return 'row';
}
return null;
});
const internalRefs = reactive({
body: null
});
const updateInternalRefs = refs => {
_extends(internalRefs, refs);
};
// ============================ RowKey ============================
const getRowKey = computed(() => {
if (typeof props.rowKey === 'function') {
return props.rowKey;
}
return record => record === null || record === void 0 ? void 0 : record[props.rowKey];
});
const [getRecordByKey] = useLazyKVMap(rawData, childrenColumnName, getRowKey);
// ============================ Events =============================
const changeEventInfo = {};
const triggerOnChange = function (info, action) {
let reset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
const {
pagination,
scroll,
onChange
} = props;
const changeInfo = _extends(_extends({}, changeEventInfo), info);
if (reset) {
changeEventInfo.resetPagination();
// Reset event param
if (changeInfo.pagination.current) {
changeInfo.pagination.current = 1;
}
// Trigger pagination events
if (pagination && pagination.onChange) {
pagination.onChange(1, changeInfo.pagination.pageSize);
}
}
if (scroll && scroll.scrollToFirstRowOnChange !== false && internalRefs.body) {
scrollTo(0, {
getContainer: () => internalRefs.body
});
}
onChange === null || onChange === void 0 ? void 0 : onChange(changeInfo.pagination, changeInfo.filters, changeInfo.sorter, {
currentDataSource: getFilterData(getSortData(rawData.value, changeInfo.sorterStates, childrenColumnName.value), changeInfo.filterStates),
action
});
};
/**
* Controlled state in `columns` is not a good idea that makes too many code (1000+ line?) to read
* state out and then put it back to title render. Move these code into `hooks` but still too
* complex. We should provides Table props like `sorter` & `filter` to handle control in next big version.
*/
// ============================ Sorter =============================
const onSorterChange = (sorter, sorterStates) => {
triggerOnChange({
sorter,
sorterStates
}, 'sort', false);
};
const [transformSorterColumns, sortStates, sorterTitleProps, sorters] = useSorter({
prefixCls,
mergedColumns,
onSorterChange,
sortDirections: computed(() => props.sortDirections || ['ascend', 'descend']),
tableLocale,
showSorterTooltip: toRef(props, 'showSorterTooltip')
});
const sortedData = computed(() => getSortData(rawData.value, sortStates.value, childrenColumnName.value));
// ============================ Filter ============================
const onFilterChange = (filters, filterStates) => {
triggerOnChange({
filters,
filterStates
}, 'filter', true);
};
const [transformFilterColumns, filterStates, filters] = useFilter({
prefixCls,
locale: tableLocale,
dropdownPrefixCls,
mergedColumns,
onFilterChange,
getPopupContainer: toRef(props, 'getPopupContainer')
});
const mergedData = computed(() => getFilterData(sortedData.value, filterStates.value));
// ============================ Column ============================
const [transformBasicColumns] = useColumns(toRef(props, 'contextSlots'));
const columnTitleProps = computed(() => {
const mergedFilters = {};
const filtersValue = filters.value;
Object.keys(filtersValue).forEach(filterKey => {
if (filtersValue[filterKey] !== null) {
mergedFilters[filterKey] = filtersValue[filterKey];
}
});
return _extends(_extends({}, sorterTitleProps.value), {
filters: mergedFilters
});
});
const [transformTitleColumns] = useTitleColumns(columnTitleProps);
// ========================== Pagination ==========================
const onPaginationChange = (current, pageSize) => {
triggerOnChange({
pagination: _extends(_extends({}, changeEventInfo.pagination), {
current,
pageSize
})
}, 'paginate');
};
const [mergedPagination, resetPagination] = usePagination(computed(() => mergedData.value.length), toRef(props, 'pagination'), onPaginationChange);
watchEffect(() => {
changeEventInfo.sorter = sorters.value;
changeEventInfo.sorterStates = sortStates.value;
changeEventInfo.filters = filters.value;
changeEventInfo.filterStates = filterStates.value;
changeEventInfo.pagination = props.pagination === false ? {} : getPaginationParam(mergedPagination.value, props.pagination);
changeEventInfo.resetPagination = resetPagination;
});
// ============================= Data =============================
const pageData = computed(() => {
if (props.pagination === false || !mergedPagination.value.pageSize) {
return mergedData.value;
}
const {
current = 1,
total,
pageSize = DEFAULT_PAGE_SIZE
} = mergedPagination.value;
devWarning(current > 0, 'Table', '`current` should be positive number.');
// Dynamic table data
if (mergedData.value.length < total) {
if (mergedData.value.length > pageSize) {
return mergedData.value.slice((current - 1) * pageSize, current * pageSize);
}
return mergedData.value;
}
return mergedData.value.slice((current - 1) * pageSize, current * pageSize);
});
watchEffect(() => {
nextTick(() => {
const {
total,
pageSize = DEFAULT_PAGE_SIZE
} = mergedPagination.value;
// Dynamic table data
if (mergedData.value.length < total) {
if (mergedData.value.length > pageSize) {
devWarning(false, 'Table', '`dataSource` length is less than `pagination.total` but large than `pagination.pageSize`. Please make sure your config correct data with async mode.');
}
}
});
}, {
flush: 'post'
});
const expandIconColumnIndex = computed(() => {
if (props.showExpandColumn === false) return -1;
// Adjust expand icon index, no overwrite expandIconColumnIndex if set.
if (expandType.value === 'nest' && props.expandIconColumnIndex === undefined) {
return props.rowSelection ? 1 : 0;
} else if (props.expandIconColumnIndex > 0 && props.rowSelection) {
return props.expandIconColumnIndex - 1;
}
return props.expandIconColumnIndex;
});
const rowSelection = ref();
watch(() => props.rowSelection, () => {
rowSelection.value = props.rowSelection ? _extends({}, props.rowSelection) : props.rowSelection;
}, {
deep: true,
immediate: true
});
// ========================== Selections ==========================
const [transformSelectionColumns, selectedKeySet] = useSelection(rowSelection, {
prefixCls,
data: mergedData,
pageData,
getRowKey,
getRecordByKey,
expandType,
childrenColumnName,
locale: tableLocale,
getPopupContainer: computed(() => props.getPopupContainer)
});
const internalRowClassName = (record, index, indent) => {
let mergedRowClassName;
const {
rowClassName
} = props;
if (typeof rowClassName === 'function') {
mergedRowClassName = classNames(rowClassName(record, index, indent));
} else {
mergedRowClassName = classNames(rowClassName);
}
return classNames({
[`${prefixCls.value}-row-selected`]: selectedKeySet.value.has(getRowKey.value(record, index))
}, mergedRowClassName);
};
expose({
selectedKeySet,
scrollBodyRef: computed(() => {
var _a;
return (_a = vcTableRef.value) === null || _a === void 0 ? void 0 : _a.scrollBodyRef;
})
});
const indentSize = computed(() => {
// Indent size
return typeof props.indentSize === 'number' ? props.indentSize : 15;
});
const transformColumns = innerColumns => {
const res = transformTitleColumns(transformSelectionColumns(transformFilterColumns(transformSorterColumns(transformBasicColumns(innerColumns)))));
return res;
};
return () => {
var _a, _b;
const {
expandIcon = slots.expandIcon || renderExpandIcon(tableLocale.value),
pagination,
loading,
bordered
} = props;
let topPaginationNode;
let bottomPaginationNode;
if (pagination !== false && ((_a = mergedPagination.value) === null || _a === void 0 ? void 0 : _a.total)) {
let paginationSize;
if (mergedPagination.value.size) {
paginationSize = mergedPagination.value.size;
} else {
paginationSize = mergedSize.value === 'small' || mergedSize.value === 'middle' ? 'small' : undefined;
}
const renderPagination = position => _createVNode(Pagination, _objectSpread(_objectSpread({}, mergedPagination.value), {}, {
"class": [`${prefixCls.value}-pagination ${prefixCls.value}-pagination-${position}`, mergedPagination.value.class],
"size": paginationSize
}), null);
const defaultPosition = direction.value === 'rtl' ? 'left' : 'right';
const {
position
} = mergedPagination.value;
if (position !== null && Array.isArray(position)) {
const topPos = position.find(p => p.includes('top'));
const bottomPos = position.find(p => p.includes('bottom'));
const isDisable = position.every(p => `${p}` === 'none');
if (!topPos && !bottomPos && !isDisable) {
bottomPaginationNode = renderPagination(defaultPosition);
}
if (topPos) {
topPaginationNode = renderPagination(topPos.toLowerCase().replace('top', ''));
}
if (bottomPos) {
bottomPaginationNode = renderPagination(bottomPos.toLowerCase().replace('bottom', ''));
}
} else {
bottomPaginationNode = renderPagination(defaultPosition);
}
}
// >>>>>>>>> Spinning
let spinProps;
if (typeof loading === 'boolean') {
spinProps = {
spinning: loading
};
} else if (typeof loading === 'object') {
spinProps = _extends({
spinning: true
}, loading);
}
const wrapperClassNames = classNames(`${prefixCls.value}-wrapper`, {
[`${prefixCls.value}-wrapper-rtl`]: direction.value === 'rtl'
}, attrs.class, hashId.value);
const tableProps = omit(props, ['columns']);
return wrapSSR(_createVNode("div", {
"class": wrapperClassNames,
"style": attrs.style
}, [_createVNode(Spin, _objectSpread({
"spinning": false
}, spinProps), {
default: () => [topPaginationNode, _createVNode(RcTable, _objectSpread(_objectSpread(_objectSpread({
"ref": vcTableRef
}, attrs), tableProps), {}, {
"expandedRowKeys": props.expandedRowKeys,
"defaultExpandedRowKeys": props.defaultExpandedRowKeys,
"expandIconColumnIndex": expandIconColumnIndex.value,
"indentSize": indentSize.value,
"expandIcon": expandIcon,
"columns": mergedColumns.value,
"direction": direction.value,
"prefixCls": prefixCls.value,
"class": classNames({
[`${prefixCls.value}-middle`]: mergedSize.value === 'middle',
[`${prefixCls.value}-small`]: mergedSize.value === 'small',
[`${prefixCls.value}-bordered`]: bordered,
[`${prefixCls.value}-empty`]: rawData.value.length === 0
}),
"data": pageData.value,
"rowKey": getRowKey.value,
"rowClassName": internalRowClassName,
"internalHooks": INTERNAL_HOOKS,
"internalRefs": internalRefs,
"onUpdateInternalRefs": updateInternalRefs,
"transformColumns": transformColumns,
"transformCellText": transformCellText.value
}), _extends(_extends({}, slots), {
emptyText: () => {
var _a, _b;
return ((_a = slots.emptyText) === null || _a === void 0 ? void 0 : _a.call(slots)) || ((_b = props.locale) === null || _b === void 0 ? void 0 : _b.emptyText) || renderEmpty('Table');
}
})), (_b = slots.bottomPaginationTop) === null || _b === void 0 ? void 0 : _b.call(slots), bottomPaginationNode]
})]));
};
}
});
const Table = defineComponent({
name: 'ATable',
inheritAttrs: false,
props: initDefaultProps(tableProps(), {
rowKey: 'key'
}),
slots: Object,
setup(props, _ref2) {
let {
attrs,
slots,
expose
} = _ref2;
const table = ref();
expose({
table
});
return () => {
var _a;
const columns = props.columns || convertChildrenToColumns((_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots));
return _createVNode(InternalTable, _objectSpread(_objectSpread(_objectSpread({
"ref": table
}, attrs), props), {}, {
"columns": columns || [],
"expandedRowRender": slots.expandedRowRender || props.expandedRowRender,
"contextSlots": _extends({}, slots)
}), slots);
};
}
});
export default Table;