fix: Text relayout caused by external link decorations rendered async
This commit is contained in:
@@ -728,8 +728,11 @@ const EditorStyles = styled.div<{
|
||||
}
|
||||
|
||||
.external-link {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.code-actions,
|
||||
|
||||
@@ -13,12 +13,20 @@ import { EditorState, Plugin } from "prosemirror-state";
|
||||
import { Decoration, DecorationSet } from "prosemirror-view";
|
||||
import * as React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { isInternalUrl } from "../../utils/urls";
|
||||
import { isExternalUrl } from "../../utils/urls";
|
||||
import findLinkNodes from "../queries/findLinkNodes";
|
||||
import { EventType, Dispatch } from "../types";
|
||||
import Mark from "./Mark";
|
||||
|
||||
const LINK_INPUT_REGEX = /\[([^[]+)]\((\S+)\)$/;
|
||||
let icon: HTMLSpanElement;
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
const component = <OpenIcon color="currentColor" size={16} />;
|
||||
icon = document.createElement("span");
|
||||
icon.className = "external-link";
|
||||
ReactDOM.render(component, icon);
|
||||
}
|
||||
|
||||
function isPlainURL(
|
||||
link: ProsemirrorMark,
|
||||
@@ -116,20 +124,15 @@ export default class Link extends Mark {
|
||||
}
|
||||
|
||||
get plugins() {
|
||||
const component = <OpenIcon color="currentColor" size={16} />;
|
||||
const icon = document.createElement("span");
|
||||
icon.className = "external-link";
|
||||
ReactDOM.render(component, icon);
|
||||
|
||||
const getLinkDecorations = (doc: Node) => {
|
||||
const getLinkDecorations = (state: EditorState) => {
|
||||
const decorations: Decoration[] = [];
|
||||
const links = findLinkNodes(doc);
|
||||
const links = findLinkNodes(state.doc);
|
||||
|
||||
links.forEach((nodeWithPos) => {
|
||||
const linkMark = nodeWithPos.node.marks.find(
|
||||
(mark) => mark.type.name === "link"
|
||||
);
|
||||
if (linkMark && !isInternalUrl(linkMark.attrs.href)) {
|
||||
if (linkMark && isExternalUrl(linkMark.attrs.href)) {
|
||||
decorations.push(
|
||||
Decoration.widget(
|
||||
// place the decoration at the end of the link
|
||||
@@ -145,16 +148,16 @@ export default class Link extends Mark {
|
||||
}
|
||||
});
|
||||
|
||||
return DecorationSet.create(doc, decorations);
|
||||
return DecorationSet.create(state.doc, decorations);
|
||||
};
|
||||
|
||||
const plugin: Plugin = new Plugin({
|
||||
state: {
|
||||
init: (config, state) => {
|
||||
return getLinkDecorations(state.doc);
|
||||
return getLinkDecorations(state);
|
||||
},
|
||||
apply: (tr, oldState) => {
|
||||
return tr.docChanged ? getLinkDecorations(tr.doc) : oldState;
|
||||
apply: (tr, decorationSet, _oldState, newState) => {
|
||||
return tr.docChanged ? getLinkDecorations(newState) : decorationSet;
|
||||
},
|
||||
},
|
||||
props: {
|
||||
|
||||
@@ -28,3 +28,7 @@ export function isInternalUrl(href: string) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isExternalUrl(href: string) {
|
||||
return !isInternalUrl(href);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user