diff --git a/src/components/BaseRow/BaseRow.tsx b/src/components/BaseRow/BaseRow.tsx index 3facfe8..41a2190 100644 --- a/src/components/BaseRow/BaseRow.tsx +++ b/src/components/BaseRow/BaseRow.tsx @@ -13,7 +13,7 @@ import {b} from '../BaseTable/BaseTable.classname'; export interface BaseRowProps extends Omit, 'className' | 'onClick'> { cellClassName?: BaseCellProps['className']; - className?: string | ((row: RowType) => string); + className?: string | ((row?: RowType) => string); getGroupTitle?: (row: RowType) => React.ReactNode; getIsCustomRow?: (row: RowType) => boolean; getIsGroupHeaderRow?: (row: RowType) => boolean; diff --git a/src/components/BaseTable/BaseTable.tsx b/src/components/BaseTable/BaseTable.tsx index 2007f83..214558e 100644 --- a/src/components/BaseTable/BaseTable.tsx +++ b/src/components/BaseTable/BaseTable.tsx @@ -3,6 +3,7 @@ import React from 'react'; import type {Row as RowType, Table as TableType} from '@tanstack/react-table'; import type {VirtualItem, Virtualizer} from '@tanstack/react-virtual'; +import {getCellClassModes} from '../../utils'; import {BaseDraggableRow} from '../BaseDraggableRow'; import {BaseFooterRow} from '../BaseFooterRow'; import type {BaseHeaderRowProps} from '../BaseHeaderRow'; @@ -21,6 +22,7 @@ export interface BaseTableProps['cellClassName']; className?: string; + emptyContent?: React.ReactNode | (() => React.ReactNode); enableNesting?: boolean; footerCellClassName?: string; footerClassName?: string; @@ -62,6 +64,7 @@ export const BaseTable = React.forwardRef( bodyClassName, cellClassName, className, + emptyContent, enableNesting, footerCellClassName, footerClassName, @@ -116,6 +119,59 @@ export const BaseTable = React.forwardRef( const footerRowCount = footerGroups ? footerGroups.length : 0; const rowCount = bodyRowCount + headerRowCount + footerRowCount; + const renderBodyRows = () => { + const bodyRows = rowVirtualizer?.getVirtualItems() || rows; + + if (bodyRows.length === 0) { + const rClassName = + typeof rowClassName === 'function' ? rowClassName() : rowClassName; + + const cClassName = + typeof cellClassName === 'function' ? cellClassName() : cellClassName; + + return ( + + + {typeof emptyContent === 'function' ? emptyContent() : emptyContent} + + + ); + } + + return bodyRows.map((virtualItemOrRow) => { + const row = rowVirtualizer + ? rows[virtualItemOrRow.index] + : (virtualItemOrRow as RowType); + + const rowProps: BaseRowProps = { + cellClassName, + className: rowClassName, + getGroupTitle, + getIsGroupHeaderRow, + attributes: rowAttributes, + cellAttributes, + onClick: onRowClick, + renderGroupHeader, + renderGroupHeaderRowContent, + row, + rowVirtualizer, + virtualItem: rowVirtualizer + ? (virtualItemOrRow as VirtualItem) + : undefined, + 'aria-rowindex': headerRowCount + row.index + 1, + }; + + if (draggableContext) { + return ; + } + + return ; + }); + }; + return ( - {(rowVirtualizer?.getVirtualItems() || rows).map((virtualItemOrRow) => { - const row = rowVirtualizer - ? rows[virtualItemOrRow.index] - : (virtualItemOrRow as RowType); - - const rowProps: BaseRowProps = { - cellClassName, - className: rowClassName, - getGroupTitle, - getIsGroupHeaderRow, - attributes: rowAttributes, - cellAttributes, - onClick: onRowClick, - renderGroupHeader, - renderGroupHeaderRowContent, - row, - rowVirtualizer, - virtualItem: rowVirtualizer - ? (virtualItemOrRow as VirtualItem) - : undefined, - 'aria-rowindex': headerRowCount + row.index + 1, - }; - - if (draggableContext) { - return ; - } - - return ; - })} + {renderBodyRows()} {footerGroups && ( diff --git a/src/components/__stories__/BaseTable.stories.tsx b/src/components/__stories__/BaseTable.stories.tsx index 3696f68..1efa74b 100644 --- a/src/components/__stories__/BaseTable.stories.tsx +++ b/src/components/__stories__/BaseTable.stories.tsx @@ -8,6 +8,7 @@ import {ColumnPinningDemo} from './ColumnPinningDemo'; import {ColumnPinningWithReorderingDemo} from './ColumnPinningWithReorderingDemo'; import {ColumnPinningWithSelectionDemo} from './ColumnPinningWithSelectionDemo'; import {DefaultDemo} from './DefaultDemo'; +import {EmptyContentDemo} from './EmptyContent'; import {GroupingDemo} from './GroupingDemo'; import {GroupingDemo2} from './GroupingDemo2'; import {GroupingWithSelectionDemo} from './GroupingWithSelectionDemo'; @@ -89,3 +90,6 @@ export const ColumnPinningWithSelection: StoryFn = ColumnPinningWithSelectionTem const StickyHeaderTamplate: StoryFn = () => ; export const StickyHeader: StoryFn = StickyHeaderTamplate.bind({}); + +const EmptyContentTamplate: StoryFn = () => ; +export const EmptyContent: StoryFn = EmptyContentTamplate.bind({}); diff --git a/src/components/__stories__/EmptyContent.classname.ts b/src/components/__stories__/EmptyContent.classname.ts new file mode 100644 index 0000000..42afa4e --- /dev/null +++ b/src/components/__stories__/EmptyContent.classname.ts @@ -0,0 +1,3 @@ +import {cn} from '../../utils'; + +export const cnEmptyContentDemo = cn('empty-content-demo'); diff --git a/src/components/__stories__/EmptyContent.scss b/src/components/__stories__/EmptyContent.scss new file mode 100644 index 0000000..efee187 --- /dev/null +++ b/src/components/__stories__/EmptyContent.scss @@ -0,0 +1,11 @@ +.empty-content-demo { + &__placeholder { + min-height: 20px; + + display: flex; + align-items: center; + justify-content: center; + + color: #ff0000; + } +} diff --git a/src/components/__stories__/EmptyContent.tsx b/src/components/__stories__/EmptyContent.tsx new file mode 100644 index 0000000..310d602 --- /dev/null +++ b/src/components/__stories__/EmptyContent.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +import {useTable} from '../../hooks'; +import {BaseTable} from '../BaseTable'; + +import {cnEmptyContentDemo} from './EmptyContent.classname'; +import {columns} from './constants/columns'; + +import './EmptyContent.scss'; + +const emptyContentPlaceholder =
No data
; + +export const EmptyContentDemo = () => { + const table = useTable({ + columns, + data: [], + }); + + return ; +};