@@ -4,54 +4,115 @@ import React from 'react';
4
4
5
5
import { withRef } from '@udecode/cn' ;
6
6
import { toDOMNode , useEditorRef } from '@udecode/plate-common/react' ;
7
+ import { ArrowDownToLineIcon } from 'lucide-react' ;
7
8
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' ;
9
22
10
- export const PdfToolbarButton = withRef < typeof ToolbarButton > (
11
- ( { children, ...rest } , ref ) => {
23
+ export const ExportToolbarButton = withRef < typeof ToolbarSplitButton > (
24
+ ( { children, ...props } , ref ) => {
12
25
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
+ } ;
13
76
14
77
return (
15
- < ToolbarButton
78
+ < ToolbarSplitButton
16
79
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
+ }
51
86
} }
87
+ pressed = { openState . open }
88
+ tooltip = "Export"
89
+ { ...props }
52
90
>
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 >
55
116
) ;
56
117
}
57
118
) ;
0 commit comments