diff --git a/apps/client/src/widgets/sidebar/TableOfContents.tsx b/apps/client/src/widgets/sidebar/TableOfContents.tsx index 3d63ef0df..55178811c 100644 --- a/apps/client/src/widgets/sidebar/TableOfContents.tsx +++ b/apps/client/src/widgets/sidebar/TableOfContents.tsx @@ -9,16 +9,13 @@ import { useActiveNoteContext, useIsNoteReadOnly, useNoteProperty, useTextEditor import Icon from "../react/Icon"; import RightPanelWidget from "./RightPanelWidget"; +//#region Generic impl. interface RawHeading { id: string; level: number; text: string; } -interface CKHeading extends RawHeading { - element: ModelElement; -} - interface HeadingsWithNesting extends RawHeading { children: HeadingsWithNesting[]; } @@ -35,38 +32,6 @@ export default function TableOfContents() { ); } -function EditableTextTableOfContents() { - const { note, noteContext } = useActiveNoteContext(); - const textEditor = useTextEditor(noteContext); - const [ headings, setHeadings ] = useState([]); - - useEffect(() => { - if (!textEditor) return; - const headings = extractTocFromTextEditor(textEditor); - - // React to changes. - const changeCallback = () => { - const changes = textEditor.model.document.differ.getChanges(); - - const affectsHeadings = changes.some( change => { - return ( - change.type === 'insert' || change.type === 'remove' || (change.type === 'attribute' && change.attributeKey === 'headingLevel') - ); - }); - if (affectsHeadings) { - setHeadings(extractTocFromTextEditor(textEditor)); - } - }; - - textEditor.model.document.on("change:data", changeCallback); - setHeadings(headings); - - return () => textEditor.model.document.off("change:data", changeCallback); - }, [ textEditor, note ]); - - return ; -} - function AbstractTableOfContents({ headings }: { headings: RawHeading[]; }) { @@ -124,9 +89,47 @@ function buildHeadingTree(headings: RawHeading[]): HeadingsWithNesting[] { return root.children; } +//#endregion +//#region Editable text (CKEditor) const TOC_ID = 'tocId'; +interface CKHeading extends RawHeading { + element: ModelElement; +} + +function EditableTextTableOfContents() { + const { note, noteContext } = useActiveNoteContext(); + const textEditor = useTextEditor(noteContext); + const [ headings, setHeadings ] = useState([]); + + useEffect(() => { + if (!textEditor) return; + const headings = extractTocFromTextEditor(textEditor); + + // React to changes. + const changeCallback = () => { + const changes = textEditor.model.document.differ.getChanges(); + + const affectsHeadings = changes.some( change => { + return ( + change.type === 'insert' || change.type === 'remove' || (change.type === 'attribute' && change.attributeKey === 'headingLevel') + ); + }); + if (affectsHeadings) { + setHeadings(extractTocFromTextEditor(textEditor)); + } + }; + + textEditor.model.document.on("change:data", changeCallback); + setHeadings(headings); + + return () => textEditor.model.document.off("change:data", changeCallback); + }, [ textEditor, note ]); + + return ; +} + function extractTocFromTextEditor(editor: CKTextEditor) { const headings: CKHeading[] = []; @@ -155,4 +158,4 @@ function extractTocFromTextEditor(editor: CKTextEditor) { return headings; } - +//#endregion