diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index b5e66fd84a2..f9b7772a5aa 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -17,10 +17,12 @@ import { ButtonContext, CellRenderProps, Collection, + CollectionRendererContext, ColumnRenderProps, ColumnResizer, ContextValue, DEFAULT_SLOT, + DefaultCollectionRenderer, Form, Key, OverlayTriggerStateContext, @@ -439,7 +441,9 @@ export const TableBody = /*#__PURE__*/ (forwardRef as forwardRefType)(function T if (renderEmptyState != null && !isLoading) { emptyRender = (props: TableBodyRenderProps) => (
- {renderEmptyState(props)} + + {renderEmptyState(props)} +
); } else if (loadingState === 'loading') { diff --git a/packages/@react-spectrum/s2/stories/TableView.stories.tsx b/packages/@react-spectrum/s2/stories/TableView.stories.tsx index e32ff026983..688bd635bbd 100644 --- a/packages/@react-spectrum/s2/stories/TableView.stories.tsx +++ b/packages/@react-spectrum/s2/stories/TableView.stories.tsx @@ -27,21 +27,24 @@ import { PickerItem, Row, StatusLight, + Tab, TableBody, TableHeader, TableView, TableViewProps, + TabList, + Tabs, Text, TextField } from '../src'; import {categorizeArgTypes, getActionArgs} from './utils'; +import {CollectionRendererContext, DefaultCollectionRenderer, SortDescriptor} from 'react-aria-components'; import Edit from '../s2wf-icons/S2_Icon_Edit_20_N.svg'; import Filter from '../s2wf-icons/S2_Icon_Filter_20_N.svg'; import FolderOpen from '../spectrum-illustrations/linear/FolderOpen'; import {Key} from '@react-types/shared'; import type {Meta, StoryObj} from '@storybook/react'; import React, {ReactElement, useCallback, useEffect, useRef, useState} from 'react'; -import {SortDescriptor} from 'react-aria-components'; import {style} from '../style/spectrum-theme' with {type: 'macro'}; import {useAsyncList, useListData} from '@react-stately/data'; import {useEffectEvent} from '@react-aria/utils'; @@ -1714,3 +1717,57 @@ export const EditableTableWithAsyncSaving: StoryObj = { ); } }; + +export const TableViewCollectionError: StoryObj = { + render: function DynamicColumnsExample() { + const columns: Array<{ + key: string, + label: string, + align?: 'start' | 'center' | 'end' + }> = [ + {key: 'name', label: 'Name'}, + {key: 'count', label: 'Count', align: 'end'} + ]; + + const tabs = [ + {id: 'general', label: 'General'}, + {id: 'advanced', label: 'Advanced'}, + {id: 'about', label: 'About'} + ]; + const renderEmptyState = () => ( + + {/* */} + + + {tabs.map((tab) => ( + + {tab.label} + + ))} + + + + ); + + return ( + + + + {columns.map((column) => ( + + {column.label} + + ))} + + + + + ); + }, + args: Example.args, + parameters: { + docs: { + disable: true + } + } +}; diff --git a/packages/@react-spectrum/s2/test/TableView.test.tsx b/packages/@react-spectrum/s2/test/TableView.test.tsx index d00e9980c0a..9b37f5c1d32 100644 --- a/packages/@react-spectrum/s2/test/TableView.test.tsx +++ b/packages/@react-spectrum/s2/test/TableView.test.tsx @@ -28,6 +28,7 @@ import {DisabledBehavior} from '@react-types/shared'; import Filter from '../s2wf-icons/S2_Icon_Filter_20_N.svg'; import {pointerMap, User} from '@react-aria/test-utils'; import React, {useState} from 'react'; +import {Tab, TabList, Tabs} from 'react-aria-components'; import userEvent from '@testing-library/user-event'; // @ts-ignore @@ -148,4 +149,42 @@ describe('TableView', () => { await user.tab(); expect(document.activeElement).toBe(cells[3]); }); + + it('should render empty state + nested collection without crashing', async () => { + const tabs = [ + {id: 'general', label: 'General'}, + {id: 'advanced', label: 'Advanced'} + ]; + const renderEmptyState = () => ( + + + {tabs.map((tab) => ( + + {tab.label} + + ))} + + + ); + + let renderResult: ReturnType; + await act(async () => { + renderResult = render( + + + {(column) => ( + + {column.name} + + )} + + + + ); + await Promise.resolve(); + }); + let {getAllByRole} = renderResult!; + + expect(getAllByRole('tab')).toHaveLength(tabs.length); + }); });