Skip to content

Commit 2673f0a

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.
1 parent 9194bf5 commit 2673f0a

File tree

11 files changed

+114
-16
lines changed

11 files changed

+114
-16
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to
1111

1212
## [2.0.1] - 2025-01-17
1313

14+
## Added
15+
16+
✨(frontend) add multi columns support for editor #533
17+
1418
## Fixed
1519

1620
-🐛(frontend) share modal is shown when you don't have the abilities #557

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,4 +366,27 @@ test.describe('Doc Editor', () => {
366366

367367
await expect(editor.getByText('Bonjour le monde')).toBeVisible();
368368
});
369+
370+
test('it checks the multi columns', async ({ page, browserName }) => {
371+
await createDoc(page, 'doc-multi-columns', browserName, 1);
372+
373+
await page.locator('.bn-block-outer').last().fill('/');
374+
375+
await page.getByText('Three Columns', { exact: true }).click();
376+
377+
await page.locator('.bn-block-column').first().fill('Column 1');
378+
await page.locator('.bn-block-column').nth(1).fill('Column 2');
379+
await page.locator('.bn-block-column').last().fill('Column 3');
380+
381+
expect(await page.locator('.bn-block-column').count()).toBe(3);
382+
await expect(
383+
page.locator('.bn-block-column[data-node-type="column"]').first(),
384+
).toHaveText('Column 1');
385+
await expect(
386+
page.locator('.bn-block-column[data-node-type="column"]').nth(1),
387+
).toHaveText('Column 2');
388+
await expect(
389+
page.locator('.bn-block-column[data-node-type="column"]').last(),
390+
).toHaveText('Column 3');
391+
});
369392
});

src/frontend/apps/impress/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@blocknote/core": "0.21.0",
1919
"@blocknote/mantine": "0.21.0",
2020
"@blocknote/react": "0.21.0",
21+
"@blocknote/xl-multi-column": "0.21.0",
2122
"@gouvfr-lasuite/integration": "1.0.2",
2223
"@hocuspocus/provider": "2.15.0",
2324
"@openfun/cunningham-react": "2.9.4",

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

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
1-
import { Dictionary, locales } from '@blocknote/core';
1+
import {
2+
Dictionary,
3+
combineByGroup,
4+
filterSuggestionItems,
5+
locales,
6+
} from '@blocknote/core';
27
import '@blocknote/core/fonts/inter.css';
38
import { BlockNoteView } from '@blocknote/mantine';
49
import '@blocknote/mantine/style.css';
5-
import { useCreateBlockNote } from '@blocknote/react';
10+
import {
11+
SuggestionMenuController,
12+
getDefaultReactSlashMenuItems,
13+
useCreateBlockNote,
14+
} from '@blocknote/react';
15+
import {
16+
getMultiColumnSlashMenuItems,
17+
multiColumnDropCursor,
18+
locales as multiColumnLocales,
19+
} from '@blocknote/xl-multi-column';
620
import { HocuspocusProvider } from '@hocuspocus/provider';
7-
import { useEffect } from 'react';
21+
import { useEffect, useMemo } from 'react';
822
import { useTranslation } from 'react-i18next';
923
import { css } from 'styled-components';
1024
import * as Y from 'yjs';
@@ -17,7 +31,7 @@ import { useUploadFile } from '../hook';
1731
import { useHeadings } from '../hook/useHeadings';
1832
import useSaveDoc from '../hook/useSaveDoc';
1933
import { useEditorStore } from '../stores';
20-
import { randomColor } from '../utils';
34+
import { blockNoteWithMultiColumn, randomColor } from '../utils';
2135

2236
import { BlockNoteToolbar } from './BlockNoteToolbar';
2337

