UNPKG

@aplus-frontend/antdv

Version:

Vue basic component library maintained based on ant-design-vue

474 lines 18.9 kB
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;