From 1b4501d7bfe45d662a20e4db81b65cb8483066db Mon Sep 17 00:00:00 2001 From: Chloe Rice Date: Thu, 23 May 2019 16:08:20 -0400 Subject: [PATCH 1/9] start shifting language away from fixed column logic --- src/components/DataTable/DataTable.scss | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/DataTable/DataTable.scss b/src/components/DataTable/DataTable.scss index 51150e7dd16..3db7a0d48ea 100644 --- a/src/components/DataTable/DataTable.scss +++ b/src/components/DataTable/DataTable.scss @@ -1,4 +1,4 @@ -$fixed-column-width: rem(145px); +$first-column-width: rem(145px); $breakpoint: 768px; .DataTable { @@ -26,7 +26,7 @@ $breakpoint: 768px; } .ScrollContainer { - margin-left: rem($fixed-column-width); + margin-left: rem($first-column-width); } } @@ -71,7 +71,7 @@ $breakpoint: 768px; position: absolute; top: 0; bottom: 0; - left: $fixed-column-width; + left: $first-column-width; display: none; width: rem(6px); background: linear-gradient( @@ -111,9 +111,10 @@ $breakpoint: 768px; @include text-emphasis-normal; @include text-breakword; position: absolute; + z-index: 5; top: auto; left: 0; - width: $fixed-column-width; + width: $first-column-width; white-space: unset; text-align: left; backface-visibility: hidden; // stops painting on scroll (due to positioning) From 63aedf56e0b58567828241331e1f5d3f8509cc45 Mon Sep 17 00:00:00 2001 From: Chloe Rice Date: Thu, 30 May 2019 12:53:59 -0400 Subject: [PATCH 2/9] fixed column => first column --- src/components/DataTable/DataTable.scss | 47 ++++--------------- src/components/DataTable/DataTable.tsx | 6 +-- .../DataTable/components/Cell/Cell.tsx | 10 ++-- 3 files changed, 16 insertions(+), 47 deletions(-) diff --git a/src/components/DataTable/DataTable.scss b/src/components/DataTable/DataTable.scss index 3db7a0d48ea..4b104405321 100644 --- a/src/components/DataTable/DataTable.scss +++ b/src/components/DataTable/DataTable.scss @@ -7,12 +7,6 @@ $breakpoint: 768px; } .collapsed { - .Table { - &::after { - display: block; - } - } - .Navigation { display: flex; align-items: center; @@ -24,10 +18,6 @@ $breakpoint: 768px; justify-content: flex-end; } } - - .ScrollContainer { - margin-left: rem($first-column-width); - } } .hasFooter { @@ -57,29 +47,12 @@ $breakpoint: 768px; .ScrollContainer { overflow-x: auto; - // account for a mysterious gap in Safari when not collapsed - margin-left: rem(140px); -webkit-overflow-scrolling: touch; } .Table { width: 100%; border-spacing: 0; - - &::after { - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: $first-column-width; - display: none; - width: rem(6px); - background: linear-gradient( - to right, - rgba(color('black'), 0.12), - rgba(color('black'), 0) - ); - } } .TableRow { @@ -103,21 +76,17 @@ $breakpoint: 768px; vertical-align: top; } -.Cell-numeric { - text-align: right; -} - -.Cell-fixed { +.Cell-firstColumn { @include text-emphasis-normal; @include text-breakword; - position: absolute; - z-index: 5; - top: auto; - left: 0; - width: $first-column-width; - white-space: unset; + min-width: $first-column-width; + max-width: $first-column-width; text-align: left; - backface-visibility: hidden; // stops painting on scroll (due to positioning) + white-space: normal; +} + +.Cell-numeric { + text-align: right; } .Cell-truncated { diff --git a/src/components/DataTable/DataTable.tsx b/src/components/DataTable/DataTable.tsx index acdfbae1f82..4541e8d50ae 100644 --- a/src/components/DataTable/DataTable.tsx +++ b/src/components/DataTable/DataTable.tsx @@ -189,7 +189,7 @@ class DataTable extends React.PureComponent { height={height} content={heading} contentType={columnContentTypes[headingIndex]} - fixed={headingIndex === 0} + firstColumn={headingIndex === 0} truncate={truncate} {...sortableHeadingProps} /> @@ -388,7 +388,7 @@ class DataTable extends React.PureComponent { return ( { height={bodyCellHeights[index]} content={content} contentType={columnContentTypes[cellIndex]} - fixed={cellIndex === 0} + firstColumn={cellIndex === 0} truncate={truncate} /> ); diff --git a/src/components/DataTable/components/Cell/Cell.tsx b/src/components/DataTable/components/Cell/Cell.tsx index 035b7b27c64..d2226fa0fbf 100644 --- a/src/components/DataTable/components/Cell/Cell.tsx +++ b/src/components/DataTable/components/Cell/Cell.tsx @@ -14,7 +14,7 @@ export interface Props { height?: number; content?: React.ReactNode; contentType?: string; - fixed?: boolean; + firstColumn?: boolean; truncate?: boolean; header?: boolean; total?: boolean; @@ -32,7 +32,7 @@ function Cell({ height, content, contentType, - fixed, + firstColumn, truncate, header, total, @@ -50,8 +50,8 @@ function Cell({ const className = classNames( styles.Cell, - fixed && styles['Cell-fixed'], - fixed && truncate && styles['Cell-truncated'], + firstColumn && styles['Cell-firstColumn'], + firstColumn && truncate && styles['Cell-truncated'], header && styles['Cell-header'], total && styles['Cell-total'], footer && styles['Cell-footer'], @@ -113,7 +113,7 @@ function Cell({ ); const cellMarkup = - header || fixed ? ( + header || firstColumn ? ( headingMarkup ) : ( From 91f8387b0336416bd896580501817e1e527c7aff Mon Sep 17 00:00:00 2001 From: Chloe Rice Date: Thu, 30 May 2019 12:54:19 -0400 Subject: [PATCH 3/9] fix small screen navigation --- UNRELEASED.md | 1 + src/components/DataTable/DataTable.scss | 2 -- src/components/DataTable/DataTable.tsx | 47 ++++++++++++------------- src/components/DataTable/utilities.ts | 4 +-- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/UNRELEASED.md b/UNRELEASED.md index ff05efd7f83..142666c2aa8 100644 --- a/UNRELEASED.md +++ b/UNRELEASED.md @@ -27,6 +27,7 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f ### Bug fixes - Fixes `monochrome` variant of `Link` and `Button` components to support multi-line link text ([#1686](https://github.com/Shopify/polaris-react/pull/1686)) +- Fixed the first column of `DataTable` not rendering in iOS Safari (([#1605](https://github.com/Shopify/polaris-react/pull/1605)) ### Documentation diff --git a/src/components/DataTable/DataTable.scss b/src/components/DataTable/DataTable.scss index 4b104405321..8890541744b 100644 --- a/src/components/DataTable/DataTable.scss +++ b/src/components/DataTable/DataTable.scss @@ -79,8 +79,6 @@ $breakpoint: 768px; .Cell-firstColumn { @include text-emphasis-normal; @include text-breakword; - min-width: $first-column-width; - max-width: $first-column-width; text-align: left; white-space: normal; } diff --git a/src/components/DataTable/DataTable.tsx b/src/components/DataTable/DataTable.tsx index 4541e8d50ae..f8049677a06 100644 --- a/src/components/DataTable/DataTable.tsx +++ b/src/components/DataTable/DataTable.tsx @@ -70,11 +70,14 @@ class DataTable extends React.PureComponent { table: {current: table}, scrollContainer: {current: scrollContainer}, } = this; + let collapsed = false; + if (table && scrollContainer) { collapsed = table.scrollWidth > scrollContainer.clientWidth; scrollContainer.scrollLeft = 0; } + this.setState( { collapsed, @@ -249,8 +252,8 @@ class DataTable extends React.PureComponent { if (!truncate) { return (heights = rows.map((row) => { - const fixedCell = (row.childNodes as NodeListOf)[0]; - return Math.max(row.clientHeight, fixedCell.clientHeight); + const firstCell = (row.childNodes as NodeListOf)[0]; + return Math.max(row.clientHeight, firstCell.clientHeight); })); } @@ -265,16 +268,15 @@ class DataTable extends React.PureComponent { }; private resetScrollPosition = () => { - const { - scrollContainer: {current: scrollContainer}, - } = this; + const {current: scrollContainer} = this.scrollContainer; + if (scrollContainer) { - const { - preservedScrollPosition: {left, top}, - } = this.state; + const {left, top} = this.state.preservedScrollPosition; + if (left) { scrollContainer.scrollLeft = left; } + if (top) { window.scrollTo(0, top); } @@ -294,35 +296,34 @@ class DataTable extends React.PureComponent { scrollContainer: {current: scrollContainer}, dataTable: {current: dataTable}, } = this; + if (collapsed && table && scrollContainer && dataTable) { const headerCells = table.querySelectorAll( headerCell.selector, ) as NodeListOf; - const collapsedHeaderCells = Array.from(headerCells).slice(1); - const fixedColumnWidth = headerCells[0].offsetWidth; - const firstVisibleColumnIndex = collapsedHeaderCells.length - 1; - const tableLeftVisibleEdge = - scrollContainer.scrollLeft + fixedColumnWidth; + + const firstVisibleColumnIndex = headerCells.length - 1; + const tableLeftVisibleEdge = scrollContainer.scrollLeft; + const tableRightVisibleEdge = scrollContainer.scrollLeft + dataTable.offsetWidth; + const tableData = { - fixedColumnWidth, firstVisibleColumnIndex, tableLeftVisibleEdge, tableRightVisibleEdge, }; - const columnVisibilityData = collapsedHeaderCells.map( + const columnVisibilityData = Array.from(headerCells).map( measureColumn(tableData), ); const lastColumn = columnVisibilityData[columnVisibilityData.length - 1]; return { - fixedColumnWidth, columnVisibilityData, ...getPrevAndCurrentColumns(tableData, columnVisibilityData), - isScrolledFarthestLeft: tableLeftVisibleEdge === fixedColumnWidth, + isScrolledFarthestLeft: tableLeftVisibleEdge === 0, isScrolledFarthestRight: lastColumn.rightEdge <= tableRightVisibleEdge, }; } @@ -341,21 +342,19 @@ class DataTable extends React.PureComponent { }; private navigateTable = (direction: string) => { - const {currentColumn, previousColumn, fixedColumnWidth} = this.state; - const { - scrollContainer: {current: scrollContainer}, - } = this; + const {currentColumn, previousColumn} = this.state; + const {current: scrollContainer} = this.scrollContainer; const handleScroll = () => { - if (!currentColumn || !previousColumn || !fixedColumnWidth) { + if (!currentColumn || !previousColumn) { return; } if (scrollContainer) { scrollContainer.scrollLeft = direction === 'right' - ? currentColumn.rightEdge - fixedColumnWidth - : previousColumn.leftEdge - fixedColumnWidth; + ? currentColumn.rightEdge + : previousColumn.leftEdge; requestAnimationFrame(() => { this.setState((prevState) => ({ diff --git a/src/components/DataTable/utilities.ts b/src/components/DataTable/utilities.ts index 507fef9fe41..1947b178297 100644 --- a/src/components/DataTable/utilities.ts +++ b/src/components/DataTable/utilities.ts @@ -1,7 +1,6 @@ import {DataTableState} from './types'; interface TableMeasurements { - fixedColumnWidth: number; firstVisibleColumnIndex: number; tableLeftVisibleEdge: number; tableRightVisibleEdge: number; @@ -13,10 +12,9 @@ export function measureColumn(tableData: TableMeasurements) { firstVisibleColumnIndex, tableLeftVisibleEdge: tableStart, tableRightVisibleEdge: tableEnd, - fixedColumnWidth, } = tableData; - const leftEdge = column.offsetLeft + fixedColumnWidth; + const leftEdge = column.offsetLeft; const rightEdge = leftEdge + column.offsetWidth; const isVisibleLeft = isEdgeVisible(leftEdge, tableStart, tableEnd); const isVisibleRight = isEdgeVisible(rightEdge, tableStart, tableEnd); From 1e1fbbb581f0e062fe97a1126223de0c3d3f202c Mon Sep 17 00:00:00 2001 From: Chloe Rice Date: Mon, 17 Jun 2019 20:48:41 -0400 Subject: [PATCH 4/9] collapsed => condensed --- src/components/DataTable/DataTable.scss | 3 +-- src/components/DataTable/DataTable.tsx | 24 ++++++++++++------------ src/components/DataTable/types.ts | 2 +- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/components/DataTable/DataTable.scss b/src/components/DataTable/DataTable.scss index 8890541744b..ba024b2af97 100644 --- a/src/components/DataTable/DataTable.scss +++ b/src/components/DataTable/DataTable.scss @@ -6,7 +6,7 @@ $breakpoint: 768px; max-width: 100vw; } -.collapsed { +.condensed { .Navigation { display: flex; align-items: center; @@ -78,7 +78,6 @@ $breakpoint: 768px; .Cell-firstColumn { @include text-emphasis-normal; - @include text-breakword; text-align: left; white-space: normal; } diff --git a/src/components/DataTable/DataTable.tsx b/src/components/DataTable/DataTable.tsx index f8049677a06..05eccc83755 100644 --- a/src/components/DataTable/DataTable.tsx +++ b/src/components/DataTable/DataTable.tsx @@ -51,7 +51,7 @@ export interface Props { class DataTable extends React.PureComponent { state: DataTableState = { - collapsed: false, + condensed: false, columnVisibilityData: [], heights: [], preservedScrollPosition: {}, @@ -71,18 +71,18 @@ class DataTable extends React.PureComponent { scrollContainer: {current: scrollContainer}, } = this; - let collapsed = false; + let condensed = false; if (table && scrollContainer) { - collapsed = table.scrollWidth > scrollContainer.clientWidth; + condensed = table.scrollWidth > scrollContainer.clientWidth; scrollContainer.scrollLeft = 0; } this.setState( { - collapsed, + condensed, heights: [], - ...this.calculateColumnVisibilityData(collapsed), + ...this.calculateColumnVisibilityData(condensed), }, () => { if (footerContent || !truncate) { @@ -130,7 +130,7 @@ class DataTable extends React.PureComponent { } = this.props; const { - collapsed, + condensed, columnVisibilityData, heights, sortedColumnIndex = initialSortColumnIndex, @@ -141,13 +141,13 @@ class DataTable extends React.PureComponent { const className = classNames( styles.DataTable, - collapsed && styles.collapsed, + condensed && styles.condensed, footerContent && styles.hasFooter, ); const wrapperClassName = classNames( styles.TableWrapper, - collapsed && styles.collapsed, + condensed && styles.condensed, ); const footerClassName = classNames(footerContent && styles.TableFoot); @@ -290,14 +290,14 @@ class DataTable extends React.PureComponent { ); }; - private calculateColumnVisibilityData = (collapsed: boolean) => { + private calculateColumnVisibilityData = (condensed: boolean) => { const { table: {current: table}, scrollContainer: {current: scrollContainer}, dataTable: {current: dataTable}, } = this; - if (collapsed && table && scrollContainer && dataTable) { + if (condensed && table && scrollContainer && dataTable) { const headerCells = table.querySelectorAll( headerCell.selector, ) as NodeListOf; @@ -337,7 +337,7 @@ class DataTable extends React.PureComponent { private scrollListener = () => { this.setState((prevState) => ({ - ...this.calculateColumnVisibilityData(prevState.collapsed), + ...this.calculateColumnVisibilityData(prevState.condensed), })); }; @@ -358,7 +358,7 @@ class DataTable extends React.PureComponent { requestAnimationFrame(() => { this.setState((prevState) => ({ - ...this.calculateColumnVisibilityData(prevState.collapsed), + ...this.calculateColumnVisibilityData(prevState.condensed), })); }); } diff --git a/src/components/DataTable/types.ts b/src/components/DataTable/types.ts index 8171f43eb46..5c2c79af5e8 100644 --- a/src/components/DataTable/types.ts +++ b/src/components/DataTable/types.ts @@ -12,7 +12,7 @@ interface ScrollPosition { } export interface DataTableState { - collapsed: boolean; + condensed: boolean; columnVisibilityData: ColumnVisibilityData[]; previousColumn?: ColumnVisibilityData; currentColumn?: ColumnVisibilityData; From 8b568f5afd53ee76ad15f63a8c51fbf607a01644 Mon Sep 17 00:00:00 2001 From: Chloe Rice Date: Mon, 17 Jun 2019 21:03:17 -0400 Subject: [PATCH 5/9] :fire: row height mgmt --- src/components/DataTable/DataTable.tsx | 108 ++----------------------- src/components/DataTable/types.ts | 8 -- 2 files changed, 6 insertions(+), 110 deletions(-) diff --git a/src/components/DataTable/DataTable.tsx b/src/components/DataTable/DataTable.tsx index 05eccc83755..cf2503bfdde 100644 --- a/src/components/DataTable/DataTable.tsx +++ b/src/components/DataTable/DataTable.tsx @@ -53,8 +53,6 @@ class DataTable extends React.PureComponent { state: DataTableState = { condensed: false, columnVisibilityData: [], - heights: [], - preservedScrollPosition: {}, isScrolledFarthestLeft: true, isScrolledFarthestRight: false, }; @@ -65,7 +63,6 @@ class DataTable extends React.PureComponent { private totalsRowHeading: string; private handleResize = debounce(() => { - const {footerContent, truncate} = this.props; const { table: {current: table}, scrollContainer: {current: scrollContainer}, @@ -75,21 +72,12 @@ class DataTable extends React.PureComponent { if (table && scrollContainer) { condensed = table.scrollWidth > scrollContainer.clientWidth; - scrollContainer.scrollLeft = 0; } - this.setState( - { - condensed, - heights: [], - ...this.calculateColumnVisibilityData(condensed), - }, - () => { - if (footerContent || !truncate) { - this.setHeightsAndScrollPosition(); - } - }, - ); + this.setState({ + condensed, + ...this.calculateColumnVisibilityData(condensed), + }); }); constructor(props: CombinedProps) { @@ -132,7 +120,6 @@ class DataTable extends React.PureComponent { const { condensed, columnVisibilityData, - heights, sortedColumnIndex = initialSortColumnIndex, sortDirection = defaultSortDirection, isScrolledFarthestLeft, @@ -182,14 +169,11 @@ class DataTable extends React.PureComponent { }; } - const height = !truncate ? heights[0] : undefined; - return ( { ); const bodyMarkup = rows.map(this.defaultRenderRow); - const style = footerContent - ? {marginBottom: `${heights[heights.length - 1]}px`} - : undefined; return (
@@ -216,11 +197,7 @@ class DataTable extends React.PureComponent { navigateTableRight={this.navigateTable('right')} />
-
+
{ ); } - private tallestCellHeights = () => { - const {footerContent, truncate} = this.props; - const { - table: {current: table}, - } = this; - let {heights} = this.state; - if (table) { - const rows = Array.from(table.getElementsByTagName('tr')); - - if (!truncate) { - return (heights = rows.map((row) => { - const firstCell = (row.childNodes as NodeListOf)[0]; - return Math.max(row.clientHeight, firstCell.clientHeight); - })); - } - - if (footerContent) { - const footerCellHeight = (rows[rows.length - 1] - .childNodes as NodeListOf)[0].clientHeight; - heights = [footerCellHeight]; - } - } - - return heights; - }; - - private resetScrollPosition = () => { - const {current: scrollContainer} = this.scrollContainer; - - if (scrollContainer) { - const {left, top} = this.state.preservedScrollPosition; - - if (left) { - scrollContainer.scrollLeft = left; - } - - if (top) { - window.scrollTo(0, top); - } - } - }; - - private setHeightsAndScrollPosition = () => { - this.setState( - {heights: this.tallestCellHeights()}, - this.resetScrollPosition, - ); - }; - private calculateColumnVisibilityData = (condensed: boolean) => { const { table: {current: table}, @@ -369,7 +297,6 @@ class DataTable extends React.PureComponent { private renderTotals = (total: TableData, index: number) => { const id = `totals-cell-${index}`; - const {heights} = this.state; const {truncate = false} = this.props; let content; @@ -390,7 +317,6 @@ class DataTable extends React.PureComponent { firstColumn={index === 0} testID={id} key={id} - height={heights[1]} content={content} contentType={contentType} truncate={truncate} @@ -400,18 +326,7 @@ class DataTable extends React.PureComponent { private defaultRenderRow = (row: TableData[], index: number) => { const className = classNames(styles.TableRow); - const { - columnContentTypes, - totals, - footerContent, - truncate = false, - } = this.props; - const {heights} = this.state; - const bodyCellHeights = totals ? heights.slice(2) : heights.slice(1); - - if (footerContent) { - bodyCellHeights.pop(); - } + const {columnContentTypes, truncate = false} = this.props; return ( @@ -422,7 +337,6 @@ class DataTable extends React.PureComponent { { }; private renderFooter = () => { - const {heights} = this.state; - const footerCellHeight = heights[heights.length - 1]; - return ( @@ -480,12 +390,6 @@ class DataTable extends React.PureComponent { onSort(headingIndex, newSortDirection); if (!truncate && this.scrollContainer.current) { - const preservedScrollPosition = { - left: this.scrollContainer.current.scrollLeft, - top: window.scrollY, - }; - - this.setState({preservedScrollPosition}); this.handleResize(); } } diff --git a/src/components/DataTable/types.ts b/src/components/DataTable/types.ts index 5c2c79af5e8..fbc241cc1b0 100644 --- a/src/components/DataTable/types.ts +++ b/src/components/DataTable/types.ts @@ -6,11 +6,6 @@ export interface ColumnVisibilityData { isVisible?: boolean; } -interface ScrollPosition { - left?: number; - top?: number; -} - export interface DataTableState { condensed: boolean; columnVisibilityData: ColumnVisibilityData[]; @@ -18,9 +13,6 @@ export interface DataTableState { currentColumn?: ColumnVisibilityData; sortedColumnIndex?: number; sortDirection?: SortDirection; - heights: number[]; - fixedColumnWidth?: number; - preservedScrollPosition: ScrollPosition; isScrolledFarthestLeft?: boolean; isScrolledFarthestRight?: boolean; } From e63ec8a3205dc62e0a664ca1280fee903ebde9b9 Mon Sep 17 00:00:00 2001 From: Chloe Rice Date: Mon, 17 Jun 2019 21:18:52 -0400 Subject: [PATCH 6/9] reinstate max-width for truncated first column --- src/components/DataTable/DataTable.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/DataTable/DataTable.scss b/src/components/DataTable/DataTable.scss index ba024b2af97..0b847926928 100644 --- a/src/components/DataTable/DataTable.scss +++ b/src/components/DataTable/DataTable.scss @@ -90,6 +90,7 @@ $breakpoint: 768px; white-space: nowrap; overflow-x: hidden; text-overflow: ellipsis; + max-width: $first-column-width; } .Cell-header { From d46e3c5299e67ecd44aeb035b3d838c9f00f7f77 Mon Sep 17 00:00:00 2001 From: Chloe Rice Date: Mon, 17 Jun 2019 22:34:57 -0400 Subject: [PATCH 7/9] :fire: footer position management --- src/components/DataTable/DataTable.scss | 21 ++---------- src/components/DataTable/DataTable.tsx | 33 +++++-------------- .../DataTable/components/Cell/Cell.tsx | 18 ++-------- 3 files changed, 13 insertions(+), 59 deletions(-) diff --git a/src/components/DataTable/DataTable.scss b/src/components/DataTable/DataTable.scss index 0b847926928..bae2c9001ac 100644 --- a/src/components/DataTable/DataTable.scss +++ b/src/components/DataTable/DataTable.scss @@ -20,12 +20,6 @@ $breakpoint: 768px; } } -.hasFooter { - .ScrollContainer { - margin-bottom: rem(52px); - } -} - .Navigation { display: none; } @@ -63,10 +57,6 @@ $breakpoint: 768px; } } -.TableFoot { - border-bottom: 0; -} - .Cell { padding: spacing(); border-bottom: border-width() solid color('sky', 'light'); @@ -148,16 +138,9 @@ $breakpoint: 768px; border-bottom: border(); } -.Cell-footer { - @include text-emphasis-normal; - position: absolute; - top: 100%; - left: 0; - width: 100%; - border-bottom: 0; +.Footer { + padding: spacing(); background: color('sky', 'light'); color: color('ink', 'lighter'); - white-space: unset; text-align: center; - backface-visibility: hidden; // stop painting on scroll (due to positioning) } diff --git a/src/components/DataTable/DataTable.tsx b/src/components/DataTable/DataTable.tsx index cf2503bfdde..5d38bf40d45 100644 --- a/src/components/DataTable/DataTable.tsx +++ b/src/components/DataTable/DataTable.tsx @@ -137,18 +137,6 @@ class DataTable extends React.PureComponent { condensed && styles.condensed, ); - const footerClassName = classNames(footerContent && styles.TableFoot); - - const footerMarkup = footerContent ? ( - - {this.renderFooter()} - - ) : null; - - const totalsMarkup = totals ? ( - {totals.map(this.renderTotals)} - ) : null; - const headingMarkup = ( {headings.map((heading, headingIndex) => { @@ -185,8 +173,16 @@ class DataTable extends React.PureComponent { ); + const totalsMarkup = totals ? ( + {totals.map(this.renderTotals)} + ) : null; + const bodyMarkup = rows.map(this.defaultRenderRow); + const footerMarkup = footerContent ? ( +
{footerContent}
+ ) : null; + return (
{ {totalsMarkup} {bodyMarkup} - {footerMarkup}
+ {footerMarkup}
); @@ -348,17 +344,6 @@ class DataTable extends React.PureComponent { ); }; - private renderFooter = () => { - return ( - - ); - }; - private defaultOnSort = (headingIndex: number) => { const { onSort, diff --git a/src/components/DataTable/components/Cell/Cell.tsx b/src/components/DataTable/components/Cell/Cell.tsx index d2226fa0fbf..b4f069f54fc 100644 --- a/src/components/DataTable/components/Cell/Cell.tsx +++ b/src/components/DataTable/components/Cell/Cell.tsx @@ -11,14 +11,12 @@ import styles from '../../DataTable.scss'; export interface Props { testID?: string; - height?: number; content?: React.ReactNode; contentType?: string; firstColumn?: boolean; truncate?: boolean; header?: boolean; total?: boolean; - footer?: boolean; sorted?: boolean; sortable?: boolean; sortDirection?: SortDirection; @@ -29,14 +27,12 @@ export interface Props { type CombinedProps = Props & WithAppProviderProps; function Cell({ - height, content, contentType, firstColumn, truncate, header, total, - footer, sorted, sortable, sortDirection, @@ -47,14 +43,12 @@ function Cell({ onSort, }: CombinedProps) { const numeric = contentType === 'numeric'; - const className = classNames( styles.Cell, firstColumn && styles['Cell-firstColumn'], firstColumn && truncate && styles['Cell-truncated'], header && styles['Cell-header'], total && styles['Cell-total'], - footer && styles['Cell-footer'], numeric && styles['Cell-numeric'], sortable && styles['Cell-sortable'], sorted && styles['Cell-sorted'], @@ -66,11 +60,6 @@ function Cell({ ); const iconClassName = classNames(sortable && styles.Icon); - - const style = { - height: height ? `${height}px` : undefined, - }; - const direction = sorted ? sortDirection : defaultSortDirection; const source = direction === 'ascending' ? CaretUpMinor : CaretDownMinor; const oppositeDirection = @@ -102,12 +91,11 @@ function Cell({ className={className} scope="col" aria-sort={sortDirection} - style={style} > {columnHeadingContent} ) : ( - + {content} ); @@ -116,9 +104,7 @@ function Cell({ header || firstColumn ? ( headingMarkup ) : ( - - {content} - + {content} ); return cellMarkup; From 11bd7b1a4a12d4cf0eca8e769006f87c0969219a Mon Sep 17 00:00:00 2001 From: Chloe Rice Date: Tue, 18 Jun 2019 07:31:14 -0400 Subject: [PATCH 8/9] bump code coverage --- src/components/DataTable/DataTable.tsx | 103 ++--- .../DataTable/components/Cell/Cell.tsx | 5 +- .../components/Cell/tests/Cell.test.tsx | 263 +++++++++++ .../DataTable/tests/DataTable.test.tsx | 418 ++++++++++++------ 4 files changed, 593 insertions(+), 196 deletions(-) create mode 100644 src/components/DataTable/components/Cell/tests/Cell.test.tsx diff --git a/src/components/DataTable/DataTable.tsx b/src/components/DataTable/DataTable.tsx index 5d38bf40d45..f546a164610 100644 --- a/src/components/DataTable/DataTable.tsx +++ b/src/components/DataTable/DataTable.tsx @@ -105,23 +105,10 @@ class DataTable extends React.PureComponent { } render() { - const { - columnContentTypes, - headings, - totals, - rows, - truncate, - footerContent, - sortable, - defaultSortDirection = 'ascending', - initialSortColumnIndex = 0, - } = this.props; - + const {headings, totals, rows, footerContent} = this.props; const { condensed, columnVisibilityData, - sortedColumnIndex = initialSortColumnIndex, - sortDirection = defaultSortDirection, isScrolledFarthestLeft, isScrolledFarthestRight, } = this.state; @@ -129,7 +116,6 @@ class DataTable extends React.PureComponent { const className = classNames( styles.DataTable, condensed && styles.condensed, - footerContent && styles.hasFooter, ); const wrapperClassName = classNames( @@ -137,41 +123,7 @@ class DataTable extends React.PureComponent { condensed && styles.condensed, ); - const headingMarkup = ( - - {headings.map((heading, headingIndex) => { - let sortableHeadingProps; - const id = `heading-cell-${headingIndex}`; - - if (sortable) { - const isSortable = sortable[headingIndex]; - const isSorted = sortedColumnIndex === headingIndex; - const direction = isSorted ? sortDirection : 'none'; - - sortableHeadingProps = { - defaultSortDirection, - sorted: isSorted, - sortable: isSortable, - sortDirection: direction, - onSort: this.defaultOnSort(headingIndex), - }; - } - - return ( - - ); - })} - - ); + const headingMarkup = {headings.map(this.renderHeadings)}; const totalsMarkup = totals ? ( {totals.map(this.renderTotals)} @@ -291,6 +243,50 @@ class DataTable extends React.PureComponent { return handleScroll; }; + private renderHeadings = (heading: string, headingIndex: number) => { + const { + sortable, + truncate = false, + columnContentTypes, + defaultSortDirection, + initialSortColumnIndex = 0, + } = this.props; + + const { + sortDirection = defaultSortDirection, + sortedColumnIndex = initialSortColumnIndex, + } = this.state; + + let sortableHeadingProps; + const id = `heading-cell-${headingIndex}`; + + if (sortable) { + const isSortable = sortable[headingIndex]; + const isSorted = isSortable && sortedColumnIndex === headingIndex; + const direction = isSorted ? sortDirection : 'none'; + + sortableHeadingProps = { + defaultSortDirection, + sorted: isSorted, + sortable: isSortable, + sortDirection: direction, + onSort: this.defaultOnSort(headingIndex), + }; + } + + return ( + + ); + }; + private renderTotals = (total: TableData, index: number) => { const id = `totals-cell-${index}`; const {truncate = false} = this.props; @@ -311,7 +307,6 @@ class DataTable extends React.PureComponent { { return ( { private defaultOnSort = (headingIndex: number) => { const { onSort, - truncate, defaultSortDirection = 'ascending', initialSortColumnIndex, } = this.props; @@ -373,10 +366,6 @@ class DataTable extends React.PureComponent { () => { if (onSort) { onSort(headingIndex, newSortDirection); - - if (!truncate && this.scrollContainer.current) { - this.handleResize(); - } } }, ); diff --git a/src/components/DataTable/components/Cell/Cell.tsx b/src/components/DataTable/components/Cell/Cell.tsx index b4f069f54fc..9b1ce7a5171 100644 --- a/src/components/DataTable/components/Cell/Cell.tsx +++ b/src/components/DataTable/components/Cell/Cell.tsx @@ -10,7 +10,6 @@ import {SortDirection} from '../../types'; import styles from '../../DataTable.scss'; export interface Props { - testID?: string; content?: React.ReactNode; contentType?: string; firstColumn?: boolean; @@ -36,7 +35,7 @@ function Cell({ sorted, sortable, sortDirection, - defaultSortDirection, + defaultSortDirection = 'ascending', polaris: { intl: {translate}, }, @@ -61,7 +60,7 @@ function Cell({ const iconClassName = classNames(sortable && styles.Icon); const direction = sorted ? sortDirection : defaultSortDirection; - const source = direction === 'ascending' ? CaretUpMinor : CaretDownMinor; + const source = direction === 'descending' ? CaretDownMinor : CaretUpMinor; const oppositeDirection = sortDirection === 'ascending' ? 'descending' : 'ascending'; diff --git a/src/components/DataTable/components/Cell/tests/Cell.test.tsx b/src/components/DataTable/components/Cell/tests/Cell.test.tsx new file mode 100644 index 00000000000..1a7e49cb541 --- /dev/null +++ b/src/components/DataTable/components/Cell/tests/Cell.test.tsx @@ -0,0 +1,263 @@ +import * as React from 'react'; +import {CaretUpMinor, CaretDownMinor} from '@shopify/polaris-icons'; +import { + mountWithAppProvider, + shallowWithAppProvider, + trigger, +} from 'test-utilities'; + +import {Icon} from '../../../..'; +import Cell from '../Cell'; + +describe('', () => { + describe('content', () => { + it('sets text content when provided', () => { + const cellContent = 'Data'; + const cell = shallowWithAppProvider(); + + expect(cell.text()).toBe(cellContent); + }); + + it('sets markup content when provided', () => { + const cellContent = 'Data'; + const cellMarkup =

{cellContent}

; + const cell = shallowWithAppProvider(); + + expect(cell.find('p')).toHaveLength(1); + expect(cell.text()).toBe(cellContent); + }); + }); + + describe('firstColumn', () => { + it('renders a table heading element when true', () => { + const cell = shallowWithAppProvider(); + + expect(cell.find('th')).toHaveLength(1); + }); + }); + + describe('header', () => { + it('renders a table heading element when true', () => { + const cell = shallowWithAppProvider(); + + expect(cell.find('th')).toHaveLength(1); + }); + }); + + describe('sorted', () => { + it('sets the aria-sort attribute to the sortDirection when the table is currently sorted by that column', () => { + const sortDirection = 'ascending'; + const cell = shallowWithAppProvider( + , + ); + + expect(cell.prop('aria-sort')).toBe(sortDirection); + }); + + it('sets the aria-sort attribute to none when the table is not currently sorted by that column', () => { + const sortDirection = 'none'; + const cell = shallowWithAppProvider( + , + ); + + expect(cell.prop('aria-sort')).toBe('none'); + }); + }); + + describe('sortable', () => { + it('renders an Icon when table is sortable by that column', () => { + const cell = shallowWithAppProvider(); + + expect(cell.find(Icon)).toHaveLength(1); + }); + + it('renders no Icon when table is not sortable by that column', () => { + const cell = shallowWithAppProvider( + , + ); + + expect(cell.find(Icon)).not.toHaveLength(1); + }); + }); + + describe('sortDirection', () => { + describe('when set to none', () => { + it('renders a down caret Icon when defaultSortDirection is descending', () => { + const cell = shallowWithAppProvider( + , + ); + + expect(cell.find(Icon).prop('source')).toBe(CaretDownMinor); + }); + + it('renders an up caret Icon when defaultSortDirection is ascending', () => { + const cell = shallowWithAppProvider( + , + ); + + expect(cell.find(Icon).prop('source')).toBe(CaretUpMinor); + }); + }); + + describe('when set to ascending', () => { + it('renders an up caret Icon when table is currently sorted by that column', () => { + const cell = shallowWithAppProvider( + , + ); + + expect(cell.find(Icon).prop('source')).toBe(CaretUpMinor); + }); + + it('renders an Icon with an accessibility label indicating the next sort direction is descending', () => { + const cell = mountWithAppProvider( + , + ); + + const expectedLabel = cell + .instance() + .context.polaris.intl.translate( + 'Polaris.DataTable.sortAccessibilityLabel', + { + direction: 'descending', + }, + ); + + expect(cell.find(Icon).prop('accessibilityLabel')).toBe(expectedLabel); + }); + }); + + describe('when set to descending', () => { + it('renders a down caret Icon when table is currently sorted by that column', () => { + const cell = shallowWithAppProvider( + , + ); + + expect(cell.find(Icon).prop('source')).toBe(CaretDownMinor); + }); + + it('renders an Icon with an accessibility label indicating the next sort direction is ascending', () => { + const cell = mountWithAppProvider( + , + ); + + const expectedLabel = cell + .instance() + .context.polaris.intl.translate( + 'Polaris.DataTable.sortAccessibilityLabel', + { + direction: 'ascending', + }, + ); + + expect(cell.find(Icon).prop('accessibilityLabel')).toBe(expectedLabel); + }); + }); + }); + + describe('defaultSortDirection', () => { + describe('when set to none', () => { + it('renders an up caret Icon when table is not currently sorted by that column', () => { + const cell = shallowWithAppProvider( + , + ); + + expect(cell.find(Icon).prop('source')).toBe(CaretUpMinor); + }); + }); + describe('when set to ascending', () => { + it('renders an up caret Icon when table is not currently sorted by that column', () => { + const cell = shallowWithAppProvider( + , + ); + + expect(cell.find(Icon).prop('source')).toBe(CaretUpMinor); + }); + }); + + describe('when set to descending', () => { + it('renders a down caret Icon when table is not currently sorted by that column', () => { + const cell = shallowWithAppProvider( + , + ); + + expect(cell.find(Icon).prop('source')).toBe(CaretDownMinor); + }); + }); + }); + + describe('onSort', () => { + it('gets called when a sortable cell heading is clicked', () => { + const sortSpy = jest.fn(); + const cell = shallowWithAppProvider( + , + ); + + trigger(cell.find('button'), 'onClick'); + + expect(sortSpy).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/src/components/DataTable/tests/DataTable.test.tsx b/src/components/DataTable/tests/DataTable.test.tsx index 8fe7c4e4190..b74296a786a 100644 --- a/src/components/DataTable/tests/DataTable.test.tsx +++ b/src/components/DataTable/tests/DataTable.test.tsx @@ -1,27 +1,9 @@ import * as React from 'react'; -import {mountWithAppProvider, findByTestID} from 'test-utilities'; -import {isEdgeVisible, getPrevAndCurrentColumns} from '../utilities'; -import {Cell, Navigation} from '../components'; +import {mountWithAppProvider, trigger} from 'test-utilities'; +import {Cell} from '../components'; import DataTable, {Props} from '../DataTable'; -interface DataTableTestProps { - sortable?: Props['sortable']; - defaultSortDirection?: Props['defaultSortDirection']; - initialSortColumnIndex?: Props['initialSortColumnIndex']; - onSort?: Props['onSort']; -} - -const sortable = [false, true, false, false, true, false]; -const columnContentTypes: Props['columnContentTypes'] = [ - 'text', - 'numeric', - 'numeric', - 'numeric', - 'numeric', -]; -const spyOnSort = jest.fn(); - -function setup(propOverrides?: DataTableTestProps) { +describe('', () => { const headings = ['Product', 'Price', 'Order Number', 'Quantity', 'Subtotal']; const rows = [ [ @@ -34,152 +16,316 @@ function setup(propOverrides?: DataTableTestProps) { ['Emerald Silk Gown', '$230.00', 124689, 32, '$19,090.00'], ['Mauve Cashmere Scarf', '$445.00', 124533, 140, '$14,240.00'], ]; - const summary = ['', '', '', 255, '$155,830.00']; - - const props = { - columnContentTypes, - headings, - rows, - summary, - ...propOverrides, - }; - const dataTable = mountWithAppProvider(); - - return { - ...props, - dataTable, - twoClicks: true, - }; -} -describe('', () => { - it('renders a table, thead and table body rows', () => { - const {dataTable} = setup(); + const columnContentTypes: Props['columnContentTypes'] = [ + 'text', + 'numeric', + 'numeric', + 'numeric', + 'numeric', + ]; + + const defaultProps: Props = {columnContentTypes, headings, rows}; + + describe('columnContentTypes', () => { + it('sets the provided contentType of Cells in each column', () => { + const headings = ['Column 1', 'Column 2']; + const rows = [['Cell 1', '2']]; + const columnContentTypes: Props['columnContentTypes'] = [ + 'text', + 'numeric', + ]; + const dataTable = mountWithAppProvider( + , + ); + + const cells = dataTable.find(Cell); + const firstColumnCells = cells.filterWhere( + (cell) => cell.prop('firstColumn') === true, + ); + + const secondColumnCells = cells.filterWhere( + (cell) => cell.prop('firstColumn') !== true, + ); + + expect(cells).toHaveLength(4); - expect(dataTable.find('table')).toHaveLength(1); - expect(dataTable.find('thead')).toHaveLength(1); - expect(dataTable.find('thead th')).toHaveLength(5); - expect(dataTable.find('tbody tr')).toHaveLength(3); + firstColumnCells.forEach((cell) => + expect(cell.prop('contentType')).toBe('text'), + ); + + secondColumnCells.forEach((cell) => + expect(cell.prop('contentType')).toBe('numeric'), + ); + }); }); - it('defaults to non-sorting column headings', () => { - const {dataTable} = setup(); - const sortableHeadings = dataTable.find(Cell).filter({sortable: true}); + describe('headings', () => { + it('renders a single table header row', () => { + const headings = ['Heading 1', 'Heading 2', 'Heading 3']; + const dataTable = mountWithAppProvider( + , + ); - expect(sortableHeadings).toHaveLength(0); + expect(dataTable.find('thead tr')).toHaveLength(1); + }); + + it('renders each header Cell with the content provided', () => { + const headings = ['Heading 1', 'Heading 2', 'Heading 3']; + const dataTable = mountWithAppProvider( + , + ); + + const headingCells = dataTable.find('thead tr').find(Cell); + + headingCells.forEach((headingCell, headingCellIndex) => + expect(headingCell.text()).toBe(headings[headingCellIndex]), + ); + }); }); - it('initial sort column defaults to first column if not specified', () => { - const firstColumnSortable = [true, true, false, false, true, false]; - const {dataTable} = setup({ - sortable: firstColumnSortable, - onSort: spyOnSort, + describe('totals', () => { + it('renders a second table header row with totals', () => { + const totals = ['', '$20.00', '']; + const dataTable = mountWithAppProvider( + , + ); + + expect(dataTable.find('thead tr')).toHaveLength(2); + + const totalsRow = dataTable.find('thead tr').at(1); + + expect(totalsRow.text()).toContain(totals.join('')); + }); + + it('sets the content of the first total Cell to the totals row heading', () => { + const totals = ['', '', '']; + const dataTable = mountWithAppProvider( + , + ); + + expect(dataTable.find('thead tr')).toHaveLength(2); + + const expectedTotalsHeadingContent = dataTable + .instance() + .context.polaris.intl.translate('Polaris.DataTable.totalsRowHeading'); + + const firstTotalCell = dataTable + .find(Cell) + .filterWhere((cell) => cell.prop('total') === true) + .first(); + + expect(firstTotalCell.prop('content')).toBe(expectedTotalsHeadingContent); }); - const firstHeadingCell = findByTestID(dataTable, `heading-cell-${0}`); - expect(firstHeadingCell.props().sorted).toBe(true); + it('sets the contentType of non-empty total Cells to numeric', () => { + const totals = ['', '$20.00', '']; + const dataTable = mountWithAppProvider( + , + ); + const totalsCells = dataTable + .find(Cell) + .filterWhere((cell) => cell.prop('total') === true); + + const nonEmptyTotalCells = totalsCells.filterWhere( + (cell) => cell.prop('contentType') === 'numeric', + ); + + const secondTotalsCell = totalsCells.at(1); + + expect(nonEmptyTotalCells).toHaveLength(1); + expect(secondTotalsCell.prop('contentType')).toBe('numeric'); + }); + + it('renders an empty Cell for falsey total values', () => { + const totals = ['', '', '']; + const dataTable = mountWithAppProvider( + , + ); + + expect(dataTable.find('thead tr')).toHaveLength(2); + + const totalsCells = dataTable + .find(Cell) + .filterWhere( + (cell) => + cell.prop('total') === true && cell.prop('firstColumn') !== true, + ); + + totalsCells.forEach((total) => expect(total.text()).toBe('')); + }); + }); + + describe('rows', () => { + it('renders a table body row for each list of table data provided', () => { + const rows = [['First row'], ['Second row'], ['Third row']]; + const dataTable = mountWithAppProvider( + , + ); + + expect(dataTable.find('tbody tr')).toHaveLength(3); + }); + }); + + describe('truncate', () => { + it('defaults to false', () => { + const dataTable = mountWithAppProvider(); + + const firstColumnCells = dataTable + .find(Cell) + .filterWhere((cell) => cell.prop('firstColumn') === true); + + firstColumnCells.forEach((cell) => + expect(cell.prop('truncate')).toBe(false), + ); + }); + + it('passes the value provided to its cells', () => { + const dataTable = mountWithAppProvider( + , + ); + + const firstColumnCells = dataTable + .find(Cell) + .filterWhere((cell) => cell.prop('firstColumn') === true); + + firstColumnCells.forEach((cell) => + expect(cell.prop('truncate')).toBe(true), + ); + }); }); - it('sets specified initial sort column', () => { - const {dataTable} = setup({ - sortable, - onSort: spyOnSort, - initialSortColumnIndex: 4, + describe('footerContent', () => { + it('renders string footer content when provided', () => { + const footerContent = 'Footer text'; + const dataTable = mountWithAppProvider( + , + ); + + expect(dataTable.text()).toContain(footerContent); }); - const fifthHeadingCell = findByTestID(dataTable, `heading-cell-${4}`); - expect(fifthHeadingCell.props().sorted).toBe(true); + it('renders JSX footer content when provided', () => { + const footerContent =
Footer text
; + const dataTable = mountWithAppProvider( + , + ); + + expect(dataTable.containsMatchingElement(footerContent)).toBe(true); + }); }); - describe('', () => { - const {dataTable} = setup(); - it('passes props', () => { - expect( - dataTable - .find(Cell) - .first() - .prop('header'), - ).toBe(true); - expect( - dataTable - .find(Cell) - .first() - .prop('content'), - ).toStrictEqual('Product'); - expect( - dataTable - .find(Cell) - .first() - .prop('contentType'), - ).toStrictEqual('text'); + describe('sortable', () => { + it('defaults to a non-sortable table', () => { + const dataTable = mountWithAppProvider(); + const cells = dataTable.find(Cell); + + cells.forEach((cell) => expect(cell.find('button')).toHaveLength(0)); + }); + + it('renders a sortable header Cell for each true index', () => { + const sortable = [false, true, false, false, true]; + const dataTable = mountWithAppProvider( + , + ); + + const sortableCells = dataTable + .find(Cell) + .filterWhere((cell) => cell.prop('sortable') === true); + + expect(sortableCells).toHaveLength(2); + }); + + it('renders a plain header Cell for each false index', () => { + const sortable = [false, true, false, false, true]; + const dataTable = mountWithAppProvider( + , + ); + + const nonSortableCells = dataTable + .find(Cell) + .filterWhere((cell) => cell.prop('sortable') === false); + + expect(nonSortableCells).toHaveLength(3); }); }); - describe('', () => { - const {dataTable} = setup(); - it('passes scroll props', () => { - expect( - dataTable - .find(Navigation) - .first() - .prop('isScrolledFarthestLeft'), - ).toBe(true); - expect( - dataTable - .find(Navigation) - .first() - .prop('isScrolledFarthestRight'), - ).toBe(false); + describe('defaultSortDirection', () => { + it('passes the value down to the Cell', () => { + const sortable = [false, true, false, false, true]; + const dataTable = mountWithAppProvider( + , + ); + + const firstHeadingCell = dataTable + .find(Cell) + .filterWhere((cell) => cell.props().header === true) + .first(); + + expect(firstHeadingCell.prop('defaultSortDirection')).toBe('ascending'); }); }); - describe('isEdgeVisible()', () => { - it('returns true if there is enough room', () => { - const position = 175; - const tableStart = 145; - const tableEnd = 205; + describe('initialSortColumnIndex', () => { + it('defaults to first column if not specified', () => { + const sortable = [true, true, false, false, true, false]; + const dataTable = mountWithAppProvider( + , + ); - const isVisible = isEdgeVisible(position, tableStart, tableEnd); + const firstHeadingCell = dataTable + .find(Cell) + .filterWhere((cell) => cell.props().header === true) + .first(); - expect(isVisible).toBe(true); + expect(firstHeadingCell.props().sorted).toBe(true); }); - it('returns false if there is not enough room', () => { - const position = 175; - const tableStart = 145; - const tableEnd = 200; + it('sets specified initial sort column', () => { + const sortable = [true, true, false, false, true, false]; + const initialSortColumnIndex = 4; + const dataTable = mountWithAppProvider( + , + ); - const isVisible = isEdgeVisible(position, tableStart, tableEnd); + const fifthHeadingCell = dataTable + .find(Cell) + .filterWhere((cell) => cell.props().header === true) + .at(initialSortColumnIndex); - expect(isVisible).toBe(false); + expect(fifthHeadingCell.props().sorted).toBe(true); }); }); - describe('getPrevAndCurrentColumns()', () => { - it('returns the calculated measurements', () => { - const columnVisibilityData = [ - {leftEdge: 145, rightEdge: 236, isVisible: true}, - {leftEdge: 236, rightEdge: 357, isVisible: true}, - {leftEdge: 357, rightEdge: 474, isVisible: true}, - {leftEdge: 474, rightEdge: 601, isVisible: true}, - ]; + describe('onSort', () => { + it('gets called when sortable column heading is clicked', () => { + const spyOnSort = jest.fn(); + const sortable = [true, false, false, false, false]; + const dataTable = mountWithAppProvider( + , + ); + + const firstHeadingCell = dataTable + .find(Cell) + .filterWhere((cell) => cell.props().header === true) + .first(); + + trigger(firstHeadingCell, 'onSort'); - const tableData = { - fixedColumnWidth: 145, - firstVisibleColumnIndex: 3, - tableLeftVisibleEdge: 145, - tableRightVisibleEdge: 551, - }; - - const actualMeasurement = getPrevAndCurrentColumns( - tableData, - columnVisibilityData, - ); - const expectedMeasurement = { - previousColumn: {leftEdge: 357, rightEdge: 474, isVisible: true}, - currentColumn: {leftEdge: 474, rightEdge: 601, isVisible: true}, - }; - expect(actualMeasurement).toStrictEqual(expectedMeasurement); + expect(spyOnSort).toHaveBeenCalledTimes(1); }); }); }); From 29ecb85cefe8371d8f67078e5b345afab59fe7cc Mon Sep 17 00:00:00 2001 From: Chloe Rice Date: Mon, 24 Jun 2019 16:59:12 -0400 Subject: [PATCH 9/9] Array.from => ... --- src/components/DataTable/DataTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DataTable/DataTable.tsx b/src/components/DataTable/DataTable.tsx index f546a164610..ee286e7c448 100644 --- a/src/components/DataTable/DataTable.tsx +++ b/src/components/DataTable/DataTable.tsx @@ -190,7 +190,7 @@ class DataTable extends React.PureComponent { tableRightVisibleEdge, }; - const columnVisibilityData = Array.from(headerCells).map( + const columnVisibilityData = [...headerCells].map( measureColumn(tableData), );