refactor: table to ts

pull/3053/head
Amour1688 2020-10-23 14:29:39 +08:00
parent f8750f2350
commit f8ada772ae
17 changed files with 170 additions and 102 deletions

View File

@ -213,7 +213,7 @@ const components = [
const install = function(app: App) {
components.forEach(component => {
app.use(component as { install: () => any });
app.use(component as typeof component & { install: () => void });
});
app.config.globalProperties.$message = message;

View File

@ -1,9 +1,10 @@
import { defineComponent } from 'vue';
import { ColumnProps } from './interface';
export default {
export default defineComponent({
name: 'ATableColumn',
props: ColumnProps,
render() {
return null;
},
};
});

View File

@ -1,6 +1,7 @@
import { defineComponent } from 'vue';
import PropTypes from '../_util/vue-types';
export default {
export default defineComponent({
name: 'ATableColumnGroup',
props: {
title: PropTypes.any,
@ -9,4 +10,4 @@ export default {
render() {
return null;
},
};
});

View File

@ -1,11 +0,0 @@
const FilterDropdownMenuWrapper = (_, { attrs, slots }) => {
return (
<div class={attrs.class} onClick={e => e.stopPropagation()}>
{slots.default?.()}
</div>
);
};
FilterDropdownMenuWrapper.inheritAttrs = false;
export default FilterDropdownMenuWrapper;

View File

@ -0,0 +1,20 @@
import { FunctionalComponent } from 'vue';
export interface FilterDropdownMenuWrapperProps {
class?: string;
}
const FilterDropdownMenuWrapper: FunctionalComponent<FilterDropdownMenuWrapperProps> = (
props,
{ slots },
) => {
return (
<div class={props.class} onClick={e => e.stopPropagation()}>
{slots.default?.()}
</div>
);
};
FilterDropdownMenuWrapper.inheritAttrs = false;
export default FilterDropdownMenuWrapper;

View File

@ -1,20 +1,31 @@
import { defineComponent } from 'vue';
import Checkbox from '../checkbox';
import Radio from '../radio';
import { SelectionBoxProps } from './interface';
import BaseMixin from '../_util/BaseMixin';
import { getOptionProps } from '../_util/props-util';
export default {
export default defineComponent({
name: 'SelectionBox',
mixins: [BaseMixin],
inheritAttrs: false,
props: SelectionBoxProps,
data() {
return {
checked: this.getCheckState(this.$props),
checked: false,
};
},
setup() {
return {
unsubscribe: null,
};
},
created() {
this.checked = this.getCheckState(this.$props);
},
mounted() {
this.subscribe();
},
@ -25,7 +36,7 @@ export default {
}
},
methods: {
getCheckState(props) {
getCheckState(props): boolean {
const { store, defaultSelection, rowIndex } = props;
let checked = false;
if (store.getState().selectionDirty) {
@ -47,7 +58,7 @@ export default {
},
render() {
const { type, rowIndex, ...rest } = { ...getOptionProps(this), ...this.$attrs };
const { type, rowIndex, ...rest } = { ...getOptionProps(this), ...this.$attrs } as any;
const { checked } = this;
const checkboxProps = {
checked,
@ -59,4 +70,4 @@ export default {
}
return <Checkbox {...checkboxProps} />;
},
};
});

View File

@ -5,6 +5,7 @@ import Menu from '../menu';
import classNames from '../_util/classNames';
import { SelectionCheckboxAllProps } from './interface';
import BaseMixin from '../_util/BaseMixin';
import { defineComponent } from 'vue';
function checkSelection({
store,
@ -87,13 +88,29 @@ function getCheckState(props) {
);
}
export default {
export default defineComponent({
name: 'SelectionCheckboxAll',
mixins: [BaseMixin],
inheritAttrs: false,
props: SelectionCheckboxAllProps,
data() {
const { $props: props } = this;
return {
checked: getCheckState(props),
indeterminate: getIndeterminateState(props),
};
},
setup() {
return {
defaultSelections: [],
unsubscribe: null,
};
},
created() {
const { $props: props } = this;
this.defaultSelections = props.hideDefaultSelections
? []
: [
@ -106,11 +123,6 @@ export default {
text: props.locale.selectInvert,
},
];
return {
checked: getCheckState(props),
indeterminate: getIndeterminateState(props),
};
},
watch: {
@ -149,7 +161,7 @@ export default {
const checked = getCheckState(props);
const indeterminate = getIndeterminateState(props);
this.setState(prevState => {
const newState = {};
const newState: any = {};
if (indeterminate !== prevState.indeterminate) {
newState.indeterminate = indeterminate;
}
@ -229,4 +241,4 @@ export default {
</div>
);
},
};
});

View File

@ -1,4 +1,4 @@
import { inject, markRaw } from 'vue';
import { defineComponent, inject, markRaw } from 'vue';
import CaretUpFilled from '@ant-design/icons-vue/CaretUpFilled';
import CaretDownFilled from '@ant-design/icons-vue/CaretDownFilled';
import VcTable, { INTERNAL_COL_DEFINE } from '../vc-table';
@ -12,10 +12,18 @@ import Column from './Column';
import ColumnGroup from './ColumnGroup';
import createBodyRow from './createBodyRow';
import { flatArray, treeMap, flatFilter } from './util';
import { initDefaultProps, getOptionProps } from '../_util/props-util';
import { getOptionProps } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import BaseMixin from '../_util/BaseMixin';
import { defaultConfigProvider } from '../config-provider';
import { TableProps } from './interface';
import {
TableProps,
TableComponents,
TableState,
ITableProps,
IColumnProps,
TableStateFilters,
} from './interface';
import Pagination from '../pagination';
import Spin from '../spin';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
@ -30,15 +38,15 @@ function stopPropagation(e) {
e.stopPropagation();
}
function getRowSelection(props) {
function getRowSelection(props: ITableProps) {
return props.rowSelection || {};
}
function getColumnKey(column, index) {
function getColumnKey(column: IColumnProps, index?: number) {
return column.key || column.dataIndex || index;
}
function isSameColumn(a, b) {
function isSameColumn(a: IColumnProps, b: IColumnProps): boolean {
if (a && b && a.key && a.key === b.key) {
return true;
}
@ -68,7 +76,7 @@ const defaultPagination = {
*/
const emptyObject = {};
const createComponents = (components = {}) => {
const createComponents = (components: TableComponents = {}) => {
const bodyRow = components && components.body && components.body.row;
return {
...components,
@ -79,37 +87,37 @@ const createComponents = (components = {}) => {
};
};
function isTheSameComponents(components1 = {}, components2 = {}) {
function isTheSameComponents(components1: TableComponents = {}, components2: TableComponents = {}) {
return (
components1 === components2 ||
['table', 'header', 'body'].every(key => shallowEqual(components1[key], components2[key]))
);
}
function getFilteredValueColumns(state, columns) {
function getFilteredValueColumns(state: TableState, columns?: IColumnProps) {
return flatFilter(
columns || (state || {}).columns || [],
column => typeof column.filteredValue !== 'undefined',
(column: IColumnProps) => typeof column.filteredValue !== 'undefined',
);
}
function getFiltersFromColumns(state, columns) {
function getFiltersFromColumns(state: TableState, columns: IColumnProps) {
const filters = {};
getFilteredValueColumns(state, columns).forEach(col => {
getFilteredValueColumns(state, columns).forEach((col: IColumnProps) => {
const colKey = getColumnKey(col);
filters[colKey] = col.filteredValue;
});
return filters;
}
function isFiltersChanged(state, filters) {
function isFiltersChanged(state: TableState, filters: TableStateFilters[]) {
if (Object.keys(filters).length !== Object.keys(state.filters).length) {
return true;
}
return Object.keys(filters).some(columnKey => filters[columnKey] !== state.filters[columnKey]);
}
export default {
export default defineComponent({
name: 'Table',
mixins: [BaseMixin],
inheritAttrs: false,
@ -132,24 +140,19 @@ export default {
setup() {
return {
vcTable: null,
checkboxPropsCache: {},
store: null,
configProvider: inject('configProvider', defaultConfigProvider),
};
},
data() {
this.vcTable = null;
// this.columns = props.columns || normalizeColumns(props.children)
const props = getOptionProps(this);
warning(
!props.expandedRowRender || !('scroll' in props),
'`expandedRowRender` and `scroll` are not compatible. Please use one of them at one time.',
);
this.checkboxPropsCache = {};
this.store = createStore({
selectedRowKeys: getRowSelection(this.$props).selectedRowKeys || [],
selectionDirty: false,
});
return {
...this.getDefaultSortOrder(props.columns || []),
// 减少状态
@ -160,6 +163,13 @@ export default {
filterDataCnt: 0,
};
},
created() {
const props = getOptionProps(this);
this.store = createStore({
selectedRowKeys: getRowSelection(props).selectedRowKeys || [],
selectionDirty: false,
});
},
watch: {
pagination: {
handler(val) {
@ -847,7 +857,7 @@ export default {
delete pagination.onChange;
delete pagination.onShowSizeChange;
const filters = state.sFilters;
const sorter = {};
const sorter: any = {};
let currentColumn = column;
if (state.sSortColumn && state.sSortOrder) {
currentColumn = state.sSortColumn;
@ -1088,7 +1098,7 @@ export default {
</div>
);
customHeaderCell = col => {
let colProps = {};
let colProps: any = {};
// Get original first
if (column.customHeaderCell) {
colProps = {
@ -1153,7 +1163,7 @@ export default {
const { showHeader, locale, getPopupContainer, ...restProps } = {
...getOptionProps(this),
...this.$attrs,
};
} as any;
const data = this.getCurrentPageData();
const expandIconAsCell = this.expandedRowRender && this.expandIconAsCell !== false;
@ -1278,4 +1288,4 @@ export default {
</div>
);
},
};
});

View File

@ -1,8 +1,8 @@
import PropTypes from '../_util/vue-types';
import { defineComponent } from 'vue';
import { Store } from './createStore';
import { getSlot } from '../_util/props-util';
import Omit from 'omit.js';
import omit from 'omit.js';
const BodyRowProps = {
store: Store,
@ -11,7 +11,7 @@ const BodyRowProps = {
};
export default function createBodyRow(Component = 'tr') {
const BodyRow = {
const BodyRow = defineComponent({
name: 'BodyRow',
inheritAttrs: false,
props: BodyRowProps,
@ -22,7 +22,11 @@ export default function createBodyRow(Component = 'tr') {
selected: selectedRowKeys.indexOf(this.rowKey) >= 0,
};
},
setup() {
return {
unsubscribe: null,
};
},
mounted() {
this.subscribe();
},
@ -46,7 +50,7 @@ export default function createBodyRow(Component = 'tr') {
},
render() {
const rowProps = Omit({ ...this.$props, ...this.$attrs }, [
const rowProps = omit({ ...this.$props, ...this.$attrs }, [
'prefixCls',
'rowKey',
'store',
@ -54,7 +58,7 @@ export default function createBodyRow(Component = 'tr') {
]);
const className = {
[`${this.prefixCls}-row-selected`]: this.selected,
[this.$attrs.class]: !!this.$attrs.class,
[this.$attrs.class as string]: !!this.$attrs.class,
};
return (
@ -63,7 +67,7 @@ export default function createBodyRow(Component = 'tr') {
</Component>
);
},
};
});
return BodyRow;
}

View File

@ -1,3 +1,4 @@
import { watchEffect, reactive, defineComponent } from 'vue';
import FilterFilled from '@ant-design/icons-vue/FilterFilled';
import Menu, { SubMenu, Item as MenuItem } from '../vc-menu';
import closest from 'dom-closest';
@ -8,17 +9,18 @@ import Checkbox from '../checkbox';
import Radio from '../radio';
import FilterDropdownMenuWrapper from './FilterDropdownMenuWrapper';
import { FilterMenuProps } from './interface';
import { initDefaultProps, isValidElement, findDOMNode } from '../_util/props-util';
import { isValidElement, findDOMNode } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import { cloneElement } from '../_util/vnode';
import BaseMixin2 from '../_util/BaseMixin2';
import { generateValueMaps } from './util';
import { watchEffect, reactive } from 'vue';
import { Key } from '../_util/type';
function stopPropagation(e) {
e.stopPropagation();
}
export default {
export default defineComponent({
name: 'FilterMenu',
mixins: [BaseMixin2],
inheritAttrs: false,
@ -86,7 +88,7 @@ export default {
this.setState({ sSelectedKeys: selectedKeys });
},
setVisible(visible) {
setVisible(visible: boolean) {
const { column } = this;
if (!('filterDropdownVisible' in column)) {
this.setState({ sVisible: visible });
@ -113,7 +115,7 @@ export default {
this.$nextTick(this.confirmFilter2);
},
onVisibleChange(visible) {
onVisibleChange(visible: boolean) {
this.setVisible(visible);
const { column } = this.$props;
// https://github.com/ant-design/ant-design/issues/17833
@ -121,7 +123,7 @@ export default {
this.confirmFilter2();
}
},
handleMenuItemClick(info) {
handleMenuItemClick(info: { keyPath: Key[]; key: Key }) {
const { sSelectedKeys: selectedKeys } = this;
if (!info.keyPath || info.keyPath.length <= 1) {
return;
@ -297,4 +299,4 @@ export default {
</Dropdown>
);
},
};
});

View File

@ -1,7 +1,9 @@
import { defineComponent } from 'vue';
import T from './Table';
import {} from './interface';
import { getOptionProps, getKey, getPropsData, getSlot } from '../_util/props-util';
const Table = {
const Table = defineComponent({
name: 'ATable',
Column: T.Column,
ColumnGroup: T.ColumnGroup,
@ -79,7 +81,7 @@ const Table = {
};
return <T {...tProps} ref="table" />;
},
};
});
/* istanbul ignore next */
Table.install = function(app) {
app.component(Table.name, Table);

View File

@ -2,6 +2,8 @@ import PropTypes, { withUndefined } from '../_util/vue-types';
import { PaginationProps as getPaginationProps } from '../pagination';
import { SpinProps as getSpinProps } from '../spin';
import { Store } from './createStore';
import { tuple } from '../_util/type';
import { ExtractPropTypes } from 'vue';
const PaginationProps = getPaginationProps();
const SpinProps = getSpinProps();
@ -14,13 +16,13 @@ export const ColumnFilterItem = PropTypes.shape({
}).loose;
export const ColumnProps = {
title: PropTypes.any,
// key?: React.Key;
title: PropTypes.VNodeChild,
key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
dataIndex: PropTypes.string,
customRender: PropTypes.func,
customCell: PropTypes.func,
customHeaderCell: PropTypes.func,
align: PropTypes.oneOf(['left', 'right', 'center']),
align: PropTypes.oneOf(tuple('left', 'right', 'center')),
ellipsis: PropTypes.looseBool,
filters: PropTypes.arrayOf(ColumnFilterItem),
// onFilter: (value: any, record: T) => PropTypes.looseBool,
@ -29,19 +31,19 @@ export const ColumnProps = {
filterDropdownVisible: PropTypes.looseBool,
// onFilterDropdownVisibleChange?: (visible: boolean) => void;
sorter: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func]),
defaultSortOrder: PropTypes.oneOf(['ascend', 'descend']),
defaultSortOrder: PropTypes.oneOf(tuple('ascend', 'descend')),
colSpan: PropTypes.number,
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
className: PropTypes.string,
fixed: withUndefined(
PropTypes.oneOfType([PropTypes.looseBool, PropTypes.oneOf(['left', 'right'])]),
PropTypes.oneOfType([PropTypes.looseBool, PropTypes.oneOf(tuple('left', 'right'))]),
),
filterIcon: PropTypes.any,
filteredValue: PropTypes.array,
filtered: PropTypes.looseBool,
defaultFilteredValue: PropTypes.array,
sortOrder: withUndefined(
PropTypes.oneOfType([PropTypes.looseBool, PropTypes.oneOf(['ascend', 'descend'])]),
PropTypes.oneOfType([PropTypes.looseBool, PropTypes.oneOf(tuple('ascend', 'descend'))]),
),
sortDirections: PropTypes.array,
// children?: ColumnProps<T>[];
@ -50,19 +52,21 @@ export const ColumnProps = {
// onHeaderCell?: (props: ColumnProps<T>) => any;
};
// export interface TableComponents {
// table?: any;
// header?: {
// wrapper?: any;
// row?: any;
// cell?: any;
// };
// body?: {
// wrapper?: any;
// row?: any;
// cell?: any;
// };
// }
export type IColumnProps = Partial<ExtractPropTypes<typeof ColumnProps>>;
export interface TableComponents {
table?: any;
header?: {
wrapper?: any;
row?: any;
cell?: any;
};
body?: {
wrapper?: any;
row?: any;
cell?: any;
};
}
export const TableLocale = PropTypes.shape({
filterTitle: PropTypes.string,
@ -91,7 +95,9 @@ export const TableRowSelection = {
hideDefaultSelections: PropTypes.looseBool,
fixed: PropTypes.looseBool,
columnWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
selectWay: PropTypes.oneOf(['onSelect', 'onSelectMultiple', 'onSelectAll', 'onSelectInvert']),
selectWay: PropTypes.oneOf(
tuple('onSelect', 'onSelectMultiple', 'onSelectAll', 'onSelectInvert'),
),
columnTitle: PropTypes.any,
};
@ -102,11 +108,11 @@ export const TableProps = {
pagination: PropTypes.oneOfType([
PropTypes.shape({
...PaginationProps,
position: PropTypes.oneOf(['top', 'bottom', 'both']),
position: PropTypes.oneOf(tuple('top', 'bottom', 'both')),
}).loose,
PropTypes.looseBool,
]),
size: PropTypes.oneOf(['default', 'middle', 'small', 'large']),
size: PropTypes.oneOf(tuple('default', 'middle', 'small', 'large')),
dataSource: PropTypes.array,
components: PropTypes.object,
columns: PropTypes.array,
@ -145,16 +151,21 @@ export const TableProps = {
// children?: React.ReactNode;
};
// export interface TableStateFilters {
// [key: string]: string[];
// }
export type ITableRowSelection = Partial<ExtractPropTypes<typeof TableRowSelection>>;
// export interface TableState<T> {
// pagination: PaginationProps;
// filters: TableStateFilters;
// sortColumn: ColumnProps<T> | null;
// sortOrder: PropTypes.string,
// }
export type ITableProps = Partial<ExtractPropTypes<typeof TableProps>>;
export interface TableStateFilters {
[key: string]: string[];
}
export interface TableState {
pagination?: Partial<ExtractPropTypes<typeof PaginationProps>>;
filters?: TableStateFilters;
sortColumn?: Partial<ExtractPropTypes<typeof ColumnProps>> | null;
sortOrder?: string;
columns?: IColumnProps[];
}
// export type SelectionItemSelectFn = (key: string[]) => any;

View File

@ -11,6 +11,7 @@ const Menu = {
inheritAttrs: false,
props: {
...commonPropsType,
onClick: PropTypes.func,
selectable: PropTypes.looseBool.def(true),
},
mixins: [BaseMixin],

View File

@ -37,4 +37,8 @@ export default {
itemIcon: PropTypes.any,
expandIcon: PropTypes.any,
overflowedIndicator: PropTypes.any,
onClick: PropTypes.func,
onSelect: PropTypes.func,
onDeselect: PropTypes.func,
children: PropTypes.VNodeChild,
};