diff --git a/packages/@react-spectrum/table/test/Table.ssr.test.js b/packages/@react-spectrum/table/test/Table.ssr.test.js index 58665ea39a1..820c8b13ddf 100644 --- a/packages/@react-spectrum/table/test/Table.ssr.test.js +++ b/packages/@react-spectrum/table/test/Table.ssr.test.js @@ -42,3 +42,92 @@ describe('Table SSR', function () { `); }); }); + +describe('Table Nested Rows SSR', function () { + it('should render without errors', async function () { + await testSSR(__filename, ` + import {Provider} from '@react-spectrum/provider'; + import {theme} from '@react-spectrum/theme-default'; + import {Cell, Column, Row, TableBody, TableHeader, TableView} from '../'; + import {enableTableNestedRows} from '@react-stately/flags'; + enableTableNestedRows(); + + let nestedItems = [ + {foo: 'Lvl 1 Foo 1', bar: 'Lvl 1 Bar 1', baz: 'Lvl 1 Baz 1', childRows: [ + {foo: 'Lvl 2 Foo 1', bar: 'Lvl 2 Bar 1', baz: 'Lvl 2 Baz 1', childRows: [ + {foo: 'Lvl 3 Foo 1', bar: 'Lvl 3 Bar 1', baz: 'Lvl 3 Baz 1'} + ]}, + {foo: 'Lvl 2 Foo 2', bar: 'Lvl 2 Bar 2', baz: 'Lvl 2 Baz 2'} + ]} + ]; + + let columns = [ + {name: 'Foo', key: 'foo'}, + {name: 'Bar', key: 'bar'}, + {name: 'Baz', key: 'baz'} + ]; + + + + + {column => {column.name}} + + + {(item) => + ( + {(key) => { + return {item[key.toString()]}; + }} + ) + } + + + + `); + }); +}); + +// TODO: selectionMode="multiple" errors +describe('Table Static SSR', function () { + it('should render without errors', async function () { + await testSSR(__filename, ` + import {Provider} from '@react-spectrum/provider'; + import {theme} from '@react-spectrum/theme-default'; + import {Cell, Column, Row, TableBody, TableHeader, TableView} from '../'; + import {enableTableNestedRows} from '@react-stately/flags'; + enableTableNestedRows(); + + + + + Name + Type + Date Modified + + + + Games + File folder + 6/7/2020 + + + Program Files + File folder + 4/7/2021 + + + bootmgr + System file + 11/20/2010 + + + log.txt + Text Document + 1/18/2016 + + + + + `); + }); +}); diff --git a/packages/@react-spectrum/table/test/Table.test.js b/packages/@react-spectrum/table/test/Table.test.js index 63ee4dda0ae..8e6b2e56683 100644 --- a/packages/@react-spectrum/table/test/Table.test.js +++ b/packages/@react-spectrum/table/test/Table.test.js @@ -23,7 +23,6 @@ import {Content} from '@react-spectrum/view'; import {CRUDExample} from '../stories/CRUDExample'; import {Dialog, DialogTrigger} from '@react-spectrum/dialog'; import {Divider} from '@react-spectrum/divider'; -import {enableTableNestedRows} from '@react-stately/flags'; import {getFocusableTreeWalker} from '@react-aria/focus'; import {Heading} from '@react-spectrum/text'; import {Item, Picker} from '@react-spectrum/picker'; @@ -5041,11 +5040,3 @@ export let tableTests = () => { }; describe('TableView', tableTests); - -describe('TableView with expandable rows flag on', function () { - beforeAll(() => { - enableTableNestedRows(); - }); - - tableTests(); -}); diff --git a/packages/@react-spectrum/table/test/TableNestedRows.test.js b/packages/@react-spectrum/table/test/TableNestedRows.test.js new file mode 100644 index 00000000000..415b76eb2f1 --- /dev/null +++ b/packages/@react-spectrum/table/test/TableNestedRows.test.js @@ -0,0 +1,83 @@ +/* + * Copyright 2020 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +jest.mock('@react-aria/live-announcer'); +jest.mock('@react-aria/utils/src/scrollIntoView'); +import {act, render as renderComponent} from '@react-spectrum/test-utils-internal'; +import {Cell, Column, Row, TableBody, TableHeader, TableView} from '../'; +import {enableTableNestedRows} from '@react-stately/flags'; +import {Provider} from '@react-spectrum/provider'; +import React from 'react'; +import {tableTests} from './Table.test'; +import {theme} from '@react-spectrum/theme-default'; + +describe('TableView with expandable rows flag on', function () { + beforeAll(() => { + enableTableNestedRows(); + }); + + tableTests(); + + describe('with nested rows', function () { + let offsetWidth, offsetHeight; + + beforeAll(function () { + offsetWidth = jest.spyOn(window.HTMLElement.prototype, 'clientWidth', 'get').mockImplementation(() => 1000); + offsetHeight = jest.spyOn(window.HTMLElement.prototype, 'clientHeight', 'get').mockImplementation(() => 1000); + jest.useFakeTimers(); + }); + + afterAll(function () { + offsetWidth.mockReset(); + offsetHeight.mockReset(); + }); + + afterEach(() => { + act(() => {jest.runAllTimers();}); + }); + it('can render', function () { + let columns = [ + {name: 'Foo', key: 'foo'}, + {name: 'Bar', key: 'bar'}, + {name: 'Baz', key: 'baz'} + ]; + + let nestedItems = [ + {foo: 'Lvl 1 Foo 1', bar: 'Lvl 1 Bar 1', baz: 'Lvl 1 Baz 1', childRows: [ + {foo: 'Lvl 2 Foo 1', bar: 'Lvl 2 Bar 1', baz: 'Lvl 2 Baz 1', childRows: [ + {foo: 'Lvl 3 Foo 1', bar: 'Lvl 3 Bar 1', baz: 'Lvl 3 Baz 1'} + ]}, + {foo: 'Lvl 2 Foo 2', bar: 'Lvl 2 Bar 2', baz: 'Lvl 2 Baz 2'} + ]} + ]; + + renderComponent( + + + + {column => {column.name}} + + + {(item) => + ( + {(key) => { + return {item[key]}; + }} + ) + } + + + + ); + }); + }); +}); diff --git a/packages/@react-stately/grid/src/GridCollection.ts b/packages/@react-stately/grid/src/GridCollection.ts index 20dc2db58dd..4b78da4f95f 100644 --- a/packages/@react-stately/grid/src/GridCollection.ts +++ b/packages/@react-stately/grid/src/GridCollection.ts @@ -79,20 +79,6 @@ export class GridCollection implements IGridCollection { if (last) { last.nextKey = null; - - if (rowHasCellWithColSpan && node.type === 'item') { - let lastColIndex = last?.colIndex ?? 0 + 1; // internally colIndex is 0 based - let lastColSpan = last?.colSpan ?? 1; - let numberOfCellsInRow = lastColIndex + lastColSpan; - if (numberOfCellsInRow !== this.columnCount) { - throw new Error(`Cell count must match column count. Found ${numberOfCellsInRow} cells and ${this.columnCount} columns.`); - } - } else if (node.type === 'item') { - let numberOfCellsInRow = [...node.childNodes].length; - if (numberOfCellsInRow !== this.columnCount) { - throw new Error(`Cell count must match column count. Found ${numberOfCellsInRow} cells and ${this.columnCount} columns.`); - } - } } // Remove deleted nodes and their children from the key map diff --git a/packages/@react-stately/table/src/Row.ts b/packages/@react-stately/table/src/Row.ts index b3c2d7a10fd..9cc5595538f 100644 --- a/packages/@react-stately/table/src/Row.ts +++ b/packages/@react-stately/table/src/Row.ts @@ -72,6 +72,7 @@ Row.getCollectionNode = function* getCollectionNode(props: RowProps, conte } else { let cells: PartialNode[] = []; let childRows: PartialNode[] = []; + let columnCount = 0; React.Children.forEach(children, node => { if (node.type === Row) { if (cells.length < context.columns.length) { @@ -87,9 +88,14 @@ Row.getCollectionNode = function* getCollectionNode(props: RowProps, conte type: 'cell', element: node }); + columnCount += node.props.colSpan ?? 1; } }); + if (columnCount !== context.columns.length) { + throw new Error(`Cell count must match column count. Found ${columnCount} cells and ${context.columns.length} columns.`); + } + yield* cells; yield* childRows; }