Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table cells merging #2666

Closed
wants to merge 46 commits into from
Closed
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
29c6ea7
[SlateEditor] implement merge and unmerge
dimaanj Aug 24, 2023
79c3548
[TablePlugin] fix resize
dimaanj Aug 25, 2023
2f33bf0
[TablePlugin] fix pasting table from word and other sites
dimaanj Aug 25, 2023
278bfd1
[TablePlugin] add comment
dimaanj Aug 25, 2023
b9b8bdb
[TablePlugin] change icon for unmerge button
dimaanj Aug 25, 2023
00197fc
[TablePlugin] fix bug in ff
dimaanj Aug 28, 2023
831b583
Merge branch 'main' of https://github.com/udecode/plate into table-ce…
dimaanj Aug 29, 2023
c06db8c
[TablePlugin] fix lint problems
dimaanj Aug 29, 2023
32c75d4
[TablePlugin] fix types and tests
dimaanj Aug 30, 2023
f56a9ec
[TablePlugin] fix serialisation tests for table element
dimaanj Aug 30, 2023
da2fb2a
Merge branch 'main' of https://github.com/udecode/plate into table-ce…
dimaanj Sep 5, 2023
ecf14a8
[TablePlugin] fix some issues
dimaanj Sep 6, 2023
5a79d1b
[TablePlugin] implement handy selection, make merge and unmerge stable
dimaanj Sep 8, 2023
d777438
[TablePlugin] implement column / row adding / removal functions with …
dimaanj Sep 15, 2023
7cc1c84
[SlateEditor] remove logs
dimaanj Sep 15, 2023
0ce531b
Merge branch 'main' of https://github.com/udecode/plate into table-ce…
dimaanj Sep 19, 2023
595e4f1
[SlateEditor] do not push empty cells to merged cell
dimaanj Sep 19, 2023
b07eae0
[TablePlugin] fix some tests
dimaanj Sep 21, 2023
9ef9bd7
[TablePlugin] update remaining tests
dimaanj Sep 22, 2023
884cea7
[TablePlugin] remove logs
dimaanj Sep 22, 2023
734140b
Oct 2, 2023
36d3031
Oct 2, 2023
fe2e601
Merge branch 'main' into table-cells-merging-poc-2
Oct 2, 2023
1c62e6c
Oct 2, 2023
18e4caa
Merge branch 'main' into table-cells-merging-poc-2
Oct 2, 2023
4ee33e5
Oct 2, 2023
69b9df9
🐛
Sep 27, 2023
3156954
test vercel deployment
shahriar-shojib Sep 29, 2023
748f132
revert <AnyObject> changes
shahriar-shojib Sep 30, 2023
f235424
👷
Oct 2, 2023
e94456d
👷
Oct 2, 2023
954292c
Disable tabbable when editor is read-only
12joan Oct 2, 2023
5abf727
Version Packages
github-actions[bot] Oct 2, 2023
1f4c8c7
Oct 2, 2023
a08587a
Oct 2, 2023
0723474
Oct 2, 2023
8e82f0d
👷
Oct 2, 2023
a8b9134
Version Packages
github-actions[bot] Oct 2, 2023
004974c
👷
Oct 3, 2023
6af32b2
👷
Oct 3, 2023
161e016
Create four-hornets-decide.md
zbeyens Oct 3, 2023
e92d8c5
Version Packages
github-actions[bot] Oct 3, 2023
fc70584
👷
Oct 3, 2023
f4a8914
Merge branch 'main' into table-cells-merging-poc-2
zbeyens Oct 3, 2023
bc6af88
🎨
Oct 3, 2023
c2b1fb5
🎨
Oct 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/e2e-examples/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const router = createBrowserRouter([

const rootElement = document.querySelector('#root');

// eslint-disable-next-line react/no-deprecated
ReactDOM.render(
<React.StrictMode>
<RouterProvider router={router} />
Expand Down
7 changes: 7 additions & 0 deletions apps/www/content/docs/components/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ Since Plate UI is not a component library, a changelog is maintained here.

Use the [CLI](https://platejs.org/docs/components/cli) to install the latest version of the components.

## October 2023 #5

### 2 Oct #5.1

- `table-cell-element`:
- feat: merging cells

## September 2023 #4

### 18 Sept #4.4
Expand Down
4 changes: 4 additions & 0 deletions apps/www/src/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
ChevronsUpDown,
ClipboardCheck,
Code2,
Combine,
Copy,
DownloadCloud,
ExternalLink,
Expand Down Expand Up @@ -73,6 +74,7 @@ import {
Trash,
Twitter,
Underline,
Ungroup,
Unlink,
WrapText,
X,
Expand Down Expand Up @@ -281,6 +283,8 @@ export const Icons = {
codeblock: FileCode,
color: Baseline,
column: RectangleVertical,
combine: Combine,
ungroup: Ungroup,
comment: MessageSquare,
commentAdd: MessageSquarePlus,
conflict: Unlink,
Expand Down
9 changes: 7 additions & 2 deletions apps/www/src/registry/default/plate-ui/table-cell-element.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,24 @@ const TableCellElement = React.forwardRef<
const {
colIndex,
rowIndex,
colSpan,
readOnly,
selected,
hovered,
hoveredLeft,
rowSize,
borders,
isSelectingCell,
cellRef,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should come from useTableCellElement

} = useTableCellElementState();
const { props: cellProps } = useTableCellElement({ element: props.element });

const resizableState = useTableCellElementResizableState({
colIndex,
rowIndex,
colSpan,
});

const { rightProps, bottomProps, leftProps, hiddenLeft } =
useTableCellElementResizable(resizableState);

Expand All @@ -50,7 +55,7 @@ const TableCellElement = React.forwardRef<
asChild
ref={ref}
className={cn(
'relative overflow-visible border-none bg-background p-0',
'relative h-full overflow-visible border-none bg-background p-0',
hideBorder && 'before:border-none',
element.background ? 'bg-[--cellBackground]' : 'bg-background',
!hideBorder &&
Expand Down Expand Up @@ -79,7 +84,7 @@ const TableCellElement = React.forwardRef<
} as React.CSSProperties
}
>
<Cell>
<Cell ref={cellRef}>
<div
className="relative z-20 box-border h-full px-3 py-2"
style={{
Expand Down
25 changes: 25 additions & 0 deletions apps/www/src/registry/default/plate-ui/table-dropdown-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
deleteRow,
deleteTable,
ELEMENT_TABLE,
getTableEntries,
insertTable,
insertTableColumn,
insertTableRow,
Expand All @@ -32,6 +33,8 @@ export function TableDropdownMenu(props: DropdownMenuProps) {
match: { type: ELEMENT_TABLE },
});

const { cell, row } = getTableEntries(editor) || {};

const openState = useOpenState();

return (
Expand Down Expand Up @@ -82,6 +85,17 @@ export function TableDropdownMenu(props: DropdownMenuProps) {
<span>Column</span>
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem
className="min-w-[180px]"
disabled={!tableSelected}
onSelect={async () => {
insertTableColumn(editor, { at: cell![1] });
focusEditor(editor);
}}
>
<Icons.add className={iconVariants({ variant: 'menuItem' })} />
Insert column before
</DropdownMenuItem>
<DropdownMenuItem
className="min-w-[180px]"
disabled={!tableSelected}
Expand Down Expand Up @@ -113,6 +127,17 @@ export function TableDropdownMenu(props: DropdownMenuProps) {
<span>Row</span>
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem
className="min-w-[180px]"
disabled={!tableSelected}
onSelect={async () => {
insertTableRow(editor, { at: row![1] });
focusEditor(editor);
}}
>
<Icons.add className={iconVariants({ variant: 'menuItem' })} />
Insert row before
</DropdownMenuItem>
<DropdownMenuItem
className="min-w-[180px]"
disabled={!tableSelected}
Expand Down
89 changes: 68 additions & 21 deletions apps/www/src/registry/default/plate-ui/table-element.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
import { PopoverAnchor, PopoverContentProps } from '@radix-ui/react-popover';
import {
isCollapsed,
isExpanded,
PlateElement,
PlateElementProps,
useEditorState,
useElement,
useRemoveNodeButton,
} from '@udecode/plate-common';
import {
getTableGridAbove,
mergeTableCells,
TTableElement,
unmergeTableCells,
useTableBordersDropdownMenuContentState,
useTableElement,
useTableElementState,
Expand Down Expand Up @@ -114,7 +118,64 @@ const TableFloatingToolbar = React.forwardRef<
const readOnly = useReadOnly();
const selected = useSelected();
const editor = useEditorState();
const open = !readOnly && selected && isCollapsed(editor.selection);
const collapsed = !readOnly && selected && isCollapsed(editor.selection);
const expanded = !readOnly && selected && isExpanded(editor.selection);
const open = !readOnly && selected;

const cellEntries = getTableGridAbove(editor, { format: 'cell' });

const canUnmerge =
collapsed &&
cellEntries &&
cellEntries.length === 1 &&
((cellEntries[0][0] as any)?.colSpan > 1 ||
(cellEntries[0][0] as any)?.rowSpan > 1);

const mergeContent = expanded && (
<Button
contentEditable={false}
variant="ghost"
isMenu
onClick={() => mergeTableCells(editor)}
>
<Icons.combine className="mr-2 h-4 w-4" />
Merge
</Button>
);

const unmergeButton = canUnmerge && (
<Button
contentEditable={false}
variant="ghost"
isMenu
onClick={() => unmergeTableCells(editor)}
>
<Icons.ungroup className="mr-2 h-4 w-4" />
Unmerge
</Button>
);

const bordersContent = collapsed && (
<>
<DropdownMenu modal={false}>
<DropdownMenuTrigger asChild>
<Button variant="ghost" isMenu>
<Icons.borderAll className="mr-2 h-4 w-4" />
Borders
</Button>
</DropdownMenuTrigger>

<DropdownMenuPortal>
<TableBordersDropdownMenuContent />
</DropdownMenuPortal>
</DropdownMenu>

<Button contentEditable={false} variant="ghost" isMenu {...buttonProps}>
<Icons.delete className="mr-2 h-4 w-4" />
Delete
</Button>
</>
);

return (
<Popover open={open} modal={false}>
Expand All @@ -125,23 +186,9 @@ const TableFloatingToolbar = React.forwardRef<
onOpenAutoFocus={(e) => e.preventDefault()}
{...props}
>
<DropdownMenu modal={false}>
<DropdownMenuTrigger asChild>
<Button variant="ghost" isMenu>
<Icons.borderAll className="mr-2 h-4 w-4" />
Borders
</Button>
</DropdownMenuTrigger>

<DropdownMenuPortal>
<TableBordersDropdownMenuContent />
</DropdownMenuPortal>
</DropdownMenu>

<Button contentEditable={false} variant="ghost" isMenu {...buttonProps}>
<Icons.delete className="mr-2 h-4 w-4" />
Delete
</Button>
{unmergeButton}
{mergeContent}
{bordersContent}
</PopoverContent>
</Popover>
);
Expand All @@ -152,7 +199,7 @@ const TableElement = React.forwardRef<
React.ElementRef<typeof PlateElement>,
PlateElementProps
>(({ className, children, ...props }, ref) => {
const { colSizes, isSelectingCell, minColumnWidth, marginLeft } =
const { colSizes, tableWidth, isSelectingCell, minColumnWidth, marginLeft } =
useTableElementState();
const { props: tableProps, colGroupProps } = useTableElement();

Expand All @@ -163,14 +210,14 @@ const TableElement = React.forwardRef<
asChild
ref={ref}
className={cn(
'my-4 ml-px mr-0 table h-px w-full table-fixed border-collapse',
'relative my-4 ml-px mr-0 table h-px w-full table-fixed border-collapse',
isSelectingCell && '[&_*::selection]:bg-none',
className
)}
{...tableProps}
{...props}
>
<table>
<table style={{ width: tableWidth }}>
<colgroup {...colGroupProps}>
{colSizes.map((width, index) => (
<col
Expand Down
11 changes: 9 additions & 2 deletions packages/resizable/src/components/ResizeHandle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const ResizeHandleProvider = ({

export type ResizeHandleOptions = {
direction?: ResizeDirection;
initialSize?: number;
onResize?: (event: ResizeEvent) => void;
onMouseDown?: MouseEventHandler;
onTouchStart?: TouchEventHandler;
Expand All @@ -60,6 +61,7 @@ export type ResizeHandleOptions = {

export const useResizeHandleState = ({
direction = 'left',
initialSize: _initialSize,
onResize,
onMouseDown,
onTouchStart,
Expand All @@ -71,7 +73,7 @@ export const useResizeHandleState = ({

const [isResizing, setIsResizing] = useState(false);
const [initialPosition, setInitialPosition] = useState(0);
const [initialSize, setInitialSize] = useState(0);
const [initialSize, setInitialSize] = useState(_initialSize ?? 0);

const isHorizontal = direction === 'left' || direction === 'right';

Expand All @@ -88,7 +90,12 @@ export const useResizeHandleState = ({

const currentPosition = isHorizontal ? clientX : clientY;
const delta = currentPosition - initialPosition;
onResize?.({ initialSize, delta, finished, direction });
onResize?.({
initialSize,
delta,
finished,
direction,
});
};

const handleMouseMove = (event: MouseEvent | TouchEvent) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { TableCellElementState } from './useTableCellElementState';

export type TableCellElementResizableOptions = Pick<
TableCellElementState,
'colIndex' | 'rowIndex'
'colIndex' | 'rowIndex' | 'colSpan'
> & {
/**
* Resize by step instead of by pixel.
Expand All @@ -47,6 +47,7 @@ export type TableCellElementResizableOptions = Pick<
export const useTableCellElementResizableState = ({
colIndex,
rowIndex,
colSpan,
step,
stepX = step,
stepY = step,
Expand All @@ -61,6 +62,7 @@ export const useTableCellElementResizableState = ({
disableMarginLeft,
colIndex,
rowIndex,
colSpan,
stepX,
stepY,
};
Expand All @@ -70,6 +72,7 @@ export const useTableCellElementResizable = ({
disableMarginLeft,
colIndex,
rowIndex,
colSpan,
stepX,
stepY,
}: ReturnType<typeof useTableCellElementResizableState>): {
Expand All @@ -86,6 +89,12 @@ export const useTableCellElementResizable = ({
ELEMENT_TABLE
);

// MERGE: override width for horizontally merged cell
let initialWidth: number | undefined;
if (colSpan > 1) {
initialWidth = tableElement.colSizes?.[colIndex];
}

const [hoveredColIndex, setHoveredColIndex] =
useTableStore().use.hoveredColIndex();

Expand Down Expand Up @@ -246,6 +255,7 @@ export const useTableCellElementResizable = ({
rightProps: {
options: {
direction: 'right',
initialSize: initialWidth,
onResize: handleResizeRight,
...getHandleHoverProps(colIndex),
},
Expand Down
Loading
Loading