From 966cf939251cb061db50f80c01dc0066ae47d2a4 Mon Sep 17 00:00:00 2001 From: kingmui Date: Thu, 2 Jul 2020 23:30:16 +0800 Subject: [PATCH 1/9] feat: Table summary is rendered independently --- assets/index.less | 30 ++++++++++++------ examples/fixedColumns.tsx | 2 +- src/Footer/index.tsx | 2 +- src/Table.tsx | 65 +++++++++++++++++++++++++++------------ 4 files changed, 68 insertions(+), 31 deletions(-) diff --git a/assets/index.less b/assets/index.less index 510ec4f1a..e2b16b1d9 100644 --- a/assets/index.less +++ b/assets/index.less @@ -205,19 +205,31 @@ border-radius: 5px 0 0 0; } - &-body { + &-body, + &-summary { .tableBorder(); border-top: 0; } - &-fixed-column &-body::after { - content: ''; - position: absolute; - right: 0; - top: 0; - bottom: 0; - border-right: @border; - z-index: 1; + &-fixed-column { + &-body, + &-summary { + &::after { + content: ''; + position: absolute; + right: 0; + top: 0; + bottom: 0; + border-right: @border; + z-index: 1; + } + } + } + + &-fixed-column &-summary { + &::-webkit-scrollbar { + display: none; + } } // ================= Expand ================= diff --git a/examples/fixedColumns.tsx b/examples/fixedColumns.tsx index d16faa21b..f1ee4113d 100644 --- a/examples/fixedColumns.tsx +++ b/examples/fixedColumns.tsx @@ -61,7 +61,7 @@ const Demo = () => ( b || c} - scroll={{ x: 1200 }} + scroll={{ x: 1200, y: 200 }} data={data} summary={() => ( <> diff --git a/src/Footer/index.tsx b/src/Footer/index.tsx index 732ae5a0c..3cfa6be70 100644 --- a/src/Footer/index.tsx +++ b/src/Footer/index.tsx @@ -9,7 +9,7 @@ export interface FooterProps { function Footer({ children }: FooterProps) { const { prefixCls } = React.useContext(TableContext); - return {children}; + return {children}; } export default Footer; diff --git a/src/Table.tsx b/src/Table.tsx index 879f1b081..7caad1f0f 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -83,6 +83,11 @@ interface MemoTableContentProps { props: any; } +enum IBodyContentType { + body = 'body', + summary = 'summary', +} + const MemoTableContent = React.memo( ({ children }) => children as React.ReactElement, @@ -364,6 +369,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] = useFrameState(new Map()); @@ -432,6 +438,7 @@ function Table(props: TableProps(props: TableProps{summary(mergedData)}; const customizeScrollBody = getComponent(['body']) as CustomizeScrollBody; + const getBodyContent = (type: IBodyContentType) => { + const ref = { + [IBodyContentType.body]: scrollBodyRef, + [IBodyContentType.summary]: scrollSummaryRef, + }[type]; + + const tableContent = { + [IBodyContentType.body]: bodyTable, + [IBodyContentType.summary]: footerTable, + }[type]; + + return ( +
+ + {bodyColGroup} + {tableContent} + +
+ ); + }; + if ( process.env.NODE_ENV !== 'production' && typeof customizeScrollBody === 'function' && @@ -562,26 +603,10 @@ function Table(props: TableProps - - {bodyColGroup} - {bodyTable} - {footerTable} - - + <> + {getBodyContent(IBodyContentType.body)} + {getBodyContent(IBodyContentType.summary)} + ); } From 3490ae6d7f2bda7bf6fdf2933cb98d08506f0221 Mon Sep 17 00:00:00 2001 From: kingmui Date: Fri, 3 Jul 2020 15:37:21 +0800 Subject: [PATCH 2/9] fix: fix test warning --- src/Footer/index.tsx | 2 +- src/Table.tsx | 18 +++++++++--------- tests/__snapshots__/Table.spec.js.snap | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Footer/index.tsx b/src/Footer/index.tsx index 3cfa6be70..3a59b03a8 100644 --- a/src/Footer/index.tsx +++ b/src/Footer/index.tsx @@ -9,7 +9,7 @@ export interface FooterProps { function Footer({ children }: FooterProps) { const { prefixCls } = React.useContext(TableContext); - return
{children}; + return {children}; } export default Footer; diff --git a/src/Table.tsx b/src/Table.tsx index dbe227d8a..09d838fd2 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -83,7 +83,7 @@ interface MemoTableContentProps { props: any; } -enum IBodyContentType { +enum BodyContentTypeEnum { body = 'body', summary = 'summary', } @@ -537,15 +537,15 @@ function Table(props: TableProps{summary(mergedData)}; const customizeScrollBody = getComponent(['body']) as CustomizeScrollBody; - const getBodyContent = (type: IBodyContentType) => { + const getBodyContent = (type: BodyContentTypeEnum) => { const ref = { - [IBodyContentType.body]: scrollBodyRef, - [IBodyContentType.summary]: scrollSummaryRef, + [BodyContentTypeEnum.body]: scrollBodyRef, + [BodyContentTypeEnum.summary]: scrollSummaryRef, }[type]; const tableContent = { - [IBodyContentType.body]: bodyTable, - [IBodyContentType.summary]: footerTable, + [BodyContentTypeEnum.body]: bodyTable, + [BodyContentTypeEnum.summary]: footerTable, }[type]; return ( @@ -553,7 +553,7 @@ function Table(props: TableProps(props: TableProps - {getBodyContent(IBodyContentType.body)} - {getBodyContent(IBodyContentType.summary)} + {getBodyContent(BodyContentTypeEnum.body)} + {footerTable && getBodyContent(BodyContentTypeEnum.summary)} ); } diff --git a/tests/__snapshots__/Table.spec.js.snap b/tests/__snapshots__/Table.spec.js.snap index 3fc2a1fba..665de392a 100644 --- a/tests/__snapshots__/Table.spec.js.snap +++ b/tests/__snapshots__/Table.spec.js.snap @@ -665,7 +665,7 @@ exports[`Table.Basic renders rowSpan correctly 1`] = ` exports[`Table.Basic summary support data type 1`] = ` {children}; + const { prefixCls, isSummaryShowTop } = React.useContext(TableContext); + return isSummaryShowTop ? ( + {children} + ) : ( + {children} + ); } export default Footer; diff --git a/src/Table.tsx b/src/Table.tsx index 79cf98789..0152d65b8 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -128,6 +128,8 @@ export interface TableProps extends LegacyExpandableProps< title?: PanelRender; footer?: PanelRender; summary?: (data: RecordType[]) => React.ReactNode; + summaryFixed?: boolean; + summaryPosition?: 'top' | 'bottom'; // Customize id?: string; @@ -183,6 +185,8 @@ function Table(props: TableProps(props: TableProps{summary(mergedData)}; const customizeScrollBody = getComponent(['body']) as CustomizeScrollBody; - const getBodyContent = (type: BodyContentTypeEnum) => { + const isTableFixed = fixHeader || isSticky; + + const isSummaryShowTop = isTableFixed && summaryPosition === 'top'; + + const getBodyContent = (type: BodyContentTypeEnum, mergeSummary?: boolean) => { const ref = { [BodyContentTypeEnum.body]: scrollBodyRef, [BodyContentTypeEnum.summary]: scrollSummaryRef, @@ -584,6 +592,7 @@ function Table(props: TableProps {bodyColGroup} {tableContent} + {mergeSummary && type !== BodyContentTypeEnum.summary && footerTable} ); @@ -598,7 +607,7 @@ function Table(props: TableProps(props: TableProps - {getBodyContent(BodyContentTypeEnum.body)} - {footerTable && getBodyContent(BodyContentTypeEnum.summary)} + {summaryFixed ? ( + <> + {footerTable && isSummaryShowTop && getBodyContent(BodyContentTypeEnum.summary)} + {getBodyContent(BodyContentTypeEnum.body)} + {footerTable && !isSummaryShowTop && getBodyContent(BodyContentTypeEnum.summary)} + + ) : ( + getBodyContent(BodyContentTypeEnum.body, true) + )} + {isSticky && ( (props: TableProps(props: TableProps(null); diff --git a/tests/Table.spec.js b/tests/Table.spec.js index 0d3128629..052a1e023 100644 --- a/tests/Table.spec.js +++ b/tests/Table.spec.js @@ -198,6 +198,32 @@ describe('Table.Basic', () => { expect(wrapper.find('tfoot').render()).toMatchSnapshot(); }); + + it('support data type', () => { + const wrapper = mount( +
Date: Tue, 1 Sep 2020 14:23:36 +0800 Subject: [PATCH 3/9] feat: Ability to make Table Summary Fixed Row like Table Header --- examples/fixedColumns.tsx | 2 ++ src/Footer/index.tsx | 8 ++++++-- src/Table.tsx | 27 ++++++++++++++++++++++---- src/context/TableContext.tsx | 2 ++ tests/Table.spec.js | 26 +++++++++++++++++++++++++ tests/__snapshots__/Table.spec.js.snap | 23 +++++++++++++++++++++- 6 files changed, 81 insertions(+), 7 deletions(-) diff --git a/examples/fixedColumns.tsx b/examples/fixedColumns.tsx index f1ee4113d..4d3001d51 100644 --- a/examples/fixedColumns.tsx +++ b/examples/fixedColumns.tsx @@ -77,6 +77,8 @@ const Demo = () => ( )} + summaryFixed + summaryPosition="top" /> ); diff --git a/src/Footer/index.tsx b/src/Footer/index.tsx index 3a59b03a8..34e4a797d 100644 --- a/src/Footer/index.tsx +++ b/src/Footer/index.tsx @@ -8,8 +8,12 @@ export interface FooterProps { } function Footer({ children }: FooterProps) { - const { prefixCls } = React.useContext(TableContext); - return
( + + + Light + + Bamboo + + )} + summaryFixed + summaryPosition="top" + scroll={{ x: 1200, y: 200 }} + />, + ); + + expect(wrapper.find('.rc-table-summary-content').render()).toMatchSnapshot(); + }); }); it('renders with id correctly', () => { diff --git a/tests/__snapshots__/Table.spec.js.snap b/tests/__snapshots__/Table.spec.js.snap index 39e51ce41..be551c41f 100644 --- a/tests/__snapshots__/Table.spec.js.snap +++ b/tests/__snapshots__/Table.spec.js.snap @@ -719,7 +719,7 @@ exports[`Table.Basic renders rowSpan correctly 1`] = ` exports[`Table.Basic summary support data type 1`] = ` + + + + + +`; + exports[`Table.Basic syntactic sugar 1`] = `
Date: Wed, 14 Oct 2020 00:08:40 +0800 Subject: [PATCH 4/9] feat: summary supports an object --- examples/fixedColumns.tsx | 34 ++++++++++++++++++---------------- src/Table.tsx | 27 +++++++++++++++++++++------ tests/Table.spec.js | 22 ++++++++++++---------- 3 files changed, 51 insertions(+), 32 deletions(-) diff --git a/examples/fixedColumns.tsx b/examples/fixedColumns.tsx index 4d3001d51..6e86b39cd 100644 --- a/examples/fixedColumns.tsx +++ b/examples/fixedColumns.tsx @@ -63,22 +63,24 @@ const Demo = () => ( expandedRowRender={({ b, c }) => b || c} scroll={{ x: 1200, y: 200 }} data={data} - summary={() => ( - <> - - - - Summary - - - Content - - Right - - - )} - summaryFixed - summaryPosition="top" + summary={{ + render: () => ( + <> + + + + Summary + + + Content + + Right + + + ), + fixed: true, + position: 'bottom', + }} />
); diff --git a/src/Table.tsx b/src/Table.tsx index 542210228..fb6a6fbf0 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -87,6 +87,10 @@ interface MemoTableContentProps { props: any; } +type SummaryRender = (data: RecordType[]) => React.ReactNode; + +type SummaryPosition = 'top' | 'bottom'; + enum BodyContentTypeEnum { body = 'body', summary = 'summary', @@ -128,9 +132,11 @@ export interface TableProps extends LegacyExpandableProps< // Additional Part title?: PanelRender; footer?: PanelRender; - summary?: (data: RecordType[]) => React.ReactNode; - summaryFixed?: boolean; - summaryPosition?: 'top' | 'bottom'; + summary?: SummaryRender | { + render: SummaryRender; + fixed?: boolean; + position?: SummaryPosition; + }; // Customize id?: string; @@ -186,8 +192,6 @@ function Table(props: TableProps(props: TableProps = summary as any; + let summaryFixed: boolean = false; + let summaryPosition: SummaryPosition = 'bottom'; + + if (typeof summary === 'object') { + summaryRender = summary.render; + summary.fixed && (summaryFixed = summary.fixed); + summary.position && (summaryPosition = summary.position); + } + // ===================== Effects ====================== const [scrollbarSize, setScrollbarSize] = React.useState(0); @@ -564,7 +579,7 @@ function Table(props: TableProps width)} columns={flattenColumns} /> ); - const footerTable = summary &&
{summary(mergedData)}
; + const footerTable = summaryRender &&
{summaryRender(mergedData)}
; const customizeScrollBody = getComponent(['body']) as CustomizeScrollBody; const isTableFixed = fixHeader || isSticky; diff --git a/tests/Table.spec.js b/tests/Table.spec.js index 5d8fb96e7..865d87192 100644 --- a/tests/Table.spec.js +++ b/tests/Table.spec.js @@ -176,16 +176,18 @@ describe('Table.Basic', () => { { dataIndex: 'c', width: 30 }, ]} data={[{ key: 1, a: 2, b: 3, c: 4 }]} - summary={() => ( - - - Light - - Bamboo - - )} - summaryFixed - summaryPosition="top" + summary={{ + render: () => ( + + + Light + + Bamboo + + ), + fixed: true, + position: 'top', + }} scroll={{ x: 1200, y: 200 }} />, ); From f3bb01d08efb96bf76b2eb9af7110cdab2f71825 Mon Sep 17 00:00:00 2001 From: kingmui Date: Wed, 14 Oct 2020 19:21:50 +0800 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DCI=E6=8A=A5?= =?UTF-8?q?=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @typescript-eslint/no-unused-expressions --- src/Table.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Table.tsx b/src/Table.tsx index 2bd1bbf5a..7397708a6 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -132,11 +132,13 @@ export interface TableProps extends LegacyExpandableProps< // Additional Part title?: PanelRender; footer?: PanelRender; - summary?: SummaryRender | { - render: SummaryRender; - fixed?: boolean; - position?: SummaryPosition; - }; + summary?: + | SummaryRender + | { + render: SummaryRender; + fixed?: boolean; + position?: SummaryPosition; + }; // Customize id?: string; @@ -219,8 +221,8 @@ function Table(props: TableProps Date: Mon, 26 Oct 2020 23:40:56 +0800 Subject: [PATCH 6/9] =?UTF-8?q?fix:=20code=20review=20=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=94=B9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Table.tsx | 46 ++++++++++++++++++++--------------------- src/utils/valueUtil.tsx | 22 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/Table.tsx b/src/Table.tsx index 7397708a6..86028c130 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -60,7 +60,13 @@ import BodyContext from './context/BodyContext'; import Body from './Body'; import useColumns from './hooks/useColumns'; import { useLayoutState, useTimeoutLock } from './hooks/useFrame'; -import { getPathValue, mergeObject, validateValue, getColumnsKey } from './utils/valueUtil'; +import { + getPathValue, + mergeObject, + validateValue, + getColumnsKey, + isPlainObject, +} from './utils/valueUtil'; import ResizeContext from './context/ResizeContext'; import useStickyOffsets from './hooks/useStickyOffsets'; import ColGroup from './ColGroup'; @@ -78,6 +84,12 @@ const EMPTY_DATA = []; // Used for customize scroll const EMPTY_SCROLL_TARGET = {}; +// Used for body content render +const BODY_CONTENT_TYPE = { + body: 'body', + summary: 'summary', +}; + export const INTERNAL_HOOKS = 'rc-table-internal-hook'; interface MemoTableContentProps { @@ -91,11 +103,6 @@ type SummaryRender = (data: RecordType[]) => React.ReactNode; type SummaryPosition = 'top' | 'bottom'; -enum BodyContentTypeEnum { - body = 'body', - summary = 'summary', -} - const MemoTableContent = React.memo( ({ children }) => children as React.ReactElement, @@ -219,7 +226,7 @@ function Table(props: TableProps(props: TableProps { - const ref = { - [BodyContentTypeEnum.body]: scrollBodyRef, - [BodyContentTypeEnum.summary]: scrollSummaryRef, - }[type]; - - const tableContent = { - [BodyContentTypeEnum.body]: bodyTable, - [BodyContentTypeEnum.summary]: footerTable, - }[type]; + const getBodyContent = (type: string, mergeSummary?: boolean) => { + const ref = type === BODY_CONTENT_TYPE.body ? scrollBodyRef : scrollSummaryRef; + const tableContent = type === BODY_CONTENT_TYPE.body ? bodyTable : footerTable; return (
(props: TableProps {bodyColGroup} {tableContent} - {mergeSummary && type !== BodyContentTypeEnum.summary && footerTable} + {mergeSummary && type !== BODY_CONTENT_TYPE.summary && footerTable}
); @@ -659,12 +659,12 @@ function Table(props: TableProps - {footerTable && isSummaryShowTop && getBodyContent(BodyContentTypeEnum.summary)} - {getBodyContent(BodyContentTypeEnum.body)} - {footerTable && !isSummaryShowTop && getBodyContent(BodyContentTypeEnum.summary)} + {footerTable && isSummaryShowTop && getBodyContent(BODY_CONTENT_TYPE.summary)} + {getBodyContent(BODY_CONTENT_TYPE.body)} + {footerTable && !isSummaryShowTop && getBodyContent(BODY_CONTENT_TYPE.summary)} ) : ( - getBodyContent(BodyContentTypeEnum.body, true) + getBodyContent(BODY_CONTENT_TYPE.body, true) ); } diff --git a/src/utils/valueUtil.tsx b/src/utils/valueUtil.tsx index e4f224ec9..7f9b4fec4 100644 --- a/src/utils/valueUtil.tsx +++ b/src/utils/valueUtil.tsx @@ -1,5 +1,9 @@ import { Key, DataIndex } from '../interface'; +const { toString, hasOwnProperty } = Object.prototype; +const { toString: fnToString } = Function.prototype; +const objectCtorString = fnToString.call(Object); + const INTERNAL_KEY_PREFIX = 'RC_TABLE_KEY'; function toArray(arr: T | T[]): T[] { @@ -10,6 +14,10 @@ function toArray(arr: T | T[]): T[] { return Array.isArray(arr) ? arr : [arr]; } +function isObjectLike(value) { + return typeof value === 'object' && value !== null; +} + export function getPathValue( record: ObjectType, path: DataIndex, @@ -90,3 +98,17 @@ export function mergeObject( export function validateValue(val: T) { return val !== null && val !== undefined; } + +export function isPlainObject(value) { + if (!isObjectLike(value) || toString.call(value) !== '[object Object]') { + return false; + } + + const proto = Object.getPrototypeOf(value); + if (proto === null) { + return true; + } + + const Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor === 'function' && fnToString.call(Ctor) === objectCtorString; +} From 237db9cab59d91a5b1fc75eefcdd49a3d922fb06 Mon Sep 17 00:00:00 2001 From: kingmui Date: Tue, 3 Nov 2020 00:21:51 +0800 Subject: [PATCH 7/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dcode=20review?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Table.tsx | 37 +++++++++++++++---------------------- src/utils/valueUtil.tsx | 22 ---------------------- 2 files changed, 15 insertions(+), 44 deletions(-) diff --git a/src/Table.tsx b/src/Table.tsx index 86028c130..694cfec4c 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -60,13 +60,7 @@ import BodyContext from './context/BodyContext'; import Body from './Body'; import useColumns from './hooks/useColumns'; import { useLayoutState, useTimeoutLock } from './hooks/useFrame'; -import { - getPathValue, - mergeObject, - validateValue, - getColumnsKey, - isPlainObject, -} from './utils/valueUtil'; +import { getPathValue, mergeObject, validateValue, getColumnsKey } from './utils/valueUtil'; import ResizeContext from './context/ResizeContext'; import useStickyOffsets from './hooks/useStickyOffsets'; import ColGroup from './ColGroup'; @@ -85,10 +79,8 @@ const EMPTY_DATA = []; const EMPTY_SCROLL_TARGET = {}; // Used for body content render -const BODY_CONTENT_TYPE = { - body: 'body', - summary: 'summary', -}; +const BODY_CONTENT_TBODY = 'body'; +const BODY_CONTENT_TSUMMARY = 'summary'; export const INTERNAL_HOOKS = 'rc-table-internal-hook'; @@ -226,10 +218,10 @@ function Table(props: TableProps(props: TableProps { - const ref = type === BODY_CONTENT_TYPE.body ? scrollBodyRef : scrollSummaryRef; - const tableContent = type === BODY_CONTENT_TYPE.body ? bodyTable : footerTable; + const isBody = type === BODY_CONTENT_TBODY; + const ref = isBody ? scrollBodyRef : scrollSummaryRef; + const tableContent = isBody ? bodyTable : footerTable; return (
(props: TableProps {bodyColGroup} {tableContent} - {mergeSummary && type !== BODY_CONTENT_TYPE.summary && footerTable} + {mergeSummary && type !== BODY_CONTENT_TSUMMARY && footerTable}
); @@ -659,12 +652,12 @@ function Table(props: TableProps - {footerTable && isSummaryShowTop && getBodyContent(BODY_CONTENT_TYPE.summary)} - {getBodyContent(BODY_CONTENT_TYPE.body)} - {footerTable && !isSummaryShowTop && getBodyContent(BODY_CONTENT_TYPE.summary)} + {footerTable && isSummaryShowTop && getBodyContent(BODY_CONTENT_TSUMMARY)} + {getBodyContent(BODY_CONTENT_TBODY)} + {footerTable && !isSummaryShowTop && getBodyContent(BODY_CONTENT_TSUMMARY)} ) : ( - getBodyContent(BODY_CONTENT_TYPE.body, true) + getBodyContent(BODY_CONTENT_TBODY, true) ); } diff --git a/src/utils/valueUtil.tsx b/src/utils/valueUtil.tsx index 7f9b4fec4..e4f224ec9 100644 --- a/src/utils/valueUtil.tsx +++ b/src/utils/valueUtil.tsx @@ -1,9 +1,5 @@ import { Key, DataIndex } from '../interface'; -const { toString, hasOwnProperty } = Object.prototype; -const { toString: fnToString } = Function.prototype; -const objectCtorString = fnToString.call(Object); - const INTERNAL_KEY_PREFIX = 'RC_TABLE_KEY'; function toArray(arr: T | T[]): T[] { @@ -14,10 +10,6 @@ function toArray(arr: T | T[]): T[] { return Array.isArray(arr) ? arr : [arr]; } -function isObjectLike(value) { - return typeof value === 'object' && value !== null; -} - export function getPathValue( record: ObjectType, path: DataIndex, @@ -98,17 +90,3 @@ export function mergeObject( export function validateValue(val: T) { return val !== null && val !== undefined; } - -export function isPlainObject(value) { - if (!isObjectLike(value) || toString.call(value) !== '[object Object]') { - return false; - } - - const proto = Object.getPrototypeOf(value); - if (proto === null) { - return true; - } - - const Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; - return typeof Ctor === 'function' && fnToString.call(Ctor) === objectCtorString; -} From 45988a1bd6892a669b05915c9434fa9b67c11f8d Mon Sep 17 00:00:00 2001 From: kingmui Date: Sun, 8 Nov 2020 23:09:48 +0800 Subject: [PATCH 8/9] fix: summary miss scroll spacing when scrolled --- assets/index.less | 33 +++++++------ src/Footer/Cell.tsx | 64 ++++++++++++++++++-------- src/Header/FixedHeader.tsx | 57 ++++++++++------------- src/Table.tsx | 47 +++++++++++++++++-- src/context/TableContext.tsx | 8 +++- src/hooks/useCalcStickyOffsets.ts | 30 ++++++++++++ src/hooks/useScrollBarColumns.ts | 41 +++++++++++++++++ src/interface.ts | 2 + tests/__snapshots__/Table.spec.js.snap | 3 ++ 9 files changed, 214 insertions(+), 71 deletions(-) create mode 100644 src/hooks/useCalcStickyOffsets.ts create mode 100644 src/hooks/useScrollBarColumns.ts diff --git a/assets/index.less b/assets/index.less index 8dd653792..8cfa66765 100644 --- a/assets/index.less +++ b/assets/index.less @@ -18,6 +18,23 @@ border-bottom: 0; } +.cellScrollBar(@bgColor: #fff) { + .@{tablePrefixCls}-cell-scrollbar::after { + position: absolute; + content: ''; + top: 0; + bottom: 0; + left: -1px; + width: 1px; + background: @bgColor; + + .@{tablePrefixCls}-rtl& { + right: -1px; + left: auto; + } + } +} + .@{tablePrefixCls} { font-size: @font-size-base; color: @text-color; @@ -165,20 +182,7 @@ text-align: center; } - .@{tablePrefixCls}-cell-scrollbar::after { - position: absolute; - content: ''; - top: 0; - bottom: 0; - left: -1px; - width: 1px; - background: @table-head-background-color; - - .@{tablePrefixCls}-rtl& { - right: -1px; - left: auto; - } - } + .cellScrollBar(@table-head-background-color); } &-header { @@ -298,6 +302,7 @@ td { background: #fff; } + .cellScrollBar(); } &-sticky { &-header { diff --git a/src/Footer/Cell.tsx b/src/Footer/Cell.tsx index a8d562599..bb86aa297 100644 --- a/src/Footer/Cell.tsx +++ b/src/Footer/Cell.tsx @@ -20,27 +20,53 @@ export default function SummaryCell({ rowSpan, align, }: SummaryCellProps) { - const { prefixCls, fixedInfoList } = React.useContext(TableContext); + const { + prefixCls, + fixedInfoList, + summaryFixedInfoList, + columnsWithScrollbar, + isSummaryFixed, + } = React.useContext(TableContext); + + const fixedInfo = isSummaryFixed ? summaryFixedInfoList[index] : fixedInfoList[index]; + const summaryListLength = summaryFixedInfoList.length; + const summaryColumn = columnsWithScrollbar[summaryListLength - 1]; + + let additionalProps: React.HTMLAttributes; + + if (isSummaryFixed && summaryColumn.onHeaderCell) { + additionalProps = summaryColumn.onHeaderCell(summaryColumn); + } - const fixedInfo = fixedInfoList[index]; return ( - ({ - children, - props: { - colSpan, - rowSpan, - }, - })} - {...fixedInfo} - /> + <> + ({ + children, + props: { + colSpan, + rowSpan, + }, + })} + {...fixedInfo} + /> + { + isSummaryFixed && index === summaryListLength - 2 && + + } + ); } diff --git a/src/Header/FixedHeader.tsx b/src/Header/FixedHeader.tsx index 3a04172c5..8df523367 100644 --- a/src/Header/FixedHeader.tsx +++ b/src/Header/FixedHeader.tsx @@ -6,6 +6,8 @@ import Header, { HeaderProps } from './Header'; import ColGroup from '../ColGroup'; import { ColumnsType, ColumnType } from '../interface'; import TableContext from '../context/TableContext'; +import useScrollBarColumns from '../hooks/useScrollBarColumns'; +import useCalcStickyOffsets from '../hooks/useCalcStickyOffsets'; function useColumnWidth(colWidths: number[], columCount: number) { return useMemo(() => { @@ -53,8 +55,6 @@ const FixedHeader = React.forwardRef>( ) => { const { prefixCls, scrollbarSize, isSticky } = React.useContext(TableContext); - const combinationScrollBarSize = isSticky && !fixHeader ? 0 : scrollbarSize; - // Pass wheel to scroll event const scrollRef = React.useRef(null); @@ -79,38 +79,31 @@ const FixedHeader = React.forwardRef>( }, []); // Add scrollbar column - const lastColumn = flattenColumns[flattenColumns.length - 1]; - const ScrollBarColumn: ColumnType = { - fixed: lastColumn ? lastColumn.fixed : null, - onHeaderCell: () => ({ - className: `${prefixCls}-cell-scrollbar`, - }), - }; - - const columnsWithScrollbar = useMemo>( - () => (combinationScrollBarSize ? [...columns, ScrollBarColumn] : columns), - [combinationScrollBarSize, columns], - ); - - const flattenColumnsWithScrollbar = useMemo[]>( - () => (combinationScrollBarSize ? [...flattenColumns, ScrollBarColumn] : flattenColumns), - [combinationScrollBarSize, flattenColumns], - ); + const { combinationScrollBarSize, columnsWithScrollbar } = useScrollBarColumns>({ + columns, + prefixCls, + scrollbarSize, + isSticky, + fixHeader, + }); + + const { columnsWithScrollbar: flattenColumnsWithScrollbar } = useScrollBarColumns< + ColumnType[] + >({ + columns: flattenColumns, + prefixCls, + scrollbarSize, + isSticky, + fixHeader, + }); // Calculate the sticky offsets - const headerStickyOffsets = useMemo(() => { - const { right, left } = stickyOffsets; - return { - ...stickyOffsets, - left: - direction === 'rtl' ? [...left.map(width => width + combinationScrollBarSize), 0] : left, - right: - direction === 'rtl' - ? right - : [...right.map(width => width + combinationScrollBarSize), 0], - isSticky, - }; - }, [combinationScrollBarSize, stickyOffsets, isSticky]); + const headerStickyOffsets = useCalcStickyOffsets({ + stickyOffsets, + combinationScrollBarSize, + direction, + isSticky, + }); const mergedColumnWidth = useColumnWidth(colWidths, columCount); diff --git a/src/Table.tsx b/src/Table.tsx index 694cfec4c..7a3746e6a 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -54,6 +54,7 @@ import { ColumnType, CustomizeScrollBody, TableSticky, + TableDirection, } from './interface'; import TableContext from './context/TableContext'; import BodyContext from './context/BodyContext'; @@ -71,6 +72,8 @@ import { findAllChildrenKeys, renderExpandIcon } from './utils/expandUtil'; import { getCellFixedInfo } from './utils/fixUtil'; import StickyScrollBar from './stickyScrollBar'; import useSticky from './hooks/useSticky'; +import useScrollBarColumns from './hooks/useScrollBarColumns'; +import useCalcStickyOffsets from './hooks/useCalcStickyOffsets'; // Used for conditions cache const EMPTY_DATA = []; @@ -147,7 +150,7 @@ export interface TableProps extends LegacyExpandableProps< onHeaderRow?: GetComponentProps[]>; emptyText?: React.ReactNode | (() => React.ReactNode); - direction?: 'ltr' | 'rtl'; + direction?: TableDirection; // =================================== Internal =================================== /** @@ -422,6 +425,16 @@ function Table(props: TableProps[] + >({ + columns: flattenColumns, + prefixCls, + scrollbarSize, + isSticky, + fixHeader, + }); + if (fixHeader) { scrollYStyle = { overflowY: 'scroll', @@ -579,8 +592,17 @@ function Table(props: TableProps ); - const bodyColGroup = ( -
width)} columns={flattenColumns} /> + const flattenColWidths = flattenColumns.map(({ width }) => width); + + const BodyColGroup = () => ( + + ); + + const BodyColGroupWithScrollBar = () => ( + ); const footerTable = summaryRender && ; @@ -589,6 +611,7 @@ function Table(props: TableProps { const isBody = type === BODY_CONTENT_TBODY; @@ -611,7 +634,7 @@ function Table(props: TableProps - {bodyColGroup} + {!isBody && summaryFixed ? : } {tableContent} {mergeSummary && type !== BODY_CONTENT_TSUMMARY && footerTable} @@ -704,7 +727,7 @@ function Table(props: TableProps - {bodyColGroup} + {showHeader !== false &&
} {bodyTable} {footerTable} @@ -752,6 +775,13 @@ function Table(props: TableProps{fullTable}; } + const headerStickyOffsets = useCalcStickyOffsets({ + stickyOffsets, + combinationScrollBarSize, + direction, + isSticky, + }); + const TableContextValue = React.useMemo( () => ({ prefixCls, @@ -761,8 +791,13 @@ function Table(props: TableProps getCellFixedInfo(colIndex, colIndex, flattenColumns, stickyOffsets, direction), ), + summaryFixedInfoList: columnsWithScrollbar.map((_, colIndex) => + getCellFixedInfo(colIndex, colIndex, columnsWithScrollbar, headerStickyOffsets, direction), + ), + columnsWithScrollbar, isSticky, isSummaryShowTop, + isSummaryFixed, }), [ prefixCls, @@ -770,10 +805,12 @@ function Table(props: TableProps[]; + isSticky: boolean; isSummaryShowTop: boolean; + + isSummaryFixed: boolean; } const TableContext = React.createContext(null); diff --git a/src/hooks/useCalcStickyOffsets.ts b/src/hooks/useCalcStickyOffsets.ts new file mode 100644 index 000000000..60762c270 --- /dev/null +++ b/src/hooks/useCalcStickyOffsets.ts @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { StickyOffsets, TableDirection } from '../interface'; + +interface ICalcStickyOffsets { + stickyOffsets: StickyOffsets; + combinationScrollBarSize: number; + direction: TableDirection; + isSticky: boolean; +} + +export default function useCalcStickyOffsets({ + stickyOffsets, + combinationScrollBarSize, + direction, + isSticky, +}: ICalcStickyOffsets): StickyOffsets { + const headerStickyOffsets = React.useMemo(() => { + const { right, left } = stickyOffsets; + return { + ...stickyOffsets, + left: + direction === 'rtl' ? [...left.map(width => width + combinationScrollBarSize), 0] : left, + right: + direction === 'rtl' ? right : [...right.map(width => width + combinationScrollBarSize), 0], + isSticky, + }; + }, [combinationScrollBarSize, stickyOffsets, isSticky]); + + return headerStickyOffsets; +} diff --git a/src/hooks/useScrollBarColumns.ts b/src/hooks/useScrollBarColumns.ts new file mode 100644 index 000000000..f24bd7822 --- /dev/null +++ b/src/hooks/useScrollBarColumns.ts @@ -0,0 +1,41 @@ +import * as React from 'react'; +import { ColumnType } from '../interface'; + +interface IScrollBarColumns { + columns: any; + prefixCls: string; + scrollbarSize: number; + isSticky: boolean; + fixHeader: boolean; +} + +export default function useScrollBarColumns({ + columns, + prefixCls, + scrollbarSize, + isSticky, + fixHeader, +}: IScrollBarColumns): { + combinationScrollBarSize: number; + columnsWithScrollbar: T; +} { + const combinationScrollBarSize = isSticky && !fixHeader ? 0 : scrollbarSize; + + const lastColumn = columns[columns.length - 1]; + const ScrollBarColumn: ColumnType = { + fixed: lastColumn ? lastColumn.fixed : null, + onHeaderCell: () => ({ + className: `${prefixCls}-cell-scrollbar`, + }), + }; + + const columnsWithScrollbar = React.useMemo( + () => (combinationScrollBarSize ? [...columns, ScrollBarColumn] : columns), + [combinationScrollBarSize, columns], + ); + + return { + combinationScrollBarSize, + columnsWithScrollbar, + }; +} diff --git a/src/interface.ts b/src/interface.ts index d0766c775..6acf483ea 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -25,6 +25,8 @@ export type DefaultRecordType = Record; export type TableLayout = 'auto' | 'fixed'; +export type TableDirection = 'ltr' | 'rtl'; + // ==================== Row ===================== export type RowClassName = ( record: RecordType, diff --git a/tests/__snapshots__/Table.spec.js.snap b/tests/__snapshots__/Table.spec.js.snap index 9881c87e6..991a09865 100644 --- a/tests/__snapshots__/Table.spec.js.snap +++ b/tests/__snapshots__/Table.spec.js.snap @@ -779,6 +779,9 @@ exports[`Table.Basic summary support data type 2`] = ` > Bamboo +
`; From 194d60f3791383c7ff295205465217178ff4f092 Mon Sep 17 00:00:00 2001 From: kingmui Date: Sat, 16 Jan 2021 10:15:13 +0800 Subject: [PATCH 9/9] refactor: Adjust the logic of adding the summary scroll bar column --- src/Footer/Cell.tsx | 64 ++++++++++++-------------------------- src/Footer/Row.tsx | 35 +++++++++++++++++++-- src/Header/FixedHeader.tsx | 2 +- 3 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/Footer/Cell.tsx b/src/Footer/Cell.tsx index bb86aa297..1b45c00a4 100644 --- a/src/Footer/Cell.tsx +++ b/src/Footer/Cell.tsx @@ -20,53 +20,29 @@ export default function SummaryCell({ rowSpan, align, }: SummaryCellProps) { - const { - prefixCls, - fixedInfoList, - summaryFixedInfoList, - columnsWithScrollbar, - isSummaryFixed, - } = React.useContext(TableContext); + const { prefixCls, isSummaryFixed, fixedInfoList, summaryFixedInfoList } = React.useContext( + TableContext, + ); const fixedInfo = isSummaryFixed ? summaryFixedInfoList[index] : fixedInfoList[index]; - const summaryListLength = summaryFixedInfoList.length; - const summaryColumn = columnsWithScrollbar[summaryListLength - 1]; - - let additionalProps: React.HTMLAttributes; - - if (isSummaryFixed && summaryColumn.onHeaderCell) { - additionalProps = summaryColumn.onHeaderCell(summaryColumn); - } - return ( - <> - ({ - children, - props: { - colSpan, - rowSpan, - }, - })} - {...fixedInfo} - /> - { - isSummaryFixed && index === summaryListLength - 2 && - - } - + ({ + children, + props: { + colSpan, + rowSpan, + }, + })} + {...fixedInfo} + /> ); } diff --git a/src/Footer/Row.tsx b/src/Footer/Row.tsx index e86a8b46e..926861e3b 100644 --- a/src/Footer/Row.tsx +++ b/src/Footer/Row.tsx @@ -1,4 +1,6 @@ import * as React from 'react'; +import Cell from '../Cell'; +import TableContext from '../context/TableContext'; export interface FooterRowProps { children?: React.ReactNode; @@ -6,6 +8,35 @@ export interface FooterRowProps { style?: React.CSSProperties; } -export default function FooterRow(props: FooterRowProps) { - return ; +export default function FooterRow({ children, ...props }: FooterRowProps) { + const { + prefixCls, + scrollbarSize, + isSummaryFixed, + summaryFixedInfoList, + columnsWithScrollbar, + } = React.useContext(TableContext); + + const summaryListLength = summaryFixedInfoList.length; + const summaryColumn = columnsWithScrollbar[summaryListLength - 1]; + + let additionalProps: React.HTMLAttributes; + + if (isSummaryFixed && summaryColumn.onHeaderCell) { + additionalProps = summaryColumn.onHeaderCell(summaryColumn); + } + + return ( + + {children} + {isSummaryFixed && !!scrollbarSize && ( + + )} + + ); } diff --git a/src/Header/FixedHeader.tsx b/src/Header/FixedHeader.tsx index 8df523367..e684dded7 100644 --- a/src/Header/FixedHeader.tsx +++ b/src/Header/FixedHeader.tsx @@ -86,7 +86,7 @@ const FixedHeader = React.forwardRef>( isSticky, fixHeader, }); - + const { columnsWithScrollbar: flattenColumnsWithScrollbar } = useScrollBarColumns< ColumnType[] >({
`; +exports[`Table.Basic summary support data type 2`] = ` +
+ Light + + Bamboo +