Skip to content

Commit

Permalink
feat: Page break (#1372)
Browse files Browse the repository at this point in the history
* feat: Page break block

* feat: Add page break support to PDF & DOCX exporters

* feat: Add CSS to support Page break when printing

* Small UX changes

* Removed page break from default schema

* Fixed unit tests

* Fixed lint

* Implemented PR feedback

---------

Co-authored-by: matthewlipski <matthewlipski@gmail.com>
  • Loading branch information
areknawo and matthewlipski authored Jan 20, 2025
1 parent 8461552 commit 800a1f0
Show file tree
Hide file tree
Showing 43 changed files with 2,374 additions and 1,320 deletions.
70 changes: 2 additions & 68 deletions examples/01-basic/04-all-blocks/App.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,11 @@
import {
BlockNoteSchema,
combineByGroup,
filterSuggestionItems,
locales,
} from "@blocknote/core";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import {
SuggestionMenuController,
getDefaultReactSlashMenuItems,
useCreateBlockNote,
} from "@blocknote/react";
import {
getMultiColumnSlashMenuItems,
multiColumnDropCursor,
locales as multiColumnLocales,
withMultiColumn,
} from "@blocknote/xl-multi-column";
import { useMemo } from "react";
import { useCreateBlockNote } from "@blocknote/react";

export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
schema: withMultiColumn(BlockNoteSchema.create()),
dropCursor: multiColumnDropCursor,
dictionary: {
...locales.en,
multi_column: multiColumnLocales.en,
},
initialContent: [
{
type: "paragraph",
Expand All @@ -51,35 +28,6 @@ export default function App() {
type: "paragraph",
content: "Paragraph",
},
{
type: "columnList",
children: [
{
type: "column",
props: {
width: 0.8,
},
children: [
{
type: "paragraph",
content: "Hello to the left!",
},
],
},
{
type: "column",
props: {
width: 1.2,
},
children: [
{
type: "paragraph",
content: "Hello to the right!",
},
],
},
],
},
{
type: "heading",
content: "Heading",
Expand Down Expand Up @@ -189,20 +137,6 @@ export default function App() {
],
});

const slashMenuItems = useMemo(() => {
return combineByGroup(
getDefaultReactSlashMenuItems(editor),
getMultiColumnSlashMenuItems(editor)
);
}, [editor]);

// Renders the editor instance using a React component.
return (
<BlockNoteView editor={editor} slashMenu={false}>
<SuggestionMenuController
triggerCharacter={"/"}
getItems={async (query) => filterSuggestionItems(slashMenuItems, query)}
/>
</BlockNoteView>
);
return <BlockNoteView editor={editor} />;
}
36 changes: 33 additions & 3 deletions examples/05-interoperability/05-converting-blocks-to-pdf/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import {
BlockNoteSchema,
combineByGroup,
filterSuggestionItems,
withPageBreak,
} from "@blocknote/core";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import { useCreateBlockNote } from "@blocknote/react";
import {
getDefaultReactSlashMenuItems,
getPageBreakReactSlashMenuItems,
SuggestionMenuController,
useCreateBlockNote,
} from "@blocknote/react";
import {
PDFExporter,
pdfDefaultSchemaMappings,
} from "@blocknote/xl-pdf-exporter";
import { PDFViewer } from "@react-pdf/renderer";
import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";

import "./styles.css";

export default function App() {
Expand All @@ -16,6 +28,7 @@ export default function App() {

// Creates a new editor instance with some initial content.
const editor = useCreateBlockNote({
schema: withPageBreak(BlockNoteSchema.create()),
initialContent: [
{
type: "paragraph",
Expand Down Expand Up @@ -180,6 +193,9 @@ export default function App() {
],
},
},
{
type: "pageBreak",
},
{
type: "file",
},
Expand Down Expand Up @@ -308,11 +324,25 @@ export default function App() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const slashMenuItems = useMemo(() => {
return combineByGroup(
getDefaultReactSlashMenuItems(editor),
getPageBreakReactSlashMenuItems(editor)
);
}, [editor]);

// Renders the editor instance, and its contents as HTML below.
return (
<div className="wrapper">
<div className="editor">
<BlockNoteView editor={editor} onChange={onChange} />
<BlockNoteView editor={editor} slashMenu={false} onChange={onChange}>
<SuggestionMenuController
triggerCharacter={"/"}
getItems={async (query) =>
filterSuggestionItems(slashMenuItems, query)
}
/>
</BlockNoteView>
</div>
<div className="pdf">
<PDFViewer width={"100%"}>{pdfDocument}</PDFViewer>
Expand Down
35 changes: 33 additions & 2 deletions examples/05-interoperability/06-converting-blocks-to-docx/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import {
BlockNoteSchema,
combineByGroup,
filterSuggestionItems,
withPageBreak,
} from "@blocknote/core";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import { useCreateBlockNote } from "@blocknote/react";
import {
getDefaultReactSlashMenuItems,
getPageBreakReactSlashMenuItems,
SuggestionMenuController,
useCreateBlockNote,
} from "@blocknote/react";
import {
DOCXExporter,
docxDefaultSchemaMappings,
} from "@blocknote/xl-docx-exporter";
import { useMemo } from "react";

import "./styles.css";

export default function App() {
// Creates a new editor instance with some initial content.
const editor = useCreateBlockNote({
schema: withPageBreak(BlockNoteSchema.create()),
initialContent: [
{
type: "paragraph",
Expand Down Expand Up @@ -175,6 +189,9 @@ export default function App() {
],
},
},
{
type: "pageBreak",
},
{
type: "file",
},
Expand Down Expand Up @@ -305,6 +322,13 @@ export default function App() {
window.URL.revokeObjectURL(link.href);
};

const slashMenuItems = useMemo(() => {
return combineByGroup(
getDefaultReactSlashMenuItems(editor),
getPageBreakReactSlashMenuItems(editor)
);
}, [editor]);

// Renders the editor instance, and its contents as HTML below.
return (
<div>
Expand All @@ -314,7 +338,14 @@ export default function App() {
</button>
</div>
<div className="item">
<BlockNoteView editor={editor} />
<BlockNoteView editor={editor} slashMenu={false}>
<SuggestionMenuController
triggerCharacter={"/"}
getItems={async (query) =>
filterSuggestionItems(slashMenuItems, query)
}
/>
</BlockNoteView>
</div>
</div>
);
Expand Down
39 changes: 39 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div data-page-break=""></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class="bn-block-group" data-node-type="blockGroup"><div class="bn-block-outer" data-node-type="blockOuter" data-id="1"><div class="bn-block" data-node-type="blockContainer" data-id="1"><div class="bn-block-content" data-content-type="pageBreak"><div class="bn-page-break" data-page-break=""></div></div></div></div></div>
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -1605,6 +1605,22 @@ exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert
}
`;

exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert pageBreak/basic to/from prosemirror 1`] = `
{
"attrs": {
"backgroundColor": "default",
"id": "1",
"textColor": "default",
},
"content": [
{
"type": "pageBreak",
},
],
"type": "blockContainer",
}
`;

exports[`Test BlockNote-Prosemirror conversion > Case: default schema > Convert paragraph/basic to/from prosemirror 1`] = `
{
"attrs": {
Expand Down
16 changes: 15 additions & 1 deletion packages/core/src/api/testUtil/cases/defaultSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ import {
DefaultInlineContentSchema,
DefaultStyleSchema,
} from "../../../blocks/defaultBlocks.js";
import {
pageBreakSchema,
withPageBreak,
} from "../../../blocks/PageBreakBlockContent/schema.js";
import { BlockNoteEditor } from "../../../editor/BlockNoteEditor.js";
import { BlockNoteSchema } from "../../../editor/BlockNoteSchema.js";

export const defaultSchemaTestCases: EditorTestCases<
DefaultBlockSchema,
DefaultBlockSchema & typeof pageBreakSchema.blockSchema,
DefaultInlineContentSchema,
DefaultStyleSchema
> = {
name: "default schema",
createEditor: () => {
return BlockNoteEditor.create({
schema: withPageBreak(BlockNoteSchema.create()),
uploadFile: uploadToTmpFilesDotOrg_DEV_ONLY,
});
},
Expand Down Expand Up @@ -202,6 +208,14 @@ export const defaultSchemaTestCases: EditorTestCases<
},
],
},
{
name: "pageBreak/basic",
blocks: [
{
type: "pageBreak",
},
],
},
{
name: "file/button",
blocks: [
Expand Down
Loading

0 comments on commit 800a1f0

Please sign in to comment.