Skip to content

Commit

Permalink
perf
Browse files Browse the repository at this point in the history
  • Loading branch information
zbeyens committed Dec 26, 2024
1 parent 2028e99 commit 297c112
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 120 deletions.
4 changes: 3 additions & 1 deletion apps/www/content/docs/en/components/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ v42
- Move icons to `table-icons`
- Remove `colgroup`, col width is now set in `table-cell-element`
- `table-row-element`: remove `hideBorder` prop
- `table-cell-element`, `table-cell-element-static`: column hover/resizing state is now using Tailwind instead of JS
- `table-cell-element`, `table-cell-element-static`:
- column hover/resizing state is now using Tailwind instead of JS
- React.memo
- `table-dropdown-menu`:
- dynamic table insert
- merge/split cells
Expand Down
248 changes: 160 additions & 88 deletions apps/www/src/registry/default/plate-ui/table-cell-element.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import React from 'react';

import type { BorderStylesDefault } from '@udecode/plate-table';

import { cn, withProps, withRef } from '@udecode/cn';
import { useEditorPlugin, useElement } from '@udecode/plate-common/react';
import { useBlockSelected } from '@udecode/plate-selection/react';
Expand All @@ -24,11 +26,7 @@ export const TableCellElement = withRef<
isHeader?: boolean;
}
>(({ children, className, isHeader, style, ...props }, ref) => {
const { element } = props;
const { api } = useEditorPlugin(TablePlugin);
const readOnly = useReadOnly();
const rowElement = useElement(TableRowPlugin.key);
const isSelectingRow = useBlockSelected(rowElement.id as string);

const {
borders,
Expand All @@ -49,100 +47,174 @@ export const TableCellElement = withRef<
});

return (
<PlateElement
<TableCellElementMemo
ref={ref}
as={isHeader ? 'th' : 'td'}
className={cn(
selected={selected}
borders={borders}
bottomProps={bottomProps}
colIndex={colIndex}
colSpan={colSpan}
hiddenLeft={hiddenLeft}
isSelectingCell={isSelectingCell}
leftProps={leftProps}
minHeight={minHeight}
rightProps={rightProps}
rowId={rowElement.id as string}
rowIndex={rowIndex}
width={width}
{...props}
>
{children}
</TableCellElementMemo>
);
});

const TableCellElementMemo = React.memo(
React.forwardRef<
React.ComponentRef<typeof PlateElement>,
React.ComponentPropsWithoutRef<typeof PlateElement> & {
borders: BorderStylesDefault;
bottomProps: React.ComponentPropsWithoutRef<typeof ResizeHandle>;
colIndex: number;
colSpan: number;
hiddenLeft: boolean;
isSelectingCell: boolean;
leftProps: React.ComponentPropsWithoutRef<typeof ResizeHandle>;
rightProps: React.ComponentPropsWithoutRef<typeof ResizeHandle>;
rowId: string;
rowIndex: number;
selected: boolean;
width: number | string;
isHeader?: boolean;
minHeight?: number | string;
}
>(
(
{
borders,
bottomProps,
children,
className,
'relative h-full overflow-visible border-none bg-background p-0',
element.background ? 'bg-[--cellBackground]' : 'bg-background',

cn(
isHeader && 'text-left [&_>_*]:m-0',
'before:size-full',
selected && 'before:z-10 before:bg-muted',
"before:absolute before:box-border before:select-none before:content-['']",
borders &&
colIndex,
hiddenLeft,
isHeader,
isSelectingCell,
leftProps,
minHeight,
rightProps,
rowId,
rowIndex,
selected,
style,
width,
...props
},
ref
) => {
const { api } = useEditorPlugin(TablePlugin);
const readOnly = useReadOnly();
const isSelectingRow = useBlockSelected(rowId);

const element = useElement();

return (
<PlateElement
ref={ref}
as={isHeader ? 'th' : 'td'}
className={cn(
className,
'relative h-full overflow-visible border-none bg-background p-0',
element.background ? 'bg-[--cellBackground]' : 'bg-background',

cn(
borders.bottom?.size && `before:border-b before:border-b-border`,
borders.right?.size && `before:border-r before:border-r-border`,
borders.left?.size && `before:border-l before:border-l-border`,
borders.top?.size && `before:border-t before:border-t-border`
isHeader && 'text-left [&_>_*]:m-0',
'before:size-full',
selected && 'before:z-10 before:bg-muted',
"before:absolute before:box-border before:select-none before:content-['']",
borders &&
cn(
borders.bottom?.size &&
`before:border-b before:border-b-border`,
borders.right?.size &&
`before:border-r before:border-r-border`,
borders.left?.size &&
`before:border-l before:border-l-border`,
borders.top?.size && `before:border-t before:border-t-border`
)
)
)
)}
style={
{
'--cellBackground': element.background,
maxWidth: width || 240,
minWidth: width || 120,
...style,
} as React.CSSProperties
}
{...{
colSpan: api.table.getColSpan(element),
rowSpan: api.table.getRowSpan(element),
}}
{...props}
>
<div
className="relative z-20 box-border h-full px-4 py-2"
style={{ minHeight }}
>
{children}
</div>

{!isSelectingCell && (
<div
className="group absolute top-0 size-full select-none"
contentEditable={false}
suppressContentEditableWarning={true}
)}
style={
{
'--cellBackground': element.background,
maxWidth: width || 240,
minWidth: width || 120,
...style,
} as React.CSSProperties
}
{...{
colSpan: api.table.getColSpan(element),
rowSpan: api.table.getRowSpan(element),
}}
{...props}
>
{!readOnly && (
<>
<ResizeHandle
{...rightProps}
className="-right-1 -top-2 h-[calc(100%_+_8px)] w-2"
data-col={colIndex}
/>
<ResizeHandle {...bottomProps} className="-bottom-1 h-2" />
{!hiddenLeft && (
<ResizeHandle
{...leftProps}
className="-left-1 top-0 w-2"
data-resizer-left={colIndex === 0 ? 'true' : undefined}
/>
)}
<div
className="relative z-20 box-border h-full px-4 py-2"
style={{ minHeight }}
>
{children}
</div>

{!isSelectingCell && (
<div
className="group absolute top-0 size-full select-none"
contentEditable={false}
suppressContentEditableWarning={true}
>
{!readOnly && (
<>
<ResizeHandle
{...rightProps}
className="-right-1 -top-2 h-[calc(100%_+_8px)] w-2"
data-col={colIndex}
/>
<ResizeHandle {...bottomProps} className="-bottom-1 h-2" />
{!hiddenLeft && (
<ResizeHandle
{...leftProps}
className="-left-1 top-0 w-2"
data-resizer-left={colIndex === 0 ? 'true' : undefined}
/>
)}

<div
className={cn(
'absolute top-0 z-30 hidden h-full w-1 bg-ring',
'right-[-1.5px]',
columnResizeVariants({ colIndex: colIndex as any })
)}
/>
{colIndex === 0 && (
<div
className={cn(
'absolute top-0 z-30 h-full w-1 bg-ring',
'left-[-1.5px]',
'hidden animate-in fade-in group-has-[[data-resizer-left]:hover]/table:block group-has-[[data-resizer-left][data-resizing="true"]]/table:block'
<div
className={cn(
'absolute top-0 z-30 hidden h-full w-1 bg-ring',
'right-[-1.5px]',
columnResizeVariants({ colIndex: colIndex as any })
)}
/>
{colIndex === 0 && (
<div
className={cn(
'absolute top-0 z-30 h-full w-1 bg-ring',
'left-[-1.5px]',
'hidden animate-in fade-in group-has-[[data-resizer-left]:hover]/table:block group-has-[[data-resizer-left][data-resizing="true"]]/table:block'
)}
/>
)}
/>
</>
)}
</>
</div>
)}
</div>
)}

{isSelectingRow && (
<div className={blockSelectionVariants()} contentEditable={false} />
)}
</PlateElement>
);
});

TableCellElement.displayName = 'TableCellElement';
{isSelectingRow && (
<div className={blockSelectionVariants()} contentEditable={false} />
)}
</PlateElement>
);
}
)
);

export const TableCellHeaderElement = withProps(TableCellElement, {
isHeader: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ export const useTableCellElement = (): TableCellElementState => {
[api.table, colSizes, element]
);

const borders = getTableCellBorders(editor, { element });
const borders = React.useMemo(
() => getTableCellBorders(editor, { element }),
[editor, element]
);

React.useEffect(() => {
setIndices(
Expand Down
Loading

0 comments on commit 297c112

Please sign in to comment.