Skip to content

Commit 11d0baf

Browse files
committed
✨(frontend) add multi columns support for editor
We add multi columns support for editor, now you can add columns to your document. Works with export. 📄AGPL feature.
1 parent 1ae831c commit 11d0baf

File tree

7 files changed

+106
-5
lines changed

7 files changed

+106
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to
1313
- ✨(backend) allow masking documents from the list view #1171
1414
- ✨(frontend) subdocs can manage link reach #1190
1515
- ✨(frontend) add duplicate action to doc tree #1175
16+
- ✨(frontend) add multi columns support for editor #1219
1617

1718
### Changed
1819

docs/env.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,10 @@ NODE_ENV=production NEXT_PUBLIC_PUBLISH_AS_MIT=false yarn build
136136

137137
Packages with licences incompatible with the MIT licence:
138138
* `xl-docx-exporter`: [AGPL-3.0](https://github.com/TypeCellOS/BlockNote/blob/main/packages/xl-docx-exporter/LICENSE),
139-
* `xl-pdf-exporter`: [AGPL-3.0](https://github.com/TypeCellOS/BlockNote/blob/main/packages/xl-pdf-exporter/LICENSE)
139+
* `xl-pdf-exporter`: [AGPL-3.0](https://github.com/TypeCellOS/BlockNote/blob/main/packages/xl-pdf-exporter/LICENSE),
140+
* `xl-multi-column`: [AGPL-3.0](https://github.com/TypeCellOS/BlockNote/blob/main/packages/xl-multi-column/LICENSE).
140141

141142
In `.env.development`, `PUBLISH_AS_MIT` is set to `false`, allowing developers to test Docs with all its features.
142143

143-
⚠️ If you run Docs in production with `PUBLISH_AS_MIT` set to `false` make sure you fulfill your [BlockNote licensing](https://github.com/TypeCellOS/BlockNote/blob/main/packages/xl-pdf-exporter/LICENSE) or [subscription](https://www.blocknotejs.org/about#partner-with-us) obligations.
144+
⚠️ If you run Docs in production with `PUBLISH_AS_MIT` set to `false` make sure you fulfill your BlockNote licensing or [subscription](https://www.blocknotejs.org/about#partner-with-us) obligations.
144145

src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,4 +346,69 @@ test.describe('Doc Export', () => {
346346
const pdfData = await pdf(pdfBuffer);
347347
expect(pdfData.text).toContain('Hello World');
348348
});
349+
350+
test('it exports the doc with multi columns', async ({
351+
page,
352+
browserName,
353+
}) => {
354+
const [randomDoc] = await createDoc(
355+
page,
356+
'doc-multi-columns',
357+
browserName,
358+
1,
359+
);
360+
361+
await page.locator('.bn-block-outer').last().fill('/');
362+
363+
await page.getByText('Three Columns', { exact: true }).click();
364+
365+
await page.locator('.bn-block-column').first().fill('Column 1');
366+
await page.locator('.bn-block-column').nth(1).fill('Column 2');
367+
await page.locator('.bn-block-column').last().fill('Column 3');
368+
369+
expect(await page.locator('.bn-block-column').count()).toBe(3);
370+
await expect(
371+
page.locator('.bn-block-column[data-node-type="column"]').first(),
372+
).toHaveText('Column 1');
373+
await expect(
374+
page.locator('.bn-block-column[data-node-type="column"]').nth(1),
375+
).toHaveText('Column 2');
376+
await expect(
377+
page.locator('.bn-block-column[data-node-type="column"]').last(),
378+
).toHaveText('Column 3');
379+
380+
await page
381+
.getByRole('button', {
382+
name: 'download',
383+
exact: true,
384+
})
385+
.click();
386+
387+
await expect(
388+
page.getByRole('button', {
389+
name: 'Download',
390+
exact: true,
391+
}),
392+
).toBeVisible();
393+
394+
const downloadPromise = page.waitForEvent('download', (download) => {
395+
return download.suggestedFilename().includes(`${randomDoc}.pdf`);
396+
});
397+
398+
void page
399+
.getByRole('button', {
400+
name: 'Download',
401+
exact: true,
402+
})
403+
.click();
404+
405+
const download = await downloadPromise;
406+
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
407+
408+
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
409+
const pdfData = await pdf(pdfBuffer);
410+
expect(pdfData.text).toContain('Column 1');
411+
expect(pdfData.text).toContain('Column 2');
412+
expect(pdfData.text).toContain('Column 3');
413+
});
349414
});

src/frontend/apps/impress/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"@blocknote/mantine": "0.34.0",
2222
"@blocknote/react": "0.34.0",
2323
"@blocknote/xl-docx-exporter": "0.34.0",
24+
"@blocknote/xl-multi-column": "0.34.0",
2425
"@blocknote/xl-pdf-exporter": "0.34.0",
2526
"@dnd-kit/core": "6.3.1",
2627
"@dnd-kit/modifiers": "9.0.0",

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,13 @@ import { randomColor } from '../utils';
2828
import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu';
2929
import { BlockNoteToolbar } from './BlockNoteToolBar/BlockNoteToolbar';
3030
import { CalloutBlock, DividerBlock } from './custom-blocks';
31+
import XLMultiColumn from './xl-multi-column';
3132

32-
export const blockNoteSchema = withPageBreak(
33+
const multiColumnDropCursor = XLMultiColumn?.multiColumnDropCursor;
34+
const multiColumnLocales = XLMultiColumn?.locales;
35+
const withMultiColumn = XLMultiColumn?.withMultiColumn;
36+
37+
const baseBlockNoteSchema = withPageBreak(
3338
BlockNoteSchema.create({
3439
blockSpecs: {
3540
...defaultBlockSpecs,
@@ -39,6 +44,9 @@ export const blockNoteSchema = withPageBreak(
3944
}),
4045
);
4146

47+
export const blockNoteSchema = (withMultiColumn?.(baseBlockNoteSchema) ||
48+
baseBlockNoteSchema) as typeof baseBlockNoteSchema;
49+
4250
interface BlockNoteEditorProps {
4351
doc: Doc;
4452
provider: HocuspocusProvider;
@@ -116,7 +124,11 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
116124
},
117125
showCursorLabels: showCursorLabels as 'always' | 'activity',
118126
},
119-
dictionary: locales[lang as keyof typeof locales],
127+
dictionary: {
128+
...locales[lang as keyof typeof locales],
129+
multi_column:
130+
multiColumnLocales?.[lang as keyof typeof multiColumnLocales],
131+
},
120132
tables: {
121133
splitCells: true,
122134
cellBackgroundColor: true,
@@ -125,6 +137,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
125137
},
126138
uploadFile,
127139
schema: blockNoteSchema,
140+
dropCursor: multiColumnDropCursor,
128141
},
129142
[collabName, lang, provider, uploadFile],
130143
);

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ import {
1515
getCalloutReactSlashMenuItems,
1616
getDividerReactSlashMenuItems,
1717
} from './custom-blocks';
18+
import XLMultiColumn from './xl-multi-column';
19+
20+
const getMultiColumnSlashMenuItems =
21+
XLMultiColumn?.getMultiColumnSlashMenuItems;
1822

1923
export const BlockNoteSuggestionMenu = () => {
2024
const editor = useBlockNoteEditor<DocsBlockSchema>();
@@ -27,8 +31,9 @@ export const BlockNoteSuggestionMenu = () => {
2731
filterSuggestionItems(
2832
combineByGroup(
2933
getDefaultReactSlashMenuItems(editor),
30-
getPageBreakReactSlashMenuItems(editor),
3134
getCalloutReactSlashMenuItems(editor, t, basicBlocksName),
35+
getMultiColumnSlashMenuItems?.(editor) || [],
36+
getPageBreakReactSlashMenuItems(editor),
3237
getDividerReactSlashMenuItems(editor, t, basicBlocksName),
3338
),
3439
query,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* To import XL modules you must import from the index file.
3+
* This is to ensure that the XL modules are only loaded when
4+
* the application is not published as MIT.
5+
*/
6+
import * as XLMultiColumn from '@blocknote/xl-multi-column';
7+
8+
let modulesXL = undefined;
9+
if (process.env.NEXT_PUBLIC_PUBLISH_AS_MIT === 'false') {
10+
modulesXL = XLMultiColumn;
11+
}
12+
13+
type ModulesXL = typeof XLMultiColumn | undefined;
14+
15+
export default modulesXL as ModulesXL;

0 commit comments

Comments
 (0)