@@ -163,8 +177,14 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
163177
return cursor;
164178
},
165179
},
166-
dictionary: locales[lang as keyof typeof locales] as Dictionary,
180+
dictionary: {
181+
...(locales[lang as keyof typeof locales] as Dictionary),
182+
multi_column:
183+
multiColumnLocales[lang as keyof typeof multiColumnLocales],
184+
},
167185
uploadFile,
186+
schema: blockNoteWithMultiColumn,
187+
dropCursor: multiColumnDropCursor,
168188
},
169189
[collabName, lang, provider, uploadFile],
170190
);
@@ -178,6 +198,18 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
178198
};
179199
}, [setEditor, editor]);
180200

201+
const getSlashMenuItems = useMemo(() => {
202+
// eslint-disable-next-line @typescript-eslint/require-await
203+
return async (query: string) =>
204+
filterSuggestionItems(
205+
combineByGroup(
206+
getDefaultReactSlashMenuItems(editor),
207+
getMultiColumnSlashMenuItems(editor),
208+
),
209+
query,
210+
);
211+
}, [editor]);
212+
181213
return (
182214
<Box
183215
$padding={{ top: 'md' }}
@@ -199,7 +231,12 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
199231
formattingToolbar={false}
200232
editable={!readOnly}
201233
theme="light"
234+
slashMenu={false}
202235
>
236+
<SuggestionMenuController
237+
triggerCharacter="/"
238+
getItems={getSlashMenuItems}
239+
/>
203240
<BlockNoteToolbar />
204241
</BlockNoteView>
205242
</Box>
@@ -225,6 +262,7 @@ export const BlockNoteEditorVersion = ({
225262
},
226263
provider: undefined,
227264
},
265+
schema: blockNoteWithMultiColumn,
228266
},
229267
[initialContent],
230268
);

src/frontend/apps/impress/src/features/docs/doc-editor/hook/useHeadings.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { BlockNoteEditor } from '@blocknote/core';
21
import { useEffect } from 'react';
32

43
import { useHeadingStore } from '../stores';
4+
import { DocsBlockNoteEditor } from '../types';
55

