diff --git a/.gitignore b/.gitignore index b7022dd..0b5a2cd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ dist out .env extension.js +extension.css extension.js.LICENSE.txt diff --git a/scripts/dev.ts b/scripts/dev.ts index 3b5e789..e2a21a9 100644 --- a/scripts/dev.ts +++ b/scripts/dev.ts @@ -1,5 +1,7 @@ import esbuild from "esbuild"; import dotenv from "dotenv"; +import fs from "fs"; +import path from "path"; import { compile, args } from "./compile"; dotenv.config(); @@ -9,8 +11,33 @@ const dev = () => { return new Promise((resolve) => { compile({ opts: args, - builder: (opts: esbuild.BuildOptions) => - esbuild.context(opts).then((esb) => esb.watch()), + builder: (opts: esbuild.BuildOptions) => { + const outFile = path.join(process.cwd(), "dist", "extension.js"); + const rootFile = path.join(process.cwd(), "extension.js"); + const outCssFile = path.join(process.cwd(), "dist", "extension.css"); + const rootCssFile = path.join(process.cwd(), "extension.css"); + // Keep a root extension.js so Roam dev loading can target tldraw/ instead of tldraw/dist/. + const copyOutputPlugin: esbuild.Plugin = { + name: "copy-output-to-root", + setup(build) { + build.onEnd((result) => { + if (result.errors.length) return; + if (fs.existsSync(outFile)) { + fs.cpSync(outFile, rootFile); + } + if (fs.existsSync(outCssFile)) { + fs.cpSync(outCssFile, rootCssFile); + } + }); + }, + }; + return esbuild + .context({ + ...opts, + plugins: [...(opts.plugins || []), copyOutputPlugin], + }) + .then((esb) => esb.watch()); + }, }); process.on("exit", resolve); }); diff --git a/src/components/canvas/Tldraw.tsx b/src/components/canvas/Tldraw.tsx index 56b587c..c72d7bd 100644 --- a/src/components/canvas/Tldraw.tsx +++ b/src/components/canvas/Tldraw.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useMemo, useState, useRef } from "react"; import { OnloadArgs } from "roamjs-components/types"; import renderWithUnmount from "roamjs-components/util/renderWithUnmount"; +import renderToast from "roamjs-components/components/Toast"; import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle"; import getUids from "roamjs-components/dom/getUids"; import { @@ -662,8 +663,32 @@ const renderTldrawCanvasHelper = ({ if (!childFromRoot?.parentElement) return () => {}; const parentEl = childFromRoot.parentElement; - if (parentEl.querySelector(".roamjs-tldraw-canvas-container")) - return () => {}; + const hasExistingCanvasByClass = !!parentEl.querySelector( + ".roamjs-tldraw-canvas-container", + ); + // Query Builder uses this id for the canvas mount. + const hasExistingCanvasById = !!parentEl.querySelector( + "#roamjs-tldraw-canvas-container", + ); + const hasExistingCanvas = hasExistingCanvasByClass || hasExistingCanvasById; + // Query Builder tags rm-block-children with this attribute when it owns the canvas mount. + const hasQueryBuilderCanvasOwner = childFromRoot.hasAttribute( + "data-roamjs-discourse-playground", + ); + if ( + hasQueryBuilderCanvasOwner && + !parentEl.hasAttribute("data-roamjs-tldraw-qb-warning-shown") + ) { + parentEl.setAttribute("data-roamjs-tldraw-qb-warning-shown", "true"); + renderToast({ + id: "tldraw-query-builder-canvas-conflict", + intent: "warning", + content: `Multiple canvases have been detected on this page. This may cause unexpected behavior. + +Either disable the tldraw extension or disable the Query Builder Discourse Graph flag.`, + }); + } + if (hasExistingCanvas || hasQueryBuilderCanvasOwner) return () => {}; const canvasWrapperEl = document.createElement("div"); parentEl.appendChild(canvasWrapperEl);