fix: Alternative fix to #3583, addresses some bugs that were introduced

This commit is contained in:
Tom Moor
2022-06-03 11:03:44 +02:00
parent 1dfd1e0681
commit bf233b209b
4 changed files with 55 additions and 21 deletions

View File

@@ -2,9 +2,11 @@ import { formatDistanceToNow } from "date-fns";
import { deburr, sortBy } from "lodash";
import { TextSelection } from "prosemirror-state";
import * as React from "react";
import mergeRefs from "react-merge-refs";
import { Optional } from "utility-types";
import insertFiles from "@shared/editor/commands/insertFiles";
import embeds from "@shared/editor/embeds";
import { Heading } from "@shared/editor/lib/getHeadings";
import { supportedImageMimeTypes } from "@shared/utils/files";
import getDataTransferFiles from "@shared/utils/getDataTransferFiles";
import parseDocumentSlug from "@shared/utils/parseDocumentSlug";
@@ -45,12 +47,13 @@ export type Props = Optional<
shareId?: string | undefined;
embedsDisabled?: boolean;
grow?: boolean;
onHeadingsChange?: (headings: Heading[]) => void;
onSynced?: () => Promise<void>;
onPublish?: (event: React.MouseEvent) => any;
};
function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
const { id, shareId } = props;
const { id, shareId, onChange, onHeadingsChange } = props;
const { documents } = useStores();
const { showToast } = useToasts();
const dictionary = useDictionary();
@@ -58,6 +61,7 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
activeLinkEvent,
setActiveLinkEvent,
] = React.useState<MouseEvent | null>(null);
const previousHeadings = React.useRef<Heading[] | null>(null);
const handleLinkActive = React.useCallback((event: MouseEvent) => {
setActiveLinkEvent(event);
@@ -216,11 +220,43 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
[]
);
// Calculate if headings have changed and trigger callback if so
const updateHeadings = React.useCallback(() => {
if (onHeadingsChange) {
const headings = ref?.current?.getHeadings();
if (
headings &&
headings.map((h) => h.level + h.title).join("") !==
previousHeadings.current?.map((h) => h.level + h.title).join("")
) {
previousHeadings.current = headings;
onHeadingsChange(headings);
}
}
}, [ref, onHeadingsChange]);
const handleChange = React.useCallback(
(event) => {
onChange?.(event);
updateHeadings();
},
[onChange, updateHeadings]
);
const handleRefChanged = React.useCallback(
(node: SharedEditor | null) => {
if (node && !previousHeadings.current) {
updateHeadings();
}
},
[updateHeadings]
);
return (
<ErrorBoundary reloadOnChunkMissing>
<>
<LazyLoadedEditor
ref={ref}
ref={mergeRefs([ref, handleRefChanged])}
uploadFile={onUploadFile}
onShowToast={showToast}
embeds={embeds}
@@ -229,6 +265,7 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
onHoverLink={handleLinkActive}
onClickLink={onClickLink}
onSearchLink={handleSearchLink}
onChange={handleChange}
placeholder={props.placeholder || ""}
defaultValue={props.defaultValue || ""}
/>

View File

@@ -75,7 +75,7 @@ type Props = WithTranslation &
@observer
class DocumentScene extends React.Component<Props> {
@observable
editor: TEditor | null;
editor = React.createRef<TEditor>();
@observable
isUploading = false;
@@ -157,7 +157,7 @@ class DocumentScene extends React.Component<Props> {
}
replaceDocument = (template: Document | Revision) => {
const editorRef = this.editor;
const editorRef = this.editor.current;
if (!editorRef) {
return;
@@ -194,7 +194,7 @@ class DocumentScene extends React.Component<Props> {
const { toasts, history, location, t } = this.props;
const restore = location.state?.restore;
const revisionId = location.state?.revisionId;
const editorRef = this.editor;
const editorRef = this.editor.current;
if (!editorRef || !restore) {
return;
@@ -379,17 +379,8 @@ class DocumentScene extends React.Component<Props> {
const { document, auth } = this.props;
this.getEditorText = getEditorText;
// Keep headings in sync for table of contents
const headings = this.editor?.getHeadings() ?? [];
if (
headings.map((h) => h.level + h.title).join("") !==
this.headings.map((h) => h.level + h.title).join("")
) {
this.headings = headings;
}
// Keep derived task list in sync
const tasks = this.editor?.getTasks();
const tasks = this.editor.current?.getTasks();
const total = tasks?.length ?? 0;
const completed = tasks?.filter((t) => t.completed).length ?? 0;
document.updateTasks(total, completed);
@@ -414,6 +405,10 @@ class DocumentScene extends React.Component<Props> {
}
};
onHeadingsChange = (headings: Heading[]) => {
this.headings = headings;
};
onChangeTitle = action((value: string) => {
this.title = value;
this.props.document.title = value;
@@ -427,11 +422,6 @@ class DocumentScene extends React.Component<Props> {
}
};
handleRef = (ref: TEditor | null) => {
this.editor = ref;
this.headings = this.editor?.getHeadings() ?? [];
};
render() {
const {
document,
@@ -586,7 +576,7 @@ class DocumentScene extends React.Component<Props> {
<Editor
id={document.id}
key={embedsDisabled ? "disabled" : "enabled"}
ref={this.handleRef}
ref={this.editor}
multiplayer={collaborativeEditing}
shareId={shareId}
isDraft={document.isDraft}
@@ -603,6 +593,7 @@ class DocumentScene extends React.Component<Props> {
onCreateLink={this.props.onCreateLink}
onChangeTitle={this.onChangeTitle}
onChange={this.onChange}
onHeadingsChange={this.onHeadingsChange}
onSave={this.onSave}
onPublish={this.onPublish}
onCancel={this.goBack}

View File

@@ -165,6 +165,7 @@
"react-helmet": "^6.1.0",
"react-i18next": "^11.16.6",
"react-medium-image-zoom": "^3.1.3",
"react-merge-refs": "^1.1.0",
"react-portal": "^4.2.0",
"react-router-dom": "^5.2.0",
"react-table": "^7.7.0",

View File

@@ -12459,6 +12459,11 @@ react-medium-image-zoom@^3.1.3:
resolved "https://registry.yarnpkg.com/react-medium-image-zoom/-/react-medium-image-zoom-3.1.3.tgz#b1470abc5a342d65c23021c01bafa8c731821478"
integrity sha512-5CoU8whSCz5Xz2xNeGD34dDfZ6jaf/pybdfZh8HNUmA9mbXbLfj0n6bQWfEUwkq9lsNg1sEkyeIJq2tcvZY8bw==
react-merge-refs@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/react-merge-refs/-/react-merge-refs-1.1.0.tgz#73d88b892c6c68cbb7a66e0800faa374f4c38b06"
integrity sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==
react-portal@^4.2.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/react-portal/-/react-portal-4.2.1.tgz#12c1599238c06fb08a9800f3070bea2a3f78b1a6"