From a9def8cb18b33ba5367847679c76d494a9cf4464 Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Fri, 6 Dec 2024 14:47:54 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(frontend)=20create=20useHead?= =?UTF-8?q?ings=20hook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - We create the useHeadings hook to manage the headings of the document and staty DRY. - We use the headings store in IconOpenPanelEditor and TableContent, to avoid prop drilling. - We add a debounce on the onEditorContentChange to improve a bit the performance. --- .../doc-editor/components/BlockNoteEditor.tsx | 31 +++++-------------- .../docs/doc-editor/components/DocEditor.tsx | 7 ++--- .../doc-editor/components/PanelEditor.tsx | 20 ++++-------- .../docs/doc-editor/hook/useHeadings.tsx | 23 ++++++++++++++ .../components/TableContent.tsx | 9 ++---- 5 files changed, 42 insertions(+), 48 deletions(-) create mode 100644 src/frontend/apps/impress/src/features/docs/doc-editor/hook/useHeadings.tsx diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx index cafecdbf0..6ab5294e4 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx @@ -13,8 +13,9 @@ import { useAuthStore } from '@/core/auth'; import { Doc } from '@/features/docs/doc-management'; import { useUploadFile } from '../hook'; +import { useHeadings } from '../hook/useHeadings'; import useSaveDoc from '../hook/useSaveDoc'; -import { useEditorStore, useHeadingStore } from '../stores'; +import { useEditorStore } from '../stores'; import { randomColor } from '../utils'; import { BlockNoteToolbar } from './BlockNoteToolbar'; @@ -75,7 +76,6 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => { const readOnly = !doc.abilities.partial_update; useSaveDoc(doc.id, provider.document, !readOnly); - const { setHeadings, resetHeadings } = useHeadingStore(); const { i18n } = useTranslation(); const lang = i18n.language; @@ -126,6 +126,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => { }, [collabName, lang, provider, uploadFile], ); + useHeadings(editor); useEffect(() => { setEditor(editor); @@ -135,18 +136,6 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => { }; }, [setEditor, editor]); - useEffect(() => { - setHeadings(editor); - - editor?.onEditorContentChange(() => { - setHeadings(editor); - }); - - return () => { - resetHeadings(); - }; - }, [editor, resetHeadings, setHeadings]); - return ( {errorAttachment && ( @@ -179,8 +168,7 @@ export const BlockNoteEditorVersion = ({ initialContent, }: BlockNoteEditorVersionProps) => { const readOnly = true; - const { setHeadings, resetHeadings } = useHeadingStore(); - + const { setEditor } = useEditorStore(); const editor = useCreateBlockNote( { collaboration: { @@ -194,18 +182,15 @@ export const BlockNoteEditorVersion = ({ }, [initialContent], ); + useHeadings(editor); useEffect(() => { - setHeadings(editor); - - editor?.onEditorContentChange(() => { - setHeadings(editor); - }); + setEditor(editor); return () => { - resetHeadings(); + setEditor(undefined); }; - }, [editor, resetHeadings, setHeadings]); + }, [setEditor, editor]); return ( diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx index 58cce28f6..935e193ac 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/DocEditor.tsx @@ -15,8 +15,6 @@ import { import { Versions, useDocVersion } from '@/features/docs/doc-versioning/'; import { useResponsiveStore } from '@/stores'; -import { useHeadingStore } from '../stores'; - import { BlockNoteEditor, BlockNoteEditorVersion } from './BlockNoteEditor'; import { IconOpenPanelEditor, PanelEditor } from './PanelEditor'; @@ -29,7 +27,6 @@ export const DocEditor = ({ doc }: DocEditorProps) => { query: { versionId }, } = useRouter(); const { t } = useTranslation(); - const { headings } = useHeadingStore(); const { isMobile } = useResponsiveStore(); const isVersion = versionId && typeof versionId === 'string'; @@ -79,9 +76,9 @@ export const DocEditor = ({ doc }: DocEditorProps) => { ) : ( )} - {!isMobile && } + {!isMobile && } - + ); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx index 5a79622d8..0f325f951 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/PanelEditor.tsx @@ -8,18 +8,13 @@ import { TableContent } from '@/features/docs/doc-table-content'; import { VersionList } from '@/features/docs/doc-versioning'; import { useResponsiveStore } from '@/stores'; -import { usePanelEditorStore } from '../stores'; -import { HeadingBlock } from '../types'; +import { useHeadingStore, usePanelEditorStore } from '../stores'; interface PanelProps { doc: Doc; - headings: HeadingBlock[]; } -export const PanelEditor = ({ - doc, - headings, -}: PropsWithChildren) => { +export const PanelEditor = ({ doc }: PropsWithChildren) => { const { t } = useTranslation(); const { colorsTokens } = useCunninghamTheme(); const { isMobile } = useResponsiveStore(); @@ -63,7 +58,7 @@ export const PanelEditor = ({ `} $maxHeight="99vh" > - {isMobile && } + {isMobile && } )} - {isPanelTableContentOpen && } + {isPanelTableContentOpen && } {!isPanelTableContentOpen && doc.abilities.versions_list && ( )} @@ -136,11 +131,8 @@ export const PanelEditor = ({ ); }; -interface IconOpenPanelEditorProps { - headings: HeadingBlock[]; -} - -export const IconOpenPanelEditor = ({ headings }: IconOpenPanelEditorProps) => { +export const IconOpenPanelEditor = () => { + const { headings } = useHeadingStore(); const { t } = useTranslation(); const { setIsPanelOpen, isPanelOpen, setIsPanelTableContentOpen } = usePanelEditorStore(); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useHeadings.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useHeadings.tsx new file mode 100644 index 000000000..9c6084873 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useHeadings.tsx @@ -0,0 +1,23 @@ +import { BlockNoteEditor } from '@blocknote/core'; +import { useEffect } from 'react'; + +import { useHeadingStore } from '../stores'; + +export const useHeadings = (editor: BlockNoteEditor) => { + const { setHeadings, resetHeadings } = useHeadingStore(); + + useEffect(() => { + setHeadings(editor); + + let timeout: NodeJS.Timeout; + editor?.onEditorContentChange(() => { + clearTimeout(timeout); + timeout = setTimeout(() => setHeadings(editor), 200); + }); + + return () => { + clearTimeout(timeout); + resetHeadings(); + }; + }, [editor, resetHeadings, setHeadings]); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx index f765eb799..559b268b0 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-table-content/components/TableContent.tsx @@ -2,16 +2,13 @@ import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Box, BoxButton, Text } from '@/components'; -import { HeadingBlock, useEditorStore } from '@/features/docs/doc-editor'; +import { useEditorStore, useHeadingStore } from '@/features/docs/doc-editor'; import { useResponsiveStore } from '@/stores'; import { Heading } from './Heading'; -interface TableContentProps { - headings: HeadingBlock[]; -} - -export const TableContent = ({ headings }: TableContentProps) => { +export const TableContent = () => { + const { headings } = useHeadingStore(); const { editor } = useEditorStore(); const { isMobile } = useResponsiveStore(); const { t } = useTranslation();