fix: Links with strikethrough do not have hover preview (#4841)

* fix: Links with strikethrough do not have hover preview

* refactor
This commit is contained in:
Tom Moor
2023-02-07 22:36:15 -05:00
committed by GitHub
parent bb1fe1a25f
commit 81f655f402
4 changed files with 39 additions and 43 deletions

View File

@@ -65,19 +65,18 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
const localRef = React.useRef<SharedEditor>();
const preferences = auth.user?.preferences;
const previousHeadings = React.useRef<Heading[] | null>(null);
const [
activeLinkEvent,
setActiveLinkEvent,
] = React.useState<MouseEvent | null>(null);
activeLinkElement,
setActiveLink,
] = React.useState<HTMLAnchorElement | null>(null);
const handleLinkActive = React.useCallback((event: MouseEvent) => {
setActiveLinkEvent(event);
const handleLinkActive = React.useCallback((element: HTMLAnchorElement) => {
setActiveLink(element);
return false;
}, []);
const handleLinkInactive = React.useCallback(() => {
setActiveLinkEvent(null);
setActiveLink(null);
}, []);
const handleSearchLink = React.useCallback(
@@ -309,10 +308,9 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
minHeight={props.bottomPadding}
/>
)}
{activeLinkEvent && !shareId && (
{activeLinkElement && !shareId && (
<HoverPreview
node={activeLinkEvent.target as HTMLAnchorElement}
event={activeLinkEvent}
element={activeLinkElement}
onClose={handleLinkInactive}
/>
)}

View File

@@ -14,14 +14,13 @@ const DELAY_OPEN = 300;
const DELAY_CLOSE = 300;
type Props = {
node: HTMLAnchorElement;
event: MouseEvent;
element: HTMLAnchorElement;
onClose: () => void;
};
function HoverPreviewInternal({ node, onClose }: Props) {
function HoverPreviewInternal({ element, onClose }: Props) {
const { documents } = useStores();
const slug = parseDocumentSlug(node.href);
const slug = parseDocumentSlug(element.href);
const [isVisible, setVisible] = React.useState(false);
const timerClose = React.useRef<ReturnType<typeof setTimeout>>();
const timerOpen = React.useRef<ReturnType<typeof setTimeout>>();
@@ -68,13 +67,13 @@ function HoverPreviewInternal({ node, onClose }: Props) {
cardRef.current.addEventListener("mouseleave", startCloseTimer);
}
node.addEventListener("mouseout", startCloseTimer);
node.addEventListener("mouseover", stopCloseTimer);
node.addEventListener("mouseover", startOpenTimer);
element.addEventListener("mouseout", startCloseTimer);
element.addEventListener("mouseover", stopCloseTimer);
element.addEventListener("mouseover", startOpenTimer);
return () => {
node.removeEventListener("mouseout", startCloseTimer);
node.removeEventListener("mouseover", stopCloseTimer);
node.removeEventListener("mouseover", startOpenTimer);
element.removeEventListener("mouseout", startCloseTimer);
element.removeEventListener("mouseover", stopCloseTimer);
element.removeEventListener("mouseover", startOpenTimer);
if (cardRef.current) {
cardRef.current.removeEventListener("mouseenter", stopCloseTimer);
@@ -88,9 +87,9 @@ function HoverPreviewInternal({ node, onClose }: Props) {
clearTimeout(timerClose.current);
}
};
}, [node, slug]);
}, [element, slug]);
const anchorBounds = node.getBoundingClientRect();
const anchorBounds = element.getBoundingClientRect();
const cardBounds = cardRef.current?.getBoundingClientRect();
const left = cardBounds
? Math.min(anchorBounds.left, window.innerWidth - 16 - 350)
@@ -105,7 +104,7 @@ function HoverPreviewInternal({ node, onClose }: Props) {
aria-hidden
>
<div ref={cardRef}>
<HoverPreviewDocument url={node.href}>
<HoverPreviewDocument url={element.href}>
{(content: React.ReactNode) =>
isVisible ? (
<Animate>
@@ -124,18 +123,18 @@ function HoverPreviewInternal({ node, onClose }: Props) {
);
}
function HoverPreview({ node, ...rest }: Props) {
function HoverPreview({ element, ...rest }: Props) {
const isMobile = useMobile();
if (isMobile) {
return null;
}
// previews only work for internal doc links for now
if (isExternalUrl(node.href)) {
if (isExternalUrl(element.href)) {
return null;
}
return <HoverPreviewInternal {...rest} node={node} />;
return <HoverPreviewInternal {...rest} element={element} />;
}
const Animate = styled.div`

View File

@@ -100,7 +100,7 @@ export type Props = {
event: MouseEvent | React.MouseEvent<HTMLButtonElement>
) => void;
/** Callback when user hovers on any link in the document */
onHoverLink?: (event: MouseEvent) => boolean;
onHoverLink?: (element: HTMLAnchorElement) => boolean;
/** Callback when user presses any key with document focused */
onKeyDown?: (event: React.KeyboardEvent<HTMLDivElement>) => void;
/** Collection of embed types to render in the document */

View File

@@ -10,7 +10,7 @@ import {
Mark as ProsemirrorMark,
} from "prosemirror-model";
import { EditorState, Plugin } from "prosemirror-state";
import { Decoration, DecorationSet } from "prosemirror-view";
import { Decoration, DecorationSet, EditorView } from "prosemirror-view";
import * as React from "react";
import ReactDOM from "react-dom";
import { isExternalUrl, sanitizeUrl } from "../../utils/urls";
@@ -210,29 +210,28 @@ export default class Link extends Mark {
},
},
props: {
decorations: (state) => plugin.getState(state),
decorations: (state: EditorState) => plugin.getState(state),
handleDOMEvents: {
mouseover: (view, event: MouseEvent) => {
mouseover: (view: EditorView, event: MouseEvent) => {
const target = (event.target as HTMLElement)?.closest("a");
if (
event.target instanceof HTMLAnchorElement &&
!event.target.className.includes("ProseMirror-widget") &&
target instanceof HTMLAnchorElement &&
!target.className.includes("ProseMirror-widget") &&
(!view.editable || (view.editable && !view.hasFocus()))
) {
if (this.options.onHoverLink) {
return this.options.onHoverLink(event);
return this.options.onHoverLink(target);
}
}
return false;
},
mousedown: (view, event: MouseEvent) => {
if (
!(event.target instanceof HTMLAnchorElement) ||
event.button !== 0
) {
mousedown: (view: EditorView, event: MouseEvent) => {
const target = (event.target as HTMLElement)?.closest("a");
if (!(target instanceof HTMLAnchorElement) || event.button !== 0) {
return false;
}
if (event.target.matches(".component-attachment *")) {
if (target.matches(".component-attachment *")) {
return false;
}
@@ -240,9 +239,9 @@ export default class Link extends Mark {
// clicking in read-only will navigate
if (!view.editable || (view.editable && !view.hasFocus())) {
const href =
event.target.href ||
(event.target.parentNode instanceof HTMLAnchorElement
? event.target.parentNode.href
target.href ||
(target.parentNode instanceof HTMLAnchorElement
? target.parentNode.href
: "");
try {
@@ -262,7 +261,7 @@ export default class Link extends Mark {
return false;
},
click: (view, event) => {
click: (view: EditorView, event: MouseEvent) => {
if (
!(event.target instanceof HTMLAnchorElement) ||
event.button !== 0