add table
parent
507576b2f4
commit
a01905cc6e
|
@ -7,7 +7,7 @@ import LocaleReceiver from '../locale-provider/LocaleReceiver'
|
|||
import { getOptionProps } from '../_util/props-util'
|
||||
import VcPagination from '../vc-pagination'
|
||||
|
||||
export const PaginationProps = {
|
||||
export const PaginationProps = () => ({
|
||||
total: PropTypes.number,
|
||||
defaultCurrent: PropTypes.number,
|
||||
current: PropTypes.number,
|
||||
|
@ -29,11 +29,11 @@ export const PaginationProps = {
|
|||
prefixCls: PropTypes.string,
|
||||
selectPrefixCls: PropTypes.string,
|
||||
itemRender: PropTypes.any,
|
||||
}
|
||||
})
|
||||
|
||||
export default {
|
||||
props: {
|
||||
...PaginationProps,
|
||||
...PaginationProps(),
|
||||
prefixCls: PropTypes.string.def('ant-pagination'),
|
||||
selectPrefixCls: PropTypes.string.def('ant-select'),
|
||||
},
|
||||
|
|
|
@ -2,20 +2,27 @@
|
|||
import PropTypes from '../_util/vue-types'
|
||||
import BaseMixin from '../_util/BaseMixin'
|
||||
import isCssAnimationSupported from '../_util/isCssAnimationSupported'
|
||||
import { filterEmpty } from '../_util/props-util'
|
||||
import { filterEmpty, initDefaultProps } from '../_util/props-util'
|
||||
import getTransitionProps from '../_util/getTransitionProps'
|
||||
|
||||
export const SpinProps = () => ({
|
||||
prefixCls: PropTypes.string,
|
||||
spinning: PropTypes.bool,
|
||||
size: PropTypes.oneOf(['small', 'default', 'large']),
|
||||
wrapperClassName: PropTypes.string,
|
||||
tip: PropTypes.string,
|
||||
delay: PropTypes.number,
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'Spin',
|
||||
mixins: [BaseMixin],
|
||||
props: {
|
||||
prefixCls: PropTypes.string.def('ant-spin'),
|
||||
spinning: PropTypes.bool.def(true),
|
||||
size: PropTypes.oneOf(['small', 'default', 'large']).def('default'),
|
||||
wrapperClassName: PropTypes.string.def(''),
|
||||
tip: PropTypes.string,
|
||||
delay: PropTypes.number,
|
||||
},
|
||||
props: initDefaultProps(SpinProps(), {
|
||||
prefixCls: 'ant-spin',
|
||||
size: 'default',
|
||||
spinning: true,
|
||||
wrapperClassName: '',
|
||||
}),
|
||||
data () {
|
||||
const { spinning } = this
|
||||
return {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import Spin from './Spin'
|
||||
|
||||
export { SpinProps } from './Spin'
|
||||
export default Spin
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import { ColumnProps } from './interface'
|
||||
|
||||
export default {
|
||||
name: 'Column',
|
||||
props: ColumnProps,
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
import PropTypes from '../_util/vue-types'
|
||||
|
||||
export default {
|
||||
name: 'ColumnGroup',
|
||||
props: {
|
||||
title: PropTypes.any,
|
||||
},
|
||||
__ANT_TABLE_COLUMN_GROUP: true,
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
export default {
|
||||
methods: {
|
||||
handelClick (e) {
|
||||
this.$emit('click', e)
|
||||
},
|
||||
},
|
||||
render () {
|
||||
const { $slots, handelClick } = this
|
||||
return (
|
||||
<div onClick={handelClick}>
|
||||
{$slots.default}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
import * as React from 'react';
|
||||
import Checkbox from '../checkbox';
|
||||
import Radio from '../radio';
|
||||
import { SelectionBoxProps, SelectionBoxState } from './interface';
|
||||
|
||||
export default class SelectionBox extends React.Component<SelectionBoxProps, SelectionBoxState> {
|
||||
unsubscribe: () => void;
|
||||
|
||||
constructor(props: SelectionBoxProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
checked: this.getCheckState(props),
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.subscribe();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
const { store } = this.props;
|
||||
this.unsubscribe = store.subscribe(() => {
|
||||
const checked = this.getCheckState(this.props);
|
||||
this.setState({ checked });
|
||||
});
|
||||
}
|
||||
|
||||
getCheckState(props: SelectionBoxProps) {
|
||||
const { store, defaultSelection, rowIndex } = props;
|
||||
let checked = false;
|
||||
if (store.getState().selectionDirty) {
|
||||
checked = store.getState().selectedRowKeys.indexOf(rowIndex) >= 0;
|
||||
} else {
|
||||
checked = (store.getState().selectedRowKeys.indexOf(rowIndex) >= 0 ||
|
||||
defaultSelection.indexOf(rowIndex) >= 0);
|
||||
}
|
||||
return checked;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { type, rowIndex, ...rest } = this.props;
|
||||
const { checked } = this.state;
|
||||
|
||||
if (type === 'radio') {
|
||||
return (
|
||||
<Radio
|
||||
checked={checked}
|
||||
value={rowIndex}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Checkbox
|
||||
checked={checked}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
import * as React from 'react';
|
||||
import Checkbox from '../checkbox';
|
||||
import Dropdown from '../dropdown';
|
||||
import Menu from '../menu';
|
||||
import Icon from '../icon';
|
||||
import classNames from 'classnames';
|
||||
import { SelectionCheckboxAllProps, SelectionCheckboxAllState, SelectionItem } from './interface';
|
||||
|
||||
export default class SelectionCheckboxAll<T> extends
|
||||
React.Component<SelectionCheckboxAllProps<T>, SelectionCheckboxAllState> {
|
||||
unsubscribe: () => void;
|
||||
defaultSelections: SelectionItem[];
|
||||
|
||||
constructor(props: SelectionCheckboxAllProps<T>) {
|
||||
super(props);
|
||||
|
||||
this.defaultSelections = props.hideDefaultSelections ? [] : [{
|
||||
key: 'all',
|
||||
text: props.locale.selectAll,
|
||||
onSelect: () => {},
|
||||
}, {
|
||||
key: 'invert',
|
||||
text: props.locale.selectInvert,
|
||||
onSelect: () => {},
|
||||
}];
|
||||
|
||||
this.state = {
|
||||
checked: this.getCheckState(props),
|
||||
indeterminate: this.getIndeterminateState(props),
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.subscribe();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: SelectionCheckboxAllProps<T>) {
|
||||
this.setCheckState(nextProps);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
const { store } = this.props;
|
||||
this.unsubscribe = store.subscribe(() => {
|
||||
this.setCheckState(this.props);
|
||||
});
|
||||
}
|
||||
|
||||
checkSelection(data: T[], type: string, byDefaultChecked: boolean) {
|
||||
const { store, getCheckboxPropsByItem, getRecordKey } = this.props;
|
||||
// type should be 'every' | 'some'
|
||||
if (type === 'every' || type === 'some') {
|
||||
return (
|
||||
byDefaultChecked
|
||||
? data[type]((item, i) => getCheckboxPropsByItem(item, i).defaultChecked)
|
||||
: data[type]((item, i) =>
|
||||
store.getState().selectedRowKeys.indexOf(getRecordKey(item, i)) >= 0)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
setCheckState(props: SelectionCheckboxAllProps<T>) {
|
||||
const checked = this.getCheckState(props);
|
||||
const indeterminate = this.getIndeterminateState(props);
|
||||
if (checked !== this.state.checked) {
|
||||
this.setState({ checked });
|
||||
}
|
||||
if (indeterminate !== this.state.indeterminate) {
|
||||
this.setState({ indeterminate });
|
||||
}
|
||||
}
|
||||
|
||||
getCheckState(props: SelectionCheckboxAllProps<T>) {
|
||||
const { store, data } = props;
|
||||
let checked;
|
||||
if (!data.length) {
|
||||
checked = false;
|
||||
} else {
|
||||
checked = store.getState().selectionDirty
|
||||
? this.checkSelection(data, 'every', false)
|
||||
: (
|
||||
this.checkSelection(data, 'every', false) ||
|
||||
this.checkSelection(data, 'every', true)
|
||||
);
|
||||
|
||||
}
|
||||
return checked;
|
||||
}
|
||||
|
||||
getIndeterminateState(props: SelectionCheckboxAllProps<T>) {
|
||||
const { store, data } = props;
|
||||
let indeterminate;
|
||||
if (!data.length) {
|
||||
indeterminate = false;
|
||||
} else {
|
||||
indeterminate = store.getState().selectionDirty
|
||||
? (
|
||||
this.checkSelection(data, 'some', false) &&
|
||||
!this.checkSelection(data, 'every', false)
|
||||
)
|
||||
: ((this.checkSelection(data, 'some', false) &&
|
||||
!this.checkSelection(data, 'every', false)) ||
|
||||
(this.checkSelection(data, 'some', true) &&
|
||||
!this.checkSelection(data, 'every', true))
|
||||
);
|
||||
}
|
||||
return indeterminate;
|
||||
}
|
||||
|
||||
handleSelectAllChagne = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
let checked = e.target.checked;
|
||||
this.props.onSelect(checked ? 'all' : 'removeAll', 0, null);
|
||||
}
|
||||
|
||||
renderMenus(selections: SelectionItem[]) {
|
||||
return selections.map((selection, index) => {
|
||||
return (
|
||||
<Menu.Item
|
||||
key={selection.key || index}
|
||||
>
|
||||
<div
|
||||
onClick={() => {this.props.onSelect(selection.key, index, selection.onSelect); }}
|
||||
>
|
||||
{selection.text}
|
||||
</div>
|
||||
</Menu.Item>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { disabled, prefixCls, selections, getPopupContainer } = this.props;
|
||||
const { checked, indeterminate } = this.state;
|
||||
|
||||
let selectionPrefixCls = `${prefixCls}-selection`;
|
||||
|
||||
let customSelections: React.ReactNode = null;
|
||||
|
||||
if (selections) {
|
||||
let newSelections = Array.isArray(selections) ? this.defaultSelections.concat(selections)
|
||||
: this.defaultSelections;
|
||||
|
||||
const menu = (
|
||||
<Menu
|
||||
className={`${selectionPrefixCls}-menu`}
|
||||
selectedKeys={[]}
|
||||
>
|
||||
{this.renderMenus(newSelections)}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
customSelections = newSelections.length > 0 ? (
|
||||
<Dropdown
|
||||
overlay={menu}
|
||||
getPopupContainer={getPopupContainer}
|
||||
>
|
||||
<div className={`${selectionPrefixCls}-down`}>
|
||||
<Icon type="down" />
|
||||
</div>
|
||||
</Dropdown>
|
||||
) : null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={selectionPrefixCls}>
|
||||
<Checkbox
|
||||
className={classNames({ [`${selectionPrefixCls}-select-all-custom`]: customSelections })}
|
||||
checked={checked}
|
||||
indeterminate={indeterminate}
|
||||
disabled={disabled}
|
||||
onChange={this.handleSelectAllChagne}
|
||||
/>
|
||||
{customSelections}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,59 @@
|
|||
import PropTypes from '../_util/vue-types'
|
||||
|
||||
import { Store } from './createStore'
|
||||
|
||||
const BodyRowProps = {
|
||||
store: Store,
|
||||
rowKey: PropTypes.string,
|
||||
prefixCls: PropTypes.string,
|
||||
}
|
||||
|
||||
export default function createTableRow (Component = 'tr') {
|
||||
const BodyRow = {
|
||||
name: 'BodyRow',
|
||||
props: BodyRowProps,
|
||||
data () {
|
||||
const { selectedRowKeys } = this.store.getState()
|
||||
|
||||
return {
|
||||
selected: selectedRowKeys.indexOf(this.rowKey) >= 0,
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.subscribe()
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
subscribe () {
|
||||
const { store, rowKey } = this
|
||||
this.unsubscribe = store.subscribe(() => {
|
||||
const { selectedRowKeys } = this.store.getState()
|
||||
const selected = selectedRowKeys.indexOf(rowKey) >= 0
|
||||
if (selected !== this.selected) {
|
||||
this.selected = selected
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
render () {
|
||||
const className = {
|
||||
[`${this.props.prefixCls}-row-selected`]: this.selected,
|
||||
}
|
||||
|
||||
return (
|
||||
<Component class={className}>
|
||||
{this.$slots.default}
|
||||
</Component>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
return BodyRow
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import PropTypes from '../_util/vue-types'
|
||||
export const Store = PropTypes.shape({
|
||||
setState: PropTypes.func,
|
||||
getState: PropTypes.func,
|
||||
subscribe: PropTypes.func,
|
||||
}).loose
|
||||
|
||||
import create from '../_util/store/create'
|
||||
const createStore = create
|
||||
|
||||
export default createStore
|
|
@ -0,0 +1,228 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import Menu, { SubMenu, Item as MenuItem } from 'rc-menu';
|
||||
import closest from 'dom-closest';
|
||||
import classNames from 'classnames';
|
||||
import Dropdown from '../dropdown';
|
||||
import Icon from '../icon';
|
||||
import Checkbox from '../checkbox';
|
||||
import Radio from '../radio';
|
||||
import FilterDropdownMenuWrapper from './FilterDropdownMenuWrapper';
|
||||
import { FilterMenuProps, FilterMenuState, ColumnProps, ColumnFilterItem } from './interface';
|
||||
|
||||
export default class FilterMenu<T> extends React.Component<FilterMenuProps<T>, FilterMenuState> {
|
||||
static defaultProps = {
|
||||
handleFilter() {},
|
||||
column: {},
|
||||
};
|
||||
|
||||
neverShown: boolean;
|
||||
|
||||
constructor(props: FilterMenuProps<T>) {
|
||||
super(props);
|
||||
|
||||
const visible = ('filterDropdownVisible' in props.column) ?
|
||||
props.column.filterDropdownVisible : false;
|
||||
|
||||
this.state = {
|
||||
selectedKeys: props.selectedKeys,
|
||||
keyPathOfSelectedItem: {}, // 记录所有有选中子菜单的祖先菜单
|
||||
visible,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { column } = this.props;
|
||||
this.setNeverShown(column);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: FilterMenuProps<T>) {
|
||||
const { column } = nextProps;
|
||||
this.setNeverShown(column);
|
||||
const newState = {} as {
|
||||
selectedKeys: string[];
|
||||
visible: boolean;
|
||||
};
|
||||
if ('selectedKeys' in nextProps) {
|
||||
newState.selectedKeys = nextProps.selectedKeys;
|
||||
}
|
||||
if ('filterDropdownVisible' in column) {
|
||||
newState.visible = column.filterDropdownVisible as boolean;
|
||||
}
|
||||
if (Object.keys(newState).length > 0) {
|
||||
this.setState(newState);
|
||||
}
|
||||
}
|
||||
|
||||
setNeverShown = (column: ColumnProps<T>) => {
|
||||
const rootNode = ReactDOM.findDOMNode(this);
|
||||
const filterBelongToScrollBody = !!closest(rootNode, `.ant-table-scroll`);
|
||||
if (filterBelongToScrollBody) {
|
||||
// When fixed column have filters, there will be two dropdown menus
|
||||
// Filter dropdown menu inside scroll body should never be shown
|
||||
// To fix https://github.com/ant-design/ant-design/issues/5010 and
|
||||
// https://github.com/ant-design/ant-design/issues/7909
|
||||
this.neverShown = !!column.fixed;
|
||||
}
|
||||
}
|
||||
|
||||
setSelectedKeys = ({ selectedKeys }: { selectedKeys: string[] }) => {
|
||||
this.setState({ selectedKeys });
|
||||
}
|
||||
|
||||
setVisible(visible: boolean) {
|
||||
const { column } = this.props;
|
||||
if (!('filterDropdownVisible' in column)) {
|
||||
this.setState({ visible });
|
||||
}
|
||||
if (column.onFilterDropdownVisibleChange) {
|
||||
column.onFilterDropdownVisibleChange(visible);
|
||||
}
|
||||
}
|
||||
|
||||
handleClearFilters = () => {
|
||||
this.setState({
|
||||
selectedKeys: [],
|
||||
}, this.handleConfirm);
|
||||
}
|
||||
|
||||
handleConfirm = () => {
|
||||
this.setVisible(false);
|
||||
this.confirmFilter();
|
||||
}
|
||||
|
||||
onVisibleChange = (visible: boolean) => {
|
||||
this.setVisible(visible);
|
||||
if (!visible) {
|
||||
this.confirmFilter();
|
||||
}
|
||||
}
|
||||
|
||||
confirmFilter() {
|
||||
if (this.state.selectedKeys !== this.props.selectedKeys) {
|
||||
this.props.confirmFilter(this.props.column, this.state.selectedKeys);
|
||||
}
|
||||
}
|
||||
|
||||
renderMenuItem(item: ColumnFilterItem) {
|
||||
const { column } = this.props;
|
||||
const multiple = ('filterMultiple' in column) ? column.filterMultiple : true;
|
||||
const input = multiple ? (
|
||||
<Checkbox checked={this.state.selectedKeys.indexOf(item.value.toString()) >= 0} />
|
||||
) : (
|
||||
<Radio checked={this.state.selectedKeys.indexOf(item.value.toString()) >= 0} />
|
||||
);
|
||||
|
||||
return (
|
||||
<MenuItem key={item.value}>
|
||||
{input}
|
||||
<span>{item.text}</span>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
|
||||
hasSubMenu() {
|
||||
const { column: { filters = [] } } = this.props;
|
||||
return filters.some(item => !!(item.children && item.children.length > 0));
|
||||
}
|
||||
|
||||
renderMenus(items: ColumnFilterItem[]): React.ReactElement<any>[] {
|
||||
return items.map(item => {
|
||||
if (item.children && item.children.length > 0) {
|
||||
const { keyPathOfSelectedItem } = this.state;
|
||||
const containSelected = Object.keys(keyPathOfSelectedItem).some(
|
||||
key => keyPathOfSelectedItem[key].indexOf(item.value) >= 0,
|
||||
);
|
||||
const subMenuCls = containSelected ? `${this.props.dropdownPrefixCls}-submenu-contain-selected` : '';
|
||||
return (
|
||||
<SubMenu title={item.text} className={subMenuCls} key={item.value.toString()}>
|
||||
{this.renderMenus(item.children)}
|
||||
</SubMenu>
|
||||
);
|
||||
}
|
||||
return this.renderMenuItem(item);
|
||||
});
|
||||
}
|
||||
|
||||
handleMenuItemClick = (info: { keyPath: string, key: string }) => {
|
||||
if (info.keyPath.length <= 1) {
|
||||
return;
|
||||
}
|
||||
const keyPathOfSelectedItem = this.state.keyPathOfSelectedItem;
|
||||
if (this.state.selectedKeys.indexOf(info.key) >= 0) {
|
||||
// deselect SubMenu child
|
||||
delete keyPathOfSelectedItem[info.key];
|
||||
} else {
|
||||
// select SubMenu child
|
||||
keyPathOfSelectedItem[info.key] = info.keyPath;
|
||||
}
|
||||
this.setState({ keyPathOfSelectedItem });
|
||||
}
|
||||
|
||||
renderFilterIcon = () => {
|
||||
const { column, locale, prefixCls } = this.props;
|
||||
const filterIcon = column.filterIcon as any;
|
||||
const dropdownSelectedClass = this.props.selectedKeys.length > 0 ? `${prefixCls}-selected` : '';
|
||||
|
||||
return filterIcon ? React.cloneElement(filterIcon as any, {
|
||||
title: locale.filterTitle,
|
||||
className: classNames(filterIcon.className, {
|
||||
[`${prefixCls}-icon`]: true,
|
||||
}),
|
||||
}) : <Icon title={locale.filterTitle} type="filter" className={dropdownSelectedClass} />;
|
||||
}
|
||||
render() {
|
||||
const { column, locale, prefixCls, dropdownPrefixCls, getPopupContainer } = this.props;
|
||||
// default multiple selection in filter dropdown
|
||||
const multiple = ('filterMultiple' in column) ? column.filterMultiple : true;
|
||||
const dropdownMenuClass = classNames({
|
||||
[`${dropdownPrefixCls}-menu-without-submenu`]: !this.hasSubMenu(),
|
||||
});
|
||||
const menus = column.filterDropdown ? (
|
||||
<FilterDropdownMenuWrapper>
|
||||
{column.filterDropdown}
|
||||
</FilterDropdownMenuWrapper>
|
||||
) : (
|
||||
<FilterDropdownMenuWrapper className={`${prefixCls}-dropdown`}>
|
||||
<Menu
|
||||
multiple={multiple}
|
||||
onClick={this.handleMenuItemClick}
|
||||
prefixCls={`${dropdownPrefixCls}-menu`}
|
||||
className={dropdownMenuClass}
|
||||
onSelect={this.setSelectedKeys}
|
||||
onDeselect={this.setSelectedKeys}
|
||||
selectedKeys={this.state.selectedKeys}
|
||||
>
|
||||
{this.renderMenus(column.filters!)}
|
||||
</Menu>
|
||||
<div className={`${prefixCls}-dropdown-btns`}>
|
||||
<a
|
||||
className={`${prefixCls}-dropdown-link confirm`}
|
||||
onClick={this.handleConfirm}
|
||||
>
|
||||
{locale.filterConfirm}
|
||||
</a>
|
||||
<a
|
||||
className={`${prefixCls}-dropdown-link clear`}
|
||||
onClick={this.handleClearFilters}
|
||||
>
|
||||
{locale.filterReset}
|
||||
</a>
|
||||
</div>
|
||||
</FilterDropdownMenuWrapper>
|
||||
);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
overlay={menus}
|
||||
visible={this.neverShown ? false : this.state.visible}
|
||||
onVisibleChange={this.onVisibleChange}
|
||||
getPopupContainer={getPopupContainer}
|
||||
forceRender
|
||||
>
|
||||
{this.renderFilterIcon()}
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
---
|
||||
category: Components
|
||||
cols: 1
|
||||
type: Data Display
|
||||
title: Table
|
||||
---
|
||||
|
||||
A table displays rows of data.
|
||||
|
||||
## When To Use
|
||||
|
||||
- To display a collection of structured data.
|
||||
- To sort, search, paginate, filter data.
|
||||
|
||||
## How To Use
|
||||
|
||||
Specify `dataSource` of Table as an array of data.
|
||||
|
||||
```jsx
|
||||
const dataSource = [{
|
||||
key: '1',
|
||||
name: 'Mike',
|
||||
age: 32,
|
||||
address: '10 Downing Street'
|
||||
}, {
|
||||
key: '2',
|
||||
name: 'John',
|
||||
age: 42,
|
||||
address: '10 Downing Street'
|
||||
}];
|
||||
|
||||
const columns = [{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
}, {
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
}, {
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
}];
|
||||
|
||||
<Table dataSource={dataSource} columns={columns} />
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Table
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| bordered | Whether to show all table borders | boolean | `false` |
|
||||
| columns | Columns of table | [ColumnProps](https://git.io/vMMXC)\[] | - |
|
||||
| components | Override default table elements | object | - |
|
||||
| dataSource | Data record array to be displayed | any\[] | - |
|
||||
| defaultExpandAllRows | Expand all rows initially | boolean | `false` |
|
||||
| defaultExpandedRowKeys | Initial expanded row keys | string\[] | - |
|
||||
| expandedRowKeys | Current expanded row keys | string\[] | - |
|
||||
| expandedRowRender | Expanded container render for each row | Function(record):ReactNode | - |
|
||||
| expandRowByClick | Whether to expand row by clicking anywhere in the whole row | boolean | `false` |
|
||||
| footer | Table footer renderer | Function(currentPageData) | |
|
||||
| indentSize | Indent size in pixels of tree data | number | 15 |
|
||||
| loading | Loading status of table | boolean\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/4544#issuecomment-271533135)) | `false` |
|
||||
| locale | i18n text including filter, sort, empty text, etc | object | filterConfirm: 'Ok' <br> filterReset: 'Reset' <br> emptyText: 'No Data' <br> [Default](https://github.com/ant-design/ant-design/issues/575#issuecomment-159169511) |
|
||||
| pagination | Pagination [config](/components/pagination/), hide it by setting it to `false` | object | |
|
||||
| rowClassName | Row's className | Function(record, index):string | - |
|
||||
| rowKey | Row's unique key, could be a string or function that returns a string | string\|Function(record):string | `key` |
|
||||
| rowSelection | Row selection [config](#rowSelection) | object | null |
|
||||
| scroll | Whether table can be scrolled in x/y direction, `x` or `y` can be a number that indicates the width and height of table body | object | - |
|
||||
| showHeader | Whether to show table header | boolean | `true` |
|
||||
| size | Size of table | `default` \| `middle` \| `small` | `default` |
|
||||
| title | Table title renderer | Function(currentPageData) | |
|
||||
| onChange | Callback executed when pagination, filters or sorter is changed | Function(pagination, filters, sorter) | |
|
||||
| onExpand | Callback executed when the row expand icon is clicked | Function(expanded, record) | |
|
||||
| onExpandedRowsChange | Callback executed when the expanded rows change | Function(expandedRows) | |
|
||||
| onHeaderRow | Set props on per header row | Function(column, index) | - |
|
||||
| onRow | Set props on per row | Function(record, index) | - |
|
||||
|
||||
#### onRow usage
|
||||
|
||||
Same as `onRow` `onHeaderRow` `onCell` `onHeaderCell`
|
||||
|
||||
```jsx
|
||||
<Table
|
||||
onRow={(record) => {
|
||||
return {
|
||||
onClick: () => {}, // click row
|
||||
onMouseEnter: () => {}, // mouse enter row
|
||||
onXxxx...
|
||||
};
|
||||
)}
|
||||
onHeaderRow={(column) => {
|
||||
return {
|
||||
onClick: () => {}, // click header row
|
||||
};
|
||||
)}
|
||||
/>
|
||||
```
|
||||
|
||||
### Column
|
||||
|
||||
One of the Table `columns` prop for describing the table's columns, Column has the same API.
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| className | className of this column | string | - |
|
||||
| colSpan | Span of this column's title | number | |
|
||||
| dataIndex | Display field of the data record, could be set like `a.b.c` | string | - |
|
||||
| defaultSortOrder | Default order of sorted values: `'ascend'` `'descend'` `null` | string | - |
|
||||
| filterDropdown | Customized filter overlay | ReactNode | - |
|
||||
| filterDropdownVisible | Whether `filterDropdown` is visible | boolean | - |
|
||||
| filtered | Whether the `dataSource` is filtered | boolean | `false` |
|
||||
| filteredValue | Controlled filtered value, filter icon will highlight | string\[] | - |
|
||||
| filterIcon | Customized filter icon | ReactNode | `false` |
|
||||
| filterMultiple | Whether multiple filters can be selected | boolean | `true` |
|
||||
| filters | Filter menu config | object\[] | - |
|
||||
| fixed | Set column to be fixed: `true`(same as left) `'left'` `'right'` | boolean\|string | `false` |
|
||||
| key | Unique key of this column, you can ignore this prop if you've set a unique `dataIndex` | string | - |
|
||||
| render | Renderer of the table cell. The return value should be a ReactNode, or an object for [colSpan/rowSpan config](#components-table-demo-colspan-rowspan) | Function(text, record, index) {} | - |
|
||||
| sorter | Sort function for local sort, see [Array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)'s compareFunction. If you need sort buttons only, set to `true` | Function\|boolean | - |
|
||||
| sortOrder | Order of sorted values: `'ascend'` `'descend'` `false` | boolean\|string | - |
|
||||
| title | Title of this column | string\|ReactNode | - |
|
||||
| width | Width of this column | string\|number | - |
|
||||
| onCell | Set props on per cell | Function(record) | - |
|
||||
| onFilter | Callback executed when the confirm filter button is clicked | Function | - |
|
||||
| onFilterDropdownVisibleChange | Callback executed when `filterDropdownVisible` is changed | function(visible) {} | - |
|
||||
| onHeaderCell | Set props on per header cell | Function(column) | - |
|
||||
|
||||
### ColumnGroup
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| title | Title of the column group | string\|ReactNode | - |
|
||||
|
||||
### rowSelection
|
||||
|
||||
Properties for row selection.
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| fixed | Fixed selection column on the left | boolean | - |
|
||||
| getCheckboxProps | Get Checkbox or Radio props | Function(record) | - |
|
||||
| hideDefaultSelections | Remove the default `Select All` and `Select Invert` selections | boolean | `false` |
|
||||
| selectedRowKeys | Controlled selected row keys | string\[] | \[] |
|
||||
| selections | Custom selection [config](#rowSelection), only displays default selections when set to `true` | object\[]\|boolean | - |
|
||||
| type | `checkbox` or `radio` | `checkbox` \| `radio` | `checkbox` |
|
||||
| onChange | Callback executed when selected rows change | Function(selectedRowKeys, selectedRows) | - |
|
||||
| onSelect | Callback executed when select/deselect one row | Function(record, selected, selectedRows) | - |
|
||||
| onSelectAll | Callback executed when select/deselect all rows | Function(selected, selectedRows, changeRows) | - |
|
||||
| onSelectInvert | Callback executed when row selection is inverted | Function(selectedRows) | - |
|
||||
|
||||
### selection
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| -------- | ----------- | ---- | ------- |
|
||||
| key | Unique key of this selection | string | - |
|
||||
| text | Display text of this selection | string\|React.ReactNode | - |
|
||||
| onSelect | Callback executed when this selection is clicked | Function(changeableRowKeys) | - |
|
||||
|
||||
## Using in TypeScript
|
||||
|
||||
```jsx
|
||||
import { Table } from 'antd';
|
||||
import { ColumnProps } from 'antd/lib/table';
|
||||
|
||||
interface IUser {
|
||||
key: number,
|
||||
name: string;
|
||||
}
|
||||
|
||||
const columns: ColumnProps<IUser>[] = [{
|
||||
key: 'name',
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
}];
|
||||
|
||||
const data: IUser[] = [{
|
||||
key: 0,
|
||||
name: 'Jack',
|
||||
}];
|
||||
|
||||
class UserTable extends Table<IUser> {}
|
||||
|
||||
<UserTable columns={columns} dataSource={data} />
|
||||
|
||||
// Use JSX style API
|
||||
class NameColumn extends Table.Column<IUser> {}
|
||||
|
||||
<UserTable dataSource={data}>
|
||||
<NameColumn key="name" title="Name" dataIndex="name" />
|
||||
</UserTable>
|
||||
```
|
||||
|
||||
## Note
|
||||
|
||||
According to [React documentation](https://facebook.github.io/react/docs/lists-and-keys.html#keys), every child in array should be assigned a unique key. The values inside `dataSource` and `columns` should follow this in Table, and `dataSource[i].key` would be treated as key value default for `dataSource`.
|
||||
|
||||
If `dataSource[i].key` is not provided, then you should specify the primary key of dataSource value via `rowKey`. If not, warnings like above will show in browser console.
|
||||
|
||||
![](https://os.alipayobjects.com/rmsportal/luLdLvhPOiRpyss.png)
|
||||
|
||||
```jsx
|
||||
// primary key is uid
|
||||
return <Table rowKey="uid" />;
|
||||
// or
|
||||
return <Table rowKey={record => record.uid} />;
|
||||
```
|
|
@ -0,0 +1,5 @@
|
|||
import Table from './Table'
|
||||
|
||||
export * from './interface'
|
||||
|
||||
export default Table
|
|
@ -0,0 +1,210 @@
|
|||
---
|
||||
category: Components
|
||||
cols: 1
|
||||
type: Data Display
|
||||
title: Table
|
||||
subtitle: 表格
|
||||
---
|
||||
|
||||
展示行列数据。
|
||||
|
||||
## 何时使用
|
||||
|
||||
- 当有大量结构化的数据需要展现时;
|
||||
- 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。
|
||||
|
||||
## 如何使用
|
||||
|
||||
指定表格的数据源 `dataSource` 为一个数组。
|
||||
|
||||
```jsx
|
||||
const dataSource = [{
|
||||
key: '1',
|
||||
name: '胡彦斌',
|
||||
age: 32,
|
||||
address: '西湖区湖底公园1号'
|
||||
}, {
|
||||
key: '2',
|
||||
name: '胡彦祖',
|
||||
age: 42,
|
||||
address: '西湖区湖底公园1号'
|
||||
}];
|
||||
|
||||
const columns = [{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
}, {
|
||||
title: '年龄',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
}, {
|
||||
title: '住址',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
}];
|
||||
|
||||
<Table dataSource={dataSource} columns={columns} />
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Table
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| bordered | 是否展示外边框和列边框 | boolean | false |
|
||||
| columns | 表格列的配置描述,具体项见下表 | [ColumnProps](https://git.io/vMMXC)\[] | - |
|
||||
| components | 覆盖默认的 table 元素 | object | - |
|
||||
| dataSource | 数据数组 | any\[] | |
|
||||
| defaultExpandAllRows | 初始时,是否展开所有行 | boolean | false |
|
||||
| defaultExpandedRowKeys | 默认展开的行 | string\[] | - |
|
||||
| expandedRowKeys | 展开的行,控制属性 | string\[] | - |
|
||||
| expandedRowRender | 额外的展开行 | Function(record):ReactNode | - |
|
||||
| expandRowByClick | 通过点击行来展开子行 | boolean | `false` |
|
||||
| footer | 表格尾部 | Function(currentPageData) | |
|
||||
| indentSize | 展示树形数据时,每层缩进的宽度,以 px 为单位 | number | 15 |
|
||||
| loading | 页面是否加载中 | boolean\|[object](https://ant.design/components/spin-cn/#API) ([更多](https://github.com/ant-design/ant-design/issues/4544#issuecomment-271533135)) | false |
|
||||
| locale | 默认文案设置,目前包括排序、过滤、空数据文案 | object | filterConfirm: '确定' <br> filterReset: '重置' <br> emptyText: '暂无数据' <br> [默认值](https://github.com/ant-design/ant-design/issues/575#issuecomment-159169511) |
|
||||
| pagination | 分页器,配置项参考 [pagination](/components/pagination/),设为 false 时不展示和进行分页 | object | |
|
||||
| rowClassName | 表格行的类名 | Function(record, index):string | - |
|
||||
| rowKey | 表格行 key 的取值,可以是字符串或一个函数 | string\|Function(record):string | 'key' |
|
||||
| rowSelection | 列表项是否可选择,[配置项](#rowSelection) | object | null |
|
||||
| scroll | 横向或纵向支持滚动,也可用于指定滚动区域的宽高度:`{{ x: true, y: 300 }}` | object | - |
|
||||
| showHeader | 是否显示表头 | boolean | true |
|
||||
| size | 正常或迷你类型,`default` or `small` | string | default |
|
||||
| title | 表格标题 | Function(currentPageData) | |
|
||||
| onChange | 分页、排序、筛选变化时触发 | Function(pagination, filters, sorter) | |
|
||||
| onExpand | 点击展开图标时触发 | Function(expanded, record) | |
|
||||
| onExpandedRowsChange | 展开的行变化时触发 | Function(expandedRows) | |
|
||||
| onHeaderRow | 设置头部行属性 | Function(column, index) | - |
|
||||
| onRow | 设置行属性 | Function(record, index) | - |
|
||||
|
||||
|
||||
#### onRow 用法
|
||||
|
||||
适用于 `onRow` `onHeaderRow` `onCell` `onHeaderCell`。
|
||||
|
||||
```jsx
|
||||
<Table
|
||||
onRow={(record) => {
|
||||
return {
|
||||
onClick: () => {}, // 点击行
|
||||
onMouseEnter: () => {}, // 鼠标移入行
|
||||
onXxxx...
|
||||
};
|
||||
)}
|
||||
onHeaderRow={(column) => {
|
||||
return {
|
||||
onClick: () => {}, // 点击表头行
|
||||
};
|
||||
)}
|
||||
/>
|
||||
```
|
||||
|
||||
### Column
|
||||
|
||||
列描述数据对象,是 columns 中的一项,Column 使用相同的 API。
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| className | 列的 className | string | - |
|
||||
| colSpan | 表头列合并,设置为 0 时,不渲染 | number | |
|
||||
| dataIndex | 列数据在数据项中对应的 key,支持 `a.b.c` 的嵌套写法 | string | - |
|
||||
| filterDropdown | 可以自定义筛选菜单,此函数只负责渲染图层,需要自行编写各种交互 | ReactNode | - |
|
||||
| filterDropdownVisible | 用于控制自定义筛选菜单是否可见 | boolean | - |
|
||||
| filtered | 标识数据是否经过过滤,筛选图标会高亮 | boolean | false |
|
||||
| filteredValue | 筛选的受控属性,外界可用此控制列的筛选状态,值为已筛选的 value 数组 | string\[] | - |
|
||||
| filterIcon | 自定义 fiter 图标。 | ReactNode | false |
|
||||
| filterMultiple | 是否多选 | boolean | true |
|
||||
| filters | 表头的筛选菜单项 | object\[] | - |
|
||||
| fixed | 列是否固定,可选 `true`(等效于 left) `'left'` `'right'` | boolean\|string | false |
|
||||
| key | React 需要的 key,如果已经设置了唯一的 `dataIndex`,可以忽略这个属性 | string | - |
|
||||
| render | 生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引,@return里面可以设置表格[行/列合并](#components-table-demo-colspan-rowspan) | Function(text, record, index) {} | - |
|
||||
| sorter | 排序函数,本地排序使用一个函数(参考 [Array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) 的 compareFunction),需要服务端排序可设为 true | Function\|boolean | - |
|
||||
| sortOrder | 排序的受控属性,外界可用此控制列的排序,可设置为 `'ascend'` `'descend'` `false` | boolean\|string | - |
|
||||
| title | 列头显示文字 | string\|ReactNode | - |
|
||||
| width | 列宽度 | string\|number | - |
|
||||
| onCell | 设置单元格属性 | Function(record) | - |
|
||||
| onFilter | 本地模式下,确定筛选的运行函数 | Function | - |
|
||||
| onFilterDropdownVisibleChange | 自定义筛选菜单可见变化时调用 | function(visible) {} | - |
|
||||
| onHeaderCell | 设置头部单元格属性 | Function(column) | - |
|
||||
|
||||
### ColumnGroup
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| title | 列头显示文字 | string\|ReactNode | - |
|
||||
|
||||
### rowSelection
|
||||
|
||||
选择功能的配置。
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| fixed | 把选择框列固定在左边 | boolean | - |
|
||||
| getCheckboxProps | 选择框的默认属性配置 | Function(record) | - |
|
||||
| hideDefaultSelections | 去掉『全选』『反选』两个默认选项 | boolean | false |
|
||||
| selectedRowKeys | 指定选中项的 key 数组,需要和 onChange 进行配合 | string\[] | \[] |
|
||||
| selections | 自定义选择项 [配置项](#selection), 设为 `true` 时使用默认选择项 | object\[]\|boolean | true |
|
||||
| type | 多选/单选,`checkbox` or `radio` | string | `checkbox` |
|
||||
| onChange | 选中项发生变化的时的回调 | Function(selectedRowKeys, selectedRows) | - |
|
||||
| onSelect | 用户手动选择/取消选择某列的回调 | Function(record, selected, selectedRows) | - |
|
||||
| onSelectAll | 用户手动选择/取消选择所有列的回调 | Function(selected, selectedRows, changeRows) | - |
|
||||
| onSelectInvert | 用户手动选择反选的回调 | Function(selectedRows) | - |
|
||||
|
||||
### selection
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| key | React 需要的 key,建议设置 | string | - |
|
||||
| text | 选择项显示的文字 | string\|React.ReactNode | - |
|
||||
| onSelect | 选择项点击回调 | Function(changeableRowKeys) | - |
|
||||
|
||||
## 在 TypeScript 中使用
|
||||
|
||||
```jsx
|
||||
import { Table } from 'antd';
|
||||
import { ColumnProps } from 'antd/lib/table';
|
||||
|
||||
interface IUser {
|
||||
key: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const columns: ColumnProps<IUser>[] = [{
|
||||
key: 'name',
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
}];
|
||||
|
||||
const data: IUser[] = [{
|
||||
key: 0,
|
||||
name: 'Jack',
|
||||
}];
|
||||
|
||||
class UserTable extends Table<IUser> {}
|
||||
<UserTable columns={columns} dataSource={data} />
|
||||
|
||||
// 使用 JSX 风格的 API
|
||||
class NameColumn extends Table.Column<IUser> {}
|
||||
|
||||
<UserTable dataSource={data}>
|
||||
<NameColumn key="name" title="Name" dataIndex="name" />
|
||||
</UserTable>
|
||||
```
|
||||
|
||||
## 注意
|
||||
|
||||
按照 [React 的规范](https://facebook.github.io/react/docs/lists-and-keys.html#keys),所有的组件数组必须绑定 key。在 Table 中,`dataSource` 和 `columns` 里的数据值都需要指定 `key` 值。对于 `dataSource` 默认将每列数据的 `key` 属性作为唯一的标识。
|
||||
|
||||
如果你的数据没有这个属性,务必使用 `rowKey` 来指定数据列的主键。若没有指定,控制台会出现以下的提示,表格组件也会出现各类奇怪的错误。
|
||||
|
||||
![](https://os.alipayobjects.com/rmsportal/luLdLvhPOiRpyss.png)
|
||||
|
||||
```jsx
|
||||
// 比如你的数据主键是 uid
|
||||
return <Table rowKey="uid" />;
|
||||
// 或
|
||||
return <Table rowKey={record => record.uid} />;
|
||||
```
|
|
@ -0,0 +1,186 @@
|
|||
import PropTypes from '../_util/vue-types'
|
||||
import { PaginationProps as getPaginationProps } from '../pagination'
|
||||
import { SpinProps as getSpinProps } from '../spin'
|
||||
import { Store } from './createStore'
|
||||
|
||||
const PaginationProps = getPaginationProps()
|
||||
const SpinProps = getSpinProps()
|
||||
|
||||
// export type CompareFn<T> = ((a: T, b: T) => number);
|
||||
export const ColumnFilterItem = PropTypes.shape({
|
||||
text: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
children: PropTypes.array,
|
||||
}).loose
|
||||
|
||||
export const ColumnProps = {
|
||||
title: PropTypes.any,
|
||||
// key?: React.Key;
|
||||
dataIndex: PropTypes.string,
|
||||
render: PropTypes.func,
|
||||
filters: PropTypes.arrayOf(ColumnFilterItem),
|
||||
// onFilter: (value: any, record: T) => PropTypes.bool,
|
||||
filterMultiple: PropTypes.bool,
|
||||
filterDropdown: PropTypes.any,
|
||||
filterDropdownVisible: PropTypes.bool,
|
||||
// onFilterDropdownVisibleChange?: (visible: boolean) => void;
|
||||
sorter: PropTypes.oneOfType([PropTypes.boolean, PropTypes.func]),
|
||||
defaultSortOrder: PropTypes.oneOf(['ascend', 'descend']),
|
||||
colSpan: PropTypes.number,
|
||||
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
// className: string,
|
||||
fixed: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['left', 'right'])]),
|
||||
filterIcon: PropTypes.any,
|
||||
filteredValue: PropTypes.array,
|
||||
sortOrder: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf(['ascend', 'descend'])]),
|
||||
// children?: ColumnProps<T>[];
|
||||
// onCellClick?: (record: T, event: any) => void;
|
||||
// onCell?: (record: T) => any;
|
||||
// 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 const TableLocale = PropTypes.shape({
|
||||
filterTitle: PropTypes.string,
|
||||
filterConfirm: PropTypes.any,
|
||||
filterReset: PropTypes.any,
|
||||
emptyText: PropTypes.any,
|
||||
selectAll: PropTypes.any,
|
||||
selectInvert: PropTypes.any,
|
||||
}).loose
|
||||
|
||||
export const RowSelectionType = PropTypes.oneOf(['checkbox', 'radio'])
|
||||
// export type SelectionSelectFn<T> = (record: T, selected: boolean, selectedRows: Object[]) => any;
|
||||
|
||||
export const TableRowSelection = {
|
||||
type: RowSelectionType,
|
||||
selectedRowKeys: PropTypes.array,
|
||||
// onChange?: (selectedRowKeys: string[] | number[], selectedRows: Object[]) => any;
|
||||
getCheckboxProps: PropTypes.func,
|
||||
// onSelect?: SelectionSelectFn<T>;
|
||||
// onSelectAll?: (selected: boolean, selectedRows: Object[], changeRows: Object[]) => any;
|
||||
// onSelectInvert?: (selectedRows: Object[]) => any;
|
||||
selections: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),
|
||||
hideDefaultSelections: PropTypes.bool,
|
||||
fixed: PropTypes.bool,
|
||||
}
|
||||
|
||||
export const TableProps = {
|
||||
prefixCls: PropTypes.string,
|
||||
dropdownPrefixCls: PropTypes.string,
|
||||
rowSelection: PropTypes.shape(TableRowSelection).loose,
|
||||
pagination: PropTypes.oneOfType([PropTypes.shape(PaginationProps).loose, PropTypes.bool]),
|
||||
size: PropTypes.oneOf(['default', 'middle', 'small']),
|
||||
dataSource: PropTypes.array,
|
||||
components: PropTypes.object,
|
||||
columns: PropTypes.array,
|
||||
rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||
rowClassName: PropTypes.func,
|
||||
expandedRowRender: PropTypes.any,
|
||||
defaultExpandAllRows: PropTypes.bool,
|
||||
defaultExpandedRowKeys: PropTypes.array,
|
||||
expandedRowKeys: PropTypes.array,
|
||||
expandIconAsCell: PropTypes.bool,
|
||||
expandIconColumnIndex: PropTypes.number,
|
||||
expandRowByClick: PropTypes.bool,
|
||||
// onExpandedRowsChange?: (expandedRowKeys: string[] | number[]) => void;
|
||||
// onExpand?: (expanded: boolean, record: T) => void;
|
||||
// onChange?: (pagination: PaginationProps | boolean, filters: string[], sorter: Object) => any;
|
||||
loading: PropTypes.oneOfType([PropTypes.shape(SpinProps).loose, PropTypes.bool]),
|
||||
locale: PropTypes.object,
|
||||
indentSize: PropTypes.number,
|
||||
// onRowClick?: (record: T, index: number, event: Event) => any;
|
||||
// onRow?: (record: T, index: number) => any;
|
||||
useFixedHeader: PropTypes.bool,
|
||||
bordered: PropTypes.bool,
|
||||
showHeader: PropTypes.bool,
|
||||
footer: PropTypes.any,
|
||||
title: PropTypes.any,
|
||||
scroll: PropTypes.object,
|
||||
childrenColumnName: PropTypes.string,
|
||||
bodyStyle: PropTypes.any,
|
||||
// className?: PropTypes.string,
|
||||
// style?: React.CSSProperties;
|
||||
// children?: React.ReactNode;
|
||||
}
|
||||
|
||||
// export interface TableStateFilters {
|
||||
// [key: string]: string[];
|
||||
// }
|
||||
|
||||
// export interface TableState<T> {
|
||||
// pagination: PaginationProps;
|
||||
// filters: TableStateFilters;
|
||||
// sortColumn: ColumnProps<T> | null;
|
||||
// sortOrder: PropTypes.string,
|
||||
// }
|
||||
|
||||
// export type SelectionItemSelectFn = (key: string[]) => any;
|
||||
|
||||
// export interface SelectionItem {
|
||||
// key: PropTypes.string,
|
||||
// text: PropTypes.any,
|
||||
// onSelect: SelectionItemSelectFn;
|
||||
// }
|
||||
|
||||
export const SelectionCheckboxAllProps = {
|
||||
store: Store,
|
||||
locale: PropTypes.any,
|
||||
disabled: PropTypes.bool,
|
||||
getCheckboxPropsByItem: PropTypes.func,
|
||||
getRecordKey: PropTypes.func,
|
||||
data: PropTypes.array,
|
||||
prefixCls: PropTypes.string,
|
||||
// onSelect: (key: string, index: number, selectFunc: any) => void;
|
||||
hideDefaultSelections: PropTypes.bool,
|
||||
selections: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),
|
||||
getPopupContainer: PropTypes.func,
|
||||
}
|
||||
|
||||
// export interface SelectionCheckboxAllState {
|
||||
// checked: PropTypes.bool,
|
||||
// indeterminate: PropTypes.bool,
|
||||
// }
|
||||
|
||||
export const SelectionBoxProps = {
|
||||
store: Store,
|
||||
type: RowSelectionType,
|
||||
defaultSelection: PropTypes.arrayOf(PropTypes.string),
|
||||
rowIndex: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
// onChange: React.ChangeEventHandler<HTMLInputElement>;
|
||||
}
|
||||
|
||||
// export interface SelectionBoxState {
|
||||
// checked?: PropTypes.bool,
|
||||
// }
|
||||
|
||||
export const FilterMenuProps = {
|
||||
locale: TableLocale,
|
||||
selectedKeys: PropTypes.arrayOf(PropTypes.string),
|
||||
column: PropTypes.shape(ColumnProps),
|
||||
confirmFilter: PropTypes.func,
|
||||
prefixCls: PropTypes.string,
|
||||
dropdownPrefixCls: PropTypes.string,
|
||||
getPopupContainer: PropTypes.func,
|
||||
}
|
||||
|
||||
// export interface FilterMenuState {
|
||||
// selectedKeys: string[];
|
||||
// keyPathOfSelectedItem: { [key: string]: string };
|
||||
// visible?: PropTypes.bool,
|
||||
// }
|
|
@ -0,0 +1,9 @@
|
|||
import '../../style/index.less'
|
||||
import './index.less'
|
||||
|
||||
// style dependencies
|
||||
import '../../radio/style'
|
||||
import '../../checkbox/style'
|
||||
import '../../dropdown/style'
|
||||
import '../../spin/style'
|
||||
import '../../pagination/style'
|
|
@ -0,0 +1,568 @@
|
|||
@import "../../style/themes/default";
|
||||
@import "../../style/mixins/index";
|
||||
|
||||
@table-prefix-cls: ~"@{ant-prefix}-table";
|
||||
@table-header-icon-color: @text-color-secondary;
|
||||
|
||||
.@{table-prefix-cls}-wrapper {
|
||||
.clearfix;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls} {
|
||||
.reset-component;
|
||||
position: relative;
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
|
||||
&-body {
|
||||
transition: opacity .3s;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
text-align: left;
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
}
|
||||
|
||||
&-thead > tr > th {
|
||||
background: @table-header-bg;
|
||||
transition: background .3s ease;
|
||||
text-align: left;
|
||||
color: @heading-color;
|
||||
font-weight: 500;
|
||||
border-bottom: @border-width-base @border-style-base @border-color-split;
|
||||
|
||||
&[colspan] {
|
||||
text-align: center;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.@{iconfont-css-prefix}-filter,
|
||||
.@{table-prefix-cls}-filter-icon {
|
||||
position: relative;
|
||||
margin-left: 8px;
|
||||
font-size: @font-size-base;
|
||||
cursor: pointer;
|
||||
color: @table-header-icon-color;
|
||||
transition: all .3s;
|
||||
width: 14px;
|
||||
font-weight: normal;
|
||||
vertical-align: text-bottom;
|
||||
|
||||
&:hover {
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-column-sorter + .@{iconfont-css-prefix}-filter {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-filter-selected.@{iconfont-css-prefix}-filter {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/8979
|
||||
&.@{table-prefix-cls}-column-has-filters {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&-tbody > tr > td {
|
||||
border-bottom: @border-width-base @border-style-base @border-color-split;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
&-thead > tr,
|
||||
&-tbody > tr {
|
||||
transition: all .3s;
|
||||
&.@{table-prefix-cls}-row-hover,
|
||||
&:hover {
|
||||
& > td {
|
||||
background: @table-row-hover-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-thead > tr:hover {
|
||||
background: none;
|
||||
}
|
||||
|
||||
&-footer {
|
||||
padding: @table-padding-vertical @table-padding-horizontal;
|
||||
background: @table-header-bg;
|
||||
border-radius: 0 0 @border-radius-base @border-radius-base;
|
||||
position: relative;
|
||||
border-top: @border-width-base @border-style-base @border-color-split;
|
||||
&:before {
|
||||
content: '';
|
||||
height: 1px;
|
||||
background: @table-header-bg;
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.@{table-prefix-cls}-bordered &-footer {
|
||||
border: @border-width-base @border-style-base @border-color-split;
|
||||
}
|
||||
|
||||
&-title {
|
||||
padding: @table-padding-vertical 0;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
}
|
||||
|
||||
&.@{table-prefix-cls}-bordered &-title {
|
||||
border: @border-width-base @border-style-base @border-color-split;
|
||||
padding-left: @table-padding-horizontal;
|
||||
padding-right: @table-padding-horizontal;
|
||||
}
|
||||
|
||||
&-title + &-content {
|
||||
position: relative;
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
overflow: hidden;
|
||||
.@{table-prefix-cls}-bordered & {
|
||||
&,
|
||||
table {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/4373
|
||||
&-without-column-header &-title + &-content,
|
||||
&-without-column-header table {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&-tbody > tr.@{table-prefix-cls}-row-selected td {
|
||||
background: @table-selected-row-bg;
|
||||
}
|
||||
|
||||
&-thead > tr > th.@{table-prefix-cls}-column-sort {
|
||||
background: @table-header-sort-bg;
|
||||
}
|
||||
|
||||
&-thead > tr > th,
|
||||
&-tbody > tr > td {
|
||||
padding: @table-padding-vertical @table-padding-horizontal;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
&-thead > tr > th.@{table-prefix-cls}-selection-column-custom {
|
||||
padding-left: 16px;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
&-thead > tr > th.@{table-prefix-cls}-selection-column,
|
||||
&-tbody > tr > td.@{table-prefix-cls}-selection-column {
|
||||
text-align: center;
|
||||
min-width: 62px;
|
||||
width: 62px;
|
||||
.@{ant-prefix}-radio-wrapper {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-expand-icon-th,
|
||||
&-row-expand-icon-cell {
|
||||
text-align: center;
|
||||
min-width: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
&-header {
|
||||
background: @table-header-bg;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&-header table {
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
}
|
||||
|
||||
&-loading {
|
||||
position: relative;
|
||||
.@{table-prefix-cls}-body {
|
||||
background: @component-background;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.@{table-prefix-cls}-spin-holder {
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -30px;
|
||||
position: absolute;
|
||||
}
|
||||
.@{table-prefix-cls}-with-pagination {
|
||||
margin-top: -20px;
|
||||
}
|
||||
.@{table-prefix-cls}-without-pagination {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&-column-sorter {
|
||||
position: relative;
|
||||
margin-left: 8px;
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
font-weight: normal;
|
||||
color: @table-header-icon-color;
|
||||
|
||||
&-up,
|
||||
&-down {
|
||||
line-height: 6px;
|
||||
display: block;
|
||||
width: 14px;
|
||||
height: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
&:hover .@{iconfont-css-prefix} {
|
||||
color: @primary-4;
|
||||
}
|
||||
&.on {
|
||||
.@{iconfont-css-prefix}-caret-up,
|
||||
.@{iconfont-css-prefix}-caret-down {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
height: 30px;
|
||||
width: 14px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-up:after {
|
||||
bottom: -2px;
|
||||
}
|
||||
|
||||
&-down:after {
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.@{iconfont-css-prefix}-caret-up,
|
||||
.@{iconfont-css-prefix}-caret-down {
|
||||
.iconfont-size-under-12px(8px);
|
||||
line-height: 4px;
|
||||
height: 4px;
|
||||
transition: all .3s;
|
||||
}
|
||||
}
|
||||
|
||||
&-bordered {
|
||||
.@{table-prefix-cls}-header > table,
|
||||
.@{table-prefix-cls}-body > table,
|
||||
.@{table-prefix-cls}-fixed-left table,
|
||||
.@{table-prefix-cls}-fixed-right table {
|
||||
border: @border-width-base @border-style-base @border-color-split;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
&.@{table-prefix-cls}-empty {
|
||||
.@{table-prefix-cls}-placeholder {
|
||||
border-left: @border-width-base @border-style-base @border-color-split;
|
||||
border-right: @border-width-base @border-style-base @border-color-split;
|
||||
}
|
||||
}
|
||||
|
||||
&.@{table-prefix-cls}-fixed-header {
|
||||
.@{table-prefix-cls}-header > table {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-body > table {
|
||||
border-top: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-body-inner > table {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-placeholder {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-thead > tr > th {
|
||||
border-bottom: @border-width-base @border-style-base @border-color-split;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-thead > tr > th,
|
||||
.@{table-prefix-cls}-tbody > tr > td {
|
||||
border-right: @border-width-base @border-style-base @border-color-split;
|
||||
}
|
||||
}
|
||||
|
||||
&-placeholder {
|
||||
position: relative;
|
||||
padding: @table-padding-vertical @table-padding-horizontal;
|
||||
background: @component-background;
|
||||
border-bottom: @border-width-base @border-style-base @border-color-split;
|
||||
text-align: center;
|
||||
font-size: @font-size-base;
|
||||
color: @text-color-secondary;
|
||||
z-index: 1;
|
||||
.@{iconfont-css-prefix} {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&-pagination.@{ant-prefix}-pagination {
|
||||
margin: 16px 0;
|
||||
float: right;
|
||||
}
|
||||
|
||||
&-filter-dropdown {
|
||||
min-width: 96px;
|
||||
margin-left: -8px;
|
||||
background: @component-background;
|
||||
border-radius: @border-radius-base;
|
||||
box-shadow: @box-shadow-base;
|
||||
|
||||
.@{ant-prefix}-dropdown-menu {
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/4916
|
||||
&-without-submenu {
|
||||
max-height: 400px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
&-item > label + span {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
&-sub {
|
||||
border-radius: @border-radius-base;
|
||||
box-shadow: @box-shadow-base;
|
||||
}
|
||||
|
||||
.@{ant-prefix}-dropdown-submenu-contain-selected {
|
||||
.@{ant-prefix}-dropdown-menu-submenu-title:after {
|
||||
color: @primary-color;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 0 2px @primary-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{ant-prefix}-dropdown-menu-item {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
> .@{ant-prefix}-dropdown-menu > .@{ant-prefix}-dropdown-menu-item:last-child,
|
||||
> .@{ant-prefix}-dropdown-menu > .@{ant-prefix}-dropdown-menu-submenu:last-child .@{ant-prefix}-dropdown-menu-submenu-title {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&-btns {
|
||||
overflow: hidden;
|
||||
padding: 7px 8px;
|
||||
border-top: @border-width-base @border-style-base @border-color-split;
|
||||
}
|
||||
|
||||
&-link {
|
||||
color: @link-color;
|
||||
&:hover {
|
||||
color: @link-hover-color;
|
||||
}
|
||||
&:active {
|
||||
color: @link-active-color;
|
||||
}
|
||||
&.confirm {
|
||||
float: left;
|
||||
}
|
||||
&.clear {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-selection {
|
||||
&-select-all-custom {
|
||||
margin-right: 4px !important;
|
||||
}
|
||||
|
||||
.@{iconfont-css-prefix}-down {
|
||||
color: @table-header-icon-color;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
&-menu {
|
||||
min-width: 96px;
|
||||
margin-top: 5px;
|
||||
margin-left: -30px;
|
||||
background: @component-background;
|
||||
border-radius: @border-radius-base;
|
||||
box-shadow: @box-shadow-base;
|
||||
|
||||
.@{ant-prefix}-action-down {
|
||||
color: @table-header-icon-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-down {
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
&:hover .@{iconfont-css-prefix}-down {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-row {
|
||||
&-expand-icon {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
text-align: center;
|
||||
line-height: 14px;
|
||||
border: @border-width-base @border-style-base @border-color-split;
|
||||
user-select: none;
|
||||
background: @component-background;
|
||||
}
|
||||
|
||||
&-expanded:after {
|
||||
content: '-';
|
||||
}
|
||||
|
||||
&-collapsed:after {
|
||||
content: '+';
|
||||
}
|
||||
|
||||
&-spaced {
|
||||
visibility: hidden;
|
||||
&:after {
|
||||
content: '.';
|
||||
}
|
||||
}
|
||||
|
||||
&[class*="@{table-prefix-cls}-row-level-0"] .@{table-prefix-cls}-selection-column > span {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
tr&-expanded-row {
|
||||
&,
|
||||
&:hover {
|
||||
background: #fbfbfb;
|
||||
}
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-row-indent + .@{table-prefix-cls}-row-expand-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&-scroll {
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
table {
|
||||
width: auto;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&-body-inner {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&-fixed-header > &-content > &-scroll > &-body {
|
||||
position: relative;
|
||||
background: @component-background;
|
||||
}
|
||||
|
||||
&-fixed-header &-body-inner {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
&-fixed-header &-scroll &-header {
|
||||
overflow: scroll;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: -20px;
|
||||
}
|
||||
|
||||
&-fixed-left,
|
||||
&-fixed-right {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
transition: box-shadow .3s ease;
|
||||
border-radius: 0;
|
||||
table {
|
||||
width: auto;
|
||||
background: @component-background;
|
||||
}
|
||||
}
|
||||
|
||||
&-fixed-header &-fixed-left &-body-outer &-fixed,
|
||||
&-fixed-header &-fixed-right &-body-outer &-fixed {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&-fixed-left {
|
||||
left: 0;
|
||||
box-shadow: 6px 0 6px -4px @shadow-color;
|
||||
.@{table-prefix-cls}-header {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
// hide scrollbar in left fixed columns
|
||||
.@{table-prefix-cls}-body-inner {
|
||||
margin-right: -20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
.@{table-prefix-cls}-fixed-header & .@{table-prefix-cls}-body-inner {
|
||||
padding-right: 0;
|
||||
}
|
||||
&,
|
||||
table {
|
||||
border-radius: @border-radius-base 0 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-fixed-right {
|
||||
right: 0;
|
||||
box-shadow: -6px 0 6px -4px @shadow-color;
|
||||
&,
|
||||
table {
|
||||
border-radius: 0 @border-radius-base 0 0;
|
||||
}
|
||||
// hide expand row content in right-fixed Table
|
||||
// https://github.com/ant-design/ant-design/issues/1898
|
||||
.@{table-prefix-cls}-expanded-row {
|
||||
color: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&&-scroll-position-left &-fixed-left {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&&-scroll-position-right &-fixed-right {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@import './size';
|
|
@ -0,0 +1,109 @@
|
|||
.@{table-prefix-cls}-middle {
|
||||
> .@{table-prefix-cls}-title,
|
||||
> .@{table-prefix-cls}-footer {
|
||||
padding: @table-padding-vertical*3/4 @table-padding-horizontal/2;
|
||||
}
|
||||
> .@{table-prefix-cls}-content {
|
||||
> .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-body > table,
|
||||
> .@{table-prefix-cls}-scroll > .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-scroll > .@{table-prefix-cls}-body > table,
|
||||
> .@{table-prefix-cls}-fixed-left > .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-fixed-right > .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-fixed-left > .@{table-prefix-cls}-body-outer > .@{table-prefix-cls}-body-inner > table,
|
||||
> .@{table-prefix-cls}-fixed-right > .@{table-prefix-cls}-body-outer > .@{table-prefix-cls}-body-inner > table {
|
||||
> .@{table-prefix-cls}-thead > tr > th,
|
||||
> .@{table-prefix-cls}-tbody > tr > td {
|
||||
padding: @table-padding-vertical*3/4 @table-padding-horizontal/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-small {
|
||||
border: @border-width-base @border-style-base @border-color-split;
|
||||
border-radius: @border-radius-base;
|
||||
|
||||
> .@{table-prefix-cls}-title,
|
||||
> .@{table-prefix-cls}-footer {
|
||||
padding: @table-padding-vertical/2 @table-padding-horizontal/2;
|
||||
}
|
||||
|
||||
> .@{table-prefix-cls}-title {
|
||||
border-bottom: @border-width-base @border-style-base @border-color-split;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
> .@{table-prefix-cls}-content {
|
||||
> .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-body > table,
|
||||
> .@{table-prefix-cls}-scroll > .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-scroll > .@{table-prefix-cls}-body > table,
|
||||
> .@{table-prefix-cls}-fixed-left > .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-fixed-right > .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-fixed-left > .@{table-prefix-cls}-body-outer > .@{table-prefix-cls}-body-inner > table,
|
||||
> .@{table-prefix-cls}-fixed-right > .@{table-prefix-cls}-body-outer > .@{table-prefix-cls}-body-inner > table {
|
||||
border: 0;
|
||||
padding: 0 @table-padding-horizontal/2;
|
||||
> .@{table-prefix-cls}-thead > tr > th,
|
||||
> .@{table-prefix-cls}-tbody > tr > td {
|
||||
padding: @table-padding-vertical/2 @table-padding-horizontal/2;
|
||||
}
|
||||
> .@{table-prefix-cls}-thead > tr > th {
|
||||
background: @component-background;
|
||||
border-bottom: @border-width-base @border-style-base @border-color-split;
|
||||
}
|
||||
}
|
||||
|
||||
> .@{table-prefix-cls}-scroll > .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-scroll > .@{table-prefix-cls}-body > table,
|
||||
> .@{table-prefix-cls}-fixed-left > .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-fixed-right > .@{table-prefix-cls}-header > table,
|
||||
> .@{table-prefix-cls}-fixed-left > .@{table-prefix-cls}-body-outer > .@{table-prefix-cls}-body-inner > table,
|
||||
> .@{table-prefix-cls}-fixed-right > .@{table-prefix-cls}-body-outer > .@{table-prefix-cls}-body-inner > table {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-header {
|
||||
background: @component-background;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-placeholder,
|
||||
.@{table-prefix-cls}-row:last-child td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.@{table-prefix-cls}-bordered {
|
||||
border-right: 0;
|
||||
|
||||
.@{table-prefix-cls}-title {
|
||||
border: 0;
|
||||
border-bottom: @border-width-base @border-style-base @border-color-split;
|
||||
border-right: @border-width-base @border-style-base @border-color-split;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-content {
|
||||
border-right: @border-width-base @border-style-base @border-color-split;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-footer {
|
||||
border: 0;
|
||||
border-top: @border-width-base @border-style-base @border-color-split;
|
||||
border-right: @border-width-base @border-style-base @border-color-split;
|
||||
&:before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-placeholder {
|
||||
border-left: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.@{table-prefix-cls}-thead > tr > th:last-child,
|
||||
.@{table-prefix-cls}-tbody > tr > td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
export function flatArray (data = [], childrenName = 'children') {
|
||||
const result = []
|
||||
const loop = (array) => {
|
||||
array.forEach(item => {
|
||||
if (item[childrenName]) {
|
||||
const newItem = { ...item }
|
||||
delete newItem[childrenName]
|
||||
result.push(newItem)
|
||||
if (item[childrenName].length > 0) {
|
||||
loop(item[childrenName])
|
||||
}
|
||||
} else {
|
||||
result.push(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
loop(data)
|
||||
return result
|
||||
}
|
||||
|
||||
export function treeMap (tree, mapper, childrenName = 'children') {
|
||||
return tree.map((node, index) => {
|
||||
const extra = {}
|
||||
if (node[childrenName]) {
|
||||
extra[childrenName] = treeMap(node[childrenName], mapper, childrenName)
|
||||
}
|
||||
return {
|
||||
...mapper(node, index),
|
||||
...extra,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function flatFilter (tree, callback) {
|
||||
return tree.reduce((acc, node) => {
|
||||
if (callback(node)) {
|
||||
acc.push(node)
|
||||
}
|
||||
if (node.children) {
|
||||
const children = flatFilter(node.children, callback)
|
||||
acc.push(...children)
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
}
|
||||
|
||||
// export function normalizeColumns (elements) {
|
||||
// const columns = []
|
||||
// React.Children.forEach(elements, (element) => {
|
||||
// if (!React.isValidElement(element)) {
|
||||
// return
|
||||
// }
|
||||
// const column = {
|
||||
// ...element.props,
|
||||
// }
|
||||
// if (element.key) {
|
||||
// column.key = element.key
|
||||
// }
|
||||
// if (element.type && element.type.__ANT_TABLE_COLUMN_GROUP) {
|
||||
// column.children = normalizeColumns(column.children)
|
||||
// }
|
||||
// columns.push(column)
|
||||
// })
|
||||
// return columns
|
||||
// }
|
Loading…
Reference in New Issue