From b5253e74ffe448f1936378cb2255f7087b1ef86b Mon Sep 17 00:00:00 2001 From: zombiej Date: Thu, 20 May 2021 15:47:43 +0800 Subject: [PATCH 01/15] docs: demo driven --- docs/examples/fixedColumns.tsx | 57 +++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/docs/examples/fixedColumns.tsx b/docs/examples/fixedColumns.tsx index d65281c28..2dac4d08b 100644 --- a/docs/examples/fixedColumns.tsx +++ b/docs/examples/fixedColumns.tsx @@ -55,30 +55,37 @@ const data: RecordType[] = [ { a: '133', c: 'edd12221', d: 2, key: '9' }, ]; -const Demo = () => ( -
-

Fixed columns

- b || c} - scroll={{ x: 1200 }} - data={data} - summary={() => ( - <> - - - - Summary - - - Content - - Right - - - )} - /> - -); +const Demo = () => { + const [scrollY, setScrollY] = React.useState(true); + + return ( +
+ +
b || c} + scroll={{ x: 1200, y: scrollY ? 200 : null }} + data={data} + summary={() => ( + <> + + + + Summary + + + Content + + Right + + + )} + /> + + ); +}; export default Demo; From 741c4fd4edbee23730d91cceb75807f57d0822af Mon Sep 17 00:00:00 2001 From: zombiej Date: Thu, 20 May 2021 16:47:39 +0800 Subject: [PATCH 02/15] docs: Update demo --- docs/examples/fixedColumns.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/examples/fixedColumns.tsx b/docs/examples/fixedColumns.tsx index 2dac4d08b..d3cd1766c 100644 --- a/docs/examples/fixedColumns.tsx +++ b/docs/examples/fixedColumns.tsx @@ -70,7 +70,7 @@ const Demo = () => { scroll={{ x: 1200, y: scrollY ? 200 : null }} data={data} summary={() => ( - <> + @@ -81,7 +81,7 @@ const Demo = () => { Right - + )} /> From 5c6ec16ada78d947575c1f2713babc429dba9ffc Mon Sep 17 00:00:00 2001 From: zombiej Date: Thu, 20 May 2021 16:48:00 +0800 Subject: [PATCH 03/15] chore: Add Summary Sugar --- src/Footer/FixedSummary.tsx | 40 +++++++++++++++++++++++++++++++++++++ src/Footer/Summary.tsx | 20 +++++++++++++++++++ src/Footer/index.tsx | 8 ++------ 3 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 src/Footer/FixedSummary.tsx create mode 100644 src/Footer/Summary.tsx diff --git a/src/Footer/FixedSummary.tsx b/src/Footer/FixedSummary.tsx new file mode 100644 index 000000000..a27985003 --- /dev/null +++ b/src/Footer/FixedSummary.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; +import classNames from 'classnames'; +import TableContext from '../context/TableContext'; +import { useColumnWidth } from '../hooks/useColumnWidth'; + +export interface FixedSummaryProps { + noData: boolean; + colWidths: readonly number[]; + columCount: number; + children?: React.ReactNode; +} + +export default function FixedSummary({ + noData, + colWidths, + columCount, + children, +}: FixedSummaryProps) { + const { prefixCls, scrollbarSize } = React.useContext(TableContext); + + const mergedColumnWidth = useColumnWidth(colWidths, columCount); + + return ( +
+
+ {children} +
+
+ ); +} diff --git a/src/Footer/Summary.tsx b/src/Footer/Summary.tsx new file mode 100644 index 000000000..329835b92 --- /dev/null +++ b/src/Footer/Summary.tsx @@ -0,0 +1,20 @@ +import type * as React from 'react'; +import Cell from './Cell'; +import Row from './Row'; + +export interface SummaryProps { + fixed?: boolean; + children?: React.ReactNode; +} + +/** + * Syntactic sugar. Do not support HOC. + */ +function Summary({ children }: SummaryProps) { + return children as React.ReactElement; +} + +Summary.Row = Row; +Summary.Cell = Cell; + +export default Summary; diff --git a/src/Footer/index.tsx b/src/Footer/index.tsx index d6dd703ec..d1bdc33b0 100644 --- a/src/Footer/index.tsx +++ b/src/Footer/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import TableContext from '../context/TableContext'; -import Cell from './Cell'; -import Row from './Row'; +import Summary from './Summary'; export interface FooterProps { children: React.ReactNode; @@ -14,7 +13,4 @@ function Footer({ children }: FooterProps) { export default Footer; -export const FooterComponents = { - Cell, - Row, -}; +export const FooterComponents = Summary; From ef3a1990e300cc8ec26c99079e5accb6618c5975 Mon Sep 17 00:00:00 2001 From: zombiej Date: Thu, 20 May 2021 17:18:31 +0800 Subject: [PATCH 04/15] refactor: Use FixedHolder --- .../FixedHeader.tsx => FixedHolder/index.tsx} | 25 +++++----- src/Footer/FixedSummary.tsx | 40 --------------- src/Table.tsx | 49 +++++++++++++------ 3 files changed, 46 insertions(+), 68 deletions(-) rename src/{Header/FixedHeader.tsx => FixedHolder/index.tsx} (88%) delete mode 100644 src/Footer/FixedSummary.tsx diff --git a/src/Header/FixedHeader.tsx b/src/FixedHolder/index.tsx similarity index 88% rename from src/Header/FixedHeader.tsx rename to src/FixedHolder/index.tsx index 40494e1c7..8be5ca82b 100644 --- a/src/Header/FixedHeader.tsx +++ b/src/FixedHolder/index.tsx @@ -2,8 +2,7 @@ import * as React from 'react'; import { useMemo } from 'react'; import classNames from 'classnames'; import { fillRef } from 'rc-util/lib/ref'; -import type { HeaderProps } from './Header'; -import Header from './Header'; +import type { HeaderProps } from '../Header/Header'; import ColGroup from '../ColGroup'; import type { ColumnsType, ColumnType } from '../interface'; import TableContext from '../context/TableContext'; @@ -33,9 +32,10 @@ export interface FixedHeaderProps extends HeaderProps { offsetHeader: number; stickyClassName?: string; onScroll: (info: { currentTarget: HTMLDivElement; scrollLeft?: number }) => void; + children: (info: HeaderProps) => React.ReactNode; } -const FixedHeader = React.forwardRef>( +const FixedHolder = React.forwardRef>( ( { noData, @@ -50,6 +50,7 @@ const FixedHeader = React.forwardRef>( stickyClassName, onScroll, maxContentScroll, + children, ...props }, ref, @@ -68,7 +69,7 @@ const FixedHeader = React.forwardRef>( React.useEffect(() => { function onWheel(e: WheelEvent) { - const { currentTarget, deltaX } = (e as unknown) as React.WheelEvent; + const { currentTarget, deltaX } = e as unknown as React.WheelEvent; if (deltaX) { onScroll({ currentTarget, scrollLeft: currentTarget.scrollLeft + deltaX }); e.preventDefault(); @@ -147,18 +148,18 @@ const FixedHeader = React.forwardRef>( columns={flattenColumnsWithScrollbar} /> )} -
+ {children({ + ...props, + stickyOffsets: headerStickyOffsets, + columns: columnsWithScrollbar, + flattenColumns: flattenColumnsWithScrollbar, + })} ); }, ); -FixedHeader.displayName = 'FixedHeader'; +FixedHolder.displayName = 'FixedHolder'; -export default FixedHeader; +export default FixedHolder; diff --git a/src/Footer/FixedSummary.tsx b/src/Footer/FixedSummary.tsx deleted file mode 100644 index a27985003..000000000 --- a/src/Footer/FixedSummary.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import * as React from 'react'; -import classNames from 'classnames'; -import TableContext from '../context/TableContext'; -import { useColumnWidth } from '../hooks/useColumnWidth'; - -export interface FixedSummaryProps { - noData: boolean; - colWidths: readonly number[]; - columCount: number; - children?: React.ReactNode; -} - -export default function FixedSummary({ - noData, - colWidths, - columCount, - children, -}: FixedSummaryProps) { - const { prefixCls, scrollbarSize } = React.useContext(TableContext); - - const mergedColumnWidth = useColumnWidth(colWidths, columCount); - - return ( -
- - {children} -
-
- ); -} diff --git a/src/Table.tsx b/src/Table.tsx index feb1924df..8d73e9f44 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -33,7 +33,6 @@ import ResizeObserver from 'rc-resize-observer'; import { getTargetScrollBarSize } from 'rc-util/lib/getScrollBarSize'; import ColumnGroup from './sugar/ColumnGroup'; import Column from './sugar/Column'; -import FixedHeader from './Header/FixedHeader'; import Header from './Header/Header'; import type { GetRowKey, @@ -71,6 +70,7 @@ import { findAllChildrenKeys, renderExpandIcon } from './utils/expandUtil'; import { getCellFixedInfo } from './utils/fixUtil'; import StickyScrollBar from './stickyScrollBar'; import useSticky from './hooks/useSticky'; +import FixedHolder from './FixedHolder'; // Used for conditions cache const EMPTY_DATA = []; @@ -365,6 +365,7 @@ function Table(props: TableProps(); const scrollHeaderRef = React.useRef(); const scrollBodyRef = React.useRef(); + const scrollSummaryRef = React.useRef(); const [pingedLeft, setPingedLeft] = React.useState(false); const [pingedRight, setPingedRight] = React.useState(false); const [colsWidths, updateColsWidths] = useLayoutState(new Map()); @@ -378,6 +379,10 @@ function Table(props: TableProps fixed); + // Footer (Fix footer must fixed header) + const summaryNode = summary?.(mergedData); + const fixFooter = fixHeader && React.isValidElement(summaryNode) && summaryNode.props.fixed; + // Sticky const stickyRef = React.useRef<{ setScrollLeft: (left: number) => void }>(); const { isSticky, offsetHeader, offsetScroll, stickyClassName, container } = useSticky( @@ -565,7 +570,6 @@ function Table(props: TableProps width)} columns={flattenColumns} /> ); - const footerTable = summary &&
{summary(mergedData)}
; const customizeScrollBody = getComponent(['body']) as CustomizeScrollBody; if ( @@ -578,6 +582,7 @@ function Table(props: TableProps>>>>> Fixed Header let bodyContent: React.ReactNode; if (typeof customizeScrollBody === 'function') { @@ -618,33 +623,44 @@ function Table(props: TableProps {bodyColGroup} {bodyTable} - {footerTable} + {!fixFooter && summaryNode &&
{summaryNode}
} ); } + // Fixed holder share the props + const fixedHolderProps = { + noData: !mergedData.length, + maxContentScroll: horizonScroll && scroll.x === 'max-content', + ...headerProps, + ...columnContext, + direction, + // Fixed Props + offsetHeader, + stickyClassName, + onScroll, + }; + groupTableNode = ( <> {/* Header Table */} {showHeader !== false && ( - + + {fixedHeaderProps =>
} + )} {/* Body Table */} {bodyContent} + {/* Summary Table */} + {fixFooter && ( + + {fixedHeaderProps =>
} + + )} + {isSticky && ( (props: TableProps ); } else { + // >>>>>> Unique table groupTableNode = (
(props: TableProps} {bodyTable} - {footerTable} + {summaryNode &&
{summaryNode}
}
); From 2d0c448b5380f4df3419f291aa7d7be589d3d6ac Mon Sep 17 00:00:00 2001 From: zombiej Date: Thu, 20 May 2021 17:35:49 +0800 Subject: [PATCH 05/15] chore: summary scrollable --- src/FixedHolder/index.tsx | 4 +++- src/Table.tsx | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/FixedHolder/index.tsx b/src/FixedHolder/index.tsx index 8be5ca82b..bc0aa0499 100644 --- a/src/FixedHolder/index.tsx +++ b/src/FixedHolder/index.tsx @@ -23,6 +23,7 @@ function useColumnWidth(colWidths: readonly number[], columCount: number) { } export interface FixedHeaderProps extends HeaderProps { + className: string; noData: boolean; maxContentScroll: boolean; colWidths: readonly number[]; @@ -38,6 +39,7 @@ export interface FixedHeaderProps extends HeaderProps { const FixedHolder = React.forwardRef>( ( { + className, noData, columns, flattenColumns, @@ -131,7 +133,7 @@ const FixedHolder = React.forwardRef>( ...(isSticky ? { top: offsetHeader } : {}), }} ref={setScrollRef} - className={classNames(`${prefixCls}-header`, { + className={classNames(className, { [stickyClassName]: !!stickyClassName, })} > diff --git a/src/Table.tsx b/src/Table.tsx index 8d73e9f44..d602ba06f 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -458,6 +458,7 @@ function Table(props: TableProps(props: TableProps {/* Header Table */} {showHeader !== false && ( - - {fixedHeaderProps =>
} + + {fixedHolderPassProps =>
} )} @@ -656,8 +661,12 @@ function Table(props: TableProps - {fixedHeaderProps =>
} + + {fixedHolderPassProps =>
{summaryNode}
}
)} From 354c6a9dd8e6f15eae84c3643c295735759c380a Mon Sep 17 00:00:00 2001 From: zombiej Date: Thu, 20 May 2021 18:03:42 +0800 Subject: [PATCH 06/15] chore: Patch last column scroll --- src/FixedHolder/index.tsx | 3 ++- src/Footer/Row.tsx | 14 ++++++++++++-- src/Footer/index.tsx | 16 +++++++++++++--- src/Header/Header.tsx | 2 +- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/FixedHolder/index.tsx b/src/FixedHolder/index.tsx index bc0aa0499..5f4cdb8d0 100644 --- a/src/FixedHolder/index.tsx +++ b/src/FixedHolder/index.tsx @@ -92,8 +92,9 @@ const FixedHolder = React.forwardRef>( // Add scrollbar column const lastColumn = flattenColumns[flattenColumns.length - 1]; - const ScrollBarColumn: ColumnType = { + const ScrollBarColumn: ColumnType & { scrollbar: true } = { fixed: lastColumn ? lastColumn.fixed : null, + scrollbar: true, onHeaderCell: () => ({ className: `${prefixCls}-cell-scrollbar`, }), diff --git a/src/Footer/Row.tsx b/src/Footer/Row.tsx index e86a8b46e..a04b030ff 100644 --- a/src/Footer/Row.tsx +++ b/src/Footer/Row.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import Cell from './Cell'; export interface FooterRowProps { children?: React.ReactNode; @@ -6,6 +7,15 @@ export interface FooterRowProps { style?: React.CSSProperties; } -export default function FooterRow(props: FooterRowProps) { - return ; +export const SummaryScrollIndexContext = React.createContext(null); + +export default function FooterRow({ children, ...props }: FooterRowProps) { + const scrollColumnIndex = React.useContext(SummaryScrollIndexContext); + + return ( + + {children} + {scrollColumnIndex !== null && } + + ); } diff --git a/src/Footer/index.tsx b/src/Footer/index.tsx index d1bdc33b0..84ebbb018 100644 --- a/src/Footer/index.tsx +++ b/src/Footer/index.tsx @@ -1,14 +1,24 @@ import * as React from 'react'; import TableContext from '../context/TableContext'; import Summary from './Summary'; +import type { ColumnType } from '../interface'; +import { SummaryScrollIndexContext } from './Row'; -export interface FooterProps { +export interface FooterProps { children: React.ReactNode; + flattenColumns?: readonly (ColumnType & { scrollbar?: boolean })[]; } -function Footer({ children }: FooterProps) { +function Footer({ children, flattenColumns = [] }: FooterProps) { const { prefixCls } = React.useContext(TableContext); - return {children}; + const lastColumnIndex = flattenColumns.length - 1; + const scrollColumn = flattenColumns[lastColumnIndex]; + + return ( + + {children} + + ); } export default Footer; diff --git a/src/Header/Header.tsx b/src/Header/Header.tsx index b9bf773e7..8fac6480e 100644 --- a/src/Header/Header.tsx +++ b/src/Header/Header.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { +import type { ColumnsType, CellType, StickyOffsets, From fbf30877a56edfe088f99d312ff2dd0d876c3f61 Mon Sep 17 00:00:00 2001 From: zombiej Date: Thu, 20 May 2021 18:38:15 +0800 Subject: [PATCH 07/15] fix: scrollbar summary --- src/Footer/Cell.tsx | 2 +- src/Footer/index.tsx | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/Footer/Cell.tsx b/src/Footer/Cell.tsx index a8d562599..b3c8ea5f4 100644 --- a/src/Footer/Cell.tsx +++ b/src/Footer/Cell.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import Cell from '../Cell'; import TableContext from '../context/TableContext'; -import { AlignType } from '../interface'; +import type { AlignType } from '../interface'; export interface SummaryCellProps { className?: string; diff --git a/src/Footer/index.tsx b/src/Footer/index.tsx index 84ebbb018..80478ba3f 100644 --- a/src/Footer/index.tsx +++ b/src/Footer/index.tsx @@ -1,23 +1,50 @@ import * as React from 'react'; import TableContext from '../context/TableContext'; import Summary from './Summary'; -import type { ColumnType } from '../interface'; +import type { ColumnType, StickyOffsets } from '../interface'; import { SummaryScrollIndexContext } from './Row'; +import { getCellFixedInfo } from '../utils/fixUtil'; + +type FlattenColumns = readonly (ColumnType & { scrollbar?: boolean })[]; export interface FooterProps { children: React.ReactNode; - flattenColumns?: readonly (ColumnType & { scrollbar?: boolean })[]; + stickyOffsets?: StickyOffsets; + flattenColumns?: FlattenColumns; } -function Footer({ children, flattenColumns = [] }: FooterProps) { - const { prefixCls } = React.useContext(TableContext); +const EMPTY_LIST: FlattenColumns = []; + +function Footer({ + children, + stickyOffsets, + flattenColumns = EMPTY_LIST, +}: FooterProps) { + const tableContext = React.useContext(TableContext); + const { prefixCls, direction } = tableContext; + const lastColumnIndex = flattenColumns.length - 1; const scrollColumn = flattenColumns[lastColumnIndex]; + const mergedTableContext = React.useMemo( + () => + stickyOffsets + ? { + ...tableContext, + fixedInfoList: flattenColumns.map((_, colIndex) => + getCellFixedInfo(colIndex, colIndex, flattenColumns, stickyOffsets, direction), + ), + } + : tableContext, + [tableContext, stickyOffsets, flattenColumns, direction], + ); + return ( - - {children} - + + + {children} + + ); } From 64df2cb4931471808e017c6b2981bd58ac918be3 Mon Sep 17 00:00:00 2001 From: zombiej Date: Fri, 21 May 2021 10:29:40 +0800 Subject: [PATCH 08/15] use context for passing --- docs/examples/fixedColumns.tsx | 8 +++++--- src/Footer/Cell.tsx | 16 ++++++++++++---- src/Footer/Row.tsx | 12 +----------- src/Footer/index.tsx | 21 ++++++++++++++++++--- 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/docs/examples/fixedColumns.tsx b/docs/examples/fixedColumns.tsx index d3cd1766c..273b980c8 100644 --- a/docs/examples/fixedColumns.tsx +++ b/docs/examples/fixedColumns.tsx @@ -34,7 +34,7 @@ const columns: ColumnType[] = [ { title: 'title8', dataIndex: 'b', key: 'h' }, { title: 'title9', dataIndex: 'b', key: 'i' }, { title: 'title10', dataIndex: 'b', key: 'j' }, - { title: 'title11', dataIndex: 'b', key: 'k' }, + { title: 'title11', dataIndex: 'b', key: 'k', width: 50, fixed: 'right' }, { title: 'title12', dataIndex: 'b', key: 'l', width: 100, fixed: 'right' }, ]; @@ -76,10 +76,12 @@ const Demo = () => { Summary - + Content - Right + + Right + )} diff --git a/src/Footer/Cell.tsx b/src/Footer/Cell.tsx index b3c8ea5f4..c7f686cb1 100644 --- a/src/Footer/Cell.tsx +++ b/src/Footer/Cell.tsx @@ -1,7 +1,10 @@ import * as React from 'react'; +import { SummaryContext } from '.'; import Cell from '../Cell'; import TableContext from '../context/TableContext'; import type { AlignType } from '../interface'; +import { getCellFixedInfo } from '../utils/fixUtil'; +import { SummaryScrollIndexContext } from './Row'; export interface SummaryCellProps { className?: string; @@ -16,13 +19,18 @@ export default function SummaryCell({ className, index, children, - colSpan, + colSpan = 1, rowSpan, align, }: SummaryCellProps) { - const { prefixCls, fixedInfoList } = React.useContext(TableContext); + const { prefixCls, direction } = React.useContext(TableContext); + const { scrollColumnIndex, stickyOffsets, flattenColumns } = React.useContext(SummaryContext); + const lastIndex = index + colSpan - 1; + const mergedColSpan = lastIndex + 1 === scrollColumnIndex ? colSpan + 1 : colSpan; - const fixedInfo = fixedInfoList[index]; + const fixedInfo = stickyOffsets + ? getCellFixedInfo(index, index + mergedColSpan - 1, flattenColumns, stickyOffsets, direction) + : null; return ( ({ children, props: { - colSpan, + colSpan: mergedColSpan, rowSpan, }, })} diff --git a/src/Footer/Row.tsx b/src/Footer/Row.tsx index a04b030ff..0ca5457ea 100644 --- a/src/Footer/Row.tsx +++ b/src/Footer/Row.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import Cell from './Cell'; export interface FooterRowProps { children?: React.ReactNode; @@ -7,15 +6,6 @@ export interface FooterRowProps { style?: React.CSSProperties; } -export const SummaryScrollIndexContext = React.createContext(null); - export default function FooterRow({ children, ...props }: FooterRowProps) { - const scrollColumnIndex = React.useContext(SummaryScrollIndexContext); - - return ( - - {children} - {scrollColumnIndex !== null && } - - ); + return {children}; } diff --git a/src/Footer/index.tsx b/src/Footer/index.tsx index 80478ba3f..3cb1260fc 100644 --- a/src/Footer/index.tsx +++ b/src/Footer/index.tsx @@ -2,11 +2,17 @@ import * as React from 'react'; import TableContext from '../context/TableContext'; import Summary from './Summary'; import type { ColumnType, StickyOffsets } from '../interface'; -import { SummaryScrollIndexContext } from './Row'; import { getCellFixedInfo } from '../utils/fixUtil'; type FlattenColumns = readonly (ColumnType & { scrollbar?: boolean })[]; +export const SummaryContext = + React.createContext<{ + stickyOffsets?: StickyOffsets; + scrollColumnIndex?: number; + flattenColumns?: FlattenColumns; + }>({}); + export interface FooterProps { children: React.ReactNode; stickyOffsets?: StickyOffsets; @@ -39,11 +45,20 @@ function Footer({ [tableContext, stickyOffsets, flattenColumns, direction], ); + const summaryContext = React.useMemo( + () => ({ + stickyOffsets, + flattenColumns, + scrollColumnIndex: scrollColumn?.scrollbar ? lastColumnIndex : null, + }), + [scrollColumn, flattenColumns, lastColumnIndex, stickyOffsets], + ); + return ( - + {children} - + ); } From fb71abe45a4640ca577202c300ea2d7fc5dd8d67 Mon Sep 17 00:00:00 2001 From: zombiej Date: Fri, 21 May 2021 10:43:44 +0800 Subject: [PATCH 09/15] fix: basic bind scroll logic --- src/Footer/Cell.tsx | 11 +++++++---- src/Table.tsx | 12 ++++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Footer/Cell.tsx b/src/Footer/Cell.tsx index c7f686cb1..097124d7f 100644 --- a/src/Footer/Cell.tsx +++ b/src/Footer/Cell.tsx @@ -4,7 +4,6 @@ import Cell from '../Cell'; import TableContext from '../context/TableContext'; import type { AlignType } from '../interface'; import { getCellFixedInfo } from '../utils/fixUtil'; -import { SummaryScrollIndexContext } from './Row'; export interface SummaryCellProps { className?: string; @@ -28,9 +27,13 @@ export default function SummaryCell({ const lastIndex = index + colSpan - 1; const mergedColSpan = lastIndex + 1 === scrollColumnIndex ? colSpan + 1 : colSpan; - const fixedInfo = stickyOffsets - ? getCellFixedInfo(index, index + mergedColSpan - 1, flattenColumns, stickyOffsets, direction) - : null; + const fixedInfo = getCellFixedInfo( + index, + index + mergedColSpan - 1, + flattenColumns, + stickyOffsets, + direction, + ); return ( (props: TableProps {bodyColGroup} {bodyTable} - {!fixFooter && summaryNode &&
{summaryNode}
} + {!fixFooter && summaryNode && ( +
+ {summaryNode} +
+ )} ); @@ -697,7 +701,11 @@ function Table(props: TableProps} {bodyTable} - {summaryNode &&
{summaryNode}
} + {summaryNode && ( +
+ {summaryNode} +
+ )} ); From ea4a1c07e514aa81bdcc2fcb5eaa43b0bc26cc14 Mon Sep 17 00:00:00 2001 From: zombiej Date: Fri, 21 May 2021 11:01:18 +0800 Subject: [PATCH 10/15] test: Fix test case --- tests/FixedHeader.spec.js | 105 ++++++------------------- tests/Sticky.spec.js | 6 +- tests/__snapshots__/Table.spec.js.snap | 2 +- 3 files changed, 26 insertions(+), 87 deletions(-) diff --git a/tests/FixedHeader.spec.js b/tests/FixedHeader.spec.js index 06d47a13e..5fa158837 100644 --- a/tests/FixedHeader.spec.js +++ b/tests/FixedHeader.spec.js @@ -35,21 +35,9 @@ describe('Table.FixedHeader', () => { />, ); - wrapper - .find('ResizeObserver') - .at(0) - .props() - .onResize({ width: 100, offsetWidth: 100 }); - wrapper - .find('ResizeObserver') - .at(1) - .props() - .onResize({ width: 200, offsetWidth: 200 }); - wrapper - .find('ResizeObserver') - .at(2) - .props() - .onResize({ width: 0, offsetWidth: 0 }); + wrapper.find('ResizeObserver').at(0).props().onResize({ width: 100, offsetWidth: 100 }); + wrapper.find('ResizeObserver').at(1).props().onResize({ width: 200, offsetWidth: 200 }); + wrapper.find('ResizeObserver').at(2).props().onResize({ width: 0, offsetWidth: 0 }); await act(async () => { jest.runAllTimers(); @@ -60,41 +48,16 @@ describe('Table.FixedHeader', () => { expect(wrapper.find('.rc-table-header table').props().style.visibility).toBeFalsy(); expect(); - expect( - wrapper - .find('colgroup col') - .at(0) - .props().style.width, - ).toEqual(100); - expect( - wrapper - .find('colgroup col') - .at(1) - .props().style.width, - ).toEqual(200); - expect( - wrapper - .find('colgroup col') - .at(2) - .props().style.width, - ).toEqual(0); + expect(wrapper.find('colgroup col').at(0).props().style.width).toEqual(100); + expect(wrapper.find('colgroup col').at(1).props().style.width).toEqual(200); + expect(wrapper.find('colgroup col').at(2).props().style.width).toEqual(0); // Update columns wrapper.setProps({ columns: [col2, col1] }); wrapper.update(); - expect( - wrapper - .find('colgroup col') - .at(0) - .props().style.width, - ).toEqual(200); - expect( - wrapper - .find('colgroup col') - .at(1) - .props().style.width, - ).toEqual(100); + expect(wrapper.find('colgroup col').at(0).props().style.width).toEqual(200); + expect(wrapper.find('colgroup col').at(1).props().style.width).toEqual(100); jest.useRealTimers(); }); @@ -114,22 +77,12 @@ describe('Table.FixedHeader', () => { />, ); - expect( - wrapper - .find('table') - .last() - .find('colgroup col') - .first() - .props().className, - ).toEqual('test-internal'); - expect( - wrapper - .find('table') - .first() - .find('colgroup col') - .first() - .props().className, - ).toEqual('test-internal'); + expect(wrapper.find('table').last().find('colgroup col').first().props().className).toEqual( + 'test-internal', + ); + expect(wrapper.find('table').first().find('colgroup col').first().props().className).toEqual( + 'test-internal', + ); }); it('show header when data is null', () => { @@ -194,43 +147,29 @@ describe('Table.FixedHeader', () => { />, ); - wrapper - .find('ResizeObserver') - .at(0) - .props() - .onResize({ width: 93, offsetWidth: 93 }); + wrapper.find('ResizeObserver').at(0).props().onResize({ width: 93, offsetWidth: 93 }); await act(async () => { jest.runAllTimers(); await Promise.resolve(); wrapper.update(); }); - expect( - wrapper - .find('FixedHeader col') - .first() - .props().style, - ).toEqual(expect.objectContaining({ width: 93 })); + expect(wrapper.find('FixedHolder col').first().props().style).toEqual( + expect.objectContaining({ width: 93 }), + ); // Hide Table should not modify column width visible = false; - wrapper - .find('ResizeObserver') - .at(0) - .props() - .onResize({ width: 0, offsetWidth: 0 }); + wrapper.find('ResizeObserver').at(0).props().onResize({ width: 0, offsetWidth: 0 }); act(() => { jest.runAllTimers(); wrapper.update(); }); - expect( - wrapper - .find('FixedHeader col') - .first() - .props().style, - ).toEqual(expect.objectContaining({ width: 93 })); + expect(wrapper.find('FixedHolder col').first().props().style).toEqual( + expect.objectContaining({ width: 93 }), + ); jest.useRealTimers(); }); diff --git a/tests/Sticky.spec.js b/tests/Sticky.spec.js index dbe3f1f58..178bef4f8 100644 --- a/tests/Sticky.spec.js +++ b/tests/Sticky.spec.js @@ -28,12 +28,12 @@ describe('Table.Sticky', () => { }; const wrapper = mount(); - expect(wrapper.find('.rc-table-header').prop('style')).toEqual({ + expect(wrapper.find('.rc-table-header').last().prop('style')).toEqual({ overflow: 'hidden', top: 0, }); - expect(wrapper.find('.rc-table-header').prop('className')).toBe( + expect(wrapper.find('.rc-table-header').last().prop('className')).toBe( 'rc-table-header rc-table-sticky-header', ); @@ -43,7 +43,7 @@ describe('Table.Sticky', () => { }, }); - expect(wrapper.find('.rc-table-header').prop('style')).toEqual({ + expect(wrapper.find('.rc-table-header').last().prop('style')).toEqual({ overflow: 'hidden', top: 10, }); diff --git a/tests/__snapshots__/Table.spec.js.snap b/tests/__snapshots__/Table.spec.js.snap index c19869220..c2315bb25 100644 --- a/tests/__snapshots__/Table.spec.js.snap +++ b/tests/__snapshots__/Table.spec.js.snap @@ -741,7 +741,7 @@ exports[`Table.Basic summary support data type 1`] = ` > From decd28744ffd9cd8d5c9f9d538db14028ea1fa54 Mon Sep 17 00:00:00 2001 From: zombiej Date: Fri, 21 May 2021 11:35:54 +0800 Subject: [PATCH 11/15] feat: sticy summary --- docs/demo/stickyHeaderAndSummary.md | 3 + docs/examples/stickyHeaderAndSummary.tsx | 106 +++++++++++++++++++++++ src/FixedHolder/index.tsx | 8 +- src/Table.tsx | 20 ++--- src/hooks/useSticky.ts | 14 ++- src/interface.ts | 1 + 6 files changed, 135 insertions(+), 17 deletions(-) create mode 100644 docs/demo/stickyHeaderAndSummary.md create mode 100644 docs/examples/stickyHeaderAndSummary.tsx diff --git a/docs/demo/stickyHeaderAndSummary.md b/docs/demo/stickyHeaderAndSummary.md new file mode 100644 index 000000000..8558ebf5a --- /dev/null +++ b/docs/demo/stickyHeaderAndSummary.md @@ -0,0 +1,3 @@ +## Sticky Header and Summary + + diff --git a/docs/examples/stickyHeaderAndSummary.tsx b/docs/examples/stickyHeaderAndSummary.tsx new file mode 100644 index 000000000..fd3419a95 --- /dev/null +++ b/docs/examples/stickyHeaderAndSummary.tsx @@ -0,0 +1,106 @@ +/* eslint-disable no-console,func-names,react/no-multi-comp */ +import React from 'react'; +import Table from 'rc-table'; +import '../../assets/index.less'; +import type { ColumnType } from '@/interface'; + +interface RecordType { + a: string; + b?: string; + c?: string; + d: number; + key: string; +} + +const columns: ColumnType[] = [ + { title: 'title1', dataIndex: 'a', key: 'a', width: 100, fixed: 'left' }, + { title: 'title2', dataIndex: 'b', key: 'b', width: 100, fixed: 'left', ellipsis: true }, + { title: 'title3', dataIndex: 'c', key: 'c' }, + { title: 'title4', dataIndex: 'b', key: 'd' }, + { title: 'title5', dataIndex: 'b', key: 'e' }, + { title: 'title6', dataIndex: 'b', key: 'f' }, + { + title: ( +
+ title7 +
+
+
+ Hello world! +
+ ), + dataIndex: 'b', + key: 'g', + }, + { title: 'title8', dataIndex: 'b', key: 'h' }, + { title: 'title9', dataIndex: 'b', key: 'i' }, + { title: 'title10', dataIndex: 'b', key: 'j' }, + { title: 'title11', dataIndex: 'b', key: 'k', width: 50, fixed: 'right' }, + { title: 'title12', dataIndex: 'b', key: 'l', width: 100, fixed: 'right' }, +]; + +const data: RecordType[] = [ + { + a: '123', + b: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + d: 3, + key: '1', + }, + { a: 'cdd', b: 'edd12221', d: 3, key: '2' }, + { a: '133', c: 'edd12221', d: 2, key: '3' }, + { a: '133', c: 'edd12221', d: 2, key: '4' }, + { a: '133', c: 'edd12221', d: 2, key: '5' }, + { a: '133', c: 'edd12221', d: 2, key: '6' }, + { a: '133', c: 'edd12221', d: 2, key: '7' }, + { a: '133', c: 'edd12221', d: 2, key: '8' }, + { a: '133', c: 'edd12221', d: 2, key: '9' }, +]; + +for (let i = 0; i < 20; i += 1) { + const str = `str_${i}`; + + data.push({ + a: str, + b: str, + d: i, + key: str, + }); +} + +const Demo = () => { + const [stickySummary, setStickySummary] = React.useState(true); + + return ( +
+ + b || c} + scroll={{ x: 1200 }} + data={data} + summary={() => ( + + + + + Summary + + + Content + + + Right + + + + )} + /> + + ); +}; + +export default Demo; diff --git a/src/FixedHolder/index.tsx b/src/FixedHolder/index.tsx index 5f4cdb8d0..9b588c548 100644 --- a/src/FixedHolder/index.tsx +++ b/src/FixedHolder/index.tsx @@ -30,7 +30,8 @@ export interface FixedHeaderProps extends HeaderProps { columCount: number; direction: 'ltr' | 'rtl'; fixHeader: boolean; - offsetHeader: number; + stickyTopOffset?: number; + stickyBottomOffset?: number; stickyClassName?: string; onScroll: (info: { currentTarget: HTMLDivElement; scrollLeft?: number }) => void; children: (info: HeaderProps) => React.ReactNode; @@ -48,7 +49,8 @@ const FixedHolder = React.forwardRef>( stickyOffsets, direction, fixHeader, - offsetHeader, + stickyTopOffset, + stickyBottomOffset, stickyClassName, onScroll, maxContentScroll, @@ -131,7 +133,7 @@ const FixedHolder = React.forwardRef>(
(props: TableProps fixed); - // Footer (Fix footer must fixed header) - const summaryNode = summary?.(mergedData); - const fixFooter = fixHeader && React.isValidElement(summaryNode) && summaryNode.props.fixed; - // Sticky const stickyRef = React.useRef<{ setScrollLeft: (left: number) => void }>(); - const { isSticky, offsetHeader, offsetScroll, stickyClassName, container } = useSticky( - sticky, - prefixCls, - ); + const { isSticky, offsetHeader, offsetSummary, offsetScroll, stickyClassName, container } = + useSticky(sticky, prefixCls); + + // Footer (Fix footer must fixed header) + const summaryNode = summary?.(mergedData); + const fixFooter = + (fixHeader || isSticky) && React.isValidElement(summaryNode) && summaryNode.props.fixed; + // Scroll let scrollXStyle: React.CSSProperties; let scrollYStyle: React.CSSProperties; let scrollTableStyle: React.CSSProperties; @@ -641,8 +641,6 @@ function Table(props: TableProps(props: TableProps @@ -667,6 +666,7 @@ function Table(props: TableProps diff --git a/src/hooks/useSticky.ts b/src/hooks/useSticky.ts index 92a4ef039..cda3fda52 100644 --- a/src/hooks/useSticky.ts +++ b/src/hooks/useSticky.ts @@ -1,6 +1,6 @@ import * as React from 'react'; import canUseDom from 'rc-util/lib/Dom/canUseDom'; -import { TableSticky } from '../interface'; +import type { TableSticky } from '../interface'; // fix ssr render const defaultContainer = canUseDom() ? window : null; @@ -12,12 +12,17 @@ export default function useSticky( ): { isSticky: boolean; offsetHeader: number; + offsetSummary: number; offsetScroll: number; stickyClassName: string; container: Window | HTMLElement; } { - const { offsetHeader = 0, offsetScroll = 0, getContainer = () => defaultContainer } = - typeof sticky === 'object' ? sticky : {}; + const { + offsetHeader = 0, + offsetSummary = 0, + offsetScroll = 0, + getContainer = () => defaultContainer, + } = typeof sticky === 'object' ? sticky : {}; const container = getContainer() || defaultContainer; @@ -27,8 +32,9 @@ export default function useSticky( isSticky, stickyClassName: isSticky ? `${prefixCls}-sticky-header` : '', offsetHeader, + offsetSummary, offsetScroll, container, }; - }, [offsetScroll, offsetHeader, prefixCls, container]); + }, [offsetScroll, offsetHeader, offsetSummary, prefixCls, container]); } diff --git a/src/interface.ts b/src/interface.ts index 3c8f8ecab..25575ed7e 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -226,6 +226,7 @@ export type TriggerEventHandler = ( // =================== Sticky =================== export interface TableSticky { offsetHeader?: number; + offsetSummary?: number; offsetScroll?: number; getContainer?: () => Window | HTMLElement; } From 7a58db5a0fd5d964c6a303b10a4266256271d5f4 Mon Sep 17 00:00:00 2001 From: zombiej Date: Fri, 21 May 2021 18:07:47 +0800 Subject: [PATCH 12/15] chore: Fixed style --- assets/index.less | 79 +++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/assets/index.less b/assets/index.less index f75d255dd..327b65477 100644 --- a/assets/index.less +++ b/assets/index.less @@ -19,38 +19,37 @@ } .@{tablePrefixCls} { - font-size: @font-size-base; + position: relative; + box-sizing: border-box; color: @text-color; + font-size: @font-size-base; line-height: @line-height; - box-sizing: border-box; - position: relative; &-rtl { direction: rtl; } // ================= Global ================= table { - border-spacing: 0px; width: 100%; + border-spacing: 0px; } th, td { + position: relative; + box-sizing: border-box; padding: 0; - position: relative; + padding: @cell-padding; + white-space: normal; + word-break: break-word; border: @border; border-top: 0; border-left: 0; transition: box-shadow 0.3s; - - padding: @cell-padding; - box-sizing: border-box; - white-space: normal; - word-break: break-word; .@{tablePrefixCls}-rtl& { - border-left: @border; border-right: 0; + border-left: @border; } } @@ -82,15 +81,15 @@ &-fix-left-first::after, &-fix-left-last::after { - pointer-events: none; - content: ''; - transition: box-shadow 0.3s; position: absolute; top: 0; + right: -1px; bottom: -1px; width: 20px; - right: -1px; transform: translateX(100%); + transition: box-shadow 0.3s; + content: ''; + pointer-events: none; } &-fix-right-first, @@ -102,21 +101,21 @@ } &::after { - pointer-events: none; - content: ''; - transition: box-shadow 0.3s; position: absolute; top: 0; bottom: -1px; - width: 20px; left: -1px; + width: 20px; transform: translateX(-100%); + transition: box-shadow 0.3s; + content: ''; + pointer-events: none; } } &&-ellipsis { - white-space: nowrap; overflow: hidden; + white-space: nowrap; text-overflow: ellipsis; // Fixed first or last should special process @@ -126,9 +125,9 @@ overflow: visible; .@{tablePrefixCls}-cell-content { + display: block; overflow: hidden; text-overflow: ellipsis; - display: block; } } } @@ -161,18 +160,18 @@ thead { td, th { - background: @table-head-background-color; text-align: center; + background: @table-head-background-color; } .@{tablePrefixCls}-cell-scrollbar::after { position: absolute; - content: ''; top: 0; bottom: 0; left: -1px; width: 1px; background: @table-head-background-color; + content: ''; .@{tablePrefixCls}-rtl& { right: -1px; @@ -211,13 +210,13 @@ } &-fixed-column &-body::after { - content: ''; position: absolute; - right: 0; top: 0; + right: 0; bottom: 0; - border-right: @border; z-index: 1; + border-right: @border; + content: ''; } // ================= Expand ================= @@ -229,17 +228,17 @@ &-fixed { box-sizing: border-box; margin: @cell-margin; - padding: @cell-padding; margin-right: -@horizontal-padding - 2 * @border-width; + padding: @cell-padding; &::after { - content: ''; position: absolute; - width: 0; top: 0; - bottom: 0; right: 1px; + bottom: 0; + width: 0; border-right: @border; + content: ''; } } } @@ -248,12 +247,12 @@ display: inline-block; width: 16px; height: 16px; - border: 1px solid currentColor; color: #aaa; - vertical-align: middle; + line-height: 16px; text-align: center; + vertical-align: middle; + border: 1px solid currentColor; cursor: pointer; - line-height: 16px; &.@{tablePrefixCls}-row-expanded::after { content: '-'; @@ -270,16 +269,16 @@ // ================= Title ================== &-title { + padding: @cell-padding; border: @border; border-bottom: 0; - padding: @cell-padding; } // ================= Footer ================= &-footer { + padding: @cell-padding; border: @border; border-top: 0; - padding: @cell-padding; } tfoot { @@ -287,6 +286,12 @@ background: #fff; } } + + &-summary { + border-top: @border; + border-left: @border; + } + &-sticky { &-header { position: sticky; @@ -295,20 +300,20 @@ &-scroll { position: sticky; bottom: 0; + z-index: 2; display: flex; align-items: center; border-top: 1px solid #f3f3f3; opacity: 0.6; transition: transform 0.1s ease-in 0s; - z-index: 2; &:hover { transform: scaleY(1.2); transform-origin: center bottom; } &-bar { height: 8px; - border-radius: 4px; background-color: #bbb; + border-radius: 4px; &:hover { background-color: #999; } From 0f17e7cef4f0b11a04351988111f096bdececc49 Mon Sep 17 00:00:00 2001 From: zombiej Date: Fri, 21 May 2021 21:01:37 +0800 Subject: [PATCH 13/15] test: Test coverage --- src/Table.tsx | 6 +- tests/Summary.spec.tsx | 80 ++++++++ tests/Table.spec.js | 222 ++++------------------ tests/__snapshots__/Summary.spec.tsx.snap | 28 +++ tests/__snapshots__/Table.spec.js.snap | 27 --- 5 files changed, 150 insertions(+), 213 deletions(-) create mode 100644 tests/Summary.spec.tsx create mode 100644 tests/__snapshots__/Summary.spec.tsx.snap diff --git a/src/Table.tsx b/src/Table.tsx index 9e54a0eb7..d52b9d948 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -71,6 +71,7 @@ import { getCellFixedInfo } from './utils/fixUtil'; import StickyScrollBar from './stickyScrollBar'; import useSticky from './hooks/useSticky'; import FixedHolder from './FixedHolder'; +import Summary from './Footer/Summary'; // Used for conditions cache const EMPTY_DATA = []; @@ -387,7 +388,10 @@ function Table(props: TableProps { + const data = [ + { key: 'key0', name: 'Lucy' }, + { key: 'key1', name: 'Jack' }, + ]; + const createTable = props => { + const columns = [{ title: 'Name', dataIndex: 'name', key: 'name' }]; + + return
; + }; + + it('render correctly', () => { + const wrapper = mount( + createTable({ + summary: () => ( + + + + ), + }), + ); + + expect(wrapper.find('tfoot').text()).toEqual('Good'); + }); + + it('support data type', () => { + const wrapper = mount( +
Good
( + + + Light + + Bamboo + + 112.5 + + + )} + />, + ); + + expect(wrapper.find('tfoot').render()).toMatchSnapshot(); + }); + + it('fixed summary', () => { + const wrapper = mount( +
( + + + Light + Bamboo + Little + + + )} + />, + ); + + expect(wrapper.exists('div.rc-table-summary')).toBeTruthy(); + }); +}); diff --git a/tests/Table.spec.js b/tests/Table.spec.js index 2cc5ad977..9355d1587 100644 --- a/tests/Table.spec.js +++ b/tests/Table.spec.js @@ -5,7 +5,10 @@ import Table from '../src'; import { INTERNAL_HOOKS } from '../src/Table'; describe('Table.Basic', () => { - const data = [{ key: 'key0', name: 'Lucy' }, { key: 'key1', name: 'Jack' }]; + const data = [ + { key: 'key0', name: 'Lucy' }, + { key: 'key1', name: 'Jack' }, + ]; const createTable = props => { const columns = [{ title: 'Name', dataIndex: 'name', key: 'name' }]; @@ -59,18 +62,8 @@ describe('Table.Basic', () => { }), ); expect(wrapper.render()).toMatchSnapshot(); - expect( - wrapper - .find('th') - .at(0) - .text(), - ).toEqual('姓名'); - expect( - wrapper - .find('th') - .at(1) - .text(), - ).toEqual('年龄'); + expect(wrapper.find('th').at(0).text()).toEqual('姓名'); + expect(wrapper.find('th').at(1).text()).toEqual('年龄'); }); it('falsy columns', () => { @@ -94,22 +87,12 @@ describe('Table.Basic', () => { describe('renders empty text correctly', () => { it('ReactNode', () => { const wrapper = mount(createTable({ data: [], emptyText: 'No data' })); - expect( - wrapper - .find('.rc-table-placeholder') - .hostNodes() - .text(), - ).toEqual('No data'); + expect(wrapper.find('.rc-table-placeholder').hostNodes().text()).toEqual('No data'); }); it('renderProps', () => { const wrapper = mount(createTable({ data: [], emptyText: () => 'No data' })); - expect( - wrapper - .find('.rc-table-placeholder') - .hostNodes() - .text(), - ).toEqual('No data'); + expect(wrapper.find('.rc-table-placeholder').hostNodes().text()).toEqual('No data'); }); it('effect update', () => { @@ -122,12 +105,7 @@ describe('Table.Basic', () => { }; const wrapper = mount(); wrapper.update(); - expect( - wrapper - .find('.rc-table-placeholder') - .hostNodes() - .text(), - ).toEqual('bamboo'); + expect(wrapper.find('.rc-table-placeholder').hostNodes().text()).toEqual('bamboo'); }); }); @@ -143,64 +121,12 @@ describe('Table.Basic', () => { it('renders title correctly', () => { const wrapper = mount(createTable({ title: () =>

title

})); - expect( - wrapper - .find('.rc-table-title') - .hostNodes() - .text(), - ).toEqual('title'); + expect(wrapper.find('.rc-table-title').hostNodes().text()).toEqual('title'); }); it('renders footer correctly', () => { const wrapper = mount(createTable({ footer: () =>

footer

})); - expect( - wrapper - .find('.rc-table-footer') - .hostNodes() - .text(), - ).toEqual('footer'); - }); - - describe('summary', () => { - it('render correctly', () => { - const wrapper = mount( - createTable({ - summary: () => ( -
- - - ), - }), - ); - - expect(wrapper.find('tfoot').text()).toEqual('Good'); - }); - - it('support data type', () => { - const wrapper = mount( -
Good
( - - - Light - - Bamboo - - 112.5 - - - )} - />, - ); - - expect(wrapper.find('tfoot').render()).toMatchSnapshot(); - }); + expect(wrapper.find('.rc-table-footer').hostNodes().text()).toEqual('footer'); }); it('renders with id correctly', () => { @@ -219,50 +145,20 @@ describe('Table.Basic', () => { describe('rowKey', () => { it('uses record.key', () => { const wrapper = mount(createTable()); - expect( - wrapper - .find('BodyRow') - .at(0) - .key(), - ).toBe('key0'); - expect( - wrapper - .find('BodyRow') - .at(1) - .key(), - ).toBe('key1'); + expect(wrapper.find('BodyRow').at(0).key()).toBe('key0'); + expect(wrapper.find('BodyRow').at(1).key()).toBe('key1'); }); it('sets by rowKey', () => { const wrapper = mount(createTable({ rowKey: 'name' })); - expect( - wrapper - .find('BodyRow') - .at(0) - .key(), - ).toBe('Lucy'); - expect( - wrapper - .find('BodyRow') - .at(1) - .key(), - ).toBe('Jack'); + expect(wrapper.find('BodyRow').at(0).key()).toBe('Lucy'); + expect(wrapper.find('BodyRow').at(1).key()).toBe('Jack'); }); it('sets by rowKey function', () => { const wrapper = mount(createTable({ rowKey: record => `${record.key}1` })); - expect( - wrapper - .find('BodyRow') - .at(0) - .key(), - ).toBe('key01'); - expect( - wrapper - .find('BodyRow') - .at(1) - .key(), - ).toBe('key11'); + expect(wrapper.find('BodyRow').at(0).key()).toBe('key01'); + expect(wrapper.find('BodyRow').at(1).key()).toBe('key11'); }); }); @@ -383,7 +279,10 @@ describe('Table.Basic', () => { ]; const wrapper = mount(createTable({ columns, data: localData })); - const targetData = [['John', 'Doe'], ['Terry', 'Garner']]; + const targetData = [ + ['John', 'Doe'], + ['Terry', 'Garner'], + ]; wrapper.find('tbody tr').forEach((tr, ri) => { tr.find('td').forEach((td, di) => { @@ -394,14 +293,12 @@ describe('Table.Basic', () => { }); it('render empty cell if text is empty object', () => { - const localData = [{ key: 'key0', name: {} }, { key: 'key1', name: 'Jack' }]; + const localData = [ + { key: 'key0', name: {} }, + { key: 'key1', name: 'Jack' }, + ]; const wrapper = mount(createTable({ data: localData })); - expect( - wrapper - .find('table td') - .first() - .text(), - ).toBe(''); + expect(wrapper.find('table td').first().text()).toBe(''); }); it('renders colSpan correctly', () => { @@ -573,10 +470,7 @@ describe('Table.Basic', () => { }; const wrapper = mount(); for (let i = 0; i < 10; i += 1) { - wrapper - .find('tbody tr td') - .last() - .simulate('click'); + wrapper.find('tbody tr td').last().simulate('click'); expect(wrapper.find('#count').text()).toEqual(String(i + 1)); } }); @@ -709,34 +603,12 @@ describe('Table.Basic', () => { { title: 'Age', dataIndex: 'age', key: 'age', align: 'center' }, ]; const wrapper = mount(createTable({ columns })); - expect( - wrapper - .find('th') - .at(0) - .props().style.textAlign, - ).toBeFalsy(); - expect( - wrapper - .find('th') - .at(1) - .props().style.textAlign, - ).toEqual('center'); - expect( - wrapper - .find('tbody tr') - .first() - .find('td') - .at(0) - .props().style.textAlign, - ).toBeFalsy(); - expect( - wrapper - .find('tbody tr') - .first() - .find('td') - .at(1) - .props().style.textAlign, - ).toEqual('center'); + expect(wrapper.find('th').at(0).props().style.textAlign).toBeFalsy(); + expect(wrapper.find('th').at(1).props().style.textAlign).toEqual('center'); + expect(wrapper.find('tbody tr').first().find('td').at(0).props().style.textAlign).toBeFalsy(); + expect(wrapper.find('tbody tr').first().find('td').at(1).props().style.textAlign).toEqual( + 'center', + ); }); it('align column should not override cell style', () => { @@ -751,21 +623,11 @@ describe('Table.Basic', () => { }, ]; const wrapper = mount(createTable({ columns })); - expect( - wrapper - .find('th') - .first() - .props().style, - ).toEqual({ + expect(wrapper.find('th').first().props().style).toEqual({ color: 'green', textAlign: 'center', }); - expect( - wrapper - .find('td') - .first() - .props().style, - ).toEqual({ + expect(wrapper.find('td').first().props().style).toEqual({ color: 'red', textAlign: 'center', }); @@ -869,12 +731,7 @@ describe('Table.Basic', () => { }), ); - expect( - wrapper - .find('tbody Cell') - .first() - .key(), - ).toBeTruthy(); + expect(wrapper.find('tbody Cell').first().key()).toBeTruthy(); }); it('syntactic sugar', () => { @@ -940,12 +797,7 @@ describe('Table.Basic', () => { />, ); - expect( - wrapper - .find('tr') - .last() - .props()['data-row-key'], - ).toEqual('light'); + expect(wrapper.find('tr').last().props()['data-row-key']).toEqual('light'); }); it('render with state change', () => { diff --git a/tests/__snapshots__/Summary.spec.tsx.snap b/tests/__snapshots__/Summary.spec.tsx.snap new file mode 100644 index 000000000..e72a20741 --- /dev/null +++ b/tests/__snapshots__/Summary.spec.tsx.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Table.Summary support data type 1`] = ` + + + + + + + +`; diff --git a/tests/__snapshots__/Table.spec.js.snap b/tests/__snapshots__/Table.spec.js.snap index c2315bb25..5200ea495 100644 --- a/tests/__snapshots__/Table.spec.js.snap +++ b/tests/__snapshots__/Table.spec.js.snap @@ -735,33 +735,6 @@ exports[`Table.Basic renders rowSpan correctly 1`] = ` `; -exports[`Table.Basic summary support data type 1`] = ` - - - - - - - -`; - exports[`Table.Basic syntactic sugar 1`] = `
Date: Fri, 21 May 2021 21:24:07 +0800 Subject: [PATCH 14/15] test: Test coverage --- tests/Summary.spec.tsx | 55 +++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/tests/Summary.spec.tsx b/tests/Summary.spec.tsx index 564482b96..01d195dbf 100644 --- a/tests/Summary.spec.tsx +++ b/tests/Summary.spec.tsx @@ -53,28 +53,39 @@ describe('Table.Summary', () => { expect(wrapper.find('tfoot').render()).toMatchSnapshot(); }); - it('fixed summary', () => { - const wrapper = mount( -
+ Light + + Bamboo + + 112.5 +
- Light - - Bamboo - - 112.5 -
( - - - Light - Bamboo - Little - - - )} - />, - ); + describe('fixed summary', () => { + const getSummaryTable = (fixed: boolean) => + mount( +
( + + + Light + Bamboo + Little + + + )} + />, + ); + + it('fixed', () => { + const wrapper = getSummaryTable(false); + + expect(wrapper.exists('tfoot.rc-table-summary')).toBeTruthy(); + }); + + it('sticky', () => { + const wrapper = getSummaryTable(true); - expect(wrapper.exists('div.rc-table-summary')).toBeTruthy(); + expect(wrapper.exists('div.rc-table-summary')).toBeTruthy(); + }); }); }); From 2f5e6a7c2d565a02d7f6b50e49311741ddfa4817 Mon Sep 17 00:00:00 2001 From: zombiej Date: Fri, 21 May 2021 21:35:48 +0800 Subject: [PATCH 15/15] chore: Cleanup useless code --- src/Footer/index.tsx | 47 +++++++++++--------------------------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/src/Footer/index.tsx b/src/Footer/index.tsx index 3cb1260fc..6fae4da98 100644 --- a/src/Footer/index.tsx +++ b/src/Footer/index.tsx @@ -2,49 +2,28 @@ import * as React from 'react'; import TableContext from '../context/TableContext'; import Summary from './Summary'; import type { ColumnType, StickyOffsets } from '../interface'; -import { getCellFixedInfo } from '../utils/fixUtil'; type FlattenColumns = readonly (ColumnType & { scrollbar?: boolean })[]; -export const SummaryContext = - React.createContext<{ - stickyOffsets?: StickyOffsets; - scrollColumnIndex?: number; - flattenColumns?: FlattenColumns; - }>({}); +export const SummaryContext = React.createContext<{ + stickyOffsets?: StickyOffsets; + scrollColumnIndex?: number; + flattenColumns?: FlattenColumns; +}>({}); export interface FooterProps { children: React.ReactNode; - stickyOffsets?: StickyOffsets; - flattenColumns?: FlattenColumns; + stickyOffsets: StickyOffsets; + flattenColumns: FlattenColumns; } -const EMPTY_LIST: FlattenColumns = []; - -function Footer({ - children, - stickyOffsets, - flattenColumns = EMPTY_LIST, -}: FooterProps) { +function Footer({ children, stickyOffsets, flattenColumns }: FooterProps) { const tableContext = React.useContext(TableContext); - const { prefixCls, direction } = tableContext; + const { prefixCls } = tableContext; const lastColumnIndex = flattenColumns.length - 1; const scrollColumn = flattenColumns[lastColumnIndex]; - const mergedTableContext = React.useMemo( - () => - stickyOffsets - ? { - ...tableContext, - fixedInfoList: flattenColumns.map((_, colIndex) => - getCellFixedInfo(colIndex, colIndex, flattenColumns, stickyOffsets, direction), - ), - } - : tableContext, - [tableContext, stickyOffsets, flattenColumns, direction], - ); - const summaryContext = React.useMemo( () => ({ stickyOffsets, @@ -55,11 +34,9 @@ function Footer({ ); return ( - - - {children} - - + + {children} + ); }