Skip to content

Commit 3cea502

Browse files
committed
toolbar
1 parent 9a18998 commit 3cea502

File tree

2 files changed

+104
-43
lines changed

2 files changed

+104
-43
lines changed

apps/www/src/registry/default/plate-ui/fixed-toolbar-buttons.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import { MarkToolbarButton } from './mark-toolbar-button';
5353
import { MediaToolbarButton } from './media-toolbar-button';
5454
import { ModeDropdownMenu } from './mode-dropdown-menu';
5555
import { OutdentToolbarButton } from './outdent-toolbar-button';
56-
import { PdfToolbarButton } from './pdf-toolbar-button';
56+
import { ExportToolbarButton } from './pdf-toolbar-button';
5757
import { TableDropdownMenu } from './table-dropdown-menu';
5858
import { ToggleToolbarButton } from './toggle-toolbar-button';
5959
import { ToolbarGroup } from './toolbar';
@@ -78,9 +78,9 @@ export function FixedToolbarButtons() {
7878
</ToolbarGroup>
7979

8080
<ToolbarGroup>
81-
<PdfToolbarButton tooltip="Export PDF">
81+
<ExportToolbarButton tooltip="Export File">
8282
<ArrowUpToLineIcon />
83-
</PdfToolbarButton>
83+
</ExportToolbarButton>
8484
</ToolbarGroup>
8585

8686
<ToolbarGroup>

apps/www/src/registry/default/plate-ui/pdf-toolbar-button.tsx

+101-40
Original file line numberDiff line numberDiff line change
@@ -4,54 +4,115 @@ import React from 'react';
44

55
import { withRef } from '@udecode/cn';
66
import { toDOMNode, useEditorRef } from '@udecode/plate-common/react';
7+
import { ArrowDownToLineIcon } from 'lucide-react';
78

8-
import { ToolbarButton } from './toolbar';
9+
import {
10+
DropdownMenu,
11+
DropdownMenuContent,
12+
DropdownMenuGroup,
13+
DropdownMenuItem,
14+
DropdownMenuTrigger,
15+
useOpenState,
16+
} from './dropdown-menu';
17+
import {
18+
ToolbarSplitButton,
19+
ToolbarSplitButtonPrimary,
20+
ToolbarSplitButtonSecondary,
21+
} from './toolbar';
922

10-
export const PdfToolbarButton = withRef<typeof ToolbarButton>(
11-
({ children, ...rest }, ref) => {
23+
export const ExportToolbarButton = withRef<typeof ToolbarSplitButton>(
24+
({ children, ...props }, ref) => {
1225
const editor = useEditorRef();
26+
const openState = useOpenState();
27+
28+
const getCanvas = async () => {
29+
const { default: html2canvas } = await import('html2canvas');
30+
31+
const style = document.createElement('style');
32+
document.head.append(style);
33+
style.sheet?.insertRule(
34+
'body > div:last-child img { display: inline-block !important; }'
35+
);
36+
37+
const canvas = await html2canvas(toDOMNode(editor, editor)!);
38+
style.remove();
39+
40+
return canvas;
41+
};
42+
43+
const downloadFile = (href: string, filename: string) => {
44+
const element = document.createElement('a');
45+
element.setAttribute('href', href);
46+
element.setAttribute('download', filename);
47+
element.style.display = 'none';
48+
document.body.append(element);
49+
element.click();
50+
element.remove();
51+
};
52+
53+
const exportToPdf = async () => {
54+
const canvas = await getCanvas();
55+
56+
const PDFLib = await import('pdf-lib');
57+
const pdfDoc = await PDFLib.PDFDocument.create();
58+
const page = pdfDoc.addPage([canvas.width, canvas.height]);
59+
const imageEmbed = await pdfDoc.embedPng(canvas.toDataURL('PNG'));
60+
61+
page.drawImage(imageEmbed, {
62+
height: canvas.height,
63+
width: canvas.width,
64+
x: 0,
65+
y: 0,
66+
});
67+
const pdfBase64 = await pdfDoc.saveAsBase64({ dataUri: true });
68+
69+
downloadFile(pdfBase64, 'plate.pdf');
70+
};
71+
72+
const exportToImage = async () => {
73+
const canvas = await getCanvas();
74+
downloadFile(canvas.toDataURL('image/png'), 'plate.png');
75+
};
1376

1477
return (
15-
<ToolbarButton
78+
<ToolbarSplitButton
1679
ref={ref}
17-
{...rest}
18-
onClick={async () => {
19-
const { default: html2canvas } = await import('html2canvas');
20-
21-
const style = document.createElement('style');
22-
document.head.append(style);
23-
style.sheet?.insertRule(
24-
'body > div:last-child img { display: inline-block !important; }'
25-
);
26-
27-
const canvas = await html2canvas(toDOMNode(editor, editor)!);
28-
29-
style.remove();
30-
31-
const PDFLib = await import('pdf-lib');
32-
const pdfDoc = await PDFLib.PDFDocument.create();
33-
const page = pdfDoc.addPage([canvas.width, canvas.height]);
34-
const imageEmbed = await pdfDoc.embedPng(canvas.toDataURL('PNG'));
35-
36-
page.drawImage(imageEmbed, {
37-
height: canvas.height,
38-
width: canvas.width,
39-
x: 0,
40-
y: 0,
41-
});
42-
const pdfBase64 = await pdfDoc.saveAsBase64({ dataUri: true });
43-
44-
const element = document.createElement('a');
45-
element.setAttribute('href', pdfBase64);
46-
element.setAttribute('download', 'plate.pdf');
47-
element.style.display = 'none';
48-
document.body.append(element);
49-
element.click();
50-
element.remove();
80+
onClick={exportToPdf}
81+
onKeyDown={(e) => {
82+
if (e.key === 'ArrowDown') {
83+
e.preventDefault();
84+
openState.onOpenChange(true);
85+
}
5186
}}
87+
pressed={openState.open}
88+
tooltip="Export"
89+
{...props}
5290
>
53-
{children}
54-
</ToolbarButton>
91+
<ToolbarSplitButtonPrimary>
92+
<ArrowDownToLineIcon className="size-4" />
93+
</ToolbarSplitButtonPrimary>
94+
95+
<DropdownMenu {...openState} modal={false}>
96+
<DropdownMenuTrigger asChild>
97+
<ToolbarSplitButtonSecondary />
98+
</DropdownMenuTrigger>
99+
100+
<DropdownMenuContent
101+
onClick={(e) => e.stopPropagation()}
102+
align="start"
103+
alignOffset={-32}
104+
>
105+
<DropdownMenuGroup>
106+
<DropdownMenuItem onSelect={exportToPdf}>
107+
Export as PDF
108+
</DropdownMenuItem>
109+
<DropdownMenuItem onSelect={exportToImage}>
110+
Export via Image
111+
</DropdownMenuItem>
112+
</DropdownMenuGroup>
113+
</DropdownMenuContent>
114+
</DropdownMenu>
115+
</ToolbarSplitButton>
55116
);
56117
}
57118
);

0 commit comments

Comments
 (0)