From b6e771a59f01de74acf0d1db6b3122332a9d8c8c Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Thu, 26 Dec 2024 12:14:48 +0800 Subject: [PATCH 1/9] Move tooltip from `ToolbarSplitButton` to `ToolbarSplitButtonPrimary` --- .../plate-ui/indent-list-toolbar-button.tsx | 12 +++-- .../default/plate-ui/media-toolbar-button.tsx | 3 +- .../src/registry/default/plate-ui/toolbar.tsx | 46 ++++++++++--------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/apps/www/src/registry/default/plate-ui/indent-list-toolbar-button.tsx b/apps/www/src/registry/default/plate-ui/indent-list-toolbar-button.tsx index c1d809ac33..e9ead8cc3b 100644 --- a/apps/www/src/registry/default/plate-ui/indent-list-toolbar-button.tsx +++ b/apps/www/src/registry/default/plate-ui/indent-list-toolbar-button.tsx @@ -41,15 +41,16 @@ export function NumberedIndentListToolbarButton() { ); return ( - + { + onClick={() => toggleIndentList(editor, { listStyleType: ListStyleType.Decimal, - }); - }} + }) + } data-state={pressed ? 'on' : 'off'} + tooltip="Numbered List" > @@ -128,7 +129,7 @@ export function BulletedIndentListToolbarButton() { ); return ( - + { @@ -137,6 +138,7 @@ export function BulletedIndentListToolbarButton() { }); }} data-state={pressed ? 'on' : 'off'} + tooltip="Bulleted List" > diff --git a/apps/www/src/registry/default/plate-ui/media-toolbar-button.tsx b/apps/www/src/registry/default/plate-ui/media-toolbar-button.tsx index fa9689a1bb..25a3e8c102 100644 --- a/apps/www/src/registry/default/plate-ui/media-toolbar-button.tsx +++ b/apps/www/src/registry/default/plate-ui/media-toolbar-button.tsx @@ -114,9 +114,8 @@ export function MediaToolbarButton({ } }} pressed={openState.open} - tooltip={currentConfig.tooltip} > - + {currentConfig.icon} diff --git a/apps/www/src/registry/default/plate-ui/toolbar.tsx b/apps/www/src/registry/default/plate-ui/toolbar.tsx index 1d27f55edd..38d2064918 100644 --- a/apps/www/src/registry/default/plate-ui/toolbar.tsx +++ b/apps/www/src/registry/default/plate-ui/toolbar.tsx @@ -170,28 +170,30 @@ export const ToolbarSplitButton = React.forwardRef< ); }); -export const ToolbarSplitButtonPrimary = React.forwardRef< - React.ElementRef, - Omit, 'value'> ->(({ children, className, size, variant, ...props }, ref) => { - return ( - - {children} - - ); -}); +export const ToolbarSplitButtonPrimary = withTooltip( + React.forwardRef< + React.ElementRef, + Omit, 'value'> + >(({ children, className, size, variant, ...props }, ref) => { + return ( + + {children} + + ); + }) +); export const ToolbarSplitButtonSecondary = React.forwardRef< HTMLButtonElement, From ab950537729bcc8e74bd0b5ee8a34481855d5ec2 Mon Sep 17 00:00:00 2001 From: Felix Feng Date: Thu, 26 Dec 2024 16:42:00 +0800 Subject: [PATCH 2/9] tmp --- .../styles/default/fixed-toolbar-buttons.json | 2 +- .../default/indent-list-toolbar-button.json | 2 +- .../styles/default/media-toolbar-button.json | 2 +- .../r/styles/default/table-dropdown-menu.json | 2 +- apps/www/public/r/styles/default/toolbar.json | 2 +- .../plate-ui/fixed-toolbar-buttons.tsx | 2 + .../plate-ui/font-size-toolbar-butoon.tsx | 60 +++++++++++++++++++ packages/font/src/lib/index.ts | 1 + packages/font/src/lib/utils/index.ts | 5 ++ .../font/src/lib/utils/setChangedFontSize.ts | 48 +++++++++++++++ yarn.lock | 28 ++++----- 11 files changed, 135 insertions(+), 19 deletions(-) create mode 100644 apps/www/src/registry/default/plate-ui/font-size-toolbar-butoon.tsx create mode 100644 packages/font/src/lib/utils/index.ts create mode 100644 packages/font/src/lib/utils/setChangedFontSize.ts diff --git a/apps/www/public/r/styles/default/fixed-toolbar-buttons.json b/apps/www/public/r/styles/default/fixed-toolbar-buttons.json index f22080cbdb..58df0fa98a 100644 --- a/apps/www/public/r/styles/default/fixed-toolbar-buttons.json +++ b/apps/www/public/r/styles/default/fixed-toolbar-buttons.json @@ -14,7 +14,7 @@ }, "files": [ { - "content": "'use client';\n\nimport React from 'react';\n\nimport {\n BoldPlugin,\n CodePlugin,\n ItalicPlugin,\n StrikethroughPlugin,\n UnderlinePlugin,\n} from '@udecode/plate-basic-marks/react';\nimport { useEditorReadOnly } from '@udecode/plate-common/react';\nimport {\n FontBackgroundColorPlugin,\n FontColorPlugin,\n} from '@udecode/plate-font/react';\nimport { HighlightPlugin } from '@udecode/plate-highlight/react';\nimport {\n AudioPlugin,\n FilePlugin,\n ImagePlugin,\n VideoPlugin,\n} from '@udecode/plate-media/react';\nimport {\n ArrowUpToLineIcon,\n BaselineIcon,\n BoldIcon,\n Code2Icon,\n HighlighterIcon,\n ItalicIcon,\n PaintBucketIcon,\n StrikethroughIcon,\n UnderlineIcon,\n WandSparklesIcon,\n} from 'lucide-react';\n\nimport { MoreDropdownMenu } from '@/components/plate-ui/more-dropdown-menu';\n\nimport { AIToolbarButton } from './ai-toolbar-button';\nimport { AlignDropdownMenu } from './align-dropdown-menu';\nimport { ColorDropdownMenu } from './color-dropdown-menu';\nimport { CommentToolbarButton } from './comment-toolbar-button';\nimport { EmojiDropdownMenu } from './emoji-dropdown-menu';\nimport { ExportToolbarButton } from './export-toolbar-button';\nimport { RedoToolbarButton, UndoToolbarButton } from './history-toolbar-button';\nimport {\n BulletedIndentListToolbarButton,\n NumberedIndentListToolbarButton,\n} from './indent-list-toolbar-button';\nimport { IndentTodoToolbarButton } from './indent-todo-toolbar-button';\nimport { IndentToolbarButton } from './indent-toolbar-button';\nimport { InsertDropdownMenu } from './insert-dropdown-menu';\nimport { LineHeightDropdownMenu } from './line-height-dropdown-menu';\nimport { LinkToolbarButton } from './link-toolbar-button';\nimport { MarkToolbarButton } from './mark-toolbar-button';\nimport { MediaToolbarButton } from './media-toolbar-button';\nimport { ModeDropdownMenu } from './mode-dropdown-menu';\nimport { OutdentToolbarButton } from './outdent-toolbar-button';\nimport { TableDropdownMenu } from './table-dropdown-menu';\nimport { ToggleToolbarButton } from './toggle-toolbar-button';\nimport { ToolbarGroup } from './toolbar';\nimport { TurnIntoDropdownMenu } from './turn-into-dropdown-menu';\n\nexport function FixedToolbarButtons() {\n const readOnly = useEditorReadOnly();\n\n return (\n
\n {!readOnly && (\n <>\n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n\n \n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n \n\n \n \n\n \n \n {/* */}\n {/* */}\n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n )}\n\n
\n\n \n \n \n \n \n \n\n \n \n \n
\n );\n}\n", + "content": "'use client';\n\nimport React from 'react';\n\nimport {\n BoldPlugin,\n CodePlugin,\n ItalicPlugin,\n StrikethroughPlugin,\n UnderlinePlugin,\n} from '@udecode/plate-basic-marks/react';\nimport { useEditorReadOnly } from '@udecode/plate-common/react';\nimport {\n FontBackgroundColorPlugin,\n FontColorPlugin,\n} from '@udecode/plate-font/react';\nimport { HighlightPlugin } from '@udecode/plate-highlight/react';\nimport {\n AudioPlugin,\n FilePlugin,\n ImagePlugin,\n VideoPlugin,\n} from '@udecode/plate-media/react';\nimport {\n ArrowUpToLineIcon,\n BaselineIcon,\n BoldIcon,\n Code2Icon,\n HighlighterIcon,\n ItalicIcon,\n PaintBucketIcon,\n StrikethroughIcon,\n UnderlineIcon,\n WandSparklesIcon,\n} from 'lucide-react';\n\nimport { MoreDropdownMenu } from '@/components/plate-ui/more-dropdown-menu';\n\nimport { AIToolbarButton } from './ai-toolbar-button';\nimport { AlignDropdownMenu } from './align-dropdown-menu';\nimport { ColorDropdownMenu } from './color-dropdown-menu';\nimport { CommentToolbarButton } from './comment-toolbar-button';\nimport { EmojiDropdownMenu } from './emoji-dropdown-menu';\nimport { ExportToolbarButton } from './export-toolbar-button';\nimport { FontSizeToolbarButton } from './font-size-toolbar-butoon';\nimport { RedoToolbarButton, UndoToolbarButton } from './history-toolbar-button';\nimport {\n BulletedIndentListToolbarButton,\n NumberedIndentListToolbarButton,\n} from './indent-list-toolbar-button';\nimport { IndentTodoToolbarButton } from './indent-todo-toolbar-button';\nimport { IndentToolbarButton } from './indent-toolbar-button';\nimport { InsertDropdownMenu } from './insert-dropdown-menu';\nimport { LineHeightDropdownMenu } from './line-height-dropdown-menu';\nimport { LinkToolbarButton } from './link-toolbar-button';\nimport { MarkToolbarButton } from './mark-toolbar-button';\nimport { MediaToolbarButton } from './media-toolbar-button';\nimport { ModeDropdownMenu } from './mode-dropdown-menu';\nimport { OutdentToolbarButton } from './outdent-toolbar-button';\nimport { TableDropdownMenu } from './table-dropdown-menu';\nimport { ToggleToolbarButton } from './toggle-toolbar-button';\nimport { ToolbarGroup } from './toolbar';\nimport { TurnIntoDropdownMenu } from './turn-into-dropdown-menu';\n\nexport function FixedToolbarButtons() {\n const readOnly = useEditorReadOnly();\n\n return (\n
\n {!readOnly && (\n <>\n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n \n\n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n )}\n\n
\n\n \n \n \n \n \n \n\n \n \n \n
\n );\n}\n", "path": "plate-ui/fixed-toolbar-buttons.tsx", "target": "components/plate-ui/fixed-toolbar-buttons.tsx", "type": "registry:ui" diff --git a/apps/www/public/r/styles/default/indent-list-toolbar-button.json b/apps/www/public/r/styles/default/indent-list-toolbar-button.json index 8b091ef329..8ab7b8e06a 100644 --- a/apps/www/public/r/styles/default/indent-list-toolbar-button.json +++ b/apps/www/public/r/styles/default/indent-list-toolbar-button.json @@ -15,7 +15,7 @@ }, "files": [ { - "content": "'use client';\n\nimport React from 'react';\n\nimport { useEditorRef, useEditorSelector } from '@udecode/plate-common/react';\nimport {\n ListStyleType,\n someIndentList,\n toggleIndentList,\n} from '@udecode/plate-indent-list';\nimport { List, ListOrdered } from 'lucide-react';\n\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuTrigger,\n useOpenState,\n} from './dropdown-menu';\nimport {\n ToolbarSplitButton,\n ToolbarSplitButtonPrimary,\n ToolbarSplitButtonSecondary,\n} from './toolbar';\n\nexport function NumberedIndentListToolbarButton() {\n const editor = useEditorRef();\n const openState = useOpenState();\n\n const pressed = useEditorSelector(\n (editor) =>\n someIndentList(editor, [\n ListStyleType.Decimal,\n ListStyleType.LowerAlpha,\n ListStyleType.UpperAlpha,\n ListStyleType.LowerRoman,\n ListStyleType.UpperRoman,\n ]),\n []\n );\n\n return (\n \n {\n toggleIndentList(editor, {\n listStyleType: ListStyleType.Decimal,\n });\n }}\n pressed={pressed}\n >\n \n \n\n \n \n \n \n\n \n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.Decimal,\n })\n }\n >\n Decimal (1, 2, 3)\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.LowerAlpha,\n })\n }\n >\n Lower Alpha (a, b, c)\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.UpperAlpha,\n })\n }\n >\n Upper Alpha (A, B, C)\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.LowerRoman,\n })\n }\n >\n Lower Roman (i, ii, iii)\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.UpperRoman,\n })\n }\n >\n Upper Roman (I, II, III)\n \n \n \n \n \n );\n}\n\nexport function BulletedIndentListToolbarButton() {\n const editor = useEditorRef();\n const openState = useOpenState();\n\n const pressed = useEditorSelector(\n (editor) =>\n someIndentList(editor, [\n ListStyleType.Disc,\n ListStyleType.Circle,\n ListStyleType.Square,\n ]),\n []\n );\n\n return (\n \n {\n toggleIndentList(editor, {\n listStyleType: ListStyleType.Disc,\n });\n }}\n pressed={pressed}\n >\n \n \n\n \n \n \n \n\n \n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.Disc,\n })\n }\n >\n
\n
\n Default\n
\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.Circle,\n })\n }\n >\n
\n
\n Circle\n
\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.Square,\n })\n }\n >\n
\n
\n Square\n
\n \n \n \n \n \n );\n}\n", + "content": "'use client';\n\nimport React from 'react';\n\nimport { useEditorRef, useEditorSelector } from '@udecode/plate-common/react';\nimport {\n ListStyleType,\n someIndentList,\n toggleIndentList,\n} from '@udecode/plate-indent-list';\nimport { List, ListOrdered } from 'lucide-react';\n\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuTrigger,\n useOpenState,\n} from './dropdown-menu';\nimport {\n ToolbarSplitButton,\n ToolbarSplitButtonPrimary,\n ToolbarSplitButtonSecondary,\n} from './toolbar';\n\nexport function NumberedIndentListToolbarButton() {\n const editor = useEditorRef();\n const openState = useOpenState();\n\n const pressed = useEditorSelector(\n (editor) =>\n someIndentList(editor, [\n ListStyleType.Decimal,\n ListStyleType.LowerAlpha,\n ListStyleType.UpperAlpha,\n ListStyleType.LowerRoman,\n ListStyleType.UpperRoman,\n ]),\n []\n );\n\n return (\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.Decimal,\n })\n }\n data-state={pressed ? 'on' : 'off'}\n tooltip=\"Numbered List\"\n >\n \n \n\n \n \n \n \n\n \n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.Decimal,\n })\n }\n >\n Decimal (1, 2, 3)\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.LowerAlpha,\n })\n }\n >\n Lower Alpha (a, b, c)\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.UpperAlpha,\n })\n }\n >\n Upper Alpha (A, B, C)\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.LowerRoman,\n })\n }\n >\n Lower Roman (i, ii, iii)\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.UpperRoman,\n })\n }\n >\n Upper Roman (I, II, III)\n \n \n \n \n \n );\n}\n\nexport function BulletedIndentListToolbarButton() {\n const editor = useEditorRef();\n const openState = useOpenState();\n\n const pressed = useEditorSelector(\n (editor) =>\n someIndentList(editor, [\n ListStyleType.Disc,\n ListStyleType.Circle,\n ListStyleType.Square,\n ]),\n []\n );\n\n return (\n \n {\n toggleIndentList(editor, {\n listStyleType: ListStyleType.Disc,\n });\n }}\n data-state={pressed ? 'on' : 'off'}\n tooltip=\"Bulleted List\"\n >\n \n \n\n \n \n \n \n\n \n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.Disc,\n })\n }\n >\n
\n
\n Default\n
\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.Circle,\n })\n }\n >\n
\n
\n Circle\n
\n \n \n toggleIndentList(editor, {\n listStyleType: ListStyleType.Square,\n })\n }\n >\n
\n
\n Square\n
\n \n \n \n \n \n );\n}\n", "path": "plate-ui/indent-list-toolbar-button.tsx", "target": "components/plate-ui/indent-list-toolbar-button.tsx", "type": "registry:ui" diff --git a/apps/www/public/r/styles/default/media-toolbar-button.json b/apps/www/public/r/styles/default/media-toolbar-button.json index b288486770..539ad99e6d 100644 --- a/apps/www/public/r/styles/default/media-toolbar-button.json +++ b/apps/www/public/r/styles/default/media-toolbar-button.json @@ -18,7 +18,7 @@ }, "files": [ { - "content": "'use client';\n\nimport React, { useCallback, useState } from 'react';\n\nimport type { DropdownMenuProps } from '@radix-ui/react-dropdown-menu';\n\nimport { insertNodes, isUrl } from '@udecode/plate-common';\nimport { useEditorRef } from '@udecode/plate-common/react';\nimport {\n AudioPlugin,\n FilePlugin,\n ImagePlugin,\n VideoPlugin,\n} from '@udecode/plate-media/react';\nimport {\n AudioLinesIcon,\n FileUpIcon,\n FilmIcon,\n ImageIcon,\n LinkIcon,\n} from 'lucide-react';\nimport { toast } from 'sonner';\nimport { useFilePicker } from 'use-file-picker';\n\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from './alert-dialog';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuTrigger,\n useOpenState,\n} from './dropdown-menu';\nimport { FloatingInput } from './input';\nimport {\n ToolbarSplitButton,\n ToolbarSplitButtonPrimary,\n ToolbarSplitButtonSecondary,\n} from './toolbar';\n\nconst MEDIA_CONFIG: Record<\n string,\n {\n accept: string[];\n icon: React.ReactNode;\n title: string;\n tooltip: string;\n }\n> = {\n [AudioPlugin.key]: {\n accept: ['audio/*'],\n icon: ,\n title: 'Insert Audio',\n tooltip: 'Audio',\n },\n [FilePlugin.key]: {\n accept: ['*'],\n icon: ,\n title: 'Insert File',\n tooltip: 'File',\n },\n [ImagePlugin.key]: {\n accept: ['image/*'],\n icon: ,\n title: 'Insert Image',\n tooltip: 'Image',\n },\n [VideoPlugin.key]: {\n accept: ['video/*'],\n icon: ,\n title: 'Insert Video',\n tooltip: 'Video',\n },\n};\n\nexport function MediaToolbarButton({\n children,\n nodeType,\n ...props\n}: DropdownMenuProps & { nodeType: string }) {\n const currentConfig = MEDIA_CONFIG[nodeType];\n\n const editor = useEditorRef();\n const openState = useOpenState();\n const [dialogOpen, setDialogOpen] = useState(false);\n\n const { openFilePicker } = useFilePicker({\n accept: currentConfig.accept,\n multiple: true,\n onFilesSelected: ({ plainFiles: updatedFiles }) => {\n (editor as any).tf.insert.media(updatedFiles);\n },\n });\n\n return (\n <>\n {\n openFilePicker();\n }}\n onKeyDown={(e) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n openState.onOpenChange(true);\n }\n }}\n pressed={openState.open}\n tooltip={currentConfig.tooltip}\n >\n \n {currentConfig.icon}\n \n\n \n \n \n \n\n e.stopPropagation()}\n align=\"start\"\n alignOffset={-32}\n >\n \n openFilePicker()}>\n {currentConfig.icon}\n Upload from computer\n \n setDialogOpen(true)}>\n \n Insert via URL\n \n \n \n \n \n\n {\n setDialogOpen(value);\n }}\n >\n \n \n \n \n \n );\n}\n\nfunction MediaUrlDialogContent({\n currentConfig,\n nodeType,\n setOpen,\n}: {\n currentConfig: (typeof MEDIA_CONFIG)[string];\n nodeType: string;\n setOpen: (value: boolean) => void;\n}) {\n const editor = useEditorRef();\n const [url, setUrl] = useState('');\n\n const embedMedia = useCallback(() => {\n if (!isUrl(url)) return toast.error('Invalid URL');\n\n setOpen(false);\n insertNodes(editor, {\n children: [{ text: '' }],\n name: nodeType === FilePlugin.key ? url.split('/').pop() : undefined,\n type: nodeType,\n url,\n });\n }, [url, editor, nodeType, setOpen]);\n\n return (\n <>\n \n {currentConfig.title}\n \n\n \n setUrl(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') embedMedia();\n }}\n label=\"URL\"\n placeholder=\"\"\n type=\"url\"\n autoFocus\n />\n \n\n \n Cancel\n {\n e.preventDefault();\n embedMedia();\n }}\n >\n Accept\n \n \n \n );\n}\n", + "content": "'use client';\n\nimport React, { useCallback, useState } from 'react';\n\nimport type { DropdownMenuProps } from '@radix-ui/react-dropdown-menu';\n\nimport { insertNodes, isUrl } from '@udecode/plate-common';\nimport { useEditorRef } from '@udecode/plate-common/react';\nimport {\n AudioPlugin,\n FilePlugin,\n ImagePlugin,\n VideoPlugin,\n} from '@udecode/plate-media/react';\nimport {\n AudioLinesIcon,\n FileUpIcon,\n FilmIcon,\n ImageIcon,\n LinkIcon,\n} from 'lucide-react';\nimport { toast } from 'sonner';\nimport { useFilePicker } from 'use-file-picker';\n\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from './alert-dialog';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuTrigger,\n useOpenState,\n} from './dropdown-menu';\nimport { FloatingInput } from './input';\nimport {\n ToolbarSplitButton,\n ToolbarSplitButtonPrimary,\n ToolbarSplitButtonSecondary,\n} from './toolbar';\n\nconst MEDIA_CONFIG: Record<\n string,\n {\n accept: string[];\n icon: React.ReactNode;\n title: string;\n tooltip: string;\n }\n> = {\n [AudioPlugin.key]: {\n accept: ['audio/*'],\n icon: ,\n title: 'Insert Audio',\n tooltip: 'Audio',\n },\n [FilePlugin.key]: {\n accept: ['*'],\n icon: ,\n title: 'Insert File',\n tooltip: 'File',\n },\n [ImagePlugin.key]: {\n accept: ['image/*'],\n icon: ,\n title: 'Insert Image',\n tooltip: 'Image',\n },\n [VideoPlugin.key]: {\n accept: ['video/*'],\n icon: ,\n title: 'Insert Video',\n tooltip: 'Video',\n },\n};\n\nexport function MediaToolbarButton({\n children,\n nodeType,\n ...props\n}: DropdownMenuProps & { nodeType: string }) {\n const currentConfig = MEDIA_CONFIG[nodeType];\n\n const editor = useEditorRef();\n const openState = useOpenState();\n const [dialogOpen, setDialogOpen] = useState(false);\n\n const { openFilePicker } = useFilePicker({\n accept: currentConfig.accept,\n multiple: true,\n onFilesSelected: ({ plainFiles: updatedFiles }) => {\n (editor as any).tf.insert.media(updatedFiles);\n },\n });\n\n return (\n <>\n {\n openFilePicker();\n }}\n onKeyDown={(e) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n openState.onOpenChange(true);\n }\n }}\n pressed={openState.open}\n >\n \n {currentConfig.icon}\n \n\n \n \n \n \n\n e.stopPropagation()}\n align=\"start\"\n alignOffset={-32}\n >\n \n openFilePicker()}>\n {currentConfig.icon}\n Upload from computer\n \n setDialogOpen(true)}>\n \n Insert via URL\n \n \n \n \n \n\n {\n setDialogOpen(value);\n }}\n >\n \n \n \n \n \n );\n}\n\nfunction MediaUrlDialogContent({\n currentConfig,\n nodeType,\n setOpen,\n}: {\n currentConfig: (typeof MEDIA_CONFIG)[string];\n nodeType: string;\n setOpen: (value: boolean) => void;\n}) {\n const editor = useEditorRef();\n const [url, setUrl] = useState('');\n\n const embedMedia = useCallback(() => {\n if (!isUrl(url)) return toast.error('Invalid URL');\n\n setOpen(false);\n insertNodes(editor, {\n children: [{ text: '' }],\n name: nodeType === FilePlugin.key ? url.split('/').pop() : undefined,\n type: nodeType,\n url,\n });\n }, [url, editor, nodeType, setOpen]);\n\n return (\n <>\n \n {currentConfig.title}\n \n\n \n setUrl(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') embedMedia();\n }}\n label=\"URL\"\n placeholder=\"\"\n type=\"url\"\n autoFocus\n />\n \n\n \n Cancel\n {\n e.preventDefault();\n embedMedia();\n }}\n >\n Accept\n \n \n \n );\n}\n", "path": "plate-ui/media-toolbar-button.tsx", "target": "components/plate-ui/media-toolbar-button.tsx", "type": "registry:ui" diff --git a/apps/www/public/r/styles/default/table-dropdown-menu.json b/apps/www/public/r/styles/default/table-dropdown-menu.json index 01dca91675..267c5f65e2 100644 --- a/apps/www/public/r/styles/default/table-dropdown-menu.json +++ b/apps/www/public/r/styles/default/table-dropdown-menu.json @@ -16,7 +16,7 @@ }, "files": [ { - "content": "'use client';\n\nimport React, { useCallback, useState } from 'react';\n\nimport type { DropdownMenuProps } from '@radix-ui/react-dropdown-menu';\n\nimport { cn } from '@udecode/cn';\nimport { someNode } from '@udecode/plate-common';\nimport {\n focusEditor,\n useEditorPlugin,\n useEditorSelector,\n} from '@udecode/plate-common/react';\nimport {\n deleteColumn,\n deleteRow,\n deleteTable,\n insertTable,\n insertTableRow,\n} from '@udecode/plate-table';\nimport { TablePlugin } from '@udecode/plate-table/react';\nimport {\n Minus,\n Plus,\n RectangleHorizontal,\n RectangleVertical,\n Table,\n Trash,\n} from 'lucide-react';\n\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n useOpenState,\n} from './dropdown-menu';\nimport { ToolbarButton } from './toolbar';\n\nconst COLS = 8;\n\nexport function TableDropdownMenu(props: DropdownMenuProps) {\n const tableSelected = useEditorSelector(\n (editor) => someNode(editor, { match: { type: TablePlugin.key } }),\n []\n );\n\n const { editor, tf } = useEditorPlugin(TablePlugin);\n\n const openState = useOpenState();\n\n const [table, setTable] = useState(\n Array.from({ length: COLS }, () => Array.from({ length: COLS }).fill(0))\n );\n const [info, setInfo] = useState({ colCount: 0, rowCount: 0 });\n\n const onCellMove = useCallback(\n (rowIndex: number, colIndex: number) => {\n const newTables = [...table];\n\n for (let i = 0; i < newTables.length; i++) {\n for (let j = 0; j < newTables[i].length; j++) {\n newTables[i][j] =\n i >= 0 && i <= rowIndex && j >= 0 && j <= colIndex ? 1 : 0;\n }\n }\n\n setInfo({ colCount: colIndex + 1, rowCount: rowIndex + 1 });\n setTable(newTables);\n },\n [table]\n );\n\n const onInsertTable = useCallback(() => {\n insertTable(editor, info);\n }, [editor, info]);\n\n return (\n \n \n \n \n \n \n\n \n \n \n \n
\n Table\n \n \n
\n
\n {table.map((rows, rowIndex) =>\n rows.map((value, columIndex) => {\n return (\n {\n onCellMove(rowIndex, columIndex);\n }}\n />\n );\n })\n )}\n
\n\n
\n {info.rowCount} x {info.colCount}\n
\n
\n
\n \n\n \n \n \n Column\n \n \n {\n tf.insert.tableColumn();\n focusEditor(editor);\n }}\n >\n \n Insert column after\n \n {\n deleteColumn(editor);\n focusEditor(editor);\n }}\n >\n \n Delete column\n \n \n \n\n \n \n \n Row\n \n \n {\n insertTableRow(editor);\n focusEditor(editor);\n }}\n >\n \n Insert row after\n \n {\n deleteRow(editor);\n focusEditor(editor);\n }}\n >\n \n Delete row\n \n \n {\n deleteTable(editor);\n focusEditor(editor);\n }}\n >\n \n Delete table\n \n \n \n \n \n );\n}\n", + "content": "'use client';\n\nimport React, { useCallback, useState } from 'react';\n\nimport type { DropdownMenuProps } from '@radix-ui/react-dropdown-menu';\n\nimport { cn } from '@udecode/cn';\nimport { someNode } from '@udecode/plate-common';\nimport {\n focusEditor,\n useEditorPlugin,\n useEditorSelector,\n} from '@udecode/plate-common/react';\nimport {\n deleteColumn,\n deleteRow,\n deleteTable,\n insertTable,\n insertTableRow,\n} from '@udecode/plate-table';\nimport { TablePlugin } from '@udecode/plate-table/react';\nimport {\n Minus,\n Plus,\n RectangleHorizontal,\n RectangleVertical,\n Table,\n Trash,\n} from 'lucide-react';\n\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n useOpenState,\n} from './dropdown-menu';\nimport { ToolbarButton } from './toolbar';\n\nconst COLS = 8;\n\nexport function TableDropdownMenu(props: DropdownMenuProps) {\n const tableSelected = useEditorSelector(\n (editor) => someNode(editor, { match: { type: TablePlugin.key } }),\n []\n );\n\n const { editor, tf } = useEditorPlugin(TablePlugin);\n\n const openState = useOpenState();\n\n const [table, setTable] = useState(\n Array.from({ length: COLS }, () => Array.from({ length: COLS }).fill(0))\n );\n const [size, setSize] = useState({ colCount: 0, rowCount: 0 });\n\n const onCellMove = useCallback(\n (rowIndex: number, colIndex: number) => {\n const newTables = [...table];\n\n for (let i = 0; i < newTables.length; i++) {\n for (let j = 0; j < newTables[i].length; j++) {\n newTables[i][j] =\n i >= 0 && i <= rowIndex && j >= 0 && j <= colIndex ? 1 : 0;\n }\n }\n\n setSize({ colCount: colIndex + 1, rowCount: rowIndex + 1 });\n setTable(newTables);\n },\n [table]\n );\n\n const onInsertTable = useCallback(() => {\n insertTable(editor, size);\n focusEditor(editor);\n }, [editor, size]);\n\n return (\n \n \n \n
\n \n \n\n \n \n \n \n
\n Table\n \n \n
\n
\n {table.map((rows, rowIndex) =>\n rows.map((value, columIndex) => {\n return (\n {\n onCellMove(rowIndex, columIndex);\n }}\n />\n );\n })\n )}\n
\n\n
\n {size.rowCount} x {size.colCount}\n
\n
\n
\n \n\n \n \n \n Column\n \n \n {\n tf.insert.tableColumn();\n focusEditor(editor);\n }}\n >\n \n Insert column after\n \n {\n deleteColumn(editor);\n focusEditor(editor);\n }}\n >\n \n Delete column\n \n \n \n\n \n \n \n Row\n \n \n {\n insertTableRow(editor);\n focusEditor(editor);\n }}\n >\n \n Insert row after\n \n {\n deleteRow(editor);\n focusEditor(editor);\n }}\n >\n \n Delete row\n \n \n {\n deleteTable(editor);\n focusEditor(editor);\n }}\n >\n \n Delete table\n \n \n \n \n \n );\n}\n", "path": "plate-ui/table-dropdown-menu.tsx", "target": "components/plate-ui/table-dropdown-menu.tsx", "type": "registry:ui" diff --git a/apps/www/public/r/styles/default/toolbar.json b/apps/www/public/r/styles/default/toolbar.json index 562b75dfdb..07029fd1b8 100644 --- a/apps/www/public/r/styles/default/toolbar.json +++ b/apps/www/public/r/styles/default/toolbar.json @@ -7,7 +7,7 @@ }, "files": [ { - "content": "'use client';\n\nimport * as React from 'react';\n\nimport * as ToolbarPrimitive from '@radix-ui/react-toolbar';\nimport { cn, withCn, withRef, withVariants } from '@udecode/cn';\nimport { type VariantProps, cva } from 'class-variance-authority';\nimport { ChevronDown } from 'lucide-react';\n\nimport { Separator } from './separator';\nimport { withTooltip } from './tooltip';\n\nexport const Toolbar = withCn(\n ToolbarPrimitive.Root,\n 'relative flex select-none items-center'\n);\n\nexport const ToolbarToggleGroup = withCn(\n ToolbarPrimitive.ToolbarToggleGroup,\n 'flex items-center'\n);\n\nexport const ToolbarLink = withCn(\n ToolbarPrimitive.Link,\n 'font-medium underline underline-offset-4'\n);\n\nexport const ToolbarSeparator = withCn(\n ToolbarPrimitive.Separator,\n 'mx-2 my-1 w-px shrink-0 bg-border'\n);\n\nconst toolbarButtonVariants = cva(\n cn(\n 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium text-foreground ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg:not([data-icon])]:size-4'\n ),\n {\n defaultVariants: {\n size: 'sm',\n variant: 'default',\n },\n variants: {\n size: {\n default: 'h-10 px-3',\n lg: 'h-11 px-5',\n sm: 'h-7 px-2',\n },\n variant: {\n default:\n 'bg-transparent hover:bg-muted hover:text-muted-foreground aria-checked:bg-accent aria-checked:text-accent-foreground',\n outline:\n 'border border-input bg-transparent hover:bg-accent hover:text-accent-foreground',\n },\n },\n }\n);\n\nconst dropdownArrowVariants = cva(\n cn(\n 'inline-flex items-center justify-center rounded-r-md text-sm font-medium text-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50'\n ),\n {\n defaultVariants: {\n size: 'sm',\n variant: 'default',\n },\n variants: {\n size: {\n default: 'h-10 w-6',\n lg: 'h-11 w-8',\n sm: 'h-7 w-4',\n },\n variant: {\n default:\n 'bg-transparent hover:bg-muted hover:text-muted-foreground aria-checked:bg-accent aria-checked:text-accent-foreground',\n outline:\n 'border border-l-0 border-input bg-transparent hover:bg-accent hover:text-accent-foreground',\n },\n },\n }\n);\n\nconst ToolbarButton = withTooltip(\n React.forwardRef<\n React.ElementRef,\n {\n isDropdown?: boolean;\n pressed?: boolean;\n } & Omit<\n React.ComponentPropsWithoutRef,\n 'asChild' | 'value'\n > &\n VariantProps\n >(\n (\n { children, className, isDropdown, pressed, size, variant, ...props },\n ref\n ) => {\n return typeof pressed === 'boolean' ? (\n \n \n {isDropdown ? (\n <>\n
\n {children}\n
\n
\n \n
\n \n ) : (\n children\n )}\n \n \n ) : (\n \n {children}\n \n );\n }\n )\n);\nToolbarButton.displayName = 'ToolbarButton';\n\nexport { ToolbarButton };\n\nexport const ToolbarSplitButton = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ children, className, ...props }, ref) => {\n return (\n \n {children}\n \n );\n});\n\nexport const ToolbarSplitButtonPrimary = React.forwardRef<\n React.ElementRef,\n Omit, 'value'> & {\n pressed?: boolean;\n }\n>(({ children, className, pressed, size, variant, ...props }, ref) => {\n return (\n \n {children}\n \n );\n});\n\nexport const ToolbarSplitButtonSecondary = React.forwardRef<\n HTMLButtonElement,\n React.ComponentPropsWithoutRef<'span'> &\n VariantProps\n>(({ className, size, variant, ...props }, ref) => {\n return (\n e.stopPropagation()}\n role=\"button\"\n {...props}\n >\n \n \n );\n});\n\nToolbarSplitButton.displayName = 'ToolbarButton';\n\nexport const ToolbarToggleItem = withVariants(\n ToolbarPrimitive.ToggleItem,\n toolbarButtonVariants,\n ['variant', 'size']\n);\n\nexport const ToolbarGroup = withRef<'div'>(({ children, className }, ref) => {\n return (\n