From 5fa1aed71fd90d6fe7978cf4620e7a5674f1d6ed Mon Sep 17 00:00:00 2001 From: zombiej Date: Wed, 1 Dec 2021 10:21:44 +0800 Subject: [PATCH 1/5] docs: new example --- docs/demo/colspan-rowspan-legacy.md | 3 + docs/examples/colspan-rowspan-legacy.tsx | 150 +++++++++++++++++++++++ docs/examples/colspan-rowspan.tsx | 78 +++++------- src/Cell/index.tsx | 7 ++ src/interface.ts | 2 +- 5 files changed, 191 insertions(+), 49 deletions(-) create mode 100644 docs/demo/colspan-rowspan-legacy.md create mode 100644 docs/examples/colspan-rowspan-legacy.tsx diff --git a/docs/demo/colspan-rowspan-legacy.md b/docs/demo/colspan-rowspan-legacy.md new file mode 100644 index 000000000..11809cef6 --- /dev/null +++ b/docs/demo/colspan-rowspan-legacy.md @@ -0,0 +1,3 @@ +## colspan-rowspan-legacy + + diff --git a/docs/examples/colspan-rowspan-legacy.tsx b/docs/examples/colspan-rowspan-legacy.tsx new file mode 100644 index 000000000..c67773d3c --- /dev/null +++ b/docs/examples/colspan-rowspan-legacy.tsx @@ -0,0 +1,150 @@ +import React from 'react'; +import Table from 'rc-table'; +import '../../assets/index.less'; +import { ColumnsType, RenderedCell } from '@/interface'; + +interface RecordType { + a?: string; + b?: string; + c?: string; + d?: string; + e?: string; + key?: string; +} + +const columns: ColumnsType = [ + { + title: '手机号', + dataIndex: 'a', + colSpan: 2, + width: 100, + key: 'a', + render(o, row, index) { + const obj: RenderedCell = { + children: o, + props: {}, + }; + // 设置第一行为链接 + if (index === 0) { + obj.children = {o}; + } + // 第5行合并两列 + if (index === 4) { + obj.props.colSpan = 2; + } + + if (index === 5) { + obj.props.colSpan = 6; + } + return obj; + }, + }, + { + title: '电话', + dataIndex: 'b', + colSpan: 0, + width: 100, + key: 'b', + render(o, row, index) { + const obj: RenderedCell = { + children: o, + props: {}, + }; + // 列合并掉的表格设置colSpan=0,不会去渲染 + if (index === 4 || index === 5) { + obj.props.colSpan = 0; + } + return obj; + }, + }, + { + title: 'Name', + dataIndex: 'c', + width: 100, + key: 'c', + render(o, row, index) { + const obj: RenderedCell = { + children: o, + props: {}, + }; + + if (index === 5) { + obj.props.colSpan = 0; + } + return obj; + }, + }, + { + title: 'Address', + dataIndex: 'd', + width: 200, + key: 'd', + render(o, row, index) { + const obj: RenderedCell = { + children: o, + props: {}, + }; + if (index === 0) { + obj.props.rowSpan = 2; + } + if (index === 1 || index === 5) { + obj.props.rowSpan = 0; + } + + if (index === 5) { + obj.props.colSpan = 0; + } + + return obj; + }, + }, + { + title: 'Gender', + dataIndex: 'e', + width: 200, + key: 'e', + render(o, row, index) { + const obj: RenderedCell = { + children: o, + props: {}, + }; + if (index === 5) { + obj.props.colSpan = 0; + } + return obj; + }, + }, + { + title: 'Operations', + dataIndex: '', + key: 'f', + render(o, row, index) { + if (index === 5) { + return { + props: { + colSpan: 0, + }, + }; + } + return Operations; + }, + }, +]; + +const data: RecordType[] = [ + { a: '13812340987', b: '0571-12345678', c: '张三', d: '文一西路', e: 'Male', key: '1' }, + { a: '13812340986', b: '0571-98787658', c: '张夫人', d: '文一西路', e: 'Female', key: '2' }, + { a: '13812988888', b: '0571-099877', c: '李四', d: '文二西路', e: 'Male', key: '3' }, + { a: '1381200008888', b: '0571-099877', c: '王五', d: '文二西路', e: 'Male', key: '4' }, + { a: '0571-88888110', c: '李警官', d: '武林门', e: 'Male', key: '5' }, + { a: '资料统计完毕于xxxx年xxx月xxx日', key: '6' }, +]; + +const Demo = () => ( +
+

