tjz
7 years ago
20 changed files with 2966 additions and 12 deletions
@ -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> |
||||
); |
||||
} |
||||
} |
@ -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