From 014d57e942273b12a8ceb4bda49bf1ad7a6a0569 Mon Sep 17 00:00:00 2001 From: sid597 Date: Mon, 25 May 2026 12:08:11 +0530 Subject: [PATCH 1/8] ENG-1373: Drag pages onto the canvas to create node shapes Page refs aren't draggable by default, so make them draggable via the existing rm-page-ref observer and route the drag payload through the canvas text-content handler that already turns [[name]] into a discourse-node shape. - Always-on: only the draggable attribute is global; the drag payload and drop handling live in the canvas component, so drags are inert unless a canvas is open. - Custom MIME (application/x-roam-page), not text/plain, so a drag can't leak [[title]] into other blocks or apps. - Guard the existing block-dragstart so dragging a ref doesn't also attach its containing block's UID. --- apps/roam/src/components/canvas/Tldraw.tsx | 29 ++++++++++++++++++- .../utils/initializeObserversAndListeners.ts | 3 ++ .../roam/src/utils/pageRefObserverHandlers.ts | 4 +++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/apps/roam/src/components/canvas/Tldraw.tsx b/apps/roam/src/components/canvas/Tldraw.tsx index eb102d5f1..265ff38be 100644 --- a/apps/roam/src/components/canvas/Tldraw.tsx +++ b/apps/roam/src/components/canvas/Tldraw.tsx @@ -643,8 +643,19 @@ const TldrawCanvasShared = ({ useEffect(() => { const handleDragStart = (e: DragEvent) => { const target = e.target as HTMLElement; - const uid = getBlockUidFromBullet(target); + const pageRef = target.closest(".rm-page-ref"); + if (pageRef) { + const pageTitle = ( + pageRef.getAttribute("data-tag") || + pageRef.parentElement?.getAttribute("data-link-title") + )?.replace(/\\"/g, '"'); + if (pageTitle) + e.dataTransfer?.setData("application/x-roam-page", pageTitle); + return; + } + + const uid = getBlockUidFromBullet(target); if (uid) e.dataTransfer?.setData("application/x-roam-uid", uid); }; @@ -658,6 +669,22 @@ const TldrawCanvasShared = ({ const handleDrop = (e: React.DragEvent) => { e.preventDefault(); + + const pageTitle = e.dataTransfer.getData("application/x-roam-page"); + if (pageTitle && appRef.current && extensionAPI) { + posthog.capture("Canvas: Roam Page Dropped"); + const dropPoint = appRef.current.screenToPage({ + x: e.clientX, + y: e.clientY, + }); + void appRef.current.putExternalContent({ + type: "text", + text: `[[${pageTitle}]]`, + point: dropPoint, + }); + return; + } + const uid = e.dataTransfer.getData("application/x-roam-uid"); if (!uid || !appRef.current || !extensionAPI) return; diff --git a/apps/roam/src/utils/initializeObserversAndListeners.ts b/apps/roam/src/utils/initializeObserversAndListeners.ts index 227dcd34a..f5ae8b368 100644 --- a/apps/roam/src/utils/initializeObserversAndListeners.ts +++ b/apps/roam/src/utils/initializeObserversAndListeners.ts @@ -21,6 +21,7 @@ import { addPageRefObserver, getPageRefObserversSize, previewPageRefHandler, + makePageRefDraggable, getOverlayHandler, onPageRefObserverChange, getSuggestiveOverlayHandler, @@ -242,6 +243,8 @@ export const initObservers = ({ onPageRefObserverChange(overlayHandler)(true); } + onPageRefObserverChange(makePageRefDraggable)(true); + if (getPageRefObserversSize()) enablePageRefObserver(); const configPageUid = getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE); diff --git a/apps/roam/src/utils/pageRefObserverHandlers.ts b/apps/roam/src/utils/pageRefObserverHandlers.ts index cac2d362b..b9342c893 100644 --- a/apps/roam/src/utils/pageRefObserverHandlers.ts +++ b/apps/roam/src/utils/pageRefObserverHandlers.ts @@ -181,6 +181,10 @@ export const previewPageRefHandler = (s: HTMLSpanElement) => { } }; +export const makePageRefDraggable = (s: HTMLSpanElement) => { + s.draggable = true; +}; + export const enablePageRefObserver = () => { if (pageRefObserverRef.current) return pageRefObserverRef.current; From c6e8e9177918a9bea2dd860d2d9a1187ec36f99a Mon Sep 17 00:00:00 2001 From: sid597 Date: Mon, 25 May 2026 15:08:59 +0530 Subject: [PATCH 2/8] ENG-1373: Unregister page-ref draggable handler on unload The always-on registration had no matching teardown, so the singleton rm-page-ref observer and the makePageRefDraggable callback survived extension unload/reload. Add a cleanup that unregisters the handler; for users without the overlay/preview/suggestive handlers this empties the set and disconnects the observer. --- apps/roam/src/utils/initializeObserversAndListeners.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/roam/src/utils/initializeObserversAndListeners.ts b/apps/roam/src/utils/initializeObserversAndListeners.ts index f5ae8b368..8663f983d 100644 --- a/apps/roam/src/utils/initializeObserversAndListeners.ts +++ b/apps/roam/src/utils/initializeObserversAndListeners.ts @@ -469,6 +469,11 @@ export const initObservers = ({ discourseNodeSearchTriggerListener, nodeCreationPopoverListener, }, - cleanups: [unsubGlobalTrigger, unsubPersonalTrigger, unsubSearchTrigger], + cleanups: [ + unsubGlobalTrigger, + unsubPersonalTrigger, + unsubSearchTrigger, + () => onPageRefObserverChange(makePageRefDraggable)(false), + ], }; }; From 247a42dd7f87cece18c4368cdce77c1649af49a9 Mon Sep 17 00:00:00 2001 From: sid597 Date: Thu, 28 May 2026 12:27:16 +0530 Subject: [PATCH 3/8] ENG-1373: Drag query-result page links and resolve block refs to nodes The first commit only captured spans whose data-link-title lives on the parent element. Query-builder result rows and the discourse-context overlay render page links as with the title on the element itself, which the existing parent-only read missed. Also resolve a dragged block whose text is exactly [[X]] to that discourse node's shape (instead of a gray blck-node) when X is a discourse node. The page-ref branch already does this, so factor out tryCreatePageNodeShape and reuse it from the block-ref path; the heavy page-uid + discourse-node lookup is gated behind a cheap PAGE_REF_REGEX match on the block text. - Read data-link-title on the page-ref element itself, falling back to the parent for span page-refs. - Extract tryCreatePageNodeShape; the boolean return lets callers decide the fallback (default text handler vs. blck-node). - Hoist PAGE_REF_REGEX to module scope next to BLOCK_REF_REGEX usage. --- apps/roam/src/components/canvas/Tldraw.tsx | 47 +++++++++++++++------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/apps/roam/src/components/canvas/Tldraw.tsx b/apps/roam/src/components/canvas/Tldraw.tsx index 265ff38be..b23eaa809 100644 --- a/apps/roam/src/components/canvas/Tldraw.tsx +++ b/apps/roam/src/components/canvas/Tldraw.tsx @@ -174,6 +174,8 @@ export const MAX_WIDTH = "400px"; const ICON_URL = `data:image/svg+xml;utf8,${encodeURIComponent(WHITE_LOGO_SVG)}`; +const PAGE_REF_REGEX = /^\[\[(.+?)\]\]$/; + /** Valid file size for asset props; undefined when unknown (e.g. Roam/file API not a real File) to avoid persisting null. */ const getValidFileSize = (file: { size?: number }): number | undefined => typeof file.size === "number" && Number.isFinite(file.size) && file.size > 0 @@ -648,6 +650,7 @@ const TldrawCanvasShared = ({ if (pageRef) { const pageTitle = ( pageRef.getAttribute("data-tag") || + pageRef.getAttribute("data-link-title") || pageRef.parentElement?.getAttribute("data-link-title") )?.replace(/\\"/g, '"'); if (pageTitle) @@ -1294,30 +1297,36 @@ const InsideEditorAndUiContext = ({ try { const text = content.text ?? ""; - // Check for page reference: [[pageName]] - const pageMatch = text.match(/^\[\[(.+?)\]\]$/); - if (pageMatch?.[1]) { - const pageName = pageMatch[1]; - const pageUid = getPageUidByPageTitle(pageName); - if (!pageUid) return await callDefaultTextHandler(content); - + const tryCreatePageNodeShape = async ( + title: string, + ): Promise => { + const pageUid = getPageUidByPageTitle(title); + if (!pageUid) return false; const nodeType = findDiscourseNode({ uid: pageUid, - title: pageName, + title, nodes: allNodes, }); - if (!nodeType) return await callDefaultTextHandler(content); - + if (!nodeType) return false; await createDiscourseNodeShape({ uid: pageUid, - nodeText: pageName, + nodeText: title, nodeType: nodeType.type, content, }); - posthog.capture("Canvas: Node Added from External Content", { - source: "page-reference", - }); - return; + return true; + }; + + // Check for page reference: [[pageName]] + const pageMatch = text.match(PAGE_REF_REGEX); + if (pageMatch?.[1]) { + if (await tryCreatePageNodeShape(pageMatch[1])) { + posthog.capture("Canvas: Node Added from External Content", { + source: "page-reference", + }); + return; + } + return await callDefaultTextHandler(content); } // Check for block reference: ((uid)) @@ -1330,6 +1339,14 @@ const InsideEditorAndUiContext = ({ if (!blockText || !isLive) return await callDefaultTextHandler(content); + const refMatch = blockText.match(PAGE_REF_REGEX); + if (refMatch?.[1] && (await tryCreatePageNodeShape(refMatch[1]))) { + posthog.capture("Canvas: Node Added from External Content", { + source: "block-page-reference", + }); + return; + } + await createDiscourseNodeShape({ uid, nodeText: blockText, From cbee62a78c6b6c149c46308bed52d46668e85c12 Mon Sep 17 00:00:00 2001 From: sid597 Date: Thu, 28 May 2026 13:30:45 +0530 Subject: [PATCH 4/8] Scope page ref canvas dragging --- apps/roam/src/components/canvas/Tldraw.tsx | 40 ++++++++++++++++++- .../utils/initializeObserversAndListeners.ts | 4 -- .../roam/src/utils/pageRefObserverHandlers.ts | 4 -- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/apps/roam/src/components/canvas/Tldraw.tsx b/apps/roam/src/components/canvas/Tldraw.tsx index b23eaa809..3636aea72 100644 --- a/apps/roam/src/components/canvas/Tldraw.tsx +++ b/apps/roam/src/components/canvas/Tldraw.tsx @@ -643,11 +643,38 @@ const TldrawCanvasShared = ({ // Handle Roam block drag and drop useEffect(() => { + const temporaryDraggableAttribute = + "data-roamjs-canvas-page-ref-draggable"; + let activePageRef: HTMLElement | null = null; + const isPageRefDragSource = (pageRef: HTMLElement): boolean => + !!pageRef.closest( + ".roamjs-query-results-view, .roamjs-discourse-result-panel, .roamjs-discourse-context-overlay-container, .rm-query, .rm-query-content", + ); + const clearActivePageRef = () => { + if (activePageRef?.hasAttribute(temporaryDraggableAttribute)) { + activePageRef.draggable = false; + activePageRef.removeAttribute(temporaryDraggableAttribute); + } + activePageRef = null; + }; + const handlePointerDown = (e: PointerEvent) => { + if (e.defaultPrevented || e.button !== 0) return; + const target = e.target as HTMLElement; + const pageRef = target.closest(".rm-page-ref"); + if (!pageRef || pageRef.draggable || !isPageRefDragSource(pageRef)) + return; + + activePageRef = pageRef; + pageRef.draggable = true; + pageRef.setAttribute(temporaryDraggableAttribute, "true"); + }; const handleDragStart = (e: DragEvent) => { const target = e.target as HTMLElement; const pageRef = target.closest(".rm-page-ref"); if (pageRef) { + if (!isPageRefDragSource(pageRef)) return; + const pageTitle = ( pageRef.getAttribute("data-tag") || pageRef.getAttribute("data-link-title") || @@ -662,8 +689,19 @@ const TldrawCanvasShared = ({ if (uid) e.dataTransfer?.setData("application/x-roam-uid", uid); }; + document.addEventListener("pointerdown", handlePointerDown); + document.addEventListener("pointerup", clearActivePageRef); + document.addEventListener("pointercancel", clearActivePageRef); document.addEventListener("dragstart", handleDragStart); - return () => document.removeEventListener("dragstart", handleDragStart); + document.addEventListener("dragend", clearActivePageRef); + return () => { + clearActivePageRef(); + document.removeEventListener("pointerdown", handlePointerDown); + document.removeEventListener("pointerup", clearActivePageRef); + document.removeEventListener("pointercancel", clearActivePageRef); + document.removeEventListener("dragstart", handleDragStart); + document.removeEventListener("dragend", clearActivePageRef); + }; }, []); const handleDragOver = (e: React.DragEvent) => { diff --git a/apps/roam/src/utils/initializeObserversAndListeners.ts b/apps/roam/src/utils/initializeObserversAndListeners.ts index 8663f983d..5e440023e 100644 --- a/apps/roam/src/utils/initializeObserversAndListeners.ts +++ b/apps/roam/src/utils/initializeObserversAndListeners.ts @@ -21,7 +21,6 @@ import { addPageRefObserver, getPageRefObserversSize, previewPageRefHandler, - makePageRefDraggable, getOverlayHandler, onPageRefObserverChange, getSuggestiveOverlayHandler, @@ -243,8 +242,6 @@ export const initObservers = ({ onPageRefObserverChange(overlayHandler)(true); } - onPageRefObserverChange(makePageRefDraggable)(true); - if (getPageRefObserversSize()) enablePageRefObserver(); const configPageUid = getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE); @@ -473,7 +470,6 @@ export const initObservers = ({ unsubGlobalTrigger, unsubPersonalTrigger, unsubSearchTrigger, - () => onPageRefObserverChange(makePageRefDraggable)(false), ], }; }; diff --git a/apps/roam/src/utils/pageRefObserverHandlers.ts b/apps/roam/src/utils/pageRefObserverHandlers.ts index b9342c893..cac2d362b 100644 --- a/apps/roam/src/utils/pageRefObserverHandlers.ts +++ b/apps/roam/src/utils/pageRefObserverHandlers.ts @@ -181,10 +181,6 @@ export const previewPageRefHandler = (s: HTMLSpanElement) => { } }; -export const makePageRefDraggable = (s: HTMLSpanElement) => { - s.draggable = true; -}; - export const enablePageRefObserver = () => { if (pageRefObserverRef.current) return pageRefObserverRef.current; From 4cef9697684a354258312d367bb1f1adefd5b076 Mon Sep 17 00:00:00 2001 From: sid597 Date: Thu, 28 May 2026 15:29:48 +0530 Subject: [PATCH 5/8] Format canvas drag changes --- apps/roam/src/components/canvas/Tldraw.tsx | 3 +-- apps/roam/src/utils/initializeObserversAndListeners.ts | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/roam/src/components/canvas/Tldraw.tsx b/apps/roam/src/components/canvas/Tldraw.tsx index 3636aea72..0298f1628 100644 --- a/apps/roam/src/components/canvas/Tldraw.tsx +++ b/apps/roam/src/components/canvas/Tldraw.tsx @@ -643,8 +643,7 @@ const TldrawCanvasShared = ({ // Handle Roam block drag and drop useEffect(() => { - const temporaryDraggableAttribute = - "data-roamjs-canvas-page-ref-draggable"; + const temporaryDraggableAttribute = "data-roamjs-canvas-page-ref-draggable"; let activePageRef: HTMLElement | null = null; const isPageRefDragSource = (pageRef: HTMLElement): boolean => !!pageRef.closest( diff --git a/apps/roam/src/utils/initializeObserversAndListeners.ts b/apps/roam/src/utils/initializeObserversAndListeners.ts index 5e440023e..227dcd34a 100644 --- a/apps/roam/src/utils/initializeObserversAndListeners.ts +++ b/apps/roam/src/utils/initializeObserversAndListeners.ts @@ -466,10 +466,6 @@ export const initObservers = ({ discourseNodeSearchTriggerListener, nodeCreationPopoverListener, }, - cleanups: [ - unsubGlobalTrigger, - unsubPersonalTrigger, - unsubSearchTrigger, - ], + cleanups: [unsubGlobalTrigger, unsubPersonalTrigger, unsubSearchTrigger], }; }; From 459fba17395838ef06c379c4bb482f8925dc5b8c Mon Sep 17 00:00:00 2001 From: Siddharth Date: Fri, 29 May 2026 00:06:10 +0530 Subject: [PATCH 6/8] Fix canvas block drag fallback --- apps/roam/src/components/canvas/Tldraw.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/roam/src/components/canvas/Tldraw.tsx b/apps/roam/src/components/canvas/Tldraw.tsx index 0298f1628..2fa8b799d 100644 --- a/apps/roam/src/components/canvas/Tldraw.tsx +++ b/apps/roam/src/components/canvas/Tldraw.tsx @@ -671,17 +671,16 @@ const TldrawCanvasShared = ({ const target = e.target as HTMLElement; const pageRef = target.closest(".rm-page-ref"); - if (pageRef) { - if (!isPageRefDragSource(pageRef)) return; - + if (pageRef && isPageRefDragSource(pageRef)) { const pageTitle = ( pageRef.getAttribute("data-tag") || pageRef.getAttribute("data-link-title") || pageRef.parentElement?.getAttribute("data-link-title") )?.replace(/\\"/g, '"'); - if (pageTitle) + if (pageTitle) { e.dataTransfer?.setData("application/x-roam-page", pageTitle); - return; + return; + } } const uid = getBlockUidFromBullet(target); From 472b58818421553cbc61e4773b783533e5adbf76 Mon Sep 17 00:00:00 2001 From: sid597 Date: Tue, 16 Jun 2026 22:46:40 +0530 Subject: [PATCH 7/8] Enable page reference drags to canvas --- apps/roam/src/components/canvas/Tldraw.tsx | 156 +++++++++++------- .../src/components/results-view/Kanban.tsx | 2 + 2 files changed, 100 insertions(+), 58 deletions(-) diff --git a/apps/roam/src/components/canvas/Tldraw.tsx b/apps/roam/src/components/canvas/Tldraw.tsx index 2fa8b799d..f9b991254 100644 --- a/apps/roam/src/components/canvas/Tldraw.tsx +++ b/apps/roam/src/components/canvas/Tldraw.tsx @@ -174,8 +174,99 @@ export const MAX_WIDTH = "400px"; const ICON_URL = `data:image/svg+xml;utf8,${encodeURIComponent(WHITE_LOGO_SVG)}`; +const ROAM_PAGE_DROP_MIME_TYPE = "application/x-roam-page"; +const ROAM_BLOCK_DROP_MIME_TYPE = "application/x-roam-uid"; +const TEMP_DRAG_ATTR = "data-roamjs-canvas-page-ref-draggable"; const PAGE_REF_REGEX = /^\[\[(.+?)\]\]$/; +const getClosestPageRef = (target: EventTarget | null): HTMLElement | null => + target instanceof HTMLElement + ? target.closest(".rm-page-ref") + : null; + +const getPageTitleFromPageRef = (pageRef: HTMLElement): string | undefined => { + const pageTitle = + pageRef.getAttribute("data-tag") || + pageRef.getAttribute("data-link-title") || + pageRef + .closest("[data-link-title]") + ?.getAttribute("data-link-title"); + + return pageTitle?.replace(/\\"/g, '"') || undefined; +}; + +let pageRefDragSourceSubscriptionCount = 0; +let cleanupRoamPageRefDragSources: (() => void) | undefined; + +const createRoamPageRefDragSourceCleanup = (): (() => void) => { + let activePageRef: HTMLElement | null = null; + + const clearActivePageRef = (): void => { + if (activePageRef?.hasAttribute(TEMP_DRAG_ATTR)) { + activePageRef.draggable = false; + activePageRef.removeAttribute(TEMP_DRAG_ATTR); + } + activePageRef = null; + }; + + const handlePointerDown = (e: MouseEvent | PointerEvent): void => { + if (e.defaultPrevented || e.button !== 0) return; + const pageRef = getClosestPageRef(e.target); + if (!pageRef || pageRef.draggable || !getPageTitleFromPageRef(pageRef)) { + return; + } + + clearActivePageRef(); + activePageRef = pageRef; + pageRef.draggable = true; + pageRef.setAttribute(TEMP_DRAG_ATTR, "true"); + }; + + const handleDragStart = (e: DragEvent): void => { + const pageRef = getClosestPageRef(e.target); + const pageTitle = pageRef ? getPageTitleFromPageRef(pageRef) : undefined; + if (pageTitle) { + e.dataTransfer?.setData(ROAM_PAGE_DROP_MIME_TYPE, pageTitle); + } + }; + + document.addEventListener("pointerdown", handlePointerDown, true); + document.addEventListener("mousedown", handlePointerDown, true); + document.addEventListener("pointerup", clearActivePageRef, true); + document.addEventListener("mouseup", clearActivePageRef, true); + document.addEventListener("pointercancel", clearActivePageRef, true); + document.addEventListener("dragstart", handleDragStart, true); + document.addEventListener("dragend", clearActivePageRef, true); + + return () => { + clearActivePageRef(); + document.removeEventListener("pointerdown", handlePointerDown, true); + document.removeEventListener("mousedown", handlePointerDown, true); + document.removeEventListener("pointerup", clearActivePageRef, true); + document.removeEventListener("mouseup", clearActivePageRef, true); + document.removeEventListener("pointercancel", clearActivePageRef, true); + document.removeEventListener("dragstart", handleDragStart, true); + document.removeEventListener("dragend", clearActivePageRef, true); + }; +}; + +const enableRoamPageRefDragSources = (): (() => void) => { + pageRefDragSourceSubscriptionCount += 1; + cleanupRoamPageRefDragSources ||= createRoamPageRefDragSourceCleanup(); + + let subscribed = true; + return () => { + if (!subscribed) return; + subscribed = false; + pageRefDragSourceSubscriptionCount -= 1; + + if (pageRefDragSourceSubscriptionCount === 0) { + cleanupRoamPageRefDragSources?.(); + cleanupRoamPageRefDragSources = undefined; + } + }; +}; + /** Valid file size for asset props; undefined when unknown (e.g. Roam/file API not a real File) to avoid persisting null. */ const getValidFileSize = (file: { size?: number }): number | undefined => typeof file.size === "number" && Number.isFinite(file.size) && file.size > 0 @@ -641,64 +732,21 @@ const TldrawCanvasShared = ({ return getUids(blockInput as HTMLDivElement).blockUid; }; - // Handle Roam block drag and drop + // Handle Roam page reference and block drag sources useEffect(() => { - const temporaryDraggableAttribute = "data-roamjs-canvas-page-ref-draggable"; - let activePageRef: HTMLElement | null = null; - const isPageRefDragSource = (pageRef: HTMLElement): boolean => - !!pageRef.closest( - ".roamjs-query-results-view, .roamjs-discourse-result-panel, .roamjs-discourse-context-overlay-container, .rm-query, .rm-query-content", - ); - const clearActivePageRef = () => { - if (activePageRef?.hasAttribute(temporaryDraggableAttribute)) { - activePageRef.draggable = false; - activePageRef.removeAttribute(temporaryDraggableAttribute); - } - activePageRef = null; - }; - const handlePointerDown = (e: PointerEvent) => { - if (e.defaultPrevented || e.button !== 0) return; - const target = e.target as HTMLElement; - const pageRef = target.closest(".rm-page-ref"); - if (!pageRef || pageRef.draggable || !isPageRefDragSource(pageRef)) - return; - - activePageRef = pageRef; - pageRef.draggable = true; - pageRef.setAttribute(temporaryDraggableAttribute, "true"); - }; + const disablePageRefDragSources = enableRoamPageRefDragSources(); const handleDragStart = (e: DragEvent) => { const target = e.target as HTMLElement; - - const pageRef = target.closest(".rm-page-ref"); - if (pageRef && isPageRefDragSource(pageRef)) { - const pageTitle = ( - pageRef.getAttribute("data-tag") || - pageRef.getAttribute("data-link-title") || - pageRef.parentElement?.getAttribute("data-link-title") - )?.replace(/\\"/g, '"'); - if (pageTitle) { - e.dataTransfer?.setData("application/x-roam-page", pageTitle); - return; - } - } + if (getClosestPageRef(target)) return; const uid = getBlockUidFromBullet(target); - if (uid) e.dataTransfer?.setData("application/x-roam-uid", uid); + if (uid) e.dataTransfer?.setData(ROAM_BLOCK_DROP_MIME_TYPE, uid); }; - document.addEventListener("pointerdown", handlePointerDown); - document.addEventListener("pointerup", clearActivePageRef); - document.addEventListener("pointercancel", clearActivePageRef); document.addEventListener("dragstart", handleDragStart); - document.addEventListener("dragend", clearActivePageRef); return () => { - clearActivePageRef(); - document.removeEventListener("pointerdown", handlePointerDown); - document.removeEventListener("pointerup", clearActivePageRef); - document.removeEventListener("pointercancel", clearActivePageRef); + disablePageRefDragSources(); document.removeEventListener("dragstart", handleDragStart); - document.removeEventListener("dragend", clearActivePageRef); }; }, []); @@ -709,7 +757,7 @@ const TldrawCanvasShared = ({ const handleDrop = (e: React.DragEvent) => { e.preventDefault(); - const pageTitle = e.dataTransfer.getData("application/x-roam-page"); + const pageTitle = e.dataTransfer.getData(ROAM_PAGE_DROP_MIME_TYPE); if (pageTitle && appRef.current && extensionAPI) { posthog.capture("Canvas: Roam Page Dropped"); const dropPoint = appRef.current.screenToPage({ @@ -724,7 +772,7 @@ const TldrawCanvasShared = ({ return; } - const uid = e.dataTransfer.getData("application/x-roam-uid"); + const uid = e.dataTransfer.getData(ROAM_BLOCK_DROP_MIME_TYPE); if (!uid || !appRef.current || !extensionAPI) return; posthog.capture("Canvas: Roam Block Dropped"); @@ -1375,14 +1423,6 @@ const InsideEditorAndUiContext = ({ if (!blockText || !isLive) return await callDefaultTextHandler(content); - const refMatch = blockText.match(PAGE_REF_REGEX); - if (refMatch?.[1] && (await tryCreatePageNodeShape(refMatch[1]))) { - posthog.capture("Canvas: Node Added from External Content", { - source: "block-page-reference", - }); - return; - } - await createDiscourseNodeShape({ uid, nodeText: blockText, diff --git a/apps/roam/src/components/results-view/Kanban.tsx b/apps/roam/src/components/results-view/Kanban.tsx index 9ff747423..ffde64212 100644 --- a/apps/roam/src/components/results-view/Kanban.tsx +++ b/apps/roam/src/components/results-view/Kanban.tsx @@ -141,6 +141,8 @@ const KanbanCard = (card: { ) : cardView.mode === "link" ? (
{ if (e.shiftKey) { From 467b9251e7c6ed41e24aa8c758ca1d1f416ed177 Mon Sep 17 00:00:00 2001 From: sid597 Date: Tue, 16 Jun 2026 23:17:13 +0530 Subject: [PATCH 8/8] Clarify canvas text content analytics --- apps/roam/src/components/canvas/Tldraw.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/roam/src/components/canvas/Tldraw.tsx b/apps/roam/src/components/canvas/Tldraw.tsx index f9b991254..5f776c0db 100644 --- a/apps/roam/src/components/canvas/Tldraw.tsx +++ b/apps/roam/src/components/canvas/Tldraw.tsx @@ -1405,7 +1405,7 @@ const InsideEditorAndUiContext = ({ const pageMatch = text.match(PAGE_REF_REGEX); if (pageMatch?.[1]) { if (await tryCreatePageNodeShape(pageMatch[1])) { - posthog.capture("Canvas: Node Added from External Content", { + posthog.capture("Canvas: Node Added from Text Content", { source: "page-reference", }); return; @@ -1429,7 +1429,7 @@ const InsideEditorAndUiContext = ({ nodeType: "blck-node", content, }); - posthog.capture("Canvas: Node Added from External Content", { + posthog.capture("Canvas: Node Added from Text Content", { source: "block-reference", }); } catch (error) {