diff --git a/apps/www/content/docs/components/changelog.mdx b/apps/www/content/docs/components/changelog.mdx index fa9390d5bd..c0f17ad0db 100644 --- a/apps/www/content/docs/components/changelog.mdx +++ b/apps/www/content/docs/components/changelog.mdx @@ -10,10 +10,15 @@ Use the [CLI](https://platejs.org/docs/components/cli) to install the latest ver ## November 2023 #5 -### 5 Nov #5.1 - -- `comment-more-dropdown`: fix edit and delete comments -- `comment-value`: remove `useCommentValue` (deprecated from plate 25) +### 28 Nov #5.1 + +- `table-element`: merging support (plate 26) +- `table-cell-element`: merging support (plate 26) +- `comments-popover` + - `comment-more-dropdown`: fix edit and delete comments + - `comment-value`: remove `useCommentValue` (deprecated from plate 25) +- `toolbar` + - [fix](https://github.com/udecode/plate/pull/2742/files): pressed state ## September 2023 #4 diff --git a/apps/www/content/docs/table.mdx b/apps/www/content/docs/table.mdx index 0f4a5a6e8a..43a71b6341 100644 --- a/apps/www/content/docs/table.mdx +++ b/apps/www/content/docs/table.mdx @@ -14,6 +14,8 @@ docs: + + ## Features diff --git a/apps/www/public/registry/styles/default/comments-popover.json b/apps/www/public/registry/styles/default/comments-popover.json index de37152307..23259ea590 100644 --- a/apps/www/public/registry/styles/default/comments-popover.json +++ b/apps/www/public/registry/styles/default/comments-popover.json @@ -26,7 +26,7 @@ }, { "name": "comment-more-dropdown.tsx", - "content": "'use client';\n\nimport React from 'react';\nimport {\n useCommentDeleteButton,\n useCommentDeleteButtonState,\n useCommentEditButton,\n useCommentEditButtonState,\n} from '@udecode/plate-comments';\n\nimport { cn } from '@/lib/utils';\nimport { Icons } from '@/components/icons';\nimport { Button } from '@/registry/default/plate-ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@/registry/default/plate-ui/dropdown-menu';\n\nexport function CommentMoreDropdown() {\n const editButtonState = useCommentEditButtonState();\n const editProps = useCommentEditButton(editButtonState);\n const deleteButtonState = useCommentDeleteButtonState();\n const deleteProps = useCommentDeleteButton(deleteButtonState);\n\n return (\n \n \n \n \n \n \n Edit comment\n \n \n Delete comment\n \n \n \n );\n}\n" + "content": "'use client';\n\nimport React from 'react';\nimport {\n useCommentDeleteButton,\n useCommentDeleteButtonState,\n useCommentEditButton,\n useCommentEditButtonState,\n} from '@udecode/plate-comments';\n\nimport { cn } from '@/lib/utils';\nimport { Icons } from '@/components/icons';\nimport { Button } from '@/registry/default/plate-ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@/registry/default/plate-ui/dropdown-menu';\n\nexport function CommentMoreDropdown() {\n const editButtonState = useCommentEditButtonState();\n const { props: editProps } = useCommentEditButton(editButtonState);\n const deleteButtonState = useCommentDeleteButtonState();\n const { props: deleteProps } = useCommentDeleteButton(deleteButtonState);\n\n return (\n \n \n \n \n \n Edit comment\n Delete comment\n \n \n );\n}\n" }, { "name": "comment-reply-items.tsx", @@ -38,7 +38,7 @@ }, { "name": "comment-value.tsx", - "content": "'use client';\n\nimport React from 'react';\nimport {\n CommentEditActions,\n CommentEditTextarea,\n useCommentValue,\n} from '@udecode/plate-comments';\n\nimport { cn } from '@/lib/utils';\nimport { buttonVariants } from '@/registry/default/plate-ui/button';\nimport { inputVariants } from '@/registry/default/plate-ui/input';\n\nexport function CommentValue() {\n const { textareaRef } = useCommentValue();\n\n return (\n
\n \n\n
\n \n Cancel\n \n\n \n Save\n \n
\n
\n );\n}\n" + "content": "'use client';\n\nimport React from 'react';\nimport {\n CommentEditActions,\n CommentEditTextarea,\n} from '@udecode/plate-comments';\n\nimport { cn } from '@/lib/utils';\nimport { buttonVariants } from '@/registry/default/plate-ui/button';\nimport { inputVariants } from '@/registry/default/plate-ui/input';\n\nexport function CommentValue() {\n return (\n
\n \n\n
\n \n Cancel\n \n\n \n Save\n \n
\n
\n );\n}\n" } ], "type": "components:plate-ui" diff --git a/apps/www/public/registry/styles/default/table-cell-element.json b/apps/www/public/registry/styles/default/table-cell-element.json index 60e93f2774..9175604cb5 100644 --- a/apps/www/public/registry/styles/default/table-cell-element.json +++ b/apps/www/public/registry/styles/default/table-cell-element.json @@ -9,7 +9,7 @@ "files": [ { "name": "table-cell-element.tsx", - "content": "import React from 'react';\nimport { PlateElement, PlateElementProps, Value } from '@udecode/plate-common';\nimport {\n TTableCellElement,\n useTableCellElement,\n useTableCellElementResizable,\n useTableCellElementResizableState,\n useTableCellElementState,\n} from '@udecode/plate-table';\n\nimport { cn } from '@/lib/utils';\n\nimport { ResizeHandle } from './resizable';\n\nexport interface TableCellElementProps\n extends PlateElementProps {\n hideBorder?: boolean;\n isHeader?: boolean;\n}\n\nconst TableCellElement = React.forwardRef<\n React.ElementRef,\n TableCellElementProps\n>(({ children, className, style, hideBorder, isHeader, ...props }, ref) => {\n const { element } = props;\n\n const {\n colIndex,\n rowIndex,\n readOnly,\n selected,\n hovered,\n hoveredLeft,\n rowSize,\n borders,\n isSelectingCell,\n } = useTableCellElementState();\n const { props: cellProps } = useTableCellElement({ element: props.element });\n const resizableState = useTableCellElementResizableState({\n colIndex,\n rowIndex,\n });\n const { rightProps, bottomProps, leftProps, hiddenLeft } =\n useTableCellElementResizable(resizableState);\n\n const Cell = isHeader ? 'th' : 'td';\n\n return (\n _*]:m-0',\n 'before:h-full before:w-full',\n selected && 'before:z-10 before:bg-muted',\n \"before:absolute before:box-border before:select-none before:content-['']\",\n borders &&\n cn(\n borders.bottom?.size &&\n `before:border-b before:border-b-border`,\n borders.right?.size && `before:border-r before:border-r-border`,\n borders.left?.size && `before:border-l before:border-l-border`,\n borders.top?.size && `before:border-t before:border-t-border`\n )\n ),\n className\n )}\n {...cellProps}\n {...props}\n style={\n {\n '--cellBackground': element.background,\n ...style,\n } as React.CSSProperties\n }\n >\n \n \n {children}\n \n\n {!isSelectingCell && (\n \n {!readOnly && (\n <>\n \n \n {!hiddenLeft && (\n \n )}\n\n {hovered && (\n \n )}\n {hoveredLeft && (\n \n )}\n \n )}\n \n )}\n \n \n );\n});\nTableCellElement.displayName = 'TableCellElement';\n\nconst TableCellHeaderElement = React.forwardRef<\n React.ElementRef,\n TableCellElementProps\n>((props, ref) => {\n return ;\n});\nTableCellHeaderElement.displayName = 'TableCellHeaderElement';\n\nexport { TableCellElement, TableCellHeaderElement };\n" + "content": "import React from 'react';\nimport { PlateElement, PlateElementProps, Value } from '@udecode/plate-common';\nimport {\n TTableCellElement,\n useTableCellElement,\n useTableCellElementResizable,\n useTableCellElementResizableState,\n useTableCellElementState,\n} from '@udecode/plate-table';\n\nimport { cn } from '@/lib/utils';\n\nimport { ResizeHandle } from './resizable';\n\nexport interface TableCellElementProps\n extends PlateElementProps {\n hideBorder?: boolean;\n isHeader?: boolean;\n}\n\nconst TableCellElement = React.forwardRef<\n React.ElementRef,\n TableCellElementProps\n>(({ children, className, style, hideBorder, isHeader, ...props }, ref) => {\n const { element } = props;\n\n const {\n colIndex,\n rowIndex,\n readOnly,\n selected,\n hovered,\n hoveredLeft,\n rowSize,\n borders,\n isSelectingCell,\n colSpan,\n } = useTableCellElementState();\n const { props: cellProps } = useTableCellElement({ element: props.element });\n const resizableState = useTableCellElementResizableState({\n colIndex,\n rowIndex,\n colSpan,\n });\n\n const { rightProps, bottomProps, leftProps, hiddenLeft } =\n useTableCellElementResizable(resizableState);\n\n const Cell = isHeader ? 'th' : 'td';\n\n return (\n _*]:m-0',\n 'before:h-full before:w-full',\n selected && 'before:z-10 before:bg-muted',\n \"before:absolute before:box-border before:select-none before:content-['']\",\n borders &&\n cn(\n borders.bottom?.size &&\n `before:border-b before:border-b-border`,\n borders.right?.size && `before:border-r before:border-r-border`,\n borders.left?.size && `before:border-l before:border-l-border`,\n borders.top?.size && `before:border-t before:border-t-border`\n )\n ),\n className\n )}\n {...cellProps}\n {...props}\n style={\n {\n '--cellBackground': element.background,\n ...style,\n } as React.CSSProperties\n }\n >\n \n \n {children}\n \n\n {!isSelectingCell && (\n \n {!readOnly && (\n <>\n \n \n {!hiddenLeft && (\n \n )}\n\n {hovered && (\n \n )}\n {hoveredLeft && (\n \n )}\n \n )}\n \n )}\n \n \n );\n});\nTableCellElement.displayName = 'TableCellElement';\n\nconst TableCellHeaderElement = React.forwardRef<\n React.ElementRef,\n TableCellElementProps\n>((props, ref) => {\n return ;\n});\nTableCellHeaderElement.displayName = 'TableCellHeaderElement';\n\nexport { TableCellElement, TableCellHeaderElement };\n" } ], "type": "components:plate-ui" diff --git a/apps/www/public/registry/styles/default/table-element.json b/apps/www/public/registry/styles/default/table-element.json index eaa8db65bc..a119ed97df 100644 --- a/apps/www/public/registry/styles/default/table-element.json +++ b/apps/www/public/registry/styles/default/table-element.json @@ -9,7 +9,7 @@ "files": [ { "name": "table-element.tsx", - "content": "import React, { forwardRef } from 'react';\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';\nimport { PopoverAnchor, PopoverContentProps } from '@radix-ui/react-popover';\nimport {\n isCollapsed,\n PlateElement,\n PlateElementProps,\n useEditorState,\n useElement,\n useRemoveNodeButton,\n} from '@udecode/plate-common';\nimport {\n TTableElement,\n useTableBordersDropdownMenuContentState,\n useTableElement,\n useTableElementState,\n} from '@udecode/plate-table';\nimport { useReadOnly, useSelected } from 'slate-react';\n\nimport { cn } from '@/lib/utils';\nimport { Icons, iconVariants } from '@/components/icons';\n\nimport { Button } from './button';\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n} from './dropdown-menu';\nimport { Popover, PopoverContent, popoverVariants } from './popover';\nimport { Separator } from './separator';\n\nconst TableBordersDropdownMenuContent = forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => {\n const {\n getOnSelectTableBorder,\n hasOuterBorders,\n hasBottomBorder,\n hasLeftBorder,\n hasNoBorders,\n hasRightBorder,\n hasTopBorder,\n } = useTableBordersDropdownMenuContentState();\n\n return (\n \n \n \n
Bottom Border
\n \n \n \n
Top Border
\n \n \n \n
Left Border
\n \n \n \n
Right Border
\n \n\n \n\n \n \n
No Border
\n \n \n \n
Outside Borders
\n \n \n );\n});\nTableBordersDropdownMenuContent.displayName = 'TableBordersDropdownMenuContent';\n\nconst TableFloatingToolbar = React.forwardRef<\n React.ElementRef,\n PopoverContentProps\n>(({ children, ...props }, ref) => {\n const element = useElement();\n const { props: buttonProps } = useRemoveNodeButton({ element });\n\n const readOnly = useReadOnly();\n const selected = useSelected();\n const editor = useEditorState();\n const open = !readOnly && selected && isCollapsed(editor.selection);\n\n return (\n \n {children}\n e.preventDefault()}\n {...props}\n >\n \n \n \n \n\n \n \n \n \n\n \n \n \n );\n});\nTableFloatingToolbar.displayName = 'TableFloatingToolbar';\n\nconst TableElement = React.forwardRef<\n React.ElementRef,\n PlateElementProps\n>(({ className, children, ...props }, ref) => {\n const { colSizes, isSelectingCell, minColumnWidth, marginLeft } =\n useTableElementState();\n const { props: tableProps, colGroupProps } = useTableElement();\n\n return (\n \n
\n \n \n \n {colSizes.map((width, index) => (\n \n ))}\n \n\n {children}\n
\n \n
\n
\n );\n});\nTableElement.displayName = 'TableElement';\n\nexport { TableElement, TableFloatingToolbar, TableBordersDropdownMenuContent };\n" + "content": "import React, { forwardRef } from 'react';\nimport * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';\nimport { PopoverAnchor, PopoverContentProps } from '@radix-ui/react-popover';\nimport {\n isCollapsed,\n PlateElement,\n PlateElementProps,\n useEditorState,\n useElement,\n useRemoveNodeButton,\n} from '@udecode/plate-common';\nimport {\n mergeTableCells,\n TTableElement,\n unmergeTableCells,\n useTableBordersDropdownMenuContentState,\n useTableElement,\n useTableElementState,\n useTableMergeState,\n} from '@udecode/plate-table';\nimport { useReadOnly, useSelected } from 'slate-react';\n\nimport { cn } from '@/lib/utils';\nimport { Icons, iconVariants } from '@/components/icons';\n\nimport { Button } from './button';\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n} from './dropdown-menu';\nimport { Popover, PopoverContent, popoverVariants } from './popover';\nimport { Separator } from './separator';\n\nconst TableBordersDropdownMenuContent = forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => {\n const {\n getOnSelectTableBorder,\n hasOuterBorders,\n hasBottomBorder,\n hasLeftBorder,\n hasNoBorders,\n hasRightBorder,\n hasTopBorder,\n } = useTableBordersDropdownMenuContentState();\n\n return (\n \n \n \n
Bottom Border
\n \n \n \n
Top Border
\n \n \n \n
Left Border
\n \n \n \n
Right Border
\n \n\n \n\n \n \n
No Border
\n \n \n \n
Outside Borders
\n \n \n );\n});\nTableBordersDropdownMenuContent.displayName = 'TableBordersDropdownMenuContent';\n\nconst TableFloatingToolbar = React.forwardRef<\n React.ElementRef,\n PopoverContentProps\n>(({ children, ...props }, ref) => {\n const element = useElement();\n const { props: buttonProps } = useRemoveNodeButton({ element });\n\n const readOnly = useReadOnly();\n const selected = useSelected();\n const editor = useEditorState();\n\n const collapsed = !readOnly && selected && isCollapsed(editor.selection);\n const open = !readOnly && selected;\n\n const { canMerge, canUnmerge } = useTableMergeState();\n\n const mergeContent = canMerge && (\n mergeTableCells(editor)}\n >\n \n Merge\n \n );\n\n const unmergeButton = canUnmerge && (\n unmergeTableCells(editor)}\n >\n \n Unmerge\n \n );\n\n const bordersContent = collapsed && (\n <>\n \n \n \n \n\n \n \n \n \n\n \n \n );\n\n return (\n \n {children}\n {(canMerge || canUnmerge || collapsed) && (\n e.preventDefault()}\n {...props}\n >\n {unmergeButton}\n {mergeContent}\n {bordersContent}\n \n )}\n \n );\n});\nTableFloatingToolbar.displayName = 'TableFloatingToolbar';\n\nconst TableElement = React.forwardRef<\n React.ElementRef,\n PlateElementProps\n>(({ className, children, ...props }, ref) => {\n const { colSizes, isSelectingCell, minColumnWidth, marginLeft } =\n useTableElementState();\n const { props: tableProps, colGroupProps } = useTableElement();\n\n return (\n \n
\n \n \n \n {colSizes.map((width, index) => (\n \n ))}\n \n\n {children}\n
\n \n
\n
\n );\n});\nTableElement.displayName = 'TableElement';\n\nexport { TableElement, TableFloatingToolbar, TableBordersDropdownMenuContent };\n" } ], "type": "components:plate-ui" diff --git a/apps/www/public/registry/styles/default/toolbar.json b/apps/www/public/registry/styles/default/toolbar.json index 18aa2435fc..24ce7ade72 100644 --- a/apps/www/public/registry/styles/default/toolbar.json +++ b/apps/www/public/registry/styles/default/toolbar.json @@ -11,7 +11,7 @@ "files": [ { "name": "toolbar.tsx", - "content": "'use client';\n\nimport * as React from 'react';\nimport { ReactNode } from 'react';\nimport * as ToolbarPrimitive from '@radix-ui/react-toolbar';\nimport { cva, VariantProps } from 'class-variance-authority';\n\nimport { cn } from '@/lib/utils';\nimport { Icons } from '@/components/icons';\n\nimport { Separator } from './separator';\nimport { ToggleProps, toggleVariants } from './toggle';\nimport {\n Tooltip,\n TooltipContent,\n TooltipPortal,\n TooltipTrigger,\n} from './tooltip';\n\nconst toolbarVariants = cva(\n 'relative flex select-none items-stretch gap-1 bg-background'\n);\n\nexport const linkVariants = cva('font-medium underline underline-offset-4');\n\nconst ToolbarToggleGroup = ToolbarPrimitive.ToggleGroup;\n\nexport interface ToolbarProps\n extends React.ComponentPropsWithoutRef {}\n\nconst Toolbar = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef &\n VariantProps\n>(({ className, ...props }, ref) => (\n \n));\nToolbar.displayName = ToolbarPrimitive.Root.displayName;\n\nconst ToolbarLink = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef &\n VariantProps\n>(({ className, ...props }, ref) => (\n \n));\nToolbarLink.displayName = ToolbarPrimitive.Link.displayName;\n\nconst ToolbarSeparator = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n));\nToolbarSeparator.displayName = ToolbarPrimitive.Separator.displayName;\n\nexport interface ToolbarButtonProps\n extends React.ComponentPropsWithoutRef,\n VariantProps,\n Omit {\n buttonType?: 'button' | 'toggle';\n pressed?: boolean;\n tooltip?: ReactNode;\n isDropdown?: boolean;\n}\n\nconst ToolbarButton = React.forwardRef<\n React.ElementRef,\n ToolbarButtonProps\n>(\n (\n {\n className,\n variant,\n size = 'sm',\n isDropdown,\n children,\n pressed,\n value,\n tooltip,\n ...props\n },\n ref\n ) => {\n const [isLoaded, setIsLoaded] = React.useState(false);\n\n React.useEffect(() => {\n setIsLoaded(true);\n }, []);\n\n const content =\n typeof pressed === 'boolean' ? (\n \n \n
{children}
\n
\n {isDropdown && (\n \n )}\n
\n \n \n ) : (\n \n {children}\n \n );\n\n return isLoaded && tooltip ? (\n \n {content}\n\n \n {tooltip}\n \n \n ) : (\n <>{content}\n );\n }\n);\nToolbarButton.displayName = ToolbarPrimitive.Button.displayName;\n\nconst ToolbarToggleItem = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef &\n VariantProps\n>(({ className, variant, size, ...props }, ref) => (\n \n));\nToolbarToggleItem.displayName = ToolbarPrimitive.ToggleItem.displayName;\n\nconst ToolbarGroup = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes & { noSeparator?: boolean }\n>(({ noSeparator, className, children }, ref) => {\n const childArr = React.Children.map(children, (c) => c);\n if (!childArr || childArr.length === 0) return null;\n\n return (\n
\n {!noSeparator && (\n
\n \n
\n )}\n\n
{children}
\n
\n );\n});\nToolbarGroup.displayName = 'ToolbarGroup';\n\nexport {\n Toolbar,\n ToolbarLink,\n ToolbarToggleGroup,\n ToolbarSeparator,\n ToolbarToggleItem,\n ToolbarButton,\n ToolbarGroup,\n};\n" + "content": "'use client';\n\nimport * as React from 'react';\nimport { ReactNode } from 'react';\nimport * as ToolbarPrimitive from '@radix-ui/react-toolbar';\nimport { cva, VariantProps } from 'class-variance-authority';\n\nimport { cn } from '@/lib/utils';\nimport { Icons } from '@/components/icons';\n\nimport { Separator } from './separator';\nimport { ToggleProps, toggleVariants } from './toggle';\nimport {\n Tooltip,\n TooltipContent,\n TooltipPortal,\n TooltipTrigger,\n} from './tooltip';\n\nconst toolbarVariants = cva(\n 'relative flex select-none items-stretch gap-1 bg-background'\n);\n\nexport const linkVariants = cva('font-medium underline underline-offset-4');\n\nconst ToolbarToggleGroup = ToolbarPrimitive.ToggleGroup;\n\nexport interface ToolbarProps\n extends React.ComponentPropsWithoutRef {}\n\nconst Toolbar = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef &\n VariantProps\n>(({ className, ...props }, ref) => (\n \n));\nToolbar.displayName = ToolbarPrimitive.Root.displayName;\n\nconst ToolbarLink = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef &\n VariantProps\n>(({ className, ...props }, ref) => (\n \n));\nToolbarLink.displayName = ToolbarPrimitive.Link.displayName;\n\nconst ToolbarSeparator = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n));\nToolbarSeparator.displayName = ToolbarPrimitive.Separator.displayName;\n\nexport interface ToolbarButtonProps\n extends React.ComponentPropsWithoutRef,\n VariantProps,\n Omit {\n buttonType?: 'button' | 'toggle';\n pressed?: boolean;\n tooltip?: ReactNode;\n isDropdown?: boolean;\n}\n\nconst ToolbarButton = React.forwardRef<\n React.ElementRef,\n ToolbarButtonProps\n>(\n (\n {\n className,\n variant,\n size = 'sm',\n isDropdown,\n children,\n pressed,\n value,\n tooltip,\n ...props\n },\n ref\n ) => {\n const [isLoaded, setIsLoaded] = React.useState(false);\n\n React.useEffect(() => {\n setIsLoaded(true);\n }, []);\n\n const content =\n typeof pressed === 'boolean' ? (\n \n \n
{children}
\n
\n {isDropdown && (\n \n )}\n
\n \n \n ) : (\n \n {children}\n \n );\n\n return isLoaded && tooltip ? (\n \n {content}\n\n \n {tooltip}\n \n \n ) : (\n <>{content}\n );\n }\n);\nToolbarButton.displayName = ToolbarPrimitive.Button.displayName;\n\nconst ToolbarToggleItem = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef &\n VariantProps\n>(({ className, variant, size, ...props }, ref) => (\n \n));\nToolbarToggleItem.displayName = ToolbarPrimitive.ToggleItem.displayName;\n\nconst ToolbarGroup = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes & { noSeparator?: boolean }\n>(({ noSeparator, className, children }, ref) => {\n const childArr = React.Children.map(children, (c) => c);\n if (!childArr || childArr.length === 0) return null;\n\n return (\n
\n {!noSeparator && (\n
\n \n
\n )}\n\n
{children}
\n
\n );\n});\nToolbarGroup.displayName = 'ToolbarGroup';\n\nexport {\n Toolbar,\n ToolbarLink,\n ToolbarToggleGroup,\n ToolbarSeparator,\n ToolbarToggleItem,\n ToolbarButton,\n ToolbarGroup,\n};\n" } ], "type": "components:plate-ui" diff --git a/apps/www/src/components/counting-numbers.tsx b/apps/www/src/components/counting-numbers.tsx index b5720e7a49..05ea324d80 100644 --- a/apps/www/src/components/counting-numbers.tsx +++ b/apps/www/src/components/counting-numbers.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/rules-of-hooks */ 'use client'; import { useEffect, useMemo, useRef, useState } from 'react'; @@ -56,17 +57,23 @@ export function CountingNumbers({ start = reverse ? 1000 : 0, interval = 10, duration = 800, + noAnimation, }) { const ref = useRef(null); - const isInView = useInView(ref); - const number = useCounting({ - start, - end: value, - interval, - duration, - reverse, - isInView, - }); + + let number = value; + + if (!noAnimation) { + const isInView = useInView(ref); + number = useCounting({ + start, + end: value, + interval, + duration, + reverse, + isInView, + }); + } const formattedNumber = useMemo( () => Intl.NumberFormat().format(number), diff --git a/apps/www/src/components/star-on-github.tsx b/apps/www/src/components/star-on-github.tsx index 6c4961792d..5b7d697f79 100644 --- a/apps/www/src/components/star-on-github.tsx +++ b/apps/www/src/components/star-on-github.tsx @@ -45,6 +45,7 @@ export function StarOnGithub({ count }: { count: number }) { )} diff --git a/apps/www/src/config/customizer-plugins.ts b/apps/www/src/config/customizer-plugins.ts index 69e93a5cc1..e3874bbda8 100644 --- a/apps/www/src/config/customizer-plugins.ts +++ b/apps/www/src/config/customizer-plugins.ts @@ -66,7 +66,7 @@ import { KEY_TABBABLE } from '@udecode/plate-tabbable'; import { ELEMENT_TABLE } from '@udecode/plate-table'; import { KEY_TRAILING_BLOCK } from '@udecode/plate-trailing-block'; -export type ValueId = keyof typeof customizerPlugins; +export type ValueId = keyof typeof customizerPlugins | 'tableMerge'; // cmdk needs lowercase export const customizerPlugins = { diff --git a/apps/www/src/lib/plate/demo/values/tableValue.tsx b/apps/www/src/lib/plate/demo/values/tableValue.tsx index e124c81caf..ffff8dc056 100644 --- a/apps/www/src/lib/plate/demo/values/tableValue.tsx +++ b/apps/www/src/lib/plate/demo/values/tableValue.tsx @@ -4,31 +4,42 @@ import { jsx } from '@udecode/plate-test-utils'; jsx; -export const createTable = (): any => ( +export const createTable = (spanning?: boolean): any => ( - - - - - Plugin - - - - - Element - - - - - Inline - - - - - Void - - - + + {spanning ? ( + + + + Plugin + + + + ) : ( + + + + Plugin + + + + + Element + + + + + Inline + + + + + Void + + + + )} + @@ -81,30 +92,6 @@ export const createTable = (): any => ( ); -export const createSpanningTable = (): any => ( - - - - - - Heading - - - - - - - Cell 1 - - - - Cell 2 - - - - -); - export const tableValue: any = ( 🏓 Table @@ -113,9 +100,16 @@ export const tableValue: any = ( to design structured layouts. {createTable()} + +); + +export const tableMergeValue: any = ( + + Table Merge - This table is an example of rendering a table spanning multiple columns: + You can enable merging using enableMerging: true{' '} + option. Try it out: - {createSpanningTable()} + {createTable(true)} ); diff --git a/apps/www/src/lib/plate/demo/values/usePlaygroundValue.ts b/apps/www/src/lib/plate/demo/values/usePlaygroundValue.ts index 9f1b303e3b..0dcd69bc75 100644 --- a/apps/www/src/lib/plate/demo/values/usePlaygroundValue.ts +++ b/apps/www/src/lib/plate/demo/values/usePlaygroundValue.ts @@ -31,7 +31,7 @@ import { mediaValue } from './mediaValue'; import { mentionValue } from './mentionValue'; import { softBreakValue } from './softBreakValue'; import { tabbableValue } from './tabbableValue'; -import { tableValue } from './tableValue'; +import { tableMergeValue, tableValue } from './tableValue'; export const usePlaygroundValue = (id?: ValueId) => { let valueId = settingsStore.use.valueId(); @@ -48,8 +48,13 @@ export const usePlaygroundValue = (id?: ValueId) => { value.push(...basicMarksValue); + console.log(valueId); + if (valueId === 'tableMerge') { + return mapNodeId(tableMergeValue); + } + if (valueId !== customizerPlugins.playground.id) { - const newValue = customizerPlugins[valueId].value ?? []; + const newValue = customizerPlugins[valueId]?.value ?? []; if (newValue.length === 0) { return mapNodeId(value); diff --git a/apps/www/src/registry/default/example/playground-demo.tsx b/apps/www/src/registry/default/example/playground-demo.tsx index e5a1074dd0..02a0941919 100644 --- a/apps/www/src/registry/default/example/playground-demo.tsx +++ b/apps/www/src/registry/default/example/playground-demo.tsx @@ -150,7 +150,12 @@ export const usePlaygroundPlugins = ({ triggerPreviousCharPattern: /^$|^[\s"']$/, }, }), - createTablePlugin({ enabled: !!enabled.table }), + createTablePlugin({ + enabled: !!enabled.table, + options: { + enableMerging: id === 'tableMerge', + }, + }), createTodoListPlugin({ enabled: !!enabled.action_item }), createExcalidrawPlugin({ enabled: !!enabled.excalidraw }), diff --git a/apps/www/src/registry/default/plate-ui/toolbar.tsx b/apps/www/src/registry/default/plate-ui/toolbar.tsx index 535897952d..7748b6e0c6 100644 --- a/apps/www/src/registry/default/plate-ui/toolbar.tsx +++ b/apps/www/src/registry/default/plate-ui/toolbar.tsx @@ -104,7 +104,7 @@ const ToolbarButton = React.forwardRef< typeof pressed === 'boolean' ? (
{children}
diff --git a/packages/plate/CHANGELOG.md b/packages/plate/CHANGELOG.md index 0a4e4a8152..f73beb1cd9 100644 --- a/packages/plate/CHANGELOG.md +++ b/packages/plate/CHANGELOG.md @@ -1,5 +1,11 @@ # @udecode/plate +## 26.0.3 + +## 26.0.2 + +## 26.0.1 + ## 26.0.0 ## 25.0.1 diff --git a/packages/plate/package.json b/packages/plate/package.json index b1e66559eb..0f3252efd5 100644 --- a/packages/plate/package.json +++ b/packages/plate/package.json @@ -1,6 +1,6 @@ { "name": "@udecode/plate", - "version": "26.0.0", + "version": "26.0.3", "description": "Plate – a plugin system for slate", "license": "MIT", "homepage": "https://platejs.org", @@ -72,13 +72,13 @@ "@udecode/plate-reset-node": "25.0.1", "@udecode/plate-resizable": "25.0.1", "@udecode/plate-select": "25.0.1", - "@udecode/plate-serializer-csv": "26.0.0", - "@udecode/plate-serializer-docx": "26.0.0", + "@udecode/plate-serializer-csv": "26.0.3", + "@udecode/plate-serializer-docx": "26.0.3", "@udecode/plate-serializer-html": "26.0.0", "@udecode/plate-serializer-md": "25.0.1", "@udecode/plate-suggestion": "25.0.1", "@udecode/plate-tabbable": "25.0.1", - "@udecode/plate-table": "26.0.0", + "@udecode/plate-table": "26.0.3", "@udecode/plate-trailing-block": "25.0.1" }, "peerDependencies": { diff --git a/packages/serializer-csv/CHANGELOG.md b/packages/serializer-csv/CHANGELOG.md index 259e0fb5c0..5488e7425d 100644 --- a/packages/serializer-csv/CHANGELOG.md +++ b/packages/serializer-csv/CHANGELOG.md @@ -1,5 +1,11 @@ # @udecode/plate-serializer-csv +## 26.0.3 + +## 26.0.2 + +## 26.0.1 + ## 26.0.0 ## 25.0.1 diff --git a/packages/serializer-csv/package.json b/packages/serializer-csv/package.json index 98c0a92ec7..7183d8a6d2 100644 --- a/packages/serializer-csv/package.json +++ b/packages/serializer-csv/package.json @@ -1,6 +1,6 @@ { "name": "@udecode/plate-serializer-csv", - "version": "26.0.0", + "version": "26.0.3", "description": "CSV serializer plugin for Plate", "license": "MIT", "homepage": "https://platejs.org", @@ -40,7 +40,7 @@ }, "dependencies": { "@udecode/plate-common": "25.0.1", - "@udecode/plate-table": "26.0.0", + "@udecode/plate-table": "26.0.3", "papaparse": "^5.4.1" }, "peerDependencies": { diff --git a/packages/serializer-docx/CHANGELOG.md b/packages/serializer-docx/CHANGELOG.md index 4041a392d7..5ec2d73ed2 100644 --- a/packages/serializer-docx/CHANGELOG.md +++ b/packages/serializer-docx/CHANGELOG.md @@ -1,5 +1,11 @@ # @udecode/plate-docx-serializer +## 26.0.3 + +## 26.0.2 + +## 26.0.1 + ## 26.0.0 ## 25.0.1 diff --git a/packages/serializer-docx/package.json b/packages/serializer-docx/package.json index 9c5f8b23d9..ce07c7f61d 100644 --- a/packages/serializer-docx/package.json +++ b/packages/serializer-docx/package.json @@ -1,6 +1,6 @@ { "name": "@udecode/plate-serializer-docx", - "version": "26.0.0", + "version": "26.0.3", "description": "Docx serializer plugin for Plate", "license": "MIT", "homepage": "https://platejs.org", @@ -45,7 +45,7 @@ "@udecode/plate-indent-list": "25.0.1", "@udecode/plate-media": "25.0.1", "@udecode/plate-paragraph": "25.0.1", - "@udecode/plate-table": "26.0.0", + "@udecode/plate-table": "26.0.3", "validator": "^13.9.0" }, "peerDependencies": { diff --git a/packages/table/CHANGELOG.md b/packages/table/CHANGELOG.md index e27bfd0ea5..9d42306d55 100644 --- a/packages/table/CHANGELOG.md +++ b/packages/table/CHANGELOG.md @@ -1,5 +1,29 @@ # @udecode/plate-table +## 26.0.3 + +### Patch Changes + +- [#2724](https://github.com/udecode/plate/pull/2724) by [@duckRabbitPy](https://github.com/duckRabbitPy) – Table row insertion: cells in a newly added row will now receive header styling only if they satisfy specific criteria: + + - Every cell in the column is a header cell, + - The table contains more than one row, or + - The column possesses a predefined header property. + +- [`0b5962d0`](https://github.com/udecode/plate/commit/0b5962d06d6121526e09ff8b3e164d358bbc881c) by [@zbeyens](https://github.com/zbeyens) – Fix: `useTableMergeState` should return false values when `enableMerging: false` + +## 26.0.2 + +### Patch Changes + +- [#2771](https://github.com/udecode/plate/pull/2771) by [@KorovinQuantori](https://github.com/KorovinQuantori) – Fixed table insertion inside text nodes + +## 26.0.1 + +### Patch Changes + +- [#2768](https://github.com/udecode/plate/pull/2768) by [@KorovinQuantori](https://github.com/KorovinQuantori) – Fixed copy behaviour, when not all table cells are filled with some nodes + ## 26.0.0 ### Minor Changes diff --git a/packages/table/package.json b/packages/table/package.json index da43de6ba3..1406f65a8d 100644 --- a/packages/table/package.json +++ b/packages/table/package.json @@ -1,6 +1,6 @@ { "name": "@udecode/plate-table", - "version": "26.0.0", + "version": "26.0.3", "description": "Table plugin for Plate", "license": "MIT", "homepage": "https://platejs.org", diff --git a/packages/table/src/merge/useTableMergeState.ts b/packages/table/src/merge/useTableMergeState.ts index 5c8308e296..32e8806e92 100644 --- a/packages/table/src/merge/useTableMergeState.ts +++ b/packages/table/src/merge/useTableMergeState.ts @@ -1,12 +1,30 @@ +/* eslint-disable react-hooks/rules-of-hooks */ import { useMemo } from 'react'; -import { isCollapsed, isExpanded, useEditorState } from '@udecode/plate-common'; +import { + getPluginOptions, + isCollapsed, + isExpanded, + useEditorRef, + useEditorState, +} from '@udecode/plate-common'; import { useReadOnly, useSelected } from 'slate-react'; +import { ELEMENT_TABLE } from '../createTablePlugin'; import { getTableGridAbove } from '../queries'; import { useTableStore } from '../stores'; +import { TablePlugin } from '../types'; import { isTableRectangular } from './isTableRectangular'; export const useTableMergeState = () => { + const editorRef = useEditorRef(); + + const { enableMerging } = getPluginOptions( + editorRef, + ELEMENT_TABLE + ); + + if (!enableMerging) return { canMerge: false, canUnmerge: false }; + const editor = useEditorState(); const readOnly = useReadOnly(); @@ -32,7 +50,7 @@ export const useTableMergeState = () => { isExpanded(editor.selection) && isTableRectangular(selectedTable) ); - }, [editor.selection, selectedTable, readOnly, selected]); + }, [readOnly, selected, editor.selection, selectedTable]); const canUnmerge = collapsed && diff --git a/packages/table/src/transforms/insertTableRow.ts b/packages/table/src/transforms/insertTableRow.ts index 575543feb8..3e520d0093 100644 --- a/packages/table/src/transforms/insertTableRow.ts +++ b/packages/table/src/transforms/insertTableRow.ts @@ -65,16 +65,18 @@ export const insertTableRow = ( const getEmptyRowNode = () => ({ type: getPluginType(editor, ELEMENT_TR), - children: (trNode.children as TElement[]).map((_, i) => - getEmptyCellNode(editor, { - header: - header ?? - (tableEntry[0].children as TElement[]).every( - (n) => n.children[i].type === ELEMENT_TH - ), + children: (trNode.children as TElement[]).map((_, i) => { + const hasSingleRow = tableEntry[0].children.length === 1; + const isHeaderColumn = + !hasSingleRow && + (tableEntry[0].children as TElement[]).every( + (n) => n.children[i].type === ELEMENT_TH + ); + return getEmptyCellNode(editor, { + header: header ?? isHeaderColumn, ...newCellChildren, - }) - ), + }); + }), }); withoutNormalizing(editor, () => { diff --git a/packages/table/src/withInsertFragmentTable.ts b/packages/table/src/withInsertFragmentTable.ts index fd3e59af7d..d23c6a7a76 100644 --- a/packages/table/src/withInsertFragmentTable.ts +++ b/packages/table/src/withInsertFragmentTable.ts @@ -156,6 +156,10 @@ export const withInsertFragmentTable = < return; } + } else if (fragment.length === 1 && fragment[0].type === ELEMENT_TABLE) { + // needed to insert as node, otherwise it will be inserted as text + editor.insertNode(fragment[0]); + return; } } diff --git a/packages/table/src/withSetFragmentDataTable.ts b/packages/table/src/withSetFragmentDataTable.ts index 5177dcbb5f..fa69a88063 100644 --- a/packages/table/src/withSetFragmentDataTable.ts +++ b/packages/table/src/withSetFragmentDataTable.ts @@ -86,6 +86,9 @@ export const withSetFragmentDataTable = < : document.createElement('tr'); rowCells.forEach((_, cellIndex) => { + // need to clean data before every iteration + data.clearData(); + const cellPath = rowPath.concat(x + cellIndex); // select cell by cell diff --git a/yarn.lock b/yarn.lock index f295813e68..ea7f98f48f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7747,13 +7747,13 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-serializer-csv@npm:26.0.0, @udecode/plate-serializer-csv@workspace:^, @udecode/plate-serializer-csv@workspace:packages/serializer-csv": +"@udecode/plate-serializer-csv@npm:26.0.3, @udecode/plate-serializer-csv@workspace:^, @udecode/plate-serializer-csv@workspace:packages/serializer-csv": version: 0.0.0-use.local resolution: "@udecode/plate-serializer-csv@workspace:packages/serializer-csv" dependencies: "@types/papaparse": "npm:^5.3.7" "@udecode/plate-common": "npm:25.0.1" - "@udecode/plate-table": "npm:26.0.0" + "@udecode/plate-table": "npm:26.0.3" papaparse: "npm:^5.4.1" peerDependencies: react: ">=16.8.0" @@ -7765,7 +7765,7 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-serializer-docx@npm:26.0.0, @udecode/plate-serializer-docx@workspace:^, @udecode/plate-serializer-docx@workspace:packages/serializer-docx": +"@udecode/plate-serializer-docx@npm:26.0.3, @udecode/plate-serializer-docx@workspace:^, @udecode/plate-serializer-docx@workspace:packages/serializer-docx": version: 0.0.0-use.local resolution: "@udecode/plate-serializer-docx@workspace:packages/serializer-docx" dependencies: @@ -7775,7 +7775,7 @@ __metadata: "@udecode/plate-indent-list": "npm:25.0.1" "@udecode/plate-media": "npm:25.0.1" "@udecode/plate-paragraph": "npm:25.0.1" - "@udecode/plate-table": "npm:26.0.0" + "@udecode/plate-table": "npm:26.0.3" validator: "npm:^13.9.0" peerDependencies: react: ">=16.8.0" @@ -7861,7 +7861,7 @@ __metadata: languageName: unknown linkType: soft -"@udecode/plate-table@npm:26.0.0, @udecode/plate-table@workspace:^, @udecode/plate-table@workspace:packages/table": +"@udecode/plate-table@npm:26.0.3, @udecode/plate-table@workspace:^, @udecode/plate-table@workspace:packages/table": version: 0.0.0-use.local resolution: "@udecode/plate-table@workspace:packages/table" dependencies: @@ -8004,13 +8004,13 @@ __metadata: "@udecode/plate-reset-node": "npm:25.0.1" "@udecode/plate-resizable": "npm:25.0.1" "@udecode/plate-select": "npm:25.0.1" - "@udecode/plate-serializer-csv": "npm:26.0.0" - "@udecode/plate-serializer-docx": "npm:26.0.0" + "@udecode/plate-serializer-csv": "npm:26.0.3" + "@udecode/plate-serializer-docx": "npm:26.0.3" "@udecode/plate-serializer-html": "npm:26.0.0" "@udecode/plate-serializer-md": "npm:25.0.1" "@udecode/plate-suggestion": "npm:25.0.1" "@udecode/plate-tabbable": "npm:25.0.1" - "@udecode/plate-table": "npm:26.0.0" + "@udecode/plate-table": "npm:26.0.3" "@udecode/plate-trailing-block": "npm:25.0.1" peerDependencies: react: ">=16.8.0"