Skip to content

Commit ce59e1d

Browse files
committed
fix
1 parent 3cea502 commit ce59e1d

10 files changed

+87
-18
lines changed

apps/www/public/ai-selection.png

-107 KB
Binary file not shown.

apps/www/public/r/index.json

+31
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,37 @@
15581558
"registryDependencies": [],
15591559
"type": "registry:ui"
15601560
},
1561+
{
1562+
"dependencies": [
1563+
"html2canvas",
1564+
"pdf-lib"
1565+
],
1566+
"doc": {
1567+
"description": "A toolbar button to export editor content as PDF.",
1568+
"docs": [
1569+
{
1570+
"route": "/docs/export",
1571+
"title": "Export"
1572+
}
1573+
],
1574+
"examples": [
1575+
"basic-nodes-demo"
1576+
],
1577+
"label": "New",
1578+
"title": "PDF Toolbar Button"
1579+
},
1580+
"files": [
1581+
{
1582+
"path": "plate-ui/export-toolbar-button.tsx",
1583+
"type": "registry:ui"
1584+
}
1585+
],
1586+
"name": "export-toolbar-button",
1587+
"registryDependencies": [
1588+
"toolbar"
1589+
],
1590+
"type": "registry:ui"
1591+
},
15611592
{
15621593
"dependencies": [
15631594
"@udecode/plate-caption"

apps/www/public/r/styles/default/editor.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
},
1616
"files": [
1717
{
18-
"content": "'use client';\n\nimport React from 'react';\n\nimport type { PlateContentProps } from '@udecode/plate-common/react';\nimport type { VariantProps } from 'class-variance-authority';\n\nimport { cn } from '@udecode/cn';\nimport {\n PlateContent,\n useEditorContainerRef,\n useEditorRef,\n} from '@udecode/plate-common/react';\nimport { cva } from 'class-variance-authority';\n\nconst editorContainerVariants = cva(\n 'relative w-full cursor-text overflow-y-auto caret-primary selection:bg-brand/25 [&_.slate-selection-area]:border [&_.slate-selection-area]:border-brand/25 [&_.slate-selection-area]:bg-brand/15',\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n variant: {\n default: 'h-full',\n demo: 'h-[650px]',\n },\n },\n }\n);\n\nexport const EditorContainer = ({\n className,\n variant,\n ...props\n}: React.HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof editorContainerVariants>) => {\n const editor = useEditorRef();\n const containerRef = useEditorContainerRef();\n\n return (\n <div\n id={editor.uid}\n ref={containerRef}\n className={cn(\n 'ignore-click-outside/toolbar',\n editorContainerVariants({ variant }),\n className\n )}\n role=\"button\"\n {...props}\n />\n );\n};\n\nEditorContainer.displayName = 'EditorContainer';\n\nconst editorVariants = cva(\n cn(\n 'group/editor',\n 'relative w-full overflow-x-hidden whitespace-pre-wrap break-words',\n 'rounded-md ring-offset-background placeholder:text-muted-foreground/80 focus-visible:outline-none',\n '[&_[data-slate-placeholder]]:text-muted-foreground/80 [&_[data-slate-placeholder]]:!opacity-100',\n '[&_[data-slate-placeholder]]:top-[auto_!important]',\n '[&_strong]:font-bold'\n ),\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n disabled: {\n true: 'cursor-not-allowed opacity-50',\n },\n focused: {\n true: 'ring-2 ring-ring ring-offset-2',\n },\n variant: {\n ai: 'w-full px-0 text-base md:text-sm',\n aiChat:\n 'max-h-[min(70vh,320px)] w-full max-w-[700px] overflow-y-auto px-3 py-2 text-base md:text-sm',\n default:\n 'size-full px-16 pb-72 pt-4 text-base sm:px-[max(64px,calc(50%-350px))]',\n demo: 'size-full px-16 pb-72 pt-4 text-base sm:px-[max(64px,calc(50%-350px))]',\n fullWidth: 'size-full px-16 pb-72 pt-4 text-base sm:px-24',\n none: '',\n },\n },\n }\n);\n\nexport type EditorProps = PlateContentProps &\n VariantProps<typeof editorVariants>;\n\nexport const Editor = React.forwardRef<HTMLDivElement, EditorProps>(\n ({ className, disabled, focused, variant, ...props }, ref) => {\n return (\n <PlateContent\n ref={ref}\n className={cn(\n editorVariants({\n disabled,\n focused,\n variant,\n }),\n className\n )}\n disabled={disabled}\n disableDefaultStyles\n {...props}\n />\n );\n }\n);\n\nEditor.displayName = 'Editor';\n",
18+
"content": "'use client';\n\nimport React from 'react';\n\nimport type { PlateContentProps } from '@udecode/plate-common/react';\nimport type { VariantProps } from 'class-variance-authority';\n\nimport { cn } from '@udecode/cn';\nimport {\n PlateContent,\n useEditorContainerRef,\n useEditorRef,\n} from '@udecode/plate-common/react';\nimport { cva } from 'class-variance-authority';\n\nconst editorContainerVariants = cva(\n 'relative w-full cursor-text overflow-y-auto caret-primary selection:bg-brand/25 [&_.slate-selection-area]:border [&_.slate-selection-area]:border-brand/25 [&_.slate-selection-area]:bg-brand/15',\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n variant: {\n default: 'h-full',\n demo: 'h-[650px]',\n },\n },\n }\n);\n\nexport const EditorContainer = ({\n className,\n variant,\n ...props\n}: React.HTMLAttributes<HTMLDivElement> &\n VariantProps<typeof editorContainerVariants>) => {\n const editor = useEditorRef();\n const containerRef = useEditorContainerRef();\n\n return (\n <div\n id={editor.uid}\n ref={containerRef}\n className={cn(\n 'ignore-click-outside/toolbar',\n editorContainerVariants({ variant }),\n className\n )}\n // Adding this role attribute could cause the content captured by html2canvas to be incorrectly centered.\n // role=\"button\"\n {...props}\n />\n );\n};\n\nEditorContainer.displayName = 'EditorContainer';\n\nconst editorVariants = cva(\n cn(\n 'group/editor',\n 'relative w-full overflow-x-hidden whitespace-pre-wrap break-words',\n 'rounded-md ring-offset-background placeholder:text-muted-foreground/80 focus-visible:outline-none',\n '[&_[data-slate-placeholder]]:text-muted-foreground/80 [&_[data-slate-placeholder]]:!opacity-100',\n '[&_[data-slate-placeholder]]:top-[auto_!important]',\n '[&_strong]:font-bold'\n ),\n {\n defaultVariants: {\n variant: 'default',\n },\n variants: {\n disabled: {\n true: 'cursor-not-allowed opacity-50',\n },\n focused: {\n true: 'ring-2 ring-ring ring-offset-2',\n },\n variant: {\n ai: 'w-full px-0 text-base md:text-sm',\n aiChat:\n 'max-h-[min(70vh,320px)] w-full max-w-[700px] overflow-y-auto px-3 py-2 text-base md:text-sm',\n default:\n 'size-full px-16 pb-72 pt-4 text-base sm:px-[max(64px,calc(50%-350px))]',\n demo: 'size-full px-16 pb-72 pt-4 text-base sm:px-[max(64px,calc(50%-350px))]',\n fullWidth: 'size-full px-16 pb-72 pt-4 text-base sm:px-24',\n none: '',\n },\n },\n }\n);\n\nexport type EditorProps = PlateContentProps &\n VariantProps<typeof editorVariants>;\n\nexport const Editor = React.forwardRef<HTMLDivElement, EditorProps>(\n ({ className, disabled, focused, variant, ...props }, ref) => {\n return (\n <PlateContent\n ref={ref}\n className={cn(\n editorVariants({\n disabled,\n focused,\n variant,\n }),\n className\n )}\n disabled={disabled}\n disableDefaultStyles\n {...props}\n />\n );\n }\n);\n\nEditor.displayName = 'Editor';\n",
1919
"path": "plate-ui/editor.tsx",
2020
"target": "components/plate-ui/editor.tsx",
2121
"type": "registry:ui"

apps/www/public/r/styles/default/export-demo.json

-13
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"dependencies": [
3+
"html2canvas",
4+
"pdf-lib"
5+
],
6+
"doc": {
7+
"description": "A toolbar button to export editor content as PDF.",
8+
"docs": [
9+
{
10+
"route": "/docs/export",
11+
"title": "Export"
12+
}
13+
],
14+
"examples": [
15+
"basic-nodes-demo"
16+
],
17+
"label": "New",
18+
"title": "PDF Toolbar Button"
19+
},
20+
"files": [
21+
{
22+
"content": "'use client';\n\nimport React from 'react';\n\nimport { withRef } from '@udecode/cn';\nimport { toDOMNode, useEditorRef } from '@udecode/plate-common/react';\nimport { ArrowDownToLineIcon } 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 const ExportToolbarButton = withRef<typeof ToolbarSplitButton>(\n ({ children, ...props }, ref) => {\n const editor = useEditorRef();\n const openState = useOpenState();\n\n const getCanvas = async () => {\n const { default: html2canvas } = await import('html2canvas');\n\n const style = document.createElement('style');\n document.head.append(style);\n style.sheet?.insertRule(\n 'body > div:last-child img { display: inline-block !important; }'\n );\n\n const canvas = await html2canvas(toDOMNode(editor, editor)!);\n style.remove();\n\n return canvas;\n };\n\n const downloadFile = (href: string, filename: string) => {\n const element = document.createElement('a');\n element.setAttribute('href', href);\n element.setAttribute('download', filename);\n element.style.display = 'none';\n document.body.append(element);\n element.click();\n element.remove();\n };\n\n const exportToPdf = async () => {\n const canvas = await getCanvas();\n\n const PDFLib = await import('pdf-lib');\n const pdfDoc = await PDFLib.PDFDocument.create();\n const page = pdfDoc.addPage([canvas.width, canvas.height]);\n const imageEmbed = await pdfDoc.embedPng(canvas.toDataURL('PNG'));\n\n page.drawImage(imageEmbed, {\n height: canvas.height,\n width: canvas.width,\n x: 0,\n y: 0,\n });\n const pdfBase64 = await pdfDoc.saveAsBase64({ dataUri: true });\n\n downloadFile(pdfBase64, 'plate.pdf');\n };\n\n const exportToImage = async () => {\n const canvas = await getCanvas();\n downloadFile(canvas.toDataURL('image/png'), 'plate.png');\n };\n\n return (\n <ToolbarSplitButton\n ref={ref}\n onClick={exportToPdf}\n onKeyDown={(e) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n openState.onOpenChange(true);\n }\n }}\n pressed={openState.open}\n tooltip=\"Export\"\n {...props}\n >\n <ToolbarSplitButtonPrimary>\n <ArrowDownToLineIcon className=\"size-4\" />\n </ToolbarSplitButtonPrimary>\n\n <DropdownMenu {...openState} modal={false}>\n <DropdownMenuTrigger asChild>\n <ToolbarSplitButtonSecondary />\n </DropdownMenuTrigger>\n\n <DropdownMenuContent\n onClick={(e) => e.stopPropagation()}\n align=\"start\"\n alignOffset={-32}\n >\n <DropdownMenuGroup>\n <DropdownMenuItem onSelect={exportToPdf}>\n Export as PDF\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={exportToImage}>\n Export via Image\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </ToolbarSplitButton>\n );\n }\n);\n",
23+
"path": "plate-ui/export-toolbar-button.tsx",
24+
"target": "components/plate-ui/export-toolbar-button.tsx",
25+
"type": "registry:ui"
26+
}
27+
],
28+
"name": "export-toolbar-button",
29+
"registryDependencies": [
30+
"toolbar"
31+
],
32+
"type": "registry:ui"
33+
}

0 commit comments

Comments
 (0)