-
-
Notifications
You must be signed in to change notification settings - Fork 462
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature: file exporters (docx and pdf) #1143
Merged
Merged
Changes from all commits
Commits
Show all changes
70 commits
Select commit
Hold shift + click to select a range
1656b55
cleaned serialization code
YousefED 53eba5b
comments
YousefED f99904a
update snapshot
YousefED fe52693
add comment
YousefED 81e3758
address comments
YousefED 968bc38
fix lint
YousefED d796a6d
fix build
YousefED c692d3d
fix server test
YousefED 18ceda5
wip
YousefED 6d37862
wip
YousefED bffab06
wip
YousefED 947111e
react pdf
YousefED 1d0142a
misc
YousefED 3245a9a
move files and clean partialBlocksToBlocksForTesting
YousefED 168b8a1
wip
YousefED 7299878
refactor
YousefED ba09fff
fix build
YousefED 8e3d28e
update packagejson
YousefED df16b28
Merge branch 'main' into feature/file-exporters
YousefED caec139
fix lint
YousefED 0056dec
fix lint
YousefED 5a48b21
wip
YousefED adf189d
wip
YousefED 20a912b
wip
YousefED d252a5c
Merge branch 'main' into feature/file-exporters
YousefED 3ba81ec
fix numbered list bug
YousefED ae49c67
wip
YousefED 2d57dba
small fixes
YousefED 123c5ff
fix build
YousefED 5615c72
fix lint
YousefED faecc52
wip
YousefED 9607e34
fix build
YousefED c19841b
fix numbering, image
YousefED eacd13a
fix build
YousefED a96c1f7
docx font
YousefED 84fc6b9
update template
YousefED e0fe318
full doc
YousefED 46630f8
fix examples
YousefED 1a6c31d
refactor
YousefED 4ccc350
fix build
YousefED 97a5f76
add option for resolveFile
YousefED b196572
add resolveFileUrl_DEV_ONLY to examples
YousefED ff2c41a
fix build
YousefED 39c6042
fix emoji pdf
YousefED d67d3d3
fix pdf numbering and checkmarks
YousefED 381471c
support colors
YousefED 456b70e
Merge branch 'main' into feature/file-exporters
YousefED a8f157f
fix build
YousefED 44ad258
fix package lock
YousefED e6988ba
fix tables
YousefED 19d50f4
fix word hyperlink / caption styles
YousefED 6d6650d
file handling docx, and start of code block
YousefED 6bc21c0
file blocks pdf
YousefED 45be776
split packages
YousefED 9246c5e
wip
YousefED 576574b
fix 2 pdf bugs
YousefED ec0b2d2
tests
YousefED 67abe39
fix lint
YousefED 3bcf431
fix build
YousefED 2b93040
fix test
YousefED c86c89b
remove example pdf
YousefED 8f9e112
remove react email
YousefED 01a6886
header / footer support
YousefED 55a825b
don't write files in tests
YousefED 7e4f05d
corsproxy + docs
YousefED 29401bd
add license
YousefED 59da8c2
Merge remote-tracking branch 'origin/main' into feature/file-exporters
YousefED fab5016
fix build
YousefED 94d020a
update docs
YousefED 24e26c0
small fix
YousefED File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
--- | ||
title: Export to docx (Office Open XML) | ||
description: Export BlockNote documents to a docx word (Office Open XML) file. | ||
imageTitle: Export to docx | ||
path: /docs/export-to-docx | ||
--- | ||
|
||
import { Example } from "@/components/example"; | ||
import { Callout } from "nextra/components"; | ||
|
||
# Exporting blocks to docx | ||
|
||
It's possible to export BlockNote documents to docx, completely client-side. | ||
|
||
<Callout type={"info"}> | ||
This feature is provided by the `@blocknote/xl-docx-exporter`. `xl-` packages | ||
are fully open source, but released under a copyleft license. A commercial | ||
license for usage in closed source, proprietary products comes as part of the | ||
[Business subscription](/pricing). | ||
</Callout> | ||
|
||
First, install the `@blocknote/xl-docx-exporter` and `docx` packages: | ||
|
||
```bash | ||
npm install @blocknote/xl-docx-exporter docx | ||
``` | ||
|
||
Then, create an instance of the `DOCXExporter` class. This exposes the following methods: | ||
|
||
```typescript | ||
import { | ||
DOCXExporter, | ||
docxDefaultSchemaMappings, | ||
} from "@blocknote/xl-docx-exporter"; | ||
import { Packer } from "docx"; | ||
|
||
// Create the exporter | ||
const exporter = new DOCXExporter(editor.schema, docxDefaultSchemaMappings); | ||
|
||
// Convert the blocks to a docxjs document | ||
const docxDocument = await exporter.toDocxJsDocument(editor.document); | ||
|
||
// Use docx to write to file: | ||
await Packer.toBuffer(docxDocument); | ||
``` | ||
|
||
See the [full example](/examples/interoperability/converting-blocks-to-docx) below: | ||
|
||
<Example name="interoperability/converting-blocks-to-docx" /> | ||
|
||
### Customizing the Docx output file | ||
|
||
`toDocxJsDocument` takes an optional `options` parameter, which allows you to customize document metadata (like the author) and section options (like headers and footers). | ||
|
||
Example usage: | ||
|
||
```typescript | ||
import { Paragraph, TextRun } from "docx"; | ||
|
||
const doc = await exporter.toDocxJsDocument(testDocument, { | ||
documentOptions: { | ||
creator: "John Doe", | ||
}, | ||
sectionOptions: { | ||
headers: { | ||
default: { | ||
options: { | ||
children: [new Paragraph({ children: [new TextRun("Header")] })], | ||
}, | ||
}, | ||
}, | ||
footers: { | ||
default: { | ||
options: { | ||
children: [new Paragraph({ children: [new TextRun("Footer")] })], | ||
}, | ||
}, | ||
}, | ||
}, | ||
}); | ||
``` | ||
|
||
### Custom mappings / custom schemas | ||
|
||
The `DOCXExporter` constructor takes a `schema`, `mappings` and `options` parameter. | ||
A _mapping_ defines how to convert a BlockNote schema element (a Block, Inline Content, or Style) to a [docxjs](https://docx.js.org/) element. | ||
If you're using a [custom schema](/docs/custom-schemas) in your editor, or if you want to overwrite how default BlockNote elements are converted to docx, you can pass your own `mappings`: | ||
|
||
For example, use the following code in case your schema has an `extraBlock` type: | ||
|
||
```typescript | ||
import { | ||
DOCXExporter, | ||
docxDefaultSchemaMappings, | ||
} from "@blocknote/xl-docx-exporter"; | ||
import { Paragraph, TextRun } from "docx"; | ||
|
||
new DOCXExporter(schema, { | ||
blockMapping: { | ||
...docxDefaultSchemaMappings.blockMapping, | ||
myCustomBlock: (block, exporter) => { | ||
return new Paragraph({ | ||
children: [ | ||
new TextRun({ | ||
text: "My custom block", | ||
}), | ||
], | ||
}); | ||
}, | ||
}, | ||
inlineContentMapping: docxDefaultSchemaMappings.inlineContentMapping, | ||
styleMapping: docxDefaultSchemaMappings.styleMapping, | ||
}); | ||
``` | ||
|
||
### Exporter options | ||
|
||
The `DOCXExporter` constructor takes an optional `options` parameter. | ||
While conversion happens on the client-side, the default setup uses a server hosted proxy to resolve files: | ||
|
||
```typescript | ||
const defaultOptions = { | ||
// a function to resolve external resources in order to avoid CORS issues | ||
// by default, this calls a BlockNote hosted server-side proxy to resolve files | ||
resolveFileUrl: corsProxyResolveFileUrl, | ||
// the colors to use in the Docx for things like highlighting, background colors and font colors. | ||
colors: COLORS_DEFAULT, // defaults from @blocknote/core | ||
}; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
--- | ||
title: Export to PDF | ||
description: Export BlockNote documents to a PDF. | ||
imageTitle: Export to PDF | ||
path: /docs/export-to-pdf | ||
--- | ||
|
||
import { Example } from "@/components/example"; | ||
import { Callout } from "nextra/components"; | ||
|
||
# Exporting blocks to PDF | ||
|
||
It's possible to export BlockNote documents to PDF, completely client-side. | ||
|
||
<Callout type={"info"}> | ||
This feature is provided by the `@blocknote/xl-pdf-exporter`. `xl-` packages | ||
are fully open source, but released under a copyleft license. A commercial | ||
license for usage in closed source, proprietary products comes as part of the | ||
[Business subscription](/pricing). | ||
</Callout> | ||
|
||
First, install the `@blocknote/xl-pdf-exporter` and `@react-pdf/renderer` packages: | ||
|
||
```bash | ||
npm install @blocknote/xl-pdf-exporter @react-pdf/renderer | ||
``` | ||
|
||
Then, create an instance of the `PDFExporter` class. This exposes the following methods: | ||
|
||
```typescript | ||
import { | ||
PDFExporter, | ||
pdfDefaultSchemaMappings, | ||
} from "@blocknote/xl-pdf-exporter"; | ||
import * as ReactPDF from "@react-pdf/renderer"; | ||
|
||
// Create the exporter | ||
const exporter = new PDFExporter(editor.schema, pdfDefaultSchemaMappings); | ||
|
||
// Convert the blocks to a react-pdf document | ||
const pdfDocument = await exporter.toReactPDFDocument(editor.document); | ||
|
||
// Use react-pdf to write to file: | ||
await ReactPDF.render(pdfDocument, `filename.pdf`); | ||
``` | ||
|
||
See the [full example](/examples/interoperability/converting-blocks-to-pdf) with live PDF preview below: | ||
|
||
<Example name="interoperability/converting-blocks-to-pdf" /> | ||
|
||
### Customizing the PDF | ||
|
||
`toReactPDFDocument` takes an optional `options` parameter, which allows you to customize the header and footer of the PDF: | ||
|
||
Example usage: | ||
|
||
```typescript | ||
import { Text } from "@react-pdf/renderer"; | ||
const pdfDocument = await exporter.toReactPDFDocument(editor.document, { | ||
header: <Text>Header</Text>, | ||
footer: <Text>Footer</Text>, | ||
}); | ||
``` | ||
|
||
### Custom mappings / custom schemas | ||
|
||
The `PDFExporter` constructor takes a `schema` and `mappings` parameter. | ||
A _mapping_ defines how to convert a BlockNote schema element (a Block, Inline Content, or Style) to a React-PDF element. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Link to React-PDF needed to match the docx export docs |
||
If you're using a [custom schema](/docs/custom-schemas) in your editor, or if you want to overwrite how default BlockNote elements are converted to PDF, you can pass your own `mappings`: | ||
|
||
For example, use the following code in case your schema has an `extraBlock` type: | ||
|
||
```typescript | ||
import { PDFExporter, pdfDefaultSchemaMappings } from "@blocknote/xl-pdf-exporter"; | ||
import { Text } from "@react-pdf/renderer"; | ||
|
||
new PDFExporter(schema, { | ||
blockMapping: { | ||
...pdfDefaultSchemaMappings.blockMapping, | ||
myCustomBlock: (block, exporter) => { | ||
return <Text>My custom block</Text>; | ||
}, | ||
}, | ||
inlineContentMapping: pdfDefaultSchemaMappings.inlineContentMapping, | ||
styleMapping: pdfDefaultSchemaMappings.styleMapping, | ||
}); | ||
``` | ||
|
||
### Exporter options | ||
|
||
The `PDFExporter` constructor takes an optional `options` parameter. | ||
While conversion happens on the client-side, the default setup uses two server based resources: | ||
|
||
```typescript | ||
const defaultOptions = { | ||
// emoji source, this is passed to the react-pdf library (https://react-pdf.org/fonts#registeremojisource) | ||
// these are loaded from cloudflare + twemoji by default | ||
emojiSource: { | ||
format: "png", | ||
url: "https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/72x72/", | ||
}, | ||
// a function to resolve external resources in order to avoid CORS issues | ||
// by default, this calls a BlockNote hosted server-side proxy to resolve files | ||
resolveFileUrl: corsProxyResolveFileUrl, | ||
// the colors to use in the PDF for things like highlighting, background colors and font colors. | ||
colors: COLORS_DEFAULT, // defaults from @blocknote/core | ||
}; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
examples/05-interoperability/05-converting-blocks-to-pdf/.bnexample.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"playground": true, | ||
"docs": true, | ||
"author": "yousefed", | ||
"tags": [""], | ||
"dependencies": { | ||
"@blocknote/xl-pdf-exporter": "latest", | ||
"@react-pdf/renderer": "^4.0.0" | ||
}, | ||
"pro": true | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the docs are nice and clear in general! But I would add a sentence at the start that the backbone of the PDF and docx conversions are the React-PDF and docxjs packages, and that customizing the export functionality requires being familiar with their APIs.