From 967af65d9bceef0a695faa97cf26b2618cc2fd64 Mon Sep 17 00:00:00 2001 From: "Jinke.Li" Date: Sat, 9 May 2020 15:57:05 +0800 Subject: [PATCH 1/2] feat: support custom ellipsis tooltip --- .gitignore | 3 +- examples/ellipsis-custom-tooltip.tsx | 65 ++++++++++++++++++++++++++++ package.json | 1 + src/Body/BodyRow.tsx | 3 +- src/Body/ExpandedRow.tsx | 9 +++- src/Cell/index.tsx | 5 ++- src/Footer/Cell.tsx | 3 +- src/Header/HeaderRow.tsx | 3 +- src/Table.tsx | 15 ++++++- src/context/TableContext.tsx | 2 + tests/Table.spec.js | 21 +++++++++ 11 files changed, 122 insertions(+), 8 deletions(-) create mode 100644 examples/ellipsis-custom-tooltip.tsx diff --git a/.gitignore b/.gitignore index e3c5beadd..9f11d8f43 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,5 @@ es/ .storybook .doc !tests/__mocks__/rc-util/lib -examples/debug.tsx \ No newline at end of file +examples/debug.tsx +.history diff --git a/examples/ellipsis-custom-tooltip.tsx b/examples/ellipsis-custom-tooltip.tsx new file mode 100644 index 000000000..67a4d3e4a --- /dev/null +++ b/examples/ellipsis-custom-tooltip.tsx @@ -0,0 +1,65 @@ +import React from 'react'; +import Tooltip from 'rc-tooltip'; +import Table from '../src'; +import '../assets/index.less'; +import 'rc-tooltip/assets/bootstrap.css'; + +const createColumns = (length: number) => { + return Array.from({ length }, (_, i) => ({ + title: 'description', + dataIndex: 'description', + key: `description ${i + 1}`, + ellipsis: true, + ...(i === 0 ? { width: 50 } : null), + render(description: string) { + return ( + + {description} + + ); + }, + })); +}; + +const columns = [ + { + title: 'name', + dataIndex: 'name', + width: 100, + ellipsis: true, + render: (name: string) => ( + + {name} + + ), + }, + ...createColumns(10), + { + title: 'Operations', + key: 'operations', + ellipsis: true, + render() { + return ( + + Operations + + ); + }, + }, +]; + +const data = [ + { name: 'jack', description: 'description description', key: '1' }, + { name: 'jackjackjackjackjackjack', description: 'description description', key: '2' }, + { name: 'jack ma', description: 'description description', key: '3' }, + { name: 'jack nickson', description: 'description description', key: '4' }, +]; + +const Demo = () => ( +
+

Table ellipsis custom tooltip

+ + +); + +export default Demo; diff --git a/package.json b/package.json index 36b9ee9ad..ce163b671 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "rc-animate": "^2.10.1", "rc-dropdown": "~3.1.0", "rc-menu": "^8.0.2", + "rc-tooltip": "^4.0.3", "react": "^16.0.0", "react-dnd": "^2.5.4", "react-dnd-html5-backend": "^2.5.4", diff --git a/src/Body/BodyRow.tsx b/src/Body/BodyRow.tsx index a1753da58..a153dc90e 100644 --- a/src/Body/BodyRow.tsx +++ b/src/Body/BodyRow.tsx @@ -40,7 +40,7 @@ function BodyRow(props: BodyRowP cellComponent, childrenColumnName, } = props; - const { prefixCls, fixedInfoList } = React.useContext(TableContext); + const { prefixCls, fixedInfoList, showCellEllipsisHtmlTitle } = React.useContext(TableContext); const { fixHeader, fixColumn, @@ -162,6 +162,7 @@ function BodyRow(props: BodyRowP {...fixedInfo} appendNode={appendCellNode} additionalProps={additionalCellProps} + showCellEllipsisHtmlTitle={showCellEllipsisHtmlTitle} /> ); })} diff --git a/src/Body/ExpandedRow.tsx b/src/Body/ExpandedRow.tsx index 08c1a6fe2..f8e85b2a7 100644 --- a/src/Body/ExpandedRow.tsx +++ b/src/Body/ExpandedRow.tsx @@ -30,7 +30,7 @@ function ExpandedRow({ componentWidth, colSpan, }: ExpandedRowProps) { - const { scrollbarSize } = React.useContext(TableContext); + const { scrollbarSize, showCellEllipsisHtmlTitle } = React.useContext(TableContext); // Cache render node return React.useMemo(() => { @@ -59,7 +59,12 @@ function ExpandedRow({ display: expanded ? null : 'none', }} > - + {contentNode} diff --git a/src/Cell/index.tsx b/src/Cell/index.tsx index 48b433ac9..fdb149851 100644 --- a/src/Cell/index.tsx +++ b/src/Cell/index.tsx @@ -55,6 +55,8 @@ export interface CellProps { /** @private Used for `expandable` with nest tree */ appendNode?: React.ReactNode; additionalProps?: React.HTMLAttributes; + + showCellEllipsisHtmlTitle?: boolean; } function Cell( @@ -79,6 +81,7 @@ function Cell( additionalProps = {}, ellipsis, align, + showCellEllipsisHtmlTitle, }: CellProps, ref: React.Ref, ): React.ReactElement { @@ -157,7 +160,7 @@ function Cell( // ====================== Render ====================== let title: string; - if (ellipsis) { + if (ellipsis && (showCellEllipsisHtmlTitle || (!showCellEllipsisHtmlTitle && !render))) { if (typeof childNode === 'string') { title = childNode; } else if (React.isValidElement(childNode) && typeof childNode.props.children === 'string') { diff --git a/src/Footer/Cell.tsx b/src/Footer/Cell.tsx index f85dd55e6..08f82ae92 100644 --- a/src/Footer/Cell.tsx +++ b/src/Footer/Cell.tsx @@ -17,7 +17,7 @@ export default function SummaryCell({ colSpan, rowSpan, }: SummaryCellProps) { - const { prefixCls, fixedInfoList } = React.useContext(TableContext); + const { prefixCls, fixedInfoList, showCellEllipsisHtmlTitle } = React.useContext(TableContext); const fixedInfo = fixedInfoList[index]; @@ -29,6 +29,7 @@ export default function SummaryCell({ prefixCls={prefixCls} record={null} dataIndex={null} + showCellEllipsisHtmlTitle={showCellEllipsisHtmlTitle} render={() => ({ children, props: { diff --git a/src/Header/HeaderRow.tsx b/src/Header/HeaderRow.tsx index 74c3c39ab..37492df70 100644 --- a/src/Header/HeaderRow.tsx +++ b/src/Header/HeaderRow.tsx @@ -30,7 +30,7 @@ function HeaderRow({ onHeaderRow, index, }: RowProps) { - const { prefixCls, direction } = React.useContext(TableContext); + const { prefixCls, direction, showCellEllipsisHtmlTitle } = React.useContext(TableContext); let rowProps: React.HTMLAttributes; if (onHeaderRow) { @@ -66,6 +66,7 @@ function HeaderRow({ key={columnsKey[cellIndex]} {...fixedInfo} additionalProps={additionalProps} + showCellEllipsisHtmlTitle={showCellEllipsisHtmlTitle} /> ); })} diff --git a/src/Table.tsx b/src/Table.tsx index 06ca9637a..6e733052c 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -106,6 +106,7 @@ export interface TableProps extends LegacyExpandableProps< columns?: ColumnsType; rowKey?: string | GetRowKey; tableLayout?: TableLayout; + showCellEllipsisHtmlTitle?: boolean; // Fixed Columns scroll?: { x?: number | true | string; y?: number | string }; @@ -168,6 +169,7 @@ function Table(props: TableProps(props: TableProps getCellFixedInfo(colIndex, colIndex, flattenColumns, stickyOffsets, direction), ), }), - [prefixCls, getComponent, scrollbarSize, direction, flattenColumns, stickyOffsets, direction], + [ + prefixCls, + getComponent, + scrollbarSize, + direction, + flattenColumns, + stickyOffsets, + direction, + showCellEllipsisHtmlTitle, + ], ); const BodyContextValue = React.useMemo( @@ -730,6 +742,7 @@ Table.defaultProps = { rowKey: 'key', prefixCls: 'rc-table', emptyText: () => 'No Data', + showCellEllipsisHtmlTitle: true, }; export default Table; diff --git a/src/context/TableContext.tsx b/src/context/TableContext.tsx index cf9a9ee7a..cf457020e 100644 --- a/src/context/TableContext.tsx +++ b/src/context/TableContext.tsx @@ -13,6 +13,8 @@ export interface TableContextProps { direction: 'ltr' | 'rtl'; fixedInfoList: FixedInfo[]; + + showCellEllipsisHtmlTitle?: boolean; } const TableContext = React.createContext(null); diff --git a/tests/Table.spec.js b/tests/Table.spec.js index 9f4b3e9c0..63113cba6 100644 --- a/tests/Table.spec.js +++ b/tests/Table.spec.js @@ -267,6 +267,27 @@ describe('Table.Basic', () => { }); }); + it('not renders ellipsis origin html title', () => { + const columns = [ + { title: 'title', ellipsis: true }, + { title: 'node title', ellipsis: true, render: () =>

233

}, + ]; + const wrapper = mount( + createTable({ + showCellEllipsisHtmlTitle: false, + columns, + }), + ); + + wrapper.find('.rc-table-thead td').forEach(td => { + expect(td.getDOMNode().attributes.getNamedItem('title')).toBeTruthy(); + }); + + wrapper.find('.rc-table-tbody td').forEach(td => { + expect(td.getDOMNode().attributes.getNamedItem('title')).toBeFalsy(); + }); + }); + it('renders column correctly', () => { const columns = [ { From a89eb8eadf08713af48adf1cc1d35ccacf990977 Mon Sep 17 00:00:00 2001 From: "Jinke.Li" Date: Sun, 10 May 2020 15:15:30 +0800 Subject: [PATCH 2/2] feat: add showTitle api for ellipsis --- examples/ellipsis-custom-tooltip.tsx | 14 ++++++++++---- src/Body/BodyRow.tsx | 3 +-- src/Body/ExpandedRow.tsx | 9 ++------- src/Cell/index.tsx | 10 ++++++---- src/Footer/Cell.tsx | 3 +-- src/Header/HeaderRow.tsx | 4 ++-- src/Table.tsx | 15 +-------------- src/context/TableContext.tsx | 2 -- src/interface.ts | 4 +++- tests/Table.spec.js | 22 ++++++++++++++++++---- 10 files changed, 44 insertions(+), 42 deletions(-) diff --git a/examples/ellipsis-custom-tooltip.tsx b/examples/ellipsis-custom-tooltip.tsx index 67a4d3e4a..5241352d7 100644 --- a/examples/ellipsis-custom-tooltip.tsx +++ b/examples/ellipsis-custom-tooltip.tsx @@ -9,7 +9,9 @@ const createColumns = (length: number) => { title: 'description', dataIndex: 'description', key: `description ${i + 1}`, - ellipsis: true, + ellipsis: { + showTitle: false, + }, ...(i === 0 ? { width: 50 } : null), render(description: string) { return ( @@ -26,7 +28,9 @@ const columns = [ title: 'name', dataIndex: 'name', width: 100, - ellipsis: true, + ellipsis: { + showTitle: false, + }, render: (name: string) => ( {name} @@ -37,7 +41,9 @@ const columns = [ { title: 'Operations', key: 'operations', - ellipsis: true, + ellipsis: { + showTitle: false, + }, render() { return ( @@ -58,7 +64,7 @@ const data = [ const Demo = () => (

Table ellipsis custom tooltip

-
+
); diff --git a/src/Body/BodyRow.tsx b/src/Body/BodyRow.tsx index a153dc90e..a1753da58 100644 --- a/src/Body/BodyRow.tsx +++ b/src/Body/BodyRow.tsx @@ -40,7 +40,7 @@ function BodyRow(props: BodyRowP cellComponent, childrenColumnName, } = props; - const { prefixCls, fixedInfoList, showCellEllipsisHtmlTitle } = React.useContext(TableContext); + const { prefixCls, fixedInfoList } = React.useContext(TableContext); const { fixHeader, fixColumn, @@ -162,7 +162,6 @@ function BodyRow(props: BodyRowP {...fixedInfo} appendNode={appendCellNode} additionalProps={additionalCellProps} - showCellEllipsisHtmlTitle={showCellEllipsisHtmlTitle} /> ); })} diff --git a/src/Body/ExpandedRow.tsx b/src/Body/ExpandedRow.tsx index f8e85b2a7..08c1a6fe2 100644 --- a/src/Body/ExpandedRow.tsx +++ b/src/Body/ExpandedRow.tsx @@ -30,7 +30,7 @@ function ExpandedRow({ componentWidth, colSpan, }: ExpandedRowProps) { - const { scrollbarSize, showCellEllipsisHtmlTitle } = React.useContext(TableContext); + const { scrollbarSize } = React.useContext(TableContext); // Cache render node return React.useMemo(() => { @@ -59,12 +59,7 @@ function ExpandedRow({ display: expanded ? null : 'none', }} > - + {contentNode} diff --git a/src/Cell/index.tsx b/src/Cell/index.tsx index 02d881d59..92dd4c4d9 100644 --- a/src/Cell/index.tsx +++ b/src/Cell/index.tsx @@ -9,6 +9,7 @@ import { CellType, DefaultRecordType, AlignType, + CellEllipsisType, } from '../interface'; import { getPathValue } from '../utils/valueUtil'; @@ -38,7 +39,7 @@ export interface CellProps { children?: React.ReactNode; colSpan?: number; rowSpan?: number; - ellipsis?: boolean; + ellipsis?: CellEllipsisType; align?: AlignType; shouldCellUpdate?: (record: RecordType) => boolean; @@ -56,7 +57,7 @@ export interface CellProps { appendNode?: React.ReactNode; additionalProps?: React.HTMLAttributes; - showCellEllipsisHtmlTitle?: boolean; + rowType?: 'header' | 'body' | 'footer'; } function Cell( @@ -81,7 +82,7 @@ function Cell( additionalProps = {}, ellipsis, align, - showCellEllipsisHtmlTitle, + rowType, }: CellProps, ref: React.Ref, ): React.ReactElement { @@ -160,7 +161,8 @@ function Cell( // ====================== Render ====================== let title: string; - if (ellipsis && (showCellEllipsisHtmlTitle || (!showCellEllipsisHtmlTitle && !render))) { + const ellipsisConfig: CellEllipsisType = ellipsis === true ? { showTitle: true } : ellipsis; + if (ellipsisConfig && (ellipsisConfig.showTitle || rowType === 'header')) { if (typeof childNode === 'string' || typeof childNode === 'number') { title = childNode.toString(); } else if (React.isValidElement(childNode) && typeof childNode.props.children === 'string') { diff --git a/src/Footer/Cell.tsx b/src/Footer/Cell.tsx index 08f82ae92..f85dd55e6 100644 --- a/src/Footer/Cell.tsx +++ b/src/Footer/Cell.tsx @@ -17,7 +17,7 @@ export default function SummaryCell({ colSpan, rowSpan, }: SummaryCellProps) { - const { prefixCls, fixedInfoList, showCellEllipsisHtmlTitle } = React.useContext(TableContext); + const { prefixCls, fixedInfoList } = React.useContext(TableContext); const fixedInfo = fixedInfoList[index]; @@ -29,7 +29,6 @@ export default function SummaryCell({ prefixCls={prefixCls} record={null} dataIndex={null} - showCellEllipsisHtmlTitle={showCellEllipsisHtmlTitle} render={() => ({ children, props: { diff --git a/src/Header/HeaderRow.tsx b/src/Header/HeaderRow.tsx index 37492df70..18de958dd 100644 --- a/src/Header/HeaderRow.tsx +++ b/src/Header/HeaderRow.tsx @@ -30,7 +30,7 @@ function HeaderRow({ onHeaderRow, index, }: RowProps) { - const { prefixCls, direction, showCellEllipsisHtmlTitle } = React.useContext(TableContext); + const { prefixCls, direction } = React.useContext(TableContext); let rowProps: React.HTMLAttributes; if (onHeaderRow) { @@ -66,7 +66,7 @@ function HeaderRow({ key={columnsKey[cellIndex]} {...fixedInfo} additionalProps={additionalProps} - showCellEllipsisHtmlTitle={showCellEllipsisHtmlTitle} + rowType="header" /> ); })} diff --git a/src/Table.tsx b/src/Table.tsx index 6e733052c..06ca9637a 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -106,7 +106,6 @@ export interface TableProps extends LegacyExpandableProps< columns?: ColumnsType; rowKey?: string | GetRowKey; tableLayout?: TableLayout; - showCellEllipsisHtmlTitle?: boolean; // Fixed Columns scroll?: { x?: number | true | string; y?: number | string }; @@ -169,7 +168,6 @@ function Table(props: TableProps(props: TableProps getCellFixedInfo(colIndex, colIndex, flattenColumns, stickyOffsets, direction), ), }), - [ - prefixCls, - getComponent, - scrollbarSize, - direction, - flattenColumns, - stickyOffsets, - direction, - showCellEllipsisHtmlTitle, - ], + [prefixCls, getComponent, scrollbarSize, direction, flattenColumns, stickyOffsets, direction], ); const BodyContextValue = React.useMemo( @@ -742,7 +730,6 @@ Table.defaultProps = { rowKey: 'key', prefixCls: 'rc-table', emptyText: () => 'No Data', - showCellEllipsisHtmlTitle: true, }; export default Table; diff --git a/src/context/TableContext.tsx b/src/context/TableContext.tsx index cf457020e..cf9a9ee7a 100644 --- a/src/context/TableContext.tsx +++ b/src/context/TableContext.tsx @@ -13,8 +13,6 @@ export interface TableContextProps { direction: 'ltr' | 'rtl'; fixedInfoList: FixedInfo[]; - - showCellEllipsisHtmlTitle?: boolean; } const TableContext = React.createContext(null); diff --git a/src/interface.ts b/src/interface.ts index 3f4ac79ca..b8a56b2ad 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -55,13 +55,15 @@ export interface RenderedCell { export type DataIndex = string | number | (string | number)[]; +export type CellEllipsisType = { showTitle?: boolean } | boolean; + interface ColumnSharedType { title?: React.ReactNode; key?: Key; className?: string; fixed?: FixedType; onHeaderCell?: GetComponentProps[number]>; - ellipsis?: boolean; + ellipsis?: CellEllipsisType; align?: AlignType; } diff --git a/tests/Table.spec.js b/tests/Table.spec.js index 63113cba6..d9efbbbe7 100644 --- a/tests/Table.spec.js +++ b/tests/Table.spec.js @@ -267,19 +267,33 @@ describe('Table.Basic', () => { }); }); + it('renders ellipsis by showTitle option', () => { + const wrapper = mount( + createTable({ + columns: [ + { title: 'title', ellipsis: { showTitle: true } }, + { title: 'node title', ellipsis: { showTitle: true }, render: () =>

233

}, + ], + }), + ); + + wrapper.find('td').forEach(td => { + expect(td.hasClass('rc-table-cell-ellipsis')).toBeTruthy(); + }); + }); + it('not renders ellipsis origin html title', () => { const columns = [ - { title: 'title', ellipsis: true }, - { title: 'node title', ellipsis: true, render: () =>

233

}, + { title: 'title', ellipsis: { showTitle: false } }, + { title: 'node title', ellipsis: { showTitle: false }, render: () =>

233

}, ]; const wrapper = mount( createTable({ - showCellEllipsisHtmlTitle: false, columns, }), ); - wrapper.find('.rc-table-thead td').forEach(td => { + wrapper.find('.rc-table-thead th').forEach(td => { expect(td.getDOMNode().attributes.getNamedItem('title')).toBeTruthy(); });