Skip to content

Commit

Permalink
feat(BaseTable): additional properties for classNames and attributes …
Browse files Browse the repository at this point in the history
…customization
  • Loading branch information
beliarh committed Sep 9, 2024
1 parent 9c25359 commit e3fff9e
Show file tree
Hide file tree
Showing 29 changed files with 290 additions and 279 deletions.
16 changes: 9 additions & 7 deletions src/components/BaseCell/BaseCell.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import React from 'react';

import type {Cell as CellType} from '@tanstack/react-table';
import type {Cell} from '@tanstack/react-table';
import {flexRender} from '@tanstack/react-table';

import {getCellClassModes, getCellStyles} from '../../utils';
import {b} from '../BaseTable/BaseTable.classname';

export interface BaseCellProps<TData>
extends Omit<React.TdHTMLAttributes<HTMLTableCellElement>, 'className'> {
cell?: CellType<TData, unknown>;
className?: string | ((cell?: CellType<TData, unknown>) => string);
cell?: Cell<TData, unknown>;
className?: string | ((cell?: Cell<TData, unknown>) => string);
attributes?:
| React.TdHTMLAttributes<HTMLTableCellElement>
| ((cell?: CellType<TData, unknown>) => React.TdHTMLAttributes<HTMLTableCellElement>);
| ((cell?: Cell<TData, unknown>) => React.TdHTMLAttributes<HTMLTableCellElement>);
}

