From 36a8bbd851f2239fd2e130637d4f8e726c774426 Mon Sep 17 00:00:00 2001 From: Uyen Doan <56598021+smmr-dn@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:34:08 -0500 Subject: [PATCH] Reduced props accepted by `ColumnHeader` (#2287) --- .../src/core/Table/ColumnHeader.tsx | 100 ++++++++---------- .../itwinui-react/src/core/Table/Table.tsx | 35 +++--- .../src/core/Table/cells/DefaultCell.tsx | 8 +- .../itwinui-react/src/core/Table/utils.ts | 9 +- 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/packages/itwinui-react/src/core/Table/ColumnHeader.tsx b/packages/itwinui-react/src/core/Table/ColumnHeader.tsx index d03e454dff7..1f9f5ca9940 100644 --- a/packages/itwinui-react/src/core/Table/ColumnHeader.tsx +++ b/packages/itwinui-react/src/core/Table/ColumnHeader.tsx @@ -9,80 +9,64 @@ import { LineClamp, SvgSortDown, SvgSortUp, + useMergedRefs, + type PolymorphicForwardRefComponent, } from '../../utils/index.js'; import type { - ColumnInstance, HeaderGroup, TableKeyedProps, - TableState, } from '../../react-table/react-table.js'; -import { SELECTION_CELL_ID } from './columns/index.js'; import { FilterToggle } from './filters/FilterToggle.js'; -import { getCellStyle, getSubRowStyle, getStickyStyle } from './utils.js'; +import { + getCellStyle, + getSubRowStyle, + getStickyStyle, + TableInstanceContext, +} from './utils.js'; import cx from 'classnames'; -type ColumnHeaderProps< - T extends Record = Record, -> = TableKeyedProps & { - columnRefs: React.MutableRefObject>; - column: HeaderGroup; - index: number; +type ColumnHeaderProps = TableKeyedProps & { + column: HeaderGroup>; areFiltersSet: boolean; - hasAnySubRows: boolean; - headers: HeaderGroup[]; - state: TableState; - data: T[]; isResizable: boolean; columnResizeMode: 'fit' | 'expand'; enableColumnReordering: boolean; density: string | undefined; - visibleColumns: ColumnInstance[]; + columnHasExpanders: boolean; + isLast: boolean; + isTableEmpty: boolean; }; -export const ColumnHeader = < - T extends Record = Record, ->( - props: ColumnHeaderProps, -): JSX.Element => { +export const ColumnHeader = React.forwardRef((props, forwardedRef) => { const { - columnRefs, column, - index, areFiltersSet, - hasAnySubRows, - headers, - state, - data, isResizable, columnResizeMode, enableColumnReordering, density, - visibleColumns, + columnHasExpanders, + isLast, + isTableEmpty, ...rest } = props; const isHeaderDirectClick = React.useRef(false); + const instance = React.useContext(TableInstanceContext); const COLUMN_MIN_WIDTHS = { default: 72, withExpander: 108, // expander column should be wider to accommodate the expander icon }; - const showFilterButton = (column: HeaderGroup) => - (data.length !== 0 || areFiltersSet) && column.canFilter && !!column.Filter; + const showFilterButton = (column: HeaderGroup>) => + (!isTableEmpty || areFiltersSet) && column.canFilter && !!column.Filter; - const showSortButton = (column: HeaderGroup) => - data.length !== 0 && column.canSort; + const showSortButton = (column: HeaderGroup>) => + !isTableEmpty && column.canSort; const { onClick, ...restSortProps } = column.getSortByToggleProps(); - const columnHasExpanders = - hasAnySubRows && - index === - headers.findIndex( - (c) => c.id !== SELECTION_CELL_ID, // first non-selection column is the expander column - ); - if ([undefined, 0].includes(column.minWidth)) { // override "undefined" or zero min-width with default value column.minWidth = columnHasExpanders @@ -107,9 +91,9 @@ export const ColumnHeader = < column.columnClassName, ), style: { - ...getCellStyle(column, !!state.isTableResizing), + ...getCellStyle(column, !!instance?.state.isTableResizing), ...(columnHasExpanders && getSubRowStyle({ density })), - ...getStickyStyle(column, visibleColumns), + ...getStickyStyle(column, instance?.visibleColumns ?? []), flexWrap: 'wrap', columnGap: 'var(--iui-size-xs)', }, @@ -121,14 +105,16 @@ export const ColumnHeader = < {...rest} key={columnProps.key} title={undefined} - ref={React.useCallback( - (el: HTMLDivElement) => { - if (el) { - columnRefs.current[column.id] = el; - column.resizeWidth = el.getBoundingClientRect().width; - } - }, - [column, columnRefs], + ref={useMergedRefs( + React.useCallback( + (el?: HTMLDivElement) => { + if (el) { + column.resizeWidth = el.getBoundingClientRect().width; + } + }, + [column], + ), + forwardedRef, )} onMouseDown={() => { isHeaderDirectClick.current = true; @@ -183,7 +169,7 @@ export const ColumnHeader = < )} {isResizable && column.isResizerVisible && - (index !== headers.length - 1 || columnResizeMode === 'expand') && ( + (!isLast || columnResizeMode === 'expand') && ( )} - {column.sticky === 'left' && state.sticky.isScrolledToRight && ( - - )} - {column.sticky === 'right' && state.sticky.isScrolledToLeft && ( - - )} + {column.sticky === 'left' && + instance?.state.sticky.isScrolledToRight && ( + + )} + {column.sticky === 'right' && + instance?.state.sticky.isScrolledToLeft && ( + + )} ); -}; +}) as PolymorphicForwardRefComponent<'div', ColumnHeaderProps>; diff --git a/packages/itwinui-react/src/core/Table/Table.tsx b/packages/itwinui-react/src/core/Table/Table.tsx index e48d97e53af..42d97eae272 100644 --- a/packages/itwinui-react/src/core/Table/Table.tsx +++ b/packages/itwinui-react/src/core/Table/Table.tsx @@ -25,7 +25,6 @@ import type { ActionType, TableInstance, Column, - ColumnInstance, } from '../../react-table/react-table.js'; import { ProgressRadial } from '../ProgressIndicators/ProgressRadial.js'; import { @@ -40,7 +39,7 @@ import { useVirtualScroll, } from '../../utils/index.js'; import type { CommonProps } from '../../utils/index.js'; -import { TableColumnsContext } from './utils.js'; +import { TableInstanceContext } from './utils.js'; import { TableRowMemoized } from './TableRowMemoized.js'; import type { TableFilterValue } from './filters/index.js'; import { customFilterFunctions } from './filters/customFilterFunctions.js'; @@ -639,7 +638,6 @@ export const Table = < gotoPage, setPageSize, flatHeaders, - visibleColumns, setGlobalFilter, } = instance; @@ -950,7 +948,9 @@ export const Table = < }, []); return ( - + >} + > ( tableRef, @@ -1000,22 +1000,29 @@ export const Table = < {headerGroup.headers.map((column, index) => { const dragAndDropProps = column.getDragAndDropProps(); return ( - + >} areFiltersSet={areFiltersSet} - hasAnySubRows={hasAnySubRows} - headers={headerGroup.headers} - state={state} - data={data} + columnHasExpanders={ + hasAnySubRows && + index === + headerGroup.headers.findIndex( + (c) => c.id !== SELECTION_CELL_ID, // first non-selection column is the expander column + ) + } + isLast={index === headerGroup.headers.length - 1} + isTableEmpty={data.length === 0} isResizable={isResizable} columnResizeMode={columnResizeMode} enableColumnReordering={enableColumnReordering} density={density} - visibleColumns={visibleColumns} + ref={(el) => { + if (el) { + columnRefs.current[column.id] = el; + } + }} /> ); })} @@ -1115,7 +1122,7 @@ export const Table = < )} {paginatorRenderer?.(paginatorRendererProps)} - + ); }; if (process.env.NODE_ENV === 'development') { diff --git a/packages/itwinui-react/src/core/Table/cells/DefaultCell.tsx b/packages/itwinui-react/src/core/Table/cells/DefaultCell.tsx index dd36511c7d9..0dfa879cb45 100644 --- a/packages/itwinui-react/src/core/Table/cells/DefaultCell.tsx +++ b/packages/itwinui-react/src/core/Table/cells/DefaultCell.tsx @@ -7,7 +7,7 @@ import { defaultColumn } from 'react-table'; import type { CellRendererProps } from '../../../react-table/react-table.js'; import cx from 'classnames'; import { Box, LineClamp, ShadowRoot } from '../../../utils/index.js'; -import { TableColumnsContext } from '../utils.js'; +import { TableInstanceContext } from '../utils.js'; export type DefaultCellProps> = { /** @@ -46,12 +46,12 @@ export type DefaultCellProps> = { export const DefaultCell = >( props: DefaultCellProps, ) => { - const instanceColumns = React.useContext(TableColumnsContext); + const instance = React.useContext(TableInstanceContext); const isCustomCell = React.useMemo( () => - instanceColumns.find(({ id }) => props.cellProps.column.id === id) + instance?.columns.find(({ id }) => props.cellProps.column.id === id) ?.Cell !== defaultColumn.Cell, - [instanceColumns, props.cellProps.column.id], + [instance, props.cellProps.column.id], ); const { diff --git a/packages/itwinui-react/src/core/Table/utils.ts b/packages/itwinui-react/src/core/Table/utils.ts index 8ca35f86048..f4320a99034 100644 --- a/packages/itwinui-react/src/core/Table/utils.ts +++ b/packages/itwinui-react/src/core/Table/utils.ts @@ -3,7 +3,10 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import * as React from 'react'; -import type { ColumnInstance } from '../../react-table/react-table.js'; +import type { + ColumnInstance, + TableInstance, +} from '../../react-table/react-table.js'; export const getCellStyle = >( column: ColumnInstance, @@ -82,4 +85,6 @@ export const getSubRowStyle = ({ density = 'default', depth = 1 }) => { } satisfies React.CSSProperties; }; -export const TableColumnsContext = React.createContext([]); +export const TableInstanceContext = React.createContext< + TableInstance> | undefined +>(undefined);