6-
export const useHeadings = (editor: BlockNoteEditor) => {
6+
export const useHeadings = (editor: DocsBlockNoteEditor) => {
77
const { setHeadings, resetHeadings } = useHeadingStore();
88

99
useEffect(() => {

src/frontend/apps/impress/src/features/docs/doc-editor/stores/useEditorStore.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { BlockNoteEditor } from '@blocknote/core';
21
import { create } from 'zustand';
32

3+
import { DocsBlockNoteEditor } from '../types';
4+
45
export interface UseEditorstore {
5-
editor?: BlockNoteEditor;
6-
setEditor: (editor: BlockNoteEditor | undefined) => void;
6+
editor?: DocsBlockNoteEditor;
7+
setEditor: (editor: DocsBlockNoteEditor | undefined) => void;
78
}
89

910
export const useEditorStore = create<UseEditorstore>((set) => ({

src/frontend/apps/impress/src/features/docs/doc-editor/stores/useHeadingStore.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { BlockNoteEditor } from '@blocknote/core';
21
import { create } from 'zustand';
32

4-
import { HeadingBlock } from '../types';
3+
import { DocsBlockNoteEditor, HeadingBlock } from '../types';
54

65
const recursiveTextContent = (content: HeadingBlock['content']): string => {
76
if (!content) {
@@ -21,7 +20,7 @@ const recursiveTextContent = (content: HeadingBlock['content']): string => {
2120

2221
export interface UseHeadingStore {
2322
headings: HeadingBlock[];
24-
setHeadings: (editor: BlockNoteEditor) => void;
23+
setHeadings: (editor: DocsBlockNoteEditor) => void;
2524
resetHeadings: () => void;
2625
}
2726

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import { BlockNoteEditor } from '@blocknote/core';
2+
3+
import { blockNoteWithMultiColumn } from './utils';
4+
15
export interface DocAttachment {
26
file: string;
37
}
@@ -12,3 +16,9 @@ export type HeadingBlock = {
1216
level: number;
1317
};
1418
};
19+
20+
export type DocsBlockNoteEditor = BlockNoteEditor<
21+
typeof blockNoteWithMultiColumn.blockSchema,
22+
typeof blockNoteWithMultiColumn.inlineContentSchema,
23+
typeof blockNoteWithMultiColumn.styleSchema
24+
>;

src/frontend/apps/impress/src/features/docs/doc-editor/utils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { BlockNoteSchema } from '@blocknote/core';
2+
import { withMultiColumn } from '@blocknote/xl-multi-column';
3+
14
export const randomColor = () => {
25
const randomInt = (min: number, max: number) => {
36
return Math.floor(Math.random() * (max - min + 1)) + min;
@@ -25,3 +28,7 @@ function hslToHex(h: number, s: number, l: number) {
2528

2629
export const toBase64 = (str: Uint8Array) =>
2730
Buffer.from(str).toString('base64');
31+
32+
export const blockNoteWithMultiColumn = withMultiColumn(
33+
BlockNoteSchema.create(),
34+
);

src/frontend/apps/impress/src/features/docs/doc-table-content/components/Heading.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { BlockNoteEditor } from '@blocknote/core';
21
import { useState } from 'react';
32

43
import { BoxButton, Text } from '@/components';
54
import { useCunninghamTheme } from '@/cunningham';
5+
import { DocsBlockNoteEditor } from '@/features/docs/doc-editor';
66
import { useResponsiveStore } from '@/stores';
77

88
const leftPaddingMap: { [key: number]: string } = {
@@ -17,7 +17,7 @@ export type HeadingsHighlight = {
1717
}[];
1818

1919
interface HeadingProps {
20-
editor: BlockNoteEditor;
20+
editor: DocsBlockNoteEditor;
2121
level: number;
2222
text: string;
2323
headingId: string;

src/frontend/yarn.lock

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,21 @@
11361136
y-protocols "^1.0.6"
11371137
yjs "^13.6.15"
11381138

1139+
"@blocknote/[email protected]":
1140+
version "0.21.0"
1141+
resolved "https://registry.yarnpkg.com/@blocknote/xl-multi-column/-/xl-multi-column-0.21.0.tgz#913bf07d6fb2c5445a6e4a375646997035e351e2"
1142+
integrity sha512-nWRZCP14pcbbA4F274kBL4UXI6RNmxZRKynsqACBPC/B3bns8GDh0GWMEPz/KN/6kuOkm/bYHHCkglDlEIEF1Q==
1143+
dependencies:
1144+
"@blocknote/core" "^0.21.0"
1145+
"@blocknote/react" "^0.21.0"
1146+
"@tiptap/core" "^2.7.1"
1147+
prosemirror-model "^1.23.0"
1148+
prosemirror-state "^1.4.3"
1149+
prosemirror-tables "^1.3.7"
1150+
prosemirror-transform "^1.9.0"
1151+
prosemirror-view "^1.33.7"
1152+
react-icons "^5.2.1"
1153+
11391154
"@cspotcode/source-map-support@^0.8.0":
11401155
version "0.8.1"
11411156
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
@@ -11122,7 +11137,7 @@ prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.4.3:
1112211137
prosemirror-transform "^1.0.0"
1112311138
prosemirror-view "^1.27.0"
1112411139

11125-
prosemirror-tables@^1.6.1:
11140+
prosemirror-tables@^1.3.7, prosemirror-tables@^1.6.1:
1112611141
version "1.6.2"
1112711142
resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.6.2.tgz#cec9e9ac6ecf81d67147c19ab39125d56c8351ae"
1112811143
integrity sha512-97dKocVLrEVTQjZ4GBLdrrMw7Gv3no8H8yMwf5IRM9OoHrzbWpcH5jJxYgNQIRCtdIqwDctT1HdMHrGTiwp1dQ==

0 commit comments

Comments
 (0)