Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef77889d25 |
@@ -24,6 +24,10 @@ and this project adheres to
|
|||||||
|
|
||||||
## [2.0.1] - 2025-01-17
|
## [2.0.1] - 2025-01-17
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
✨(frontend) add multi columns support for editor #533
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
-🐛(frontend) share modal is shown when you don't have the abilities #557
|
-🐛(frontend) share modal is shown when you don't have the abilities #557
|
||||||
|
|||||||
@@ -366,4 +366,27 @@ test.describe('Doc Editor', () => {
|
|||||||
|
|
||||||
await expect(editor.getByText('Bonjour le monde')).toBeVisible();
|
await expect(editor.getByText('Bonjour le monde')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('it checks the multi columns', async ({ page, browserName }) => {
|
||||||
|
await createDoc(page, 'doc-multi-columns', browserName, 1);
|
||||||
|
|
||||||
|
await page.locator('.bn-block-outer').last().fill('/');
|
||||||
|
|
||||||
|
await page.getByText('Three Columns', { exact: true }).click();
|
||||||
|
|
||||||
|
await page.locator('.bn-block-column').first().fill('Column 1');
|
||||||
|
await page.locator('.bn-block-column').nth(1).fill('Column 2');
|
||||||
|
await page.locator('.bn-block-column').last().fill('Column 3');
|
||||||
|
|
||||||
|
expect(await page.locator('.bn-block-column').count()).toBe(3);
|
||||||
|
await expect(
|
||||||
|
page.locator('.bn-block-column[data-node-type="column"]').first(),
|
||||||
|
).toHaveText('Column 1');
|
||||||
|
await expect(
|
||||||
|
page.locator('.bn-block-column[data-node-type="column"]').nth(1),
|
||||||
|
).toHaveText('Column 2');
|
||||||
|
await expect(
|
||||||
|
page.locator('.bn-block-column[data-node-type="column"]').last(),
|
||||||
|
).toHaveText('Column 3');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"@blocknote/core": "0.21.0",
|
"@blocknote/core": "0.21.0",
|
||||||
"@blocknote/mantine": "0.21.0",
|
"@blocknote/mantine": "0.21.0",
|
||||||
"@blocknote/react": "0.21.0",
|
"@blocknote/react": "0.21.0",
|
||||||
|
"@blocknote/xl-multi-column": "0.21.0",
|
||||||
"@blocknote/xl-docx-exporter": "0.21.0",
|
"@blocknote/xl-docx-exporter": "0.21.0",
|
||||||
"@blocknote/xl-pdf-exporter": "0.21.0",
|
"@blocknote/xl-pdf-exporter": "0.21.0",
|
||||||
"@gouvfr-lasuite/integration": "1.0.2",
|
"@gouvfr-lasuite/integration": "1.0.2",
|
||||||
|
|||||||
+43
-5
@@ -1,10 +1,24 @@
|
|||||||
import { Dictionary, locales } from '@blocknote/core';
|
import {
|
||||||
|
Dictionary,
|
||||||
|
combineByGroup,
|
||||||
|
filterSuggestionItems,
|
||||||
|
locales,
|
||||||
|
} from '@blocknote/core';
|
||||||
import '@blocknote/core/fonts/inter.css';
|
import '@blocknote/core/fonts/inter.css';
|
||||||
import { BlockNoteView } from '@blocknote/mantine';
|
import { BlockNoteView } from '@blocknote/mantine';
|
||||||
import '@blocknote/mantine/style.css';
|
import '@blocknote/mantine/style.css';
|
||||||
import { useCreateBlockNote } from '@blocknote/react';
|
import {
|
||||||
|
SuggestionMenuController,
|
||||||
|
getDefaultReactSlashMenuItems,
|
||||||
|
useCreateBlockNote,
|
||||||
|
} from '@blocknote/react';
|
||||||
|
import {
|
||||||
|
getMultiColumnSlashMenuItems,
|
||||||
|
multiColumnDropCursor,
|
||||||
|
locales as multiColumnLocales,
|
||||||
|
} from '@blocknote/xl-multi-column';
|
||||||
import { HocuspocusProvider } from '@hocuspocus/provider';
|
import { HocuspocusProvider } from '@hocuspocus/provider';
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { css } from 'styled-components';
|
import { css } from 'styled-components';
|
||||||
import * as Y from 'yjs';
|
import * as Y from 'yjs';
|
||||||
@@ -17,7 +31,7 @@ import { useUploadFile } from '../hook';
|
|||||||
import { useHeadings } from '../hook/useHeadings';
|
import { useHeadings } from '../hook/useHeadings';
|
||||||
import useSaveDoc from '../hook/useSaveDoc';
|
import useSaveDoc from '../hook/useSaveDoc';
|
||||||
import { useEditorStore } from '../stores';
|
import { useEditorStore } from '../stores';
|
||||||
import { randomColor } from '../utils';
|
import { blockNoteWithMultiColumn, randomColor } from '../utils';
|
||||||
|
|
||||||
import { BlockNoteToolbar } from './BlockNoteToolbar';
|
import { BlockNoteToolbar } from './BlockNoteToolbar';
|
||||||
|
|
||||||
@@ -163,8 +177,14 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
|||||||
return cursor;
|
return cursor;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
dictionary: locales[lang as keyof typeof locales] as Dictionary,
|
dictionary: {
|
||||||
|
...(locales[lang as keyof typeof locales] as Dictionary),
|
||||||
|
multi_column:
|
||||||
|
multiColumnLocales[lang as keyof typeof multiColumnLocales],
|
||||||
|
},
|
||||||
uploadFile,
|
uploadFile,
|
||||||
|
schema: blockNoteWithMultiColumn,
|
||||||
|
dropCursor: multiColumnDropCursor,
|
||||||
},
|
},
|
||||||
[collabName, lang, provider, uploadFile],
|
[collabName, lang, provider, uploadFile],
|
||||||
);
|
);
|
||||||
@@ -178,6 +198,18 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
|||||||
};
|
};
|
||||||
}, [setEditor, editor]);
|
}, [setEditor, editor]);
|
||||||
|
|
||||||
|
const getSlashMenuItems = useMemo(() => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/require-await
|
||||||
|
return async (query: string) =>
|
||||||
|
filterSuggestionItems(
|
||||||
|
combineByGroup(
|
||||||
|
getDefaultReactSlashMenuItems(editor),
|
||||||
|
getMultiColumnSlashMenuItems(editor),
|
||||||
|
),
|
||||||
|
query,
|
||||||
|
);
|
||||||
|
}, [editor]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
$padding={{ top: 'md' }}
|
$padding={{ top: 'md' }}
|
||||||
@@ -199,7 +231,12 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
|||||||
formattingToolbar={false}
|
formattingToolbar={false}
|
||||||
editable={!readOnly}
|
editable={!readOnly}
|
||||||
theme="light"
|
theme="light"
|
||||||
|
slashMenu={false}
|
||||||
>
|
>
|
||||||
|
<SuggestionMenuController
|
||||||
|
triggerCharacter="/"
|
||||||
|
getItems={getSlashMenuItems}
|
||||||
|
/>
|
||||||
<BlockNoteToolbar />
|
<BlockNoteToolbar />
|
||||||
</BlockNoteView>
|
</BlockNoteView>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -225,6 +262,7 @@ export const BlockNoteEditorVersion = ({
|
|||||||
},
|
},
|
||||||
provider: undefined,
|
provider: undefined,
|
||||||
},
|
},
|
||||||
|
schema: blockNoteWithMultiColumn,
|
||||||
},
|
},
|
||||||
[initialContent],
|
[initialContent],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { BlockNoteEditor } from '@blocknote/core';
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { useHeadingStore } from '../stores';
|
import { useHeadingStore } from '../stores';
|
||||||
|
import { DocsBlockNoteEditor } from '../types';
|
||||||
|
|
||||||
export const useHeadings = (editor: BlockNoteEditor) => {
|
export const useHeadings = (editor: DocsBlockNoteEditor) => {
|
||||||
const { setHeadings, resetHeadings } = useHeadingStore();
|
const { setHeadings, resetHeadings } = useHeadingStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { BlockNoteEditor } from '@blocknote/core';
|
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
|
||||||
|
import { DocsBlockNoteEditor } from '../types';
|
||||||
|
|
||||||
export interface UseEditorstore {
|
export interface UseEditorstore {
|
||||||
editor?: BlockNoteEditor;
|
editor?: DocsBlockNoteEditor;
|
||||||
setEditor: (editor: BlockNoteEditor | undefined) => void;
|
setEditor: (editor: DocsBlockNoteEditor | undefined) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useEditorStore = create<UseEditorstore>((set) => ({
|
export const useEditorStore = create<UseEditorstore>((set) => ({
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { BlockNoteEditor } from '@blocknote/core';
|
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
|
||||||
import { HeadingBlock } from '../types';
|
import { DocsBlockNoteEditor, HeadingBlock } from '../types';
|
||||||
|
|
||||||
const recursiveTextContent = (content: HeadingBlock['content']): string => {
|
const recursiveTextContent = (content: HeadingBlock['content']): string => {
|
||||||
if (!content) {
|
if (!content) {
|
||||||
@@ -21,7 +20,7 @@ const recursiveTextContent = (content: HeadingBlock['content']): string => {
|
|||||||
|
|
||||||
export interface UseHeadingStore {
|
export interface UseHeadingStore {
|
||||||
headings: HeadingBlock[];
|
headings: HeadingBlock[];
|
||||||
setHeadings: (editor: BlockNoteEditor) => void;
|
setHeadings: (editor: DocsBlockNoteEditor) => void;
|
||||||
resetHeadings: () => void;
|
resetHeadings: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
import { BlockNoteEditor } from '@blocknote/core';
|
||||||
|
|
||||||
|
import { blockNoteWithMultiColumn } from './utils';
|
||||||
|
|
||||||
export interface DocAttachment {
|
export interface DocAttachment {
|
||||||
file: string;
|
file: string;
|
||||||
}
|
}
|
||||||
@@ -12,3 +16,9 @@ export type HeadingBlock = {
|
|||||||
level: number;
|
level: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DocsBlockNoteEditor = BlockNoteEditor<
|
||||||
|
typeof blockNoteWithMultiColumn.blockSchema,
|
||||||
|
typeof blockNoteWithMultiColumn.inlineContentSchema,
|
||||||
|
typeof blockNoteWithMultiColumn.styleSchema
|
||||||
|
>;
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import { BlockNoteSchema } from '@blocknote/core';
|
||||||
|
import { withMultiColumn } from '@blocknote/xl-multi-column';
|
||||||
|
|
||||||
export const randomColor = () => {
|
export const randomColor = () => {
|
||||||
const randomInt = (min: number, max: number) => {
|
const randomInt = (min: number, max: number) => {
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
@@ -25,3 +28,7 @@ function hslToHex(h: number, s: number, l: number) {
|
|||||||
|
|
||||||
export const toBase64 = (str: Uint8Array) =>
|
export const toBase64 = (str: Uint8Array) =>
|
||||||
Buffer.from(str).toString('base64');
|
Buffer.from(str).toString('base64');
|
||||||
|
|
||||||
|
export const blockNoteWithMultiColumn = withMultiColumn(
|
||||||
|
BlockNoteSchema.create(),
|
||||||
|
);
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import { BlockNoteEditor } from '@blocknote/core';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { BoxButton, Text } from '@/components';
|
import { BoxButton, Text } from '@/components';
|
||||||
import { useCunninghamTheme } from '@/cunningham';
|
import { useCunninghamTheme } from '@/cunningham';
|
||||||
|
import { DocsBlockNoteEditor } from '@/features/docs/doc-editor';
|
||||||
import { useResponsiveStore } from '@/stores';
|
import { useResponsiveStore } from '@/stores';
|
||||||
|
|
||||||
const leftPaddingMap: { [key: number]: string } = {
|
const leftPaddingMap: { [key: number]: string } = {
|
||||||
@@ -17,7 +17,7 @@ export type HeadingsHighlight = {
|
|||||||
}[];
|
}[];
|
||||||
|
|
||||||
interface HeadingProps {
|
interface HeadingProps {
|
||||||
editor: BlockNoteEditor;
|
editor: DocsBlockNoteEditor;
|
||||||
level: number;
|
level: number;
|
||||||
text: string;
|
text: string;
|
||||||
headingId: string;
|
headingId: string;
|
||||||
|
|||||||
+16
-1
@@ -1146,6 +1146,21 @@
|
|||||||
docx "^9.0.2"
|
docx "^9.0.2"
|
||||||
sharp "^0.33.5"
|
sharp "^0.33.5"
|
||||||
|
|
||||||
|
"@blocknote/xl-multi-column@0.21.0":
|
||||||
|
version "0.21.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@blocknote/xl-multi-column/-/xl-multi-column-0.21.0.tgz#913bf07d6fb2c5445a6e4a375646997035e351e2"
|
||||||
|
integrity sha512-nWRZCP14pcbbA4F274kBL4UXI6RNmxZRKynsqACBPC/B3bns8GDh0GWMEPz/KN/6kuOkm/bYHHCkglDlEIEF1Q==
|
||||||
|
dependencies:
|
||||||
|
"@blocknote/core" "^0.21.0"
|
||||||
|
"@blocknote/react" "^0.21.0"
|
||||||
|
"@tiptap/core" "^2.7.1"
|
||||||
|
prosemirror-model "^1.23.0"
|
||||||
|
prosemirror-state "^1.4.3"
|
||||||
|
prosemirror-tables "^1.3.7"
|
||||||
|
prosemirror-transform "^1.9.0"
|
||||||
|
prosemirror-view "^1.33.7"
|
||||||
|
react-icons "^5.2.1"
|
||||||
|
|
||||||
"@blocknote/xl-pdf-exporter@0.21.0":
|
"@blocknote/xl-pdf-exporter@0.21.0":
|
||||||
version "0.21.0"
|
version "0.21.0"
|
||||||
resolved "https://registry.yarnpkg.com/@blocknote/xl-pdf-exporter/-/xl-pdf-exporter-0.21.0.tgz#6e05b20ba331cdd17162f7d42678bdfc54e9914f"
|
resolved "https://registry.yarnpkg.com/@blocknote/xl-pdf-exporter/-/xl-pdf-exporter-0.21.0.tgz#6e05b20ba331cdd17162f7d42678bdfc54e9914f"
|
||||||
@@ -11478,7 +11493,7 @@ prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.4.3:
|
|||||||
prosemirror-transform "^1.0.0"
|
prosemirror-transform "^1.0.0"
|
||||||
prosemirror-view "^1.27.0"
|
prosemirror-view "^1.27.0"
|
||||||
|
|
||||||
prosemirror-tables@^1.6.1:
|
prosemirror-tables@^1.3.7, prosemirror-tables@^1.6.1:
|
||||||
version "1.6.2"
|
version "1.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.6.2.tgz#cec9e9ac6ecf81d67147c19ab39125d56c8351ae"
|
resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.6.2.tgz#cec9e9ac6ecf81d67147c19ab39125d56c8351ae"
|
||||||
integrity sha512-97dKocVLrEVTQjZ4GBLdrrMw7Gv3no8H8yMwf5IRM9OoHrzbWpcH5jJxYgNQIRCtdIqwDctT1HdMHrGTiwp1dQ==
|
integrity sha512-97dKocVLrEVTQjZ4GBLdrrMw7Gv3no8H8yMwf5IRM9OoHrzbWpcH5jJxYgNQIRCtdIqwDctT1HdMHrGTiwp1dQ==
|
||||||
|
|||||||
Reference in New Issue
Block a user