colSpan & rowSpan

+ + +); + +export default Demo; diff --git a/docs/examples/colspan-rowspan.tsx b/docs/examples/colspan-rowspan.tsx index c67773d3c..d78ab1a8f 100644 --- a/docs/examples/colspan-rowspan.tsx +++ b/docs/examples/colspan-rowspan.tsx @@ -20,23 +20,21 @@ const columns: ColumnsType = [ width: 100, key: 'a', render(o, row, index) { - const obj: RenderedCell = { - children: o, - props: {}, - }; - // 设置第一行为链接 - if (index === 0) { - obj.children = {o}; - } + return index === 0 ? {o} : o; + }, + onCell: (_, index) => { + const props: React.TdHTMLAttributes = {}; + // 第5行合并两列 if (index === 4) { - obj.props.colSpan = 2; + props.colSpan = 2; } if (index === 5) { - obj.props.colSpan = 6; + props.colSpan = 6; } - return obj; + + return props; }, }, { @@ -45,16 +43,12 @@ const columns: ColumnsType = [ colSpan: 0, width: 100, key: 'b', - render(o, row, index) { - const obj: RenderedCell = { - children: o, - props: {}, - }; + onCell(_, index) { // 列合并掉的表格设置colSpan=0,不会去渲染 if (index === 4 || index === 5) { - obj.props.colSpan = 0; + return { colSpan: 0 }; } - return obj; + return {}; }, }, { @@ -62,16 +56,11 @@ const columns: ColumnsType = [ dataIndex: 'c', width: 100, key: 'c', - render(o, row, index) { - const obj: RenderedCell = { - children: o, - props: {}, - }; - + onCell(_, index) { if (index === 5) { - obj.props.colSpan = 0; + return { colSpan: 0 }; } - return obj; + return {}; }, }, { @@ -79,23 +68,19 @@ const columns: ColumnsType = [ dataIndex: 'd', width: 200, key: 'd', - render(o, row, index) { - const obj: RenderedCell = { - children: o, - props: {}, - }; + onCell(_, index) { + const props: React.TdHTMLAttributes = {}; if (index === 0) { - obj.props.rowSpan = 2; + props.rowSpan = 2; } if (index === 1 || index === 5) { - obj.props.rowSpan = 0; + props.rowSpan = 0; } if (index === 5) { - obj.props.colSpan = 0; + props.colSpan = 0; } - - return obj; + return props; }, }, { @@ -103,30 +88,27 @@ const columns: ColumnsType = [ dataIndex: 'e', width: 200, key: 'e', - render(o, row, index) { - const obj: RenderedCell = { - children: o, - props: {}, - }; + onCell(_, index) { if (index === 5) { - obj.props.colSpan = 0; + return { colSpan: 0 }; } - return obj; + return {}; }, }, { title: 'Operations', dataIndex: '', key: 'f', - render(o, row, index) { + render() { + return Operations; + }, + onCell(_, index) { if (index === 5) { return { - props: { - colSpan: 0, - }, + colSpan: 0, }; } - return Operations; + return {}; }, }, ]; diff --git a/src/Cell/index.tsx b/src/Cell/index.tsx index fffda2850..b4fdbd07d 100644 --- a/src/Cell/index.tsx +++ b/src/Cell/index.tsx @@ -15,6 +15,7 @@ import { getPathValue, validateValue } from '../utils/valueUtil'; import StickyContext from '../context/StickyContext'; import HoverContext from '../context/HoverContext'; import type { HoverContextProps } from '../context/HoverContext'; +import { warning } from 'rc-util/lib/warning'; /** Check if cell is in hover range */ function inHoverRange(cellStartRow: number, cellRowSpan: number, startRow: number, endRow: number) { @@ -132,6 +133,12 @@ function Cell( const renderData = render(value, record, index); if (isRenderCell(renderData)) { + if (process.env.NODE_ENV !== 'production') { + warning( + false, + '`columns.render` return cell props is deprecated, please use `onCell` instead.', + ); + } childNode = renderData.children; cellProps = renderData.props; } else { diff --git a/src/interface.ts b/src/interface.ts index e762b10e9..a0d146537 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -107,7 +107,7 @@ export interface StickyOffsets { export type GetComponentProps = ( data: DataType, index?: number, -) => React.HTMLAttributes; +) => React.HTMLAttributes | React.TdHTMLAttributes; type Component

= | React.ComponentType

From 839d3cd4b416c0d64ea2982d584eaeb951fd9e95 Mon Sep 17 00:00:00 2001 From: zombiej Date: Wed, 1 Dec 2021 14:51:19 +0800 Subject: [PATCH 2/5] chore: add consumer --- src/Cell/index.tsx | 19 +++++++++++++++-- src/utils/renderUtil.tsx | 44 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 src/utils/renderUtil.tsx diff --git a/src/Cell/index.tsx b/src/Cell/index.tsx index b4fdbd07d..fddd88edc 100644 --- a/src/Cell/index.tsx +++ b/src/Cell/index.tsx @@ -65,7 +65,7 @@ interface InternalCellProps extends HoverC // ====================== Private Props ====================== /** @private Used for `expandable` with nest tree */ appendNode?: React.ReactNode; - additionalProps?: React.HTMLAttributes; + additionalProps?: React.TdHTMLAttributes; /** @private Fixed for user use `shouldCellUpdate` which block the render */ expanded?: boolean; @@ -289,8 +289,23 @@ const MemoCell = React.memo( /** Inject hover data here, we still wish MemoCell keep simple `shouldCellUpdate` logic */ const WrappedCell = React.forwardRef((props: CellProps, ref: React.Ref) => { const { onHover, startRow, endRow } = React.useContext(HoverContext); + const { additionalProps = {}, colSpan, rowSpan } = props; + const { colSpan: cellColSpan, rowSpan: cellRowSpan } = additionalProps; - return ; + const mergedColSpan = colSpan ?? cellColSpan; + const mergedRowSpan = rowSpan ?? cellRowSpan; + + return ( + + ); }); WrappedCell.displayName = 'WrappedCell'; diff --git a/src/utils/renderUtil.tsx b/src/utils/renderUtil.tsx new file mode 100644 index 000000000..32221ed4d --- /dev/null +++ b/src/utils/renderUtil.tsx @@ -0,0 +1,44 @@ +import * as React from 'react'; + +/** + * Skip render if parent node is not re-render. Works in concurrent mode. + * + * zombieJ: This is common utility for rendering react components. + * We may move this to `rc-util` if stable. + */ + +export type ContextType = React.Context; + +export function createContext(): ContextType { + return React.createContext(0); +} + +function mergeProps(props: Props, ref: any): Props { + const mergedProps = { ...props }; + if (ref) { + (mergedProps as any).ref = ref; + } + + return mergedProps; +} + +export function withProvider(Context: ContextType, Component: React.ComponentType) { + return React.forwardRef((props: Props, ref) => { + const renderTimesRef = React.useRef(0); + renderTimesRef.current += 1; + + return ( + + + + ); + }); +} + +export function withConsumer(Context: ContextType, Component: React.ComponentType) { + return React.forwardRef((props: Props, ref) => { + const renderTimes = React.useContext(Context); + + return React.useMemo(() => , [renderTimes]); + }); +} From 3f8c641b1cdb6ac616964204392089b3827f31cc Mon Sep 17 00:00:00 2001 From: zombiej Date: Wed, 1 Dec 2021 16:04:08 +0800 Subject: [PATCH 3/5] chore: clean up --- src/utils/renderUtil.tsx | 44 ---------------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 src/utils/renderUtil.tsx diff --git a/src/utils/renderUtil.tsx b/src/utils/renderUtil.tsx deleted file mode 100644 index 32221ed4d..000000000 --- a/src/utils/renderUtil.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import * as React from 'react'; - -/** - * Skip render if parent node is not re-render. Works in concurrent mode. - * - * zombieJ: This is common utility for rendering react components. - * We may move this to `rc-util` if stable. - */ - -export type ContextType = React.Context; - -export function createContext(): ContextType { - return React.createContext(0); -} - -function mergeProps(props: Props, ref: any): Props { - const mergedProps = { ...props }; - if (ref) { - (mergedProps as any).ref = ref; - } - - return mergedProps; -} - -export function withProvider(Context: ContextType, Component: React.ComponentType) { - return React.forwardRef((props: Props, ref) => { - const renderTimesRef = React.useRef(0); - renderTimesRef.current += 1; - - return ( - - - - ); - }); -} - -export function withConsumer(Context: ContextType, Component: React.ComponentType) { - return React.forwardRef((props: Props, ref) => { - const renderTimes = React.useContext(Context); - - return React.useMemo(() => , [renderTimes]); - }); -} From 0bb7da6d53487076cf6f7be53e4fcea05aca4ffe Mon Sep 17 00:00:00 2001 From: zombiej Date: Wed, 1 Dec 2021 16:37:06 +0800 Subject: [PATCH 4/5] chore: fix for render --- package.json | 1 + src/Body/index.tsx | 38 ++++++++++++++++++++------------------ src/Cell/index.tsx | 32 +++++++++++++++++--------------- 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 52337a35a..a66ed9485 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "@types/jest": "^26.0.3", "@types/react": "^17.0.35", "@types/react-dom": "^17.0.10", + "@types/shallowequal": "^1.1.1", "@umijs/fabric": "^2.0.0", "cross-env": "^7.0.0", "dumi": "^1.1.9", diff --git a/src/Body/index.tsx b/src/Body/index.tsx index 8d070f1d3..640cc2345 100644 --- a/src/Body/index.tsx +++ b/src/Body/index.tsx @@ -31,8 +31,6 @@ function Body({ emptyNode, childrenColumnName, }: BodyProps) { - const [startRow, setStartRow] = React.useState(-1); - const [endRow, setEndRow] = React.useState(-1); const { onColumnResize } = React.useContext(ResizeContext); const { prefixCls, getComponent } = React.useContext(TableContext); const { flattenColumns } = React.useContext(BodyContext); @@ -40,6 +38,10 @@ function Body({ const flattenData: { record: RecordType; indent: number; index: number }[] = useFlattenRecords(data, childrenColumnName, expandedKeys, getRowKey); + // ====================== Hover ======================= + const [startRow, setStartRow] = React.useState(-1); + const [endRow, setEndRow] = React.useState(-1); + const onHover = React.useCallback((start: number, end: number) => { setStartRow(start); setEndRow(end); @@ -50,7 +52,8 @@ function Body({ [onHover, startRow, endRow], ); - return React.useMemo(() => { + // ====================== Render ====================== + const bodyNode = React.useMemo(() => { const WrapperComponent = getComponent(['body', 'wrapper'], 'tbody'); const trComponent = getComponent(['body', 'row'], 'tr'); const tdComponent = getComponent(['body', 'cell'], 'td'); @@ -98,20 +101,18 @@ function Body({ const columnsKey = getColumnsKey(flattenColumns); return ( - - - {/* Measure body column width with additional hidden col */} - {measureColumnWidth && ( - - )} - - {rows} - - + + {/* Measure body column width with additional hidden col */} + {measureColumnWidth && ( + + )} + + {rows} + ); }, [ data, @@ -127,8 +128,9 @@ function Body({ onColumnResize, rowExpandable, flattenData, - hoverContext, ]); + + return {bodyNode}; } const MemoBody = React.memo(Body); diff --git a/src/Cell/index.tsx b/src/Cell/index.tsx index fddd88edc..11f68e3a8 100644 --- a/src/Cell/index.tsx +++ b/src/Cell/index.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import classNames from 'classnames'; +import shallowEqual from 'shallowequal'; import { supportRef } from 'rc-util/lib/ref'; import type { DataIndex, @@ -15,7 +16,7 @@ import { getPathValue, validateValue } from '../utils/valueUtil'; import StickyContext from '../context/StickyContext'; import HoverContext from '../context/HoverContext'; import type { HoverContextProps } from '../context/HoverContext'; -import { warning } from 'rc-util/lib/warning'; +import warning from 'rc-util/lib/warning'; /** Check if cell is in hover range */ function inHoverRange(cellStartRow: number, cellRowSpan: number, startRow: number, endRow: number) { @@ -37,7 +38,8 @@ function isRefComponent(component: CustomizeComponent) { return supportRef(component); } -interface InternalCellProps extends HoverContextProps { +interface InternalCellProps + extends Pick { prefixCls?: string; className?: string; record?: RecordType; @@ -72,6 +74,8 @@ interface InternalCellProps extends HoverC rowType?: 'header' | 'body' | 'footer'; isSticky?: boolean; + + hovering?: boolean; } export type CellProps = Omit< @@ -105,8 +109,7 @@ function Cell( isSticky, // Hover - startRow, - endRow, + hovering, onHover, // MISC @@ -196,9 +199,7 @@ function Cell( } // ====================== Hover ======================= - const hovering = inHoverRange(index, mergedRowSpan, startRow, endRow); - - const onMouseEnter: React.MouseEventHandler = event => { + const onMouseEnter: React.MouseEventHandler = event => { if (record) { onHover(index, index + mergedRowSpan - 1); } @@ -206,7 +207,7 @@ function Cell( additionalProps?.onMouseEnter?.(event); }; - const onMouseLeave: React.MouseEventHandler = event => { + const onMouseLeave: React.MouseEventHandler = event => { if (record) { onHover(-1, -1); } @@ -268,42 +269,43 @@ function Cell( const RefCell = React.forwardRef>(Cell); RefCell.displayName = 'Cell'; -const comparePropList: (keyof InternalCellProps)[] = ['expanded', 'className']; - const MemoCell = React.memo( RefCell, (prev: InternalCellProps, next: InternalCellProps) => { + const sameProps = shallowEqual(prev, next); + if (next.shouldCellUpdate) { return ( // Additional handle of expanded logic - comparePropList.every(propName => prev[propName] === next[propName]) && + sameProps && // User control update logic !next.shouldCellUpdate(next.record, prev.record) ); } - return false; + return sameProps; }, ); /** Inject hover data here, we still wish MemoCell keep simple `shouldCellUpdate` logic */ const WrappedCell = React.forwardRef((props: CellProps, ref: React.Ref) => { const { onHover, startRow, endRow } = React.useContext(HoverContext); - const { additionalProps = {}, colSpan, rowSpan } = props; + const { index, additionalProps = {}, colSpan, rowSpan } = props; const { colSpan: cellColSpan, rowSpan: cellRowSpan } = additionalProps; const mergedColSpan = colSpan ?? cellColSpan; const mergedRowSpan = rowSpan ?? cellRowSpan; + const hovering = inHoverRange(index, mergedRowSpan || 1, startRow, endRow); + return ( ); }); From 8b5c3d5d49c897cb925511bb28cb2d56cb264681 Mon Sep 17 00:00:00 2001 From: zombiej Date: Wed, 1 Dec 2021 17:20:31 +0800 Subject: [PATCH 5/5] test: Test coverage --- src/Cell/index.tsx | 18 +++--- tests/Hover.spec.tsx | 127 +++++++++++++++++++++++++++++++++++++++++++ tests/Table.spec.js | 25 --------- 3 files changed, 135 insertions(+), 35 deletions(-) create mode 100644 tests/Hover.spec.tsx diff --git a/src/Cell/index.tsx b/src/Cell/index.tsx index 11f68e3a8..6e70895cf 100644 --- a/src/Cell/index.tsx +++ b/src/Cell/index.tsx @@ -111,10 +111,8 @@ function Cell( // Hover hovering, onHover, - - // MISC - shouldCellUpdate, - }: InternalCellProps, + }: // MISC + InternalCellProps, ref: React.Ref, ): React.ReactElement { const cellPrefixCls = `${prefixCls}-cell`; @@ -139,7 +137,7 @@ function Cell( if (process.env.NODE_ENV !== 'production') { warning( false, - '`columns.render` return cell props is deprecated, please use `onCell` instead.', + '`columns.render` return cell props is deprecated with perf issue, please use `onCell` instead.', ); } childNode = renderData.children; @@ -247,7 +245,7 @@ function Cell( [`${cellPrefixCls}-ellipsis`]: ellipsis, [`${cellPrefixCls}-with-append`]: appendNode, [`${cellPrefixCls}-fix-sticky`]: (isFixLeft || isFixRight) && isSticky && supportSticky, - [`${cellPrefixCls}-row-hover`]: !shouldCellUpdate && hovering, // Not patch style if using shouldCellUpdate + [`${cellPrefixCls}-row-hover`]: !cellProps && hovering, }, additionalProps.className, cellClassName, @@ -269,21 +267,21 @@ function Cell( const RefCell = React.forwardRef>(Cell); RefCell.displayName = 'Cell'; +const comparePropList: (keyof InternalCellProps)[] = ['expanded', 'className', 'hovering']; + const MemoCell = React.memo( RefCell, (prev: InternalCellProps, next: InternalCellProps) => { - const sameProps = shallowEqual(prev, next); - if (next.shouldCellUpdate) { return ( // Additional handle of expanded logic - sameProps && + comparePropList.every(propName => prev[propName] === next[propName]) && // User control update logic !next.shouldCellUpdate(next.record, prev.record) ); } - return sameProps; + return shallowEqual(prev, next); }, ); diff --git a/tests/Hover.spec.tsx b/tests/Hover.spec.tsx new file mode 100644 index 000000000..2873713e0 --- /dev/null +++ b/tests/Hover.spec.tsx @@ -0,0 +1,127 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import { resetWarned } from 'rc-util/lib/warning'; +import Table from '../src'; +import type { TableProps } from '../src/Table'; + +describe('Table.Hover', () => { + const data = [ + { key: 'key0', name: 'Lucy' }, + { key: 'key1', name: 'Jack' }, + ]; + const createTable = (props?: TableProps) => { + const columns = [{ title: 'Name', dataIndex: 'name', key: 'name' }]; + + return

; + }; + + it('basic', () => { + const wrapper = mount(createTable()); + wrapper.find('tbody td').first().simulate('mouseEnter'); + expect(wrapper.exists('.rc-table-cell-row-hover')).toBeTruthy(); + + wrapper.find('tbody td').first().simulate('mouseLeave'); + expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy(); + }); + + it('works on shouldCellUpdate', () => { + const wrapper = mount( + createTable({ + columns: [{ title: 'Name', dataIndex: 'name', key: 'name', shouldCellUpdate: () => false }], + }), + ); + + wrapper.find('tbody td').first().simulate('mouseEnter'); + expect(wrapper.exists('.rc-table-cell-row-hover')).toBeTruthy(); + + wrapper.find('tbody td').first().simulate('mouseLeave'); + expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy(); + }); + + it('warning if use `render` for rowSpan', () => { + resetWarned(); + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + + const wrapper = mount( + createTable({ + columns: [ + { + dataIndex: 'name', + render: (name, _, index) => { + if (index === 0) { + return { + children: name, + props: { rowSpan: 2 }, + }; + } + return { + props: { rowSpan: 0 }, + }; + }, + }, + { + dataIndex: 'key', + }, + ], + }), + ); + + // Merge row check + expect(wrapper.find('tbody td')).toHaveLength(3); + + // Hover 0-0 + wrapper.find('tbody td').at(0).simulate('mouseEnter'); + expect(wrapper.find('td.rc-table-cell-row-hover')).toHaveLength(2); + + // Hover 0-1 + wrapper.find('tbody td').at(1).simulate('mouseEnter'); + expect(wrapper.find('td.rc-table-cell-row-hover')).toHaveLength(1); + + // Mouse leave + wrapper.find('tbody td').at(1).simulate('mouseLeave'); + expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy(); + + expect(errorSpy).toHaveBeenCalledWith( + 'Warning: `columns.render` return cell props is deprecated with perf issue, please use `onCell` instead.', + ); + errorSpy.mockRestore(); + }); + + it('onCell should work', () => { + const wrapper = mount( + createTable({ + columns: [ + { + dataIndex: 'name', + onCell: (_, index) => { + if (index === 0) { + return { + rowSpan: 2, + }; + } + return { rowSpan: 0 }; + }, + }, + { + dataIndex: 'key', + }, + ], + }), + ); + + // Merge row check + expect(wrapper.find('tbody td')).toHaveLength(3); + + // Hover 0-0 + wrapper.find('tbody td').at(0).simulate('mouseEnter'); + expect(wrapper.find('td.rc-table-cell-row-hover')).toHaveLength(3); + + // Hover 0-1 + wrapper.find('tbody td').at(1).simulate('mouseEnter'); + expect(wrapper.find('td.rc-table-cell-row-hover')).toHaveLength(2); + + // Mouse leave + wrapper.find('tbody td').at(1).simulate('mouseLeave'); + expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy(); + }); +}); diff --git a/tests/Table.spec.js b/tests/Table.spec.js index d1e989cea..b5a703fb6 100644 --- a/tests/Table.spec.js +++ b/tests/Table.spec.js @@ -774,7 +774,6 @@ describe('Table.Basic', () => { }, internalHooks: INTERNAL_HOOKS, transformColumns: columns => { - console.log(columns); existExpandColumn = columns.some( col => col[INTERNAL_COL_DEFINE]?.columnType === 'EXPAND_COLUMN', ); @@ -959,30 +958,6 @@ describe('Table.Basic', () => { }); }); - describe('hover', () => { - it('basic', () => { - const wrapper = mount(createTable()); - wrapper.find('tbody td').first().simulate('mouseEnter'); - expect(wrapper.exists('.rc-table-cell-row-hover')).toBeTruthy(); - - wrapper.find('tbody td').first().simulate('mouseLeave'); - expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy(); - }); - - it('skip when config should cell update', () => { - const wrapper = mount( - createTable({ - columns: [ - { title: 'Name', dataIndex: 'name', key: 'name', shouldCellUpdate: () => false }, - ], - }), - ); - - wrapper.find('tbody td').first().simulate('mouseEnter'); - expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy(); - }); - }); - it('render index in tree table', () => { const tColumns = [ {