feat: Responsive table columns (#23298)

This commit is contained in:
Vitaly Budovski 2020-04-24 14:17:42 +10:00 committed by GitHub
parent 7935651899
commit f09686d3df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 213 additions and 25 deletions

View File

@ -3,14 +3,17 @@ import classNames from 'classnames';
import omit from 'omit.js';
import RcTable from 'rc-table';
import { TableProps as RcTableProps, INTERNAL_HOOKS } from 'rc-table/lib/Table';
import { convertChildrenToColumns } from 'rc-table/lib/hooks/useColumns';
import Spin, { SpinProps } from '../spin';
import Pagination, { PaginationConfig } from '../pagination';
import { ConfigContext } from '../config-provider/context';
import usePagination, { DEFAULT_PAGE_SIZE, getPaginationParam } from './hooks/usePagination';
import useLazyKVMap from './hooks/useLazyKVMap';
import { Breakpoint } from '../_util/responsiveObserve';
import {
TableRowSelection,
GetRowKey,
ColumnType,
ColumnsType,
TableCurrentDataSource,
SorterResult,
@ -33,6 +36,7 @@ import SizeContext, { SizeType } from '../config-provider/SizeContext';
import Column from './Column';
import ColumnGroup from './ColumnGroup';
import warning from '../_util/warning';
import useBreakpoint from '../grid/hooks/useBreakpoint';
export { ColumnsType, TablePaginationConfig };
@ -113,7 +117,17 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
showSorterTooltip = true,
} = props;
const tableProps = omit(props, ['className', 'style']) as TableProps<RecordType>;
const screens = useBreakpoint();
const mergedColumns = React.useMemo(() => {
const matched = new Set(Object.keys(screens).filter((m: Breakpoint) => screens[m]));
return (columns || convertChildrenToColumns(children)).filter(
(c: ColumnType<RecordType>) =>
!c.responsive || c.responsive.some((r: Breakpoint) => matched.has(r)),
);
}, [children, columns, screens]);
const tableProps = omit(props, ['className', 'style', 'columns']) as TableProps<RecordType>;
const size = React.useContext(SizeContext);
const { locale: contextLocale = defaultLocale, renderEmpty, direction } = React.useContext(
@ -222,8 +236,7 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
};
const [transformSorterColumns, sortStates, sorterTitleProps, getSorters] = useSorter<RecordType>({
prefixCls,
columns,
children,
mergedColumns,
onSorterChange,
sortDirections: sortDirections || ['ascend', 'descend'],
tableLocale,
@ -255,8 +268,7 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
prefixCls,
locale: tableLocale,
dropdownPrefixCls,
columns,
children,
mergedColumns,
onFilterChange,
getPopupContainer,
});
@ -313,8 +325,7 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
return mergedData;
}
const currentPageData = mergedData.slice((current - 1) * pageSize, current * pageSize);
return currentPageData;
return mergedData.slice((current - 1) * pageSize, current * pageSize);
}, [
!!pagination,
mergedData,
@ -439,6 +450,7 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
{topPaginationNode}
<RcTable<RecordType>
{...tableProps}
columns={mergedColumns}
direction={direction}
expandable={mergedExpandable}
prefixCls={prefixCls}

View File

@ -11541,6 +11541,141 @@ exports[`renders ./components/table/demo/resizable-column.md correctly 1`] = `
</div>
`;
exports[`renders ./components/table/demo/responsive.md correctly 1`] = `
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout:auto"
>
<colgroup />
<thead
class="ant-table-thead"
>
<tr>
<th
class="ant-table-cell"
>
Name (all screens)
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
>
<td
class="ant-table-cell"
>
<a>
John Brown
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<ul
class="ant-pagination ant-table-pagination ant-table-pagination-right"
unselectable="unselectable"
>
<li
aria-disabled="true"
class="ant-pagination-prev ant-pagination-disabled"
title="Previous Page"
>
<a
class="ant-pagination-item-link"
disabled=""
>
<span
aria-label="left"
class="anticon anticon-left"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="left"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
/>
</svg>
</span>
</a>
</li>
<li
class="ant-pagination-item ant-pagination-item-1 ant-pagination-item-active"
tabindex="0"
title="1"
>
<a>
1
</a>
</li>
<li
aria-disabled="true"
class="ant-pagination-next ant-pagination-disabled"
title="Next Page"
>
<a
class="ant-pagination-item-link"
disabled=""
>
<span
aria-label="right"
class="anticon anticon-right"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="right"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
/>
</svg>
</span>
</a>
</li>
</ul>
</div>
</div>
</div>
`;
exports[`renders ./components/table/demo/row-selection.md correctly 1`] = `
<div>
<div

View File

@ -0,0 +1,50 @@
---
order: 31
title:
zh-CN: 响应式
en-US: Responsive
---
## zh-CN
响应式配置列的展示。
## en-US
Responsive columns.
```jsx
import { Table } from 'antd';
const columns = [
{
title: 'Name (all screens)',
dataIndex: 'name',
key: 'name',
render: text => <a>{text}</a>,
},
{
title: 'Age (medium screen or bigger)',
dataIndex: 'age',
key: 'age',
responsive: ['md'],
},
{
title: 'Address (large screen or bigger)',
dataIndex: 'address',
key: 'address',
responsive: ['lg'],
},
];
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
];
ReactDOM.render(<Table columns={columns} dataSource={data} />, mountNode);
```

View File

@ -1,5 +1,4 @@
import * as React from 'react';
import { convertChildrenToColumns } from 'rc-table/lib/hooks/useColumns';
import {
TransformColumns,
ColumnsType,
@ -162,8 +161,7 @@ export function getFilterData<RecordType>(
interface FilterConfig<RecordType> {
prefixCls: string;
dropdownPrefixCls: string;
columns?: ColumnsType<RecordType>;
children?: React.ReactNode;
mergedColumns: ColumnsType<RecordType>;
locale: TableLocale;
onFilterChange: (
filters: Record<string, Key[] | null>,
@ -175,8 +173,7 @@ interface FilterConfig<RecordType> {
function useFilter<RecordType>({
prefixCls,
dropdownPrefixCls,
columns,
children,
mergedColumns,
onFilterChange,
getPopupContainer,
locale: tableLocale,
@ -185,10 +182,6 @@ function useFilter<RecordType>({
FilterState<RecordType>[],
() => Record<string, Key[] | null>,
] {
const mergedColumns = React.useMemo(() => {
return columns || convertChildrenToColumns(children);
}, [children, columns]);
const [filterStates, setFilterStates] = React.useState<FilterState<RecordType>[]>(
collectFilterStates(mergedColumns, true),
);

View File

@ -1,6 +1,5 @@
import * as React from 'react';
import classNames from 'classnames';
import { convertChildrenToColumns } from 'rc-table/lib/hooks/useColumns';
import CaretDownOutlined from '@ant-design/icons/CaretDownOutlined';
import CaretUpOutlined from '@ant-design/icons/CaretUpOutlined';
import {
@ -300,8 +299,7 @@ export function getSortData<RecordType>(
interface SorterConfig<RecordType> {
prefixCls: string;
columns?: ColumnsType<RecordType>;
children?: React.ReactNode;
mergedColumns: ColumnsType<RecordType>;
onSorterChange: (
sorterResult: SorterResult<RecordType> | SorterResult<RecordType>[],
sortStates: SortState<RecordType>[],
@ -313,8 +311,7 @@ interface SorterConfig<RecordType> {
export default function useFilterSorter<RecordType>({
prefixCls,
columns,
children,
mergedColumns,
onSorterChange,
sortDirections,
tableLocale,
@ -325,10 +322,6 @@ export default function useFilterSorter<RecordType>({
ColumnTitleProps<RecordType>,
() => SorterResult<RecordType> | SorterResult<RecordType>[],
] {
const mergedColumns = React.useMemo(() => {
return columns || convertChildrenToColumns(children);
}, [children, columns]);
const [sortStates, setSortStates] = React.useState<SortState<RecordType>[]>(
collectSortStates(mergedColumns, true),
);

View File

@ -6,6 +6,7 @@ import {
} from 'rc-table/lib/interface';
import { CheckboxProps } from '../checkbox';
import { PaginationConfig } from '../pagination';
import { Breakpoint } from '../_util/responsiveObserve';
export { GetRowKey, ExpandableConfig };
@ -95,6 +96,9 @@ export interface ColumnType<RecordType> extends RcColumnType<RecordType> {
onFilter?: (value: string | number | boolean, record: RecordType) => boolean;
filterDropdownVisible?: boolean;
onFilterDropdownVisibleChange?: (visible: boolean) => void;
// Responsive
responsive?: Breakpoint[];
}
export interface ColumnGroupType<RecordType> extends Omit<ColumnType<RecordType>, 'dataIndex'> {

View File

@ -3,6 +3,7 @@ import './index.less';
// style dependencies
// deps-lint-skip: menu
// deps-lint-skip: grid
import '../../button/style';
import '../../empty/style';
import '../../radio/style';