export const BaseCell = <TData,>({
Expand All @@ -23,18 +23,20 @@ export const BaseCell = <TData,>({
attributes: attributesProp,
...restProps
}: BaseCellProps<TData>) => {
const attributes = React.useMemo(() => {
return typeof attributesProp === 'function' ? attributesProp(cell) : attributesProp;
}, [attributesProp, cell]);

const className = React.useMemo(() => {
return typeof classNameProp === 'function' ? classNameProp(cell) : classNameProp;
}, [cell, classNameProp]);

const attributes = typeof attributesProp === 'function' ? attributesProp(cell) : attributesProp;

return (
<td
className={b('cell', getCellClassModes(cell), className)}
style={getCellStyles(cell, style)}
{...restProps}
{...attributes}
style={getCellStyles(cell, {...style, ...attributes?.style})}
>
{cell ? flexRender(cell.column.columnDef.cell, cell.getContext()) : children}
</td>
Expand Down
11 changes: 6 additions & 5 deletions src/components/BaseDragHandle/BaseDragHandle.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import React from 'react';

import {useSortable} from '@dnd-kit/sortable';
import type {Row} from '@tanstack/react-table';
import type {Row, Table} from '@tanstack/react-table';

import {useDraggableRowDepth} from '../../hooks';
import {BaseDraggableRowMarker} from '../BaseDraggableRowMarker';
import {TableContext} from '../TableContext';
import {SortableListContext} from '../SortableListContext';

import {b} from './BaseDragHandle.classname';

import './BaseDragHandle.scss';

export interface BaseDragHandleProps<TData> {
row: Row<TData>;
table: Table<TData>;
}

export const BaseDragHandle = <TData,>({row}: BaseDragHandleProps<TData>) => {
export const BaseDragHandle = <TData,>({row, table}: BaseDragHandleProps<TData>) => {
const {attributes, listeners, isDragging} = useSortable({
id: row.id,
});

const {enableNesting} = React.useContext(TableContext);
const {enableNesting} = React.useContext(SortableListContext) || {};

const {depth} = useDraggableRowDepth({row, isDragging});
const {depth} = useDraggableRowDepth({row, table, isDragging});

return (
<React.Fragment>
Expand Down
17 changes: 9 additions & 8 deletions src/components/BaseDraggableRow/BaseDraggableRow.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import React from 'react';

import {useForkRef} from '@gravity-ui/uikit';
import type {Row as RowType} from '@tanstack/react-table';
import type {Row} from '@tanstack/react-table';

import {useDraggableRowDepth, useDraggableRowStyle} from '../../hooks';
import type {BaseRowProps} from '../BaseRow';
import {BaseRow} from '../BaseRow';
import {SortableListContext} from '../SortableListContext';
import {TableContext} from '../TableContext';

export interface BaseDraggableRowProps<
TData,
Expand All @@ -20,6 +19,7 @@ export const BaseDraggableRow = React.forwardRef(
attributes: attributesProp,
row,
style,
table,
...restProps
}: BaseDraggableRowProps<TData, TScrollElement>,
ref: React.Ref<HTMLTableRowElement>,
Expand All @@ -28,6 +28,7 @@ export const BaseDraggableRow = React.forwardRef(
isChildMode,
activeItemKey,
targetItemIndex = -1,
enableNesting,
// The `useSortable` hook is provided by `@dnd-kit/sortable` library and imported via `SortableListContext`.
// This is a temporary solution to prevent importing the entire `@dnd-kit` library
// when the user doesn't use the reordering feature.
Expand All @@ -43,15 +44,14 @@ export const BaseDraggableRow = React.forwardRef(
id: row.id,
}) || {};

const {enableNesting} = React.useContext(TableContext);

const isDragActive = Boolean(activeItemKey);
const isParent = isChildMode && targetItemIndex === row.index;

const handleRowRef = useForkRef(setNodeRef, ref);

const {isFirstChild, depth} = useDraggableRowDepth<TData>({
row,
table,
isDragging,
});

Expand All @@ -62,11 +62,11 @@ export const BaseDraggableRow = React.forwardRef(
isDragging,
isDragActive,
isFirstChild,
nestingEnabled: enableNesting,
enableNesting,
});

const getDraggableRowDataAttributes = React.useCallback(
(draggableRow: RowType<TData>) => {
const getDraggableRowAttributes = React.useCallback(
(draggableRow: Row<TData>) => {
const attributes =
typeof attributesProp === 'function'
? attributesProp(draggableRow)
Expand All @@ -88,9 +88,10 @@ export const BaseDraggableRow = React.forwardRef(
return (
<BaseRow
ref={handleRowRef}
attributes={getDraggableRowDataAttributes}
attributes={getDraggableRowAttributes}
row={row}
style={draggableStyle}
table={table}
{...restProps}
/>
);
Expand Down
19 changes: 16 additions & 3 deletions src/components/BaseFooterCell/BaseFooterCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,26 @@ import {getCellStyles, getHeaderCellClassModes} from '../../utils';
import {b} from '../BaseTable/BaseTable.classname';

export interface BaseFooterCellProps<TData, TValue> {
className?: string;
header: Header<TData, TValue>;
attributes?:
| React.ThHTMLAttributes<HTMLTableCellElement>
| ((header: Header<TData, TValue>) => React.ThHTMLAttributes<HTMLTableCellElement>);
className?: string | ((header: Header<TData, TValue>) => string);
}

export const BaseFooterCell = <TData, TValue>({
className,
header,
attributes: attributesProp,
className: classNameProp,
}: BaseFooterCellProps<TData, TValue>) => {
const attributes = React.useMemo(() => {
return typeof attributesProp === 'function' ? attributesProp(header) : attributesProp;
}, [attributesProp, header]);

const className = React.useMemo(() => {
return typeof classNameProp === 'function' ? classNameProp(header) : classNameProp;
}, [classNameProp, header]);

if (header.isPlaceholder) {
return null;
}
Expand All @@ -26,7 +38,8 @@ export const BaseFooterCell = <TData, TValue>({
className={b('footer-cell', getHeaderCellClassModes(header), className)}
colSpan={header.colSpan > 1 ? header.colSpan : undefined}
rowSpan={rowSpan > 1 ? rowSpan : undefined}
style={getCellStyles(header)}
{...attributes}
style={getCellStyles(header, attributes?.style)}
>
{flexRender(header.column.columnDef.footer, header.getContext())}
</th>
Expand Down
37 changes: 28 additions & 9 deletions src/components/BaseFooterRow/BaseFooterRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,48 @@ import type {BaseFooterCellProps} from '../BaseFooterCell';
import {BaseFooterCell} from '../BaseFooterCell';
import {b} from '../BaseTable/BaseTable.classname';

export interface BaseFooterRowProps<TData, TValue>
extends React.TdHTMLAttributes<HTMLTableRowElement> {
cellClassName: BaseFooterCellProps<TData, TValue>['className'];
className?: string;
export interface BaseFooterRowProps<TData, TValue = unknown>
extends Omit<React.HTMLAttributes<HTMLTableRowElement>, 'className'> {
footerGroup: HeaderGroup<TData>;
attributes?:
| React.HTMLAttributes<HTMLTableRowElement>
| ((footerGroup: HeaderGroup<TData>) => React.HTMLAttributes<HTMLTableRowElement>);
cellAttributes?: BaseFooterCellProps<TData, TValue>['attributes'];
cellClassName?: BaseFooterCellProps<TData, TValue>['className'];
className?: string | ((footerGroup: HeaderGroup<TData>) => string);
}

export const BaseFooterRow = <TData, TValue>({
cellClassName,
className,
export const BaseFooterRow = <TData, TValue = unknown>({
footerGroup,
attributes: attributesProp,
cellAttributes,
cellClassName,
className: classNameProp,
...restProps
}: BaseFooterRowProps<TData, TValue>) => {
const attributes = React.useMemo(() => {
return typeof attributesProp === 'function' ? attributesProp(footerGroup) : attributesProp;
}, [attributesProp, footerGroup]);

const className = React.useMemo(() => {
return typeof classNameProp === 'function' ? classNameProp(footerGroup) : classNameProp;
}, [classNameProp, footerGroup]);

const isEmptyRow = footerGroup.headers.every((header) => !header.column.columnDef.footer);

if (isEmptyRow) {
return null;
}

return (
<tr className={b('footer-row', className)} {...restProps}>
<tr className={b('footer-row', className)} {...restProps} {...attributes}>
{footerGroup.headers.map((header) => (
<BaseFooterCell key={header.column.id} className={cellClassName} header={header} />
<BaseFooterCell
key={header.column.id}
header={header}
attributes={cellAttributes}
className={cellClassName}
/>
))}
</tr>
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/BaseGroupHeader/BaseGroupHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import {b} from './BaseGroupHeader.classname';
import './BaseGroupHeader.scss';

export interface BaseGroupHeaderProps<TData> {
row: Row<TData>;
className?: string;
getGroupTitle?: (row: Row<TData>) => React.ReactNode;
row: Row<TData>;
}

export const BaseGroupHeader = <TData,>({
row,
className,
getGroupTitle,
row,
}: BaseGroupHeaderProps<TData>) => {
return (
<h2 className={b(null, className)}>
Expand Down
17 changes: 9 additions & 8 deletions src/components/BaseHeaderCell/BaseHeaderCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ export interface BaseHeaderCellProps<TData, TValue> {
resizeHandleClassName?: string;
sortIndicatorClassName?: string;
attributes?:
| React.TdHTMLAttributes<HTMLTableCellElement>
| React.ThHTMLAttributes<HTMLTableCellElement>
| ((
header: Header<TData, TValue>,
parentHeader?: Header<TData, unknown>,
) => React.TdHTMLAttributes<HTMLTableCellElement>);
) => React.ThHTMLAttributes<HTMLTableCellElement>);
}

export const BaseHeaderCell = <TData, TValue>({
Expand All @@ -43,6 +43,12 @@ export const BaseHeaderCell = <TData, TValue>({
sortIndicatorClassName,
attributes: attributesProp,
}: BaseHeaderCellProps<TData, TValue>) => {
const attributes = React.useMemo(() => {
return typeof attributesProp === 'function'
? attributesProp(header, parentHeader)
: attributesProp;
}, [attributesProp, header, parentHeader]);

const className = React.useMemo(() => {
return typeof classNameProp === 'function'
? classNameProp(header, parentHeader)
Expand All @@ -65,21 +71,16 @@ export const BaseHeaderCell = <TData, TValue>({

const rowSpan = header.isPlaceholder ? header.getLeafHeaders().length : 1;

const attributes =
typeof attributesProp === 'function'
? attributesProp(header, parentHeader)
: attributesProp;

return (
<th
className={b('header-cell', getHeaderCellClassModes(header), className)}
colSpan={header.colSpan > 1 ? header.colSpan : undefined}
rowSpan={rowSpan > 1 ? rowSpan : undefined}
onClick={header.column.getToggleSortingHandler()}
style={getCellStyles(header)}
aria-sort={getAriaSort(header.column.getIsSorted())}
aria-colindex={getHeaderCellAriaColIndex(header)}
{...attributes}
style={getCellStyles(header, attributes?.style)}
>
{flexRender(header.column.columnDef.header, header.getContext())}{' '}
{header.column.getCanSort() &&
Expand Down
17 changes: 9 additions & 8 deletions src/components/BaseHeaderRow/BaseHeaderRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {BaseHeaderCell} from '../BaseHeaderCell';
import type {BaseResizeHandleProps} from '../BaseResizeHandle';
import {b} from '../BaseTable/BaseTable.classname';

export interface BaseHeaderRowProps<TData, TValue>
extends Omit<React.TdHTMLAttributes<HTMLTableRowElement>, 'className'> {
export interface BaseHeaderRowProps<TData, TValue = unknown>
extends Omit<React.HTMLAttributes<HTMLTableRowElement>, 'className'> {
cellClassName?: BaseHeaderCellProps<TData, TValue>['className'];
className?:
| string
Expand All @@ -28,7 +28,7 @@ export interface BaseHeaderRowProps<TData, TValue>
cellAttributes?: BaseHeaderCellProps<TData, TValue>['attributes'];
}

export const BaseHeaderRow = <TData, TValue>({
export const BaseHeaderRow = <TData, TValue = unknown>({
cellClassName,
className: classNameProp,
headerGroup,
Expand All @@ -41,17 +41,18 @@ export const BaseHeaderRow = <TData, TValue>({
cellAttributes,
...restProps
}: BaseHeaderRowProps<TData, TValue>) => {
const attributes = React.useMemo(() => {
return typeof attributesProp === 'function'
? attributesProp(headerGroup, parentHeaderGroup)
: attributesProp;
}, [attributesProp, headerGroup, parentHeaderGroup]);

const className = React.useMemo(() => {
return typeof classNameProp === 'function'
? classNameProp(headerGroup, parentHeaderGroup)
: classNameProp;
}, [classNameProp, headerGroup, parentHeaderGroup]);

const attributes =
typeof attributesProp === 'function'
? attributesProp(headerGroup, parentHeaderGroup)
: attributesProp;

return (
<tr className={b('header-row', className)} {...restProps} {...attributes}>
{headerGroup.headers.map((header) => (
Expand Down
Loading

0 comments on commit e3fff9e

Please sign in to comment.