Notes
", + }); + const toolbarButton = document.createElement("button"); + toolbarElement.append(toolbarButton); + toolbarButton.focus(); + const shows = (from: number, to: number) => + shouldShowBubbleToolbar({ + editor: defined(editor), + element: defined(toolbarElement), + state: defined(editor).state, + from, + to, + }); + + expect(shows(1, 6)).toBe(true); + editor.commands.setNodeSelection(7); + expect(shows(editor.state.selection.from, editor.state.selection.to)).toBe( + false, + ); + }); + it("hides the color control when a selection contains no text", () => { editorElement = document.createElement("div"); toolbarElement = document.createElement("div"); diff --git a/templates/content/app/components/editor/BubbleToolbar.tsx b/templates/content/app/components/editor/BubbleToolbar.tsx index bae5b8135df..3cc8a9745f2 100644 --- a/templates/content/app/components/editor/BubbleToolbar.tsx +++ b/templates/content/app/components/editor/BubbleToolbar.tsx @@ -76,6 +76,7 @@ const BUBBLE_TOOLBAR_EXCLUDED_NODE_TYPES = new Set([ "audio", "contentReference", "localMdxComponent", + "registryBlock", ]); type SelectionFillRange = { diff --git a/templates/content/app/components/editor/clip-embed/ClipEmbedBlock.test.tsx b/templates/content/app/components/editor/clip-embed/ClipEmbedBlock.test.tsx new file mode 100644 index 00000000000..b21466d584e --- /dev/null +++ b/templates/content/app/components/editor/clip-embed/ClipEmbedBlock.test.tsx @@ -0,0 +1,372 @@ +// @vitest-environment happy-dom + +import type { ClipPlayback } from "@shared/clips-peer-contract"; +import { act } from "react"; +import { createRoot, type Root } from "react-dom/client"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +import { TooltipProvider } from "@/components/ui/tooltip"; + +import { ClipEmbed, ClipEmbedRead } from "./ClipEmbedBlock"; + +function defined{summary}
: null} + + ); +} + +/** + * The page as plain elements, for the server and the first client render. + * The editor's own static body draws into the DOM, so it has nothing to send. + */ +function ServerRenderedBody({ + content, + clipsAppUrl, +}: { + content: string; + clipsAppUrl: string | null; +}) { + return nfmToDoc(content).content.map((node, index) => { + switch (node.type) { + case "registryBlock": + return ( ++ {text} +
+ ); + } } - return ( -- {trimmed} -
- ); }); } @@ -274,19 +365,38 @@ function PublicDocumentContextSync({ return null; } -function ReadOnlyMarkdownContent({ content }: { content: string }) { +export function ReadOnlyMarkdownContent({ + documentId, + content, + clipsAppUrl, +}: { + documentId: string; + content: string; + clipsAppUrl: string | null; +}) { const [mounted, setMounted] = useState(false); + const blockContext = useMemo( + () => ({ dialect: "nfm" as const, documentId, canEdit: false }), + [documentId], + ); useEffect(() => setMounted(true), []); if (!mounted) { return ( -