From 5ca3bdc51b8f662a3706896db8f6e22cf6393c5a Mon Sep 17 00:00:00 2001 From: sid597 Date: Sat, 6 Sep 2025 13:18:10 +0530 Subject: [PATCH] Fix on hover show popup --- .../utils/initializeObserversAndListeners.ts | 104 -------- apps/roam/src/utils/renderNodeTagPopup.tsx | 244 +++++------------- 2 files changed, 62 insertions(+), 286 deletions(-) diff --git a/apps/roam/src/utils/initializeObserversAndListeners.ts b/apps/roam/src/utils/initializeObserversAndListeners.ts index 0a678eb76..8a4f11bfd 100644 --- a/apps/roam/src/utils/initializeObserversAndListeners.ts +++ b/apps/roam/src/utils/initializeObserversAndListeners.ts @@ -140,109 +140,6 @@ export const initObservers = async ({ }, }); - const tableTagObserver = createHTMLObserver({ - tag: "TD", - className: "relative", - callback: (el: HTMLElement) => { - if (!(el instanceof HTMLTableCellElement)) return; - - const td = el; - if (!td.hasAttribute("data-cell-content")) return; - - const content = td.dataset.cellContent || ""; - if (!content.includes("#")) return; - - - - const existingTags = td.querySelectorAll(".rm-page-ref--tag"); - existingTags.forEach((tag) => { - const tagName = tag.getAttribute("data-tag"); - if ( - tagName && - discourseTagSet.has(tagName.toLowerCase()) && - tag instanceof HTMLSpanElement - ) { - tag.removeAttribute("data-attribute-button-rendered"); - renderNodeTagPopupButton( - tag, - discourseNodes, - onloadArgs.extensionAPI, - ); - } - }); - - const innerContainers = [ - td.querySelector("a.rm-page-ref > span"), - td.querySelector("div.rm-block__input > span"), - td.querySelector("div.rm-block__input"), - td.querySelector("div.roamjs-query-embed span"), - ].filter(Boolean); - - innerContainers.forEach((innerSpan) => { - if (!innerSpan) return; - - const formattedTagsInside = - innerSpan.querySelectorAll(".rm-page-ref--tag"); - if (formattedTagsInside.length > 0) return; - - const textContent = innerSpan.textContent || ""; - const unformattedDiscourseTagsFound = []; - - discourseNodes.forEach((node) => { - const tag = node.tag; - if (!tag) return; - - const pattern = new RegExp(`#${tag}(?![\\w-])`, "i"); - if (pattern.test(textContent)) { - const alreadyFormatted = innerSpan.querySelector( - `.rm-page-ref--tag[data-tag="${tag}"]`, - ); - if (!alreadyFormatted) { - unformattedDiscourseTagsFound.push(tag); - } - } - }); - - if (unformattedDiscourseTagsFound.length === 0) return; - - const originalHtml = innerSpan.innerHTML; - const newHtml = originalHtml.replace(/#([\w-]+)/g, (match, tagName) => { - if ( - innerSpan.querySelector(`.rm-page-ref--tag[data-tag="${tagName}"]`) - ) { - return match; - } - - if (discourseTagSet.has(tagName.toLowerCase())) { - return `${match}`; - } - - return match; - }); - - if (originalHtml !== newHtml) { - innerSpan.innerHTML = newHtml; - - setTimeout(() => { - const newTags = innerSpan.querySelectorAll( - '.rm-page-ref--tag:not([data-attribute-button-rendered="true"])', - ); - - newTags.forEach((tag) => { - if (tag instanceof HTMLSpanElement) { - renderNodeTagPopupButton( - tag, - discourseNodes, - onloadArgs.extensionAPI, - ); - } - }); - }, 50); - } - }); - }, - }); - const pageActionListener = (( e: CustomEvent<{ action: string; @@ -455,7 +352,6 @@ export const initObservers = async ({ linkedReferencesObserver, graphOverviewExportObserver, nodeTagPopupButtonObserver, - tableTagObserver, ].filter((o): o is MutationObserver => !!o), listeners: { pageActionListener, diff --git a/apps/roam/src/utils/renderNodeTagPopup.tsx b/apps/roam/src/utils/renderNodeTagPopup.tsx index 477b501f8..cf268b62d 100644 --- a/apps/roam/src/utils/renderNodeTagPopup.tsx +++ b/apps/roam/src/utils/renderNodeTagPopup.tsx @@ -1,4 +1,4 @@ -import React, { useRef, useState, useEffect } from "react"; +import React from "react"; import ReactDOM from "react-dom"; import { Button, Popover, Position } from "@blueprintjs/core"; import { renderCreateNodeDialog } from "~/components/CreateNodeDialog"; @@ -7,109 +7,6 @@ import getUids from "roamjs-components/dom/getUids"; import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid"; import { DiscourseNode } from "./getDiscourseNodes"; -const TableEmbedPopup: React.FC<{ - parent: HTMLElement; - matchedNode: any; - extensionAPI: OnloadArgs["extensionAPI"]; - blockUid?: string; - cleanedBlockText: string; -}> = ({ parent, matchedNode, extensionAPI, blockUid, cleanedBlockText }) => { - const [showPopup, setShowPopup] = useState(false); - const [popupPosition, setPopupPosition] = useState({ x: 0, y: 0 }); - const timeoutRef = useRef(); - const popupRef = useRef(null); - - const handleMouseEnter = () => { - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - } - - const rect = parent.getBoundingClientRect(); - setPopupPosition({ - x: rect.left + rect.width / 2, - y: rect.top - 8, - }); - setShowPopup(true); - }; - - const handleMouseLeave = (e: MouseEvent) => { - const relatedTarget = e.relatedTarget as HTMLElement; - if (relatedTarget && popupRef.current?.contains(relatedTarget)) { - return; - } - - timeoutRef.current = setTimeout(() => { - setShowPopup(false); - }, 150); - }; - - const handlePopupMouseEnter = () => { - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - } - }; - - const handlePopupMouseLeave = () => { - timeoutRef.current = setTimeout(() => { - setShowPopup(false); - }, 100); - }; - - useEffect(() => { - parent.addEventListener("mouseenter", handleMouseEnter); - parent.addEventListener("mouseleave", handleMouseLeave); - parent.style.cursor = "pointer"; - - return () => { - parent.removeEventListener("mouseenter", handleMouseEnter); - parent.removeEventListener("mouseleave", handleMouseLeave); - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - } - }; - }, []); - - if (!showPopup) return null; - - return ReactDOM.createPortal( -
-
, - document.body, - ); -}; - export const renderNodeTagPopupButton = ( parent: HTMLSpanElement, discourseNodes: DiscourseNode[], @@ -118,8 +15,6 @@ export const renderNodeTagPopupButton = ( if (parent.dataset.attributeButtonRendered === "true") return; parent.dataset.attributeButtonRendered = "true"; - const isInTable = !!parent.closest("td.relative"); - const isInEmbed = !!parent.closest(".roamjs-query-embed"); const textContent = parent.textContent?.trim() || ""; const tagAttr = parent.getAttribute("data-tag") || textContent; @@ -136,80 +31,65 @@ export const renderNodeTagPopupButton = ( const rawBlockText = blockUid ? getTextByBlockUid(blockUid) : ""; const cleanedBlockText = rawBlockText.replace(textContent, "").trim(); - if (isInTable && isInEmbed) { - const reactContainer = document.createElement("div"); - reactContainer.style.display = "none"; - parent.appendChild(reactContainer); - - ReactDOM.render( - , - reactContainer, - ); - } else { - const wrapper = document.createElement("span"); - wrapper.style.position = "relative"; - wrapper.style.display = "inline-block"; - parent.parentNode?.insertBefore(wrapper, parent); - wrapper.appendChild(parent); - - const reactRoot = document.createElement("span"); - reactRoot.style.position = "absolute"; - reactRoot.style.top = "0"; - reactRoot.style.left = "0"; - reactRoot.style.width = "100%"; - reactRoot.style.height = "100%"; - reactRoot.style.pointerEvents = "none"; - reactRoot.style.zIndex = "10"; - wrapper.appendChild(reactRoot); - - ReactDOM.render( - { - renderCreateNodeDialog({ - onClose: () => {}, - defaultNodeTypeUid: matchedNode.type, - extensionAPI, - sourceBlockUid: blockUid, - initialTitle: cleanedBlockText, - }); - }} - text={`Create ${matchedNode.text}`} - /> - } - target={ - - } - interactionKind="hover" - usePortal={true} - portalClassName="dg-popover" - position={Position.TOP} - modifiers={{ - offset: { - offset: "0, 10", - }, - arrow: { - enabled: false, - }, - }} - />, - reactRoot, - ); - } + const wrapper = document.createElement("span"); + wrapper.style.position = "relative"; + wrapper.style.display = "inline-block"; + parent.parentNode?.insertBefore(wrapper, parent); + wrapper.appendChild(parent); + + const reactRoot = document.createElement("span"); + reactRoot.style.position = "absolute"; + reactRoot.style.top = "0"; + reactRoot.style.left = "0"; + reactRoot.style.width = "100%"; + reactRoot.style.height = "100%"; + reactRoot.style.pointerEvents = "none"; + reactRoot.style.zIndex = "10"; + wrapper.appendChild(reactRoot); + + const rect = parent.getBoundingClientRect(); + + ReactDOM.render( + { + renderCreateNodeDialog({ + onClose: () => {}, + defaultNodeTypeUid: matchedNode.type, + extensionAPI, + sourceBlockUid: blockUid, + initialTitle: cleanedBlockText, + }); + }} + text={`Create ${matchedNode.text}`} + /> + } + target={ + + } + interactionKind="hover" + usePortal={true} + portalClassName="dg-popover" + position={Position.TOP} + modifiers={{ + offset: { + offset: "0, 10", + }, + arrow: { + enabled: false, + }, + }} + />, + reactRoot, + ); };