@mjml-agent-editor/editor 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/editor/EmailEditor.tsx","../src/components/ui/switch.tsx"],"sourcesContent":["\"use client\";\n\nimport grapesjs, { Component, Editor } from \"grapesjs\";\nimport GjsEditor, { Canvas, useEditorMaybe } from \"@grapesjs/react\";\nimport grapesjsMJML from \"grapesjs-mjml\";\nimport { useRef, useState, type ReactNode } from \"react\";\n\nimport { STARTER_MJML, useDocumentStore, type CommentTarget } from \"../../index.js\";\nimport { cn } from \"../../lib/utils\";\nimport { toast } from \"sonner\";\nimport { ChevronRight } from \"lucide-react\";\n\nimport { Spinner } from \"../ui/spinner\";\nimport { Switch } from \"../ui/switch\";\nimport { Input } from \"../ui/input\";\nimport { Search } from \"lucide-react\";\nimport CanvasComments from \"../comments/CanvasComments.js\";\n\nexport type SaveStatus = \"idle\" | \"saving\" | \"saved\" | \"error\";\n\n/** Snapshot of editor state pushed to the header (device, undo, save, zoom, width). */\nexport type EditorState = {\n device: string;\n canUndo: boolean;\n canRedo: boolean;\n saveStatus: SaveStatus;\n zoom: number;\n contentWidth: string;\n};\n\nexport type EditorApi = {\n /** Current MJML source from the editor. */\n getMjml: () => string;\n /** Compiled email HTML (via grapesjs-mjml's mjml-get-code). */\n getCompiledHtml: () => string;\n /** Immediately saves the editor state to the DB. */\n flushSave: () => Promise<void>;\n /** Reloads the document from the DB (after agent changes). */\n reloadFromDb: () => Promise<void>;\n /** Highlights a section in the canvas while the agent edits it. */\n highlightSection: (sectionId: string, on: boolean) => void;\n /** Device manager control (used by the top header). */\n getDevices: () => { id: string; name: string }[];\n setDevice: (name: string) => void;\n undo: () => void;\n redo: () => void;\n /** Canvas zoom (percentage). */\n setZoom: (z: number) => void;\n /** Email body width (mj-body width attribute, e.g. \"600px\"). */\n setContentWidth: (w: string) => void;\n /** Subscribe to editor state changes (device/undo/save/zoom/width). Returns unsubscribe. */\n onEditorState: (cb: (s: EditorState) => void) => () => void;\n};\n\ntype Props = {\n docId: string;\n onReady: (api: EditorApi) => void;\n /** Bump to force the canvas comment layer to refetch (after agent turns). */\n commentsRefresh: number;\n /** Reports the number of open comments (for the header indicator). */\n onOpenCountChange: (n: number) => void;\n};\n\nconst SEC_ID_RE = /\\bsec-([A-Za-z0-9_-]+)\\b/;\nconst OBJ_ID_RE = /\\bobj-([A-Za-z0-9_-]+)\\b/;\n\n// Element types that can receive a comment (besides a section).\nconst TYPE_LABEL: Record<string, string> = {\n \"mj-text\": \"Text\",\n \"mj-button\": \"Button\",\n \"mj-image\": \"Image\",\n \"mj-column\": \"Column\",\n};\n\nfunction tagOf(c: Component): string {\n return String(c.get(\"tagName\") || c.get(\"type\") || \"\");\n}\n\n// \"Sparkles\" icon (lucide Sparkles) used as a label in the GrapesJS toolbar.\nconst SPARKLES_SVG =\n '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z\"/><path d=\"M20 3v4\"/><path d=\"M22 5h-4\"/><path d=\"M4 17v2\"/><path d=\"M5 18H3\"/></svg>';\n\nfunction isSection(c: Component): boolean {\n return tagOf(c) === \"mj-section\";\n}\n\nfunction isCommentable(c: Component): boolean {\n const t = tagOf(c);\n return t === \"mj-section\" || t in TYPE_LABEL;\n}\n\nfunction classMatch(c: Component, re: RegExp): string | null {\n const cssClass = String(c.getAttributes()[\"css-class\"] ?? \"\");\n return cssClass.match(re)?.[1] ?? null;\n}\n\nfunction sectionIdOf(c: Component): string | null {\n return classMatch(c, SEC_ID_RE);\n}\n\nfunction addIdClass(c: Component, prefix: \"sec\" | \"obj\"): string {\n const existing = classMatch(c, prefix === \"sec\" ? SEC_ID_RE : OBJ_ID_RE);\n if (existing) return existing;\n const cssClass = String(c.getAttributes()[\"css-class\"] ?? \"\");\n const id = Math.random().toString(36).slice(2, 10);\n c.addAttributes({ \"css-class\": `${cssClass} ${prefix}-${id}`.trim() });\n return id;\n}\n\nfunction closestSection(c: Component | undefined): Component | null {\n let cur: Component | undefined = c;\n while (cur) {\n if (isSection(cur)) return cur;\n cur = cur.parent() ?? undefined;\n }\n return null;\n}\n\n// Friendly names for the canvas breadcrumb.\nconst CRUMB_NAME: Record<string, string> = {\n \"mj-section\": \"Section\",\n \"mj-column\": \"Column\",\n \"mj-group\": \"Group\",\n \"mj-text\": \"Text\",\n \"mj-button\": \"Button\",\n \"mj-image\": \"Image\",\n \"mj-divider\": \"Divider\",\n \"mj-spacer\": \"Spacer\",\n \"mj-hero\": \"Hero\",\n \"mj-navbar\": \"Navbar\",\n \"mj-social\": \"Social\",\n \"mj-social-element\": \"Social\",\n \"mj-wrapper\": \"Wrapper\",\n};\n\nfunction crumbName(c: Component): string {\n const t = tagOf(c);\n return CRUMB_NAME[t] ?? t.replace(/^mj-/, \"\") ?? \"Element\";\n}\n\nfunction objectLabel(c: Component): string {\n const base = TYPE_LABEL[tagOf(c)] ?? tagOf(c);\n const text = String((c.getEl?.() as HTMLElement | undefined)?.textContent ?? \"\")\n .replace(/\\s+/g, \" \")\n .trim()\n .slice(0, 30);\n return text ? `${base}: “${text}”` : base;\n}\n\nconst RTE_FONTS = [\n \"Arial\",\n \"Helvetica\",\n \"Georgia\",\n \"Times New Roman\",\n \"Verdana\",\n \"Tahoma\",\n \"Trebuchet MS\",\n \"Courier New\",\n];\nconst RTE_SIZES = [11, 12, 13, 14, 16, 18, 20, 24, 28, 32, 40];\n\n// Wraps the current selection (in the canvas document) in a <span> with inline style.\nfunction wrapSelectionStyle(el: HTMLElement | undefined, style: Partial<CSSStyleDeclaration>) {\n const doc = el?.ownerDocument;\n const sel = doc?.getSelection?.();\n if (!doc || !sel || sel.rangeCount === 0 || sel.isCollapsed) return;\n const range = sel.getRangeAt(0);\n const span = doc.createElement(\"span\");\n Object.assign(span.style, style);\n try {\n span.appendChild(range.extractContents());\n range.insertNode(span);\n sel.removeAllRanges();\n const nr = doc.createRange();\n nr.selectNodeContents(span);\n sel.addRange(nr);\n } catch {\n /* ignore */\n }\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n// Extends the default GrapesJS RTE (mjml-compatible) with font/size/colors.\nfunction setupRichText(editor: Editor) {\n const rte = editor.RichTextEditor as any;\n if (!rte || rte.__customActions) return;\n rte.__customActions = true;\n const val = (action: any, sel: string) =>\n (action.btn?.querySelector(sel) as HTMLInputElement | HTMLSelectElement | null)?.value ?? \"\";\n\n rte.add(\"fontName\", {\n icon: `<select class=\"gjs-rte-select\" title=\"Font\"><option value=\"\">Font</option>${RTE_FONTS.map(\n (f) => `<option value=\"${f}\">${f}</option>`,\n ).join(\"\")}</select>`,\n event: \"change\",\n result: (r: any, action: any) => {\n const v = val(action, \"select\");\n if (v) r.exec(\"fontName\", v);\n },\n });\n\n rte.add(\"fontSize\", {\n icon: `<select class=\"gjs-rte-select\" title=\"Size\"><option value=\"\">Size</option>${RTE_SIZES.map(\n (s) => `<option value=\"${s}px\">${s}</option>`,\n ).join(\"\")}</select>`,\n event: \"change\",\n result: (r: any, action: any) => {\n const v = val(action, \"select\");\n if (v) wrapSelectionStyle(r.el, { fontSize: v });\n },\n });\n\n rte.add(\"forecolor\", {\n icon: `<input type=\"color\" class=\"gjs-rte-color\" title=\"Text color\" value=\"#000000\">`,\n event: \"change\",\n result: (r: any, action: any) => r.exec(\"foreColor\", val(action, \"input\")),\n });\n\n rte.add(\"hilitecolor\", {\n icon: `<input type=\"color\" class=\"gjs-rte-color\" title=\"Background color\" value=\"#ffff00\">`,\n event: \"change\",\n result: (r: any, action: any) => r.exec(\"hiliteColor\", val(action, \"input\")),\n });\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nexport default function EmailEditor({ docId, onReady, commentsRefresh, onOpenCountChange }: Props) {\n // Injected by the host rather than imported, so the editor carries no database.\n const documents = useDocumentStore();\n // Refs instead of state — GrapesJS lives outside React's lifecycle.\n const loadingRef = useRef(false);\n const saveTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const saveStatusRef = useRef<SaveStatus>(\"idle\");\n const stateListeners = useRef(new Set<(s: EditorState) => void>());\n const [loading, setLoading] = useState(true);\n const [sidebarView, setSidebarView] = useState<SidebarView>(\"blocks\");\n // Comment being composed (sparkles button) — opens the canvas popover.\n const [composeTarget, setComposeTarget] = useState<CommentTarget | null>(null);\n // Where the current selection came from — canvas click opens Settings,\n // selecting from the Layers tree does not (keeps you on Layers).\n const selectionSource = useRef<\"canvas\" | \"layers\" | \"other\">(\"other\");\n // Breadcrumb of the selected component's ancestry (Section › Column › …).\n const editorRef = useRef<Editor | null>(null);\n const [crumbs, setCrumbs] = useState<Component[]>([]);\n\n const onEditor = async (editor: Editor) => {\n editorRef.current = editor;\n\n // Build the breadcrumb chain from a component up to (but excluding) mj-body.\n const buildCrumbs = (c: Component | undefined) => {\n const chain: Component[] = [];\n let cur: Component | undefined = c;\n while (cur) {\n const t = tagOf(cur);\n if (!t || t === \"mj-body\" || t === \"wrapper\" || t === \"Wrapper\") break;\n chain.unshift(cur);\n cur = cur.parent() ?? undefined;\n }\n setCrumbs(chain);\n };\n\n // GrapesJS find() by MJML tag is unreliable — walk the tree instead.\n const findByTag = (tag: string): Component | undefined => {\n let found: Component | undefined;\n editor.getWrapper()?.onAll((c) => {\n if (!found && (c.get(\"tagName\") === tag || c.get(\"type\") === tag)) found = c;\n });\n return found;\n };\n const bodyWidth = (): string => {\n const body = findByTag(\"mj-body\");\n return String((body?.getAttributes?.() as Record<string, unknown>)?.width ?? \"600px\");\n };\n const snapshot = (): EditorState => ({\n device: editor.getDevice(),\n canUndo: editor.UndoManager.hasUndo(),\n canRedo: editor.UndoManager.hasRedo(),\n saveStatus: saveStatusRef.current,\n zoom: Math.round((editor.Canvas.getZoom?.() as number | undefined) ?? 100),\n contentWidth: bodyWidth(),\n });\n const notifyState = () => {\n const s = snapshot();\n stateListeners.current.forEach((l) => l(s));\n };\n const setSave = (s: SaveStatus) => {\n saveStatusRef.current = s;\n notifyState();\n };\n\n // Comment target for a component: its section + (if it's not the section\n // itself) the specific element. Assigns stable IDs (sec-/obj-) when needed.\n const targetOf = (c: Component | undefined): CommentTarget | null => {\n const section = closestSection(c);\n if (!section || !c) return null;\n const sectionId = addIdClass(section, \"sec\");\n if (isSection(c)) {\n return { sectionId, objectId: null, objectLabel: null };\n }\n const objectId = addIdClass(c, \"obj\");\n return { sectionId, objectId, objectLabel: objectLabel(c) };\n };\n\n // Gives the section a sec-<id> and adds a comment button to the toolbar of\n // every commentable element (section + text/button/image/column).\n const decorate = (c: Component) => {\n if (isSection(c)) addIdClass(c, \"sec\");\n if (!isCommentable(c)) return;\n const toolbar = [...((c.get(\"toolbar\") as { command?: string }[]) ?? [])];\n if (!toolbar.some((t) => t.command === \"open-comments\")) {\n toolbar.push({\n command: \"open-comments\",\n label: SPARKLES_SVG,\n attributes: { title: \"Comment on element / section\", \"data-role\": \"sparkles\" },\n } as never);\n c.set(\"toolbar\", toolbar as never);\n }\n };\n\n editor.Commands.add(\"open-comments\", {\n run(ed: Editor) {\n const target = targetOf(ed.getSelected() ?? undefined);\n if (target) setComposeTarget(target);\n },\n });\n\n setupRichText(editor);\n\n // Group the palette blocks into categories (the plugin ships them flat).\n const blockCategory = (label: string): string => {\n const l = label.toLowerCase();\n if (/(column|section)/.test(l)) return \"Layout\";\n if (/(text|image|button|divider|spacer|social)/.test(l)) return \"Basic\";\n return \"Advanced\";\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const bm = editor.BlockManager as any;\n bm.getAll().forEach(\n (b: { get: (k: string) => string; set: (k: string, v: unknown) => void }) => {\n b.set(\"category\", blockCategory(b.get(\"label\") || \"\"));\n },\n );\n bm.render();\n\n editor.on(\"component:add\", decorate);\n // Track selection origin: a mousedown inside the canvas iframe marks the\n // next selection as coming from the canvas (→ open Settings). Selecting via\n // the Layers tree leaves the source as \"layers\" (set by the sidebar).\n editor.on(\"load\", () => {\n const body = editor.Canvas.getBody();\n body?.addEventListener(\n \"mousedown\",\n () => {\n selectionSource.current = \"canvas\";\n },\n true,\n );\n });\n editor.on(\"component:selected\", (c: Component) => {\n if (selectionSource.current === \"canvas\") setSidebarView(\"settings\");\n selectionSource.current = \"other\";\n buildCrumbs(c);\n // mj-image has no src trait by default (src changes via the Asset\n // Manager) — add a URL field so the image can be set from the panel.\n if (c?.get(\"type\") === \"mj-image\" && !c.getTrait(\"src\")) {\n c.addTrait(\n {\n type: \"text\",\n name: \"src\",\n label: \"Image (URL)\",\n placeholder: \"https://…\",\n changeProp: true,\n } as never,\n { at: 0 },\n );\n }\n });\n editor.on(\"component:deselected\", () => setCrumbs([]));\n\n const save = async () => {\n if (loadingRef.current) return;\n setSave(\"saving\");\n try {\n await documents.save(docId, {\n mjml: editor.getHtml(),\n projectData: editor.getProjectData(),\n });\n setSave(\"saved\");\n } catch (e) {\n setSave(\"error\");\n toast.error(\"Failed to save changes.\");\n throw e;\n }\n };\n\n editor.on(\"update\", () => {\n notifyState();\n if (loadingRef.current) return;\n if (saveTimer.current) clearTimeout(saveTimer.current);\n saveTimer.current = setTimeout(() => void save().catch(console.error), 1200);\n });\n editor.on(\"change:device\", notifyState);\n\n const loadMjml = (mjml: string) => {\n // Mute autosave during loading and for a moment after — setComponents\n // can fire the \"update\" event asynchronously, which would otherwise\n // overwrite the agent's fresh change with the editor's normalized version.\n loadingRef.current = true;\n if (saveTimer.current) clearTimeout(saveTimer.current);\n editor.setComponents(mjml || STARTER_MJML);\n editor.getWrapper()?.find(\"mj-section\").forEach(decorate);\n for (const t of Object.keys(TYPE_LABEL)) {\n editor.getWrapper()?.find(t).forEach(decorate);\n }\n setTimeout(() => {\n loadingRef.current = false;\n }, 400);\n };\n\n // Highlight for the section the agent is editing. The canvas is an iframe with its\n // own document, so the host's stylesheet does not reach it and these rules have to be\n // injected. The colour is still read from the shared token rather than written out\n // again — the literal that used to live here was the pre-redesign violet and had\n // silently drifted from the brand for as long as the redesign had been in place.\n const ensureHighlightStyles = () => {\n const cdoc = editor.Canvas.getDocument();\n if (!cdoc || cdoc.getElementById(\"agent-edit-style\")) return;\n\n const accent =\n getComputedStyle(document.documentElement)\n .getPropertyValue(\"--mjml-editor-accent\")\n .trim() || \"#7c5cfc\";\n\n const style = cdoc.createElement(\"style\");\n style.id = \"agent-edit-style\";\n style.textContent = `\n @keyframes agentEditPulse {\n 0%, 100% { outline-color: color-mix(in srgb, ${accent} 25%, transparent); }\n 50% { outline-color: color-mix(in srgb, ${accent} 95%, transparent); }\n }\n .agent-editing {\n outline: 3px solid color-mix(in srgb, ${accent} 90%, transparent) !important;\n outline-offset: -3px;\n animation: agentEditPulse 1s ease-in-out infinite;\n transition: outline-color 0.2s;\n }`;\n cdoc.head.appendChild(style);\n };\n\n const sectionEl = (sectionId: string): HTMLElement | undefined => {\n const comp = editor\n .getWrapper()\n ?.find(\"mj-section\")\n .find((c) => sectionIdOf(c) === sectionId);\n return (comp?.getEl?.() as HTMLElement | undefined) ?? undefined;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const compiledHtml = (): string => {\n try {\n // grapesjs-mjml compiles MJML → email HTML via this command ({ html, errors }).\n const res = editor.runCommand(\"mjml-code-to-html\") as { html?: string } | undefined;\n return res?.html ?? editor.getHtml();\n } catch {\n return editor.getHtml();\n }\n };\n\n try {\n const doc = await documents.get(docId);\n loadMjml(doc.mjml);\n } catch (e) {\n toast.error(\"Failed to load the document.\");\n console.error(e);\n } finally {\n setLoading(false);\n }\n\n onReady({\n getMjml: () => editor.getHtml(),\n getCompiledHtml: compiledHtml,\n flushSave: async () => {\n if (saveTimer.current) clearTimeout(saveTimer.current);\n await save();\n },\n reloadFromDb: async () => {\n const fresh = await documents.get(docId);\n if (fresh.mjml !== editor.getHtml()) loadMjml(fresh.mjml);\n },\n highlightSection: (sectionId, on) => {\n ensureHighlightStyles();\n const el = sectionEl(sectionId);\n if (!el) return;\n el.classList.toggle(\"agent-editing\", on);\n },\n getDevices: () =>\n editor.Devices.getDevices().map((d) => ({\n id: String(d.id),\n name: d.getName() || String(d.id),\n })),\n setDevice: (name) => {\n editor.setDevice(name);\n notifyState();\n },\n undo: () => {\n editor.UndoManager.undo();\n notifyState();\n },\n redo: () => {\n editor.UndoManager.redo();\n notifyState();\n },\n setZoom: (z) => {\n editor.Canvas.setZoom?.(Math.max(25, Math.min(200, z)));\n notifyState();\n },\n setContentWidth: (w) => {\n findByTag(\"mj-body\")?.addAttributes({ width: w });\n notifyState();\n },\n onEditorState: (cb) => {\n stateListeners.current.add(cb);\n cb(snapshot());\n return () => stateListeners.current.delete(cb);\n },\n });\n };\n\n return (\n <GjsEditor\n grapesjs={grapesjs}\n className=\"h-full\"\n options={{\n height: \"100%\",\n storageManager: false,\n fromElement: false,\n panels: { defaults: [] },\n blockManager: { appendTo: \"#gjs-blocks\" },\n styleManager: { appendTo: \"#gjs-styles\" },\n traitManager: { appendTo: \"#gjs-traits\" },\n layerManager: { appendTo: \"#gjs-layers\" },\n deviceManager: {\n devices: [\n { id: \"desktop\", name: \"Desktop\", width: \"\" },\n { id: \"mobile\", name: \"Mobile\", width: \"375px\", widthMedia: \"480px\" },\n ],\n },\n plugins: [grapesjsMJML],\n }}\n onEditor={onEditor}\n >\n <div className=\"flex h-full min-h-0 flex-1\">\n <LeftSidebar\n view={sidebarView}\n onViewChange={setSidebarView}\n markLayersSource={() => (selectionSource.current = \"layers\")}\n />\n <div className=\"flex min-w-0 flex-1 flex-col bg-surface-muted\">\n <div className=\"relative min-h-0 flex-1\">\n <Canvas className=\"h-full\" />\n {/* Canvas comment layer (pins + thread popovers) overlays the canvas. */}\n <CanvasComments\n docId={docId}\n composeTarget={composeTarget}\n onComposeConsumed={() => setComposeTarget(null)}\n refreshSignal={commentsRefresh}\n onOpenCountChange={onOpenCountChange}\n />\n {loading && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center gap-2 bg-white/70 text-sm text-zinc-500\">\n <Spinner /> Loading editor…\n </div>\n )}\n </div>\n <Breadcrumb crumbs={crumbs} onSelect={(c) => editorRef.current?.select(c)} />\n </div>\n </div>\n </GjsEditor>\n );\n}\n\ntype SidebarView = \"blocks\" | \"settings\" | \"layers\";\n\n// Collapsible section — content ALWAYS mounted (appendTo target), hidden via `hidden`.\nfunction CollapseSection({\n title,\n defaultOpen = true,\n children,\n}: {\n title: string;\n defaultOpen?: boolean;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(defaultOpen);\n return (\n <div className=\"border-b border-panel-border\">\n <button\n type=\"button\"\n onClick={() => setOpen((o) => !o)}\n className=\"flex w-full items-center gap-1.5 px-3 py-2 text-xs font-semibold tracking-wide text-panel-muted-fg uppercase hover:text-panel-fg\"\n >\n <ChevronRight className={cn(\"size-3.5 transition-transform\", open && \"rotate-90\")} />\n {title}\n </button>\n <div className={cn(!open && \"hidden\")}>{children}</div>\n </div>\n );\n}\n\n// Left sidebar (dark): Blocks / Settings / Layers. All managers are always\n// mounted (appendTo targets for GrapesJS) — visibility toggled via `hidden`.\nfunction LeftSidebar({\n view,\n onViewChange,\n markLayersSource,\n}: {\n view: SidebarView;\n onViewChange: (v: SidebarView) => void;\n markLayersSource: () => void;\n}) {\n const editor = useEditorMaybe();\n const [layersExpanded, setLayersExpanded] = useState(false);\n const [blockSearch, setBlockSearch] = useState(\"\");\n\n const changeView = (v: SidebarView) => {\n if (v === \"settings\" && editor && !editor.getSelected()) {\n const wrapper = editor.getWrapper();\n const body = wrapper?.find(\"mj-body\")[0] ?? wrapper;\n if (body) editor.select(body);\n }\n onViewChange(v);\n };\n\n const toggleLayers = (expand: boolean) => {\n setLayersExpanded(expand);\n editor?.getWrapper()?.onAll((c) => c.set(\"open\", expand));\n };\n\n // Filter the GrapesJS-rendered blocks (DOM lives outside React) by label;\n // hide category groups that end up empty.\n const filterBlocks = (q: string) => {\n setBlockSearch(q);\n const root = document.getElementById(\"gjs-blocks\");\n if (!root) return;\n const term = q.trim().toLowerCase();\n root.querySelectorAll<HTMLElement>(\".gjs-block\").forEach((b) => {\n const label = (b.querySelector(\".gjs-block-label\")?.textContent ?? b.textContent ?? \"\")\n .toLowerCase()\n .trim();\n b.style.display = !term || label.includes(term) ? \"\" : \"none\";\n });\n root.querySelectorAll<HTMLElement>(\".gjs-block-category\").forEach((cat) => {\n const anyVisible = [...cat.querySelectorAll<HTMLElement>(\".gjs-block\")].some(\n (b) => b.style.display !== \"none\",\n );\n cat.style.display = anyVisible ? \"\" : \"none\";\n });\n };\n\n return (\n <div className=\"editor-dark flex w-64 shrink-0 flex-col border-r border-panel-border bg-panel text-panel-fg\">\n <div className=\"flex border-b border-panel-border\">\n {(\n [\n [\"blocks\", \"Blocks\"],\n [\"settings\", \"Settings\"],\n [\"layers\", \"Layers\"],\n ] as const\n ).map(([value, label]) => (\n <button\n key={value}\n type=\"button\"\n onClick={() => changeView(value)}\n className={cn(\n \"relative flex-1 px-3 py-2.5 text-sm transition-colors\",\n \"after:absolute after:inset-x-0 after:-bottom-px after:h-0.5 after:transition-colors\",\n view === value\n ? \"font-medium text-panel-fg after:bg-brand\"\n : \"text-panel-muted-fg after:bg-transparent hover:text-panel-fg\",\n )}\n >\n {label}\n </button>\n ))}\n </div>\n\n {/* Blocks: search + categorized block palette */}\n <div className={cn(\"flex min-h-0 flex-1 flex-col\", view !== \"blocks\" && \"hidden\")}>\n <div className=\"relative border-b border-panel-border p-2\">\n <Search className=\"pointer-events-none absolute top-1/2 left-4 size-3.5 -translate-y-1/2 text-panel-muted-fg\" />\n <Input\n value={blockSearch}\n onChange={(e) => filterBlocks(e.target.value)}\n placeholder=\"Search blocks…\"\n className=\"h-8 border-panel-border bg-panel-elevated pr-10 pl-7 text-sm text-panel-fg placeholder:text-panel-muted-fg\"\n />\n <kbd className=\"pointer-events-none absolute top-1/2 right-4 -translate-y-1/2 rounded border border-panel-border bg-panel px-1 py-0.5 font-mono text-[10px] text-panel-muted-fg\">\n ⌘K\n </kbd>\n </div>\n <div id=\"gjs-blocks\" className=\"min-h-0 flex-1 overflow-y-auto\" />\n </div>\n\n {/* Settings: Attributes + Style (collapsible, stacked) */}\n <div className={cn(\"min-h-0 flex-1 overflow-y-auto\", view !== \"settings\" && \"hidden\")}>\n <CollapseSection title=\"Attributes\">\n <div id=\"gjs-traits\" />\n </CollapseSection>\n <CollapseSection title=\"Style\">\n <div id=\"gjs-styles\" />\n </CollapseSection>\n </div>\n\n {/* Layers — with an expand/collapse-all switch. A pointer-down here marks\n the next selection as coming from the tree (→ do NOT open Settings). */}\n <div\n className={cn(\"flex min-h-0 flex-1 flex-col\", view !== \"layers\" && \"hidden\")}\n onMouseDownCapture={markLayersSource}\n >\n <label className=\"flex items-center justify-between gap-2 border-b border-panel-border px-3 py-2 text-xs text-panel-muted-fg\">\n <span>Expand all</span>\n <Switch\n checked={layersExpanded}\n onCheckedChange={toggleLayers}\n className=\"data-[state=checked]:bg-brand data-[state=unchecked]:bg-panel-border\"\n />\n </label>\n <div id=\"gjs-layers\" className=\"min-h-0 flex-1 overflow-y-auto\" />\n </div>\n </div>\n );\n}\n\n// Breadcrumb under the canvas: the selected component's ancestry (clickable).\nfunction Breadcrumb({\n crumbs,\n onSelect,\n}: {\n crumbs: Component[];\n onSelect: (c: Component) => void;\n}) {\n return (\n <div className=\"flex h-9 shrink-0 items-center gap-0.5 border-t border-border bg-surface px-3 text-xs text-muted-foreground\">\n {crumbs.length === 0 ? (\n <span className=\"text-muted-foreground/60\">Select an element…</span>\n ) : (\n crumbs.map((c, i) => (\n <span key={i} className=\"flex items-center gap-0.5\">\n {i > 0 && <ChevronRight className=\"size-3 opacity-40\" />}\n <button\n type=\"button\"\n onClick={() => onSelect(c)}\n className={cn(\n \"rounded px-1.5 py-0.5 hover:bg-muted hover:text-foreground\",\n i === crumbs.length - 1 && \"font-medium text-brand\",\n )}\n >\n {crumbName(c)}\n </button>\n </span>\n ))\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { Switch as SwitchPrimitive } from \"radix-ui\";\n\nimport { cn } from \"../../lib/utils\";\n\nfunction Switch({\n className,\n size = \"default\",\n ...props\n}: React.ComponentProps<typeof SwitchPrimitive.Root> & {\n size?: \"sm\" | \"default\";\n}) {\n return (\n <SwitchPrimitive.Root\n data-slot=\"switch\"\n data-size={size}\n className={cn(\n \"peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n <SwitchPrimitive.Thumb\n data-slot=\"switch-thumb\"\n className=\"pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground\"\n />\n </SwitchPrimitive.Root>\n );\n}\n\nexport { Switch };\n"],"mappings":"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","names":["jsx"]}
1
+ {"version":3,"sources":["../src/components/editor/EmailEditor.tsx","../src/components/ui/switch.tsx"],"sourcesContent":["\"use client\";\n\nimport grapesjs, { Component, Editor } from \"grapesjs\";\nimport GjsEditor, { Canvas, useEditorMaybe } from \"@grapesjs/react\";\nimport grapesjsMJML from \"grapesjs-mjml\";\nimport { useRef, useState, type ReactNode } from \"react\";\n\nimport { STARTER_MJML } from \"@mjml-agent-editor/core\";\nimport { useDocumentStore, type CommentTarget } from \"../../index.js\";\nimport { cn } from \"../../lib/utils\";\nimport { toast } from \"sonner\";\nimport { ChevronRight } from \"lucide-react\";\n\nimport { Spinner } from \"../ui/spinner\";\nimport { Switch } from \"../ui/switch\";\nimport { Input } from \"../ui/input\";\nimport { Search } from \"lucide-react\";\nimport CanvasComments from \"../comments/CanvasComments.js\";\n\nexport type SaveStatus = \"idle\" | \"saving\" | \"saved\" | \"error\";\n\n/** Snapshot of editor state pushed to the header (device, undo, save, zoom, width). */\nexport type EditorState = {\n device: string;\n canUndo: boolean;\n canRedo: boolean;\n saveStatus: SaveStatus;\n zoom: number;\n contentWidth: string;\n};\n\nexport type EditorApi = {\n /** Current MJML source from the editor. */\n getMjml: () => string;\n /** Compiled email HTML (via grapesjs-mjml's mjml-get-code). */\n getCompiledHtml: () => string;\n /** Immediately saves the editor state to the DB. */\n flushSave: () => Promise<void>;\n /** Reloads the document from the DB (after agent changes). */\n reloadFromDb: () => Promise<void>;\n /** Highlights a section in the canvas while the agent edits it. */\n highlightSection: (sectionId: string, on: boolean) => void;\n /** Device manager control (used by the top header). */\n getDevices: () => { id: string; name: string }[];\n setDevice: (name: string) => void;\n undo: () => void;\n redo: () => void;\n /** Canvas zoom (percentage). */\n setZoom: (z: number) => void;\n /** Email body width (mj-body width attribute, e.g. \"600px\"). */\n setContentWidth: (w: string) => void;\n /** Subscribe to editor state changes (device/undo/save/zoom/width). Returns unsubscribe. */\n onEditorState: (cb: (s: EditorState) => void) => () => void;\n};\n\ntype Props = {\n docId: string;\n onReady: (api: EditorApi) => void;\n /** Bump to force the canvas comment layer to refetch (after agent turns). */\n commentsRefresh: number;\n /** Reports the number of open comments (for the header indicator). */\n onOpenCountChange: (n: number) => void;\n};\n\nconst SEC_ID_RE = /\\bsec-([A-Za-z0-9_-]+)\\b/;\nconst OBJ_ID_RE = /\\bobj-([A-Za-z0-9_-]+)\\b/;\n\n// Element types that can receive a comment (besides a section).\nconst TYPE_LABEL: Record<string, string> = {\n \"mj-text\": \"Text\",\n \"mj-button\": \"Button\",\n \"mj-image\": \"Image\",\n \"mj-column\": \"Column\",\n};\n\nfunction tagOf(c: Component): string {\n return String(c.get(\"tagName\") || c.get(\"type\") || \"\");\n}\n\n// \"Sparkles\" icon (lucide Sparkles) used as a label in the GrapesJS toolbar.\nconst SPARKLES_SVG =\n '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z\"/><path d=\"M20 3v4\"/><path d=\"M22 5h-4\"/><path d=\"M4 17v2\"/><path d=\"M5 18H3\"/></svg>';\n\nfunction isSection(c: Component): boolean {\n return tagOf(c) === \"mj-section\";\n}\n\nfunction isCommentable(c: Component): boolean {\n const t = tagOf(c);\n return t === \"mj-section\" || t in TYPE_LABEL;\n}\n\nfunction classMatch(c: Component, re: RegExp): string | null {\n const cssClass = String(c.getAttributes()[\"css-class\"] ?? \"\");\n return cssClass.match(re)?.[1] ?? null;\n}\n\nfunction sectionIdOf(c: Component): string | null {\n return classMatch(c, SEC_ID_RE);\n}\n\nfunction addIdClass(c: Component, prefix: \"sec\" | \"obj\"): string {\n const existing = classMatch(c, prefix === \"sec\" ? SEC_ID_RE : OBJ_ID_RE);\n if (existing) return existing;\n const cssClass = String(c.getAttributes()[\"css-class\"] ?? \"\");\n const id = Math.random().toString(36).slice(2, 10);\n c.addAttributes({ \"css-class\": `${cssClass} ${prefix}-${id}`.trim() });\n return id;\n}\n\nfunction closestSection(c: Component | undefined): Component | null {\n let cur: Component | undefined = c;\n while (cur) {\n if (isSection(cur)) return cur;\n cur = cur.parent() ?? undefined;\n }\n return null;\n}\n\n// Friendly names for the canvas breadcrumb.\nconst CRUMB_NAME: Record<string, string> = {\n \"mj-section\": \"Section\",\n \"mj-column\": \"Column\",\n \"mj-group\": \"Group\",\n \"mj-text\": \"Text\",\n \"mj-button\": \"Button\",\n \"mj-image\": \"Image\",\n \"mj-divider\": \"Divider\",\n \"mj-spacer\": \"Spacer\",\n \"mj-hero\": \"Hero\",\n \"mj-navbar\": \"Navbar\",\n \"mj-social\": \"Social\",\n \"mj-social-element\": \"Social\",\n \"mj-wrapper\": \"Wrapper\",\n};\n\nfunction crumbName(c: Component): string {\n const t = tagOf(c);\n return CRUMB_NAME[t] ?? t.replace(/^mj-/, \"\") ?? \"Element\";\n}\n\nfunction objectLabel(c: Component): string {\n const base = TYPE_LABEL[tagOf(c)] ?? tagOf(c);\n const text = String((c.getEl?.() as HTMLElement | undefined)?.textContent ?? \"\")\n .replace(/\\s+/g, \" \")\n .trim()\n .slice(0, 30);\n return text ? `${base}: “${text}”` : base;\n}\n\nconst RTE_FONTS = [\n \"Arial\",\n \"Helvetica\",\n \"Georgia\",\n \"Times New Roman\",\n \"Verdana\",\n \"Tahoma\",\n \"Trebuchet MS\",\n \"Courier New\",\n];\nconst RTE_SIZES = [11, 12, 13, 14, 16, 18, 20, 24, 28, 32, 40];\n\n// Wraps the current selection (in the canvas document) in a <span> with inline style.\nfunction wrapSelectionStyle(el: HTMLElement | undefined, style: Partial<CSSStyleDeclaration>) {\n const doc = el?.ownerDocument;\n const sel = doc?.getSelection?.();\n if (!doc || !sel || sel.rangeCount === 0 || sel.isCollapsed) return;\n const range = sel.getRangeAt(0);\n const span = doc.createElement(\"span\");\n Object.assign(span.style, style);\n try {\n span.appendChild(range.extractContents());\n range.insertNode(span);\n sel.removeAllRanges();\n const nr = doc.createRange();\n nr.selectNodeContents(span);\n sel.addRange(nr);\n } catch {\n /* ignore */\n }\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n// Extends the default GrapesJS RTE (mjml-compatible) with font/size/colors.\nfunction setupRichText(editor: Editor) {\n const rte = editor.RichTextEditor as any;\n if (!rte || rte.__customActions) return;\n rte.__customActions = true;\n const val = (action: any, sel: string) =>\n (action.btn?.querySelector(sel) as HTMLInputElement | HTMLSelectElement | null)?.value ?? \"\";\n\n rte.add(\"fontName\", {\n icon: `<select class=\"gjs-rte-select\" title=\"Font\"><option value=\"\">Font</option>${RTE_FONTS.map(\n (f) => `<option value=\"${f}\">${f}</option>`,\n ).join(\"\")}</select>`,\n event: \"change\",\n result: (r: any, action: any) => {\n const v = val(action, \"select\");\n if (v) r.exec(\"fontName\", v);\n },\n });\n\n rte.add(\"fontSize\", {\n icon: `<select class=\"gjs-rte-select\" title=\"Size\"><option value=\"\">Size</option>${RTE_SIZES.map(\n (s) => `<option value=\"${s}px\">${s}</option>`,\n ).join(\"\")}</select>`,\n event: \"change\",\n result: (r: any, action: any) => {\n const v = val(action, \"select\");\n if (v) wrapSelectionStyle(r.el, { fontSize: v });\n },\n });\n\n rte.add(\"forecolor\", {\n icon: `<input type=\"color\" class=\"gjs-rte-color\" title=\"Text color\" value=\"#000000\">`,\n event: \"change\",\n result: (r: any, action: any) => r.exec(\"foreColor\", val(action, \"input\")),\n });\n\n rte.add(\"hilitecolor\", {\n icon: `<input type=\"color\" class=\"gjs-rte-color\" title=\"Background color\" value=\"#ffff00\">`,\n event: \"change\",\n result: (r: any, action: any) => r.exec(\"hiliteColor\", val(action, \"input\")),\n });\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\nexport default function EmailEditor({ docId, onReady, commentsRefresh, onOpenCountChange }: Props) {\n // Injected by the host rather than imported, so the editor carries no database.\n const documents = useDocumentStore();\n // Refs instead of state — GrapesJS lives outside React's lifecycle.\n const loadingRef = useRef(false);\n const saveTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const saveStatusRef = useRef<SaveStatus>(\"idle\");\n const stateListeners = useRef(new Set<(s: EditorState) => void>());\n const [loading, setLoading] = useState(true);\n const [sidebarView, setSidebarView] = useState<SidebarView>(\"blocks\");\n // Comment being composed (sparkles button) — opens the canvas popover.\n const [composeTarget, setComposeTarget] = useState<CommentTarget | null>(null);\n // Where the current selection came from — canvas click opens Settings,\n // selecting from the Layers tree does not (keeps you on Layers).\n const selectionSource = useRef<\"canvas\" | \"layers\" | \"other\">(\"other\");\n // Breadcrumb of the selected component's ancestry (Section › Column › …).\n const editorRef = useRef<Editor | null>(null);\n const [crumbs, setCrumbs] = useState<Component[]>([]);\n\n const onEditor = async (editor: Editor) => {\n editorRef.current = editor;\n\n // Build the breadcrumb chain from a component up to (but excluding) mj-body.\n const buildCrumbs = (c: Component | undefined) => {\n const chain: Component[] = [];\n let cur: Component | undefined = c;\n while (cur) {\n const t = tagOf(cur);\n if (!t || t === \"mj-body\" || t === \"wrapper\" || t === \"Wrapper\") break;\n chain.unshift(cur);\n cur = cur.parent() ?? undefined;\n }\n setCrumbs(chain);\n };\n\n // GrapesJS find() by MJML tag is unreliable — walk the tree instead.\n const findByTag = (tag: string): Component | undefined => {\n let found: Component | undefined;\n editor.getWrapper()?.onAll((c) => {\n if (!found && (c.get(\"tagName\") === tag || c.get(\"type\") === tag)) found = c;\n });\n return found;\n };\n const bodyWidth = (): string => {\n const body = findByTag(\"mj-body\");\n return String((body?.getAttributes?.() as Record<string, unknown>)?.width ?? \"600px\");\n };\n const snapshot = (): EditorState => ({\n device: editor.getDevice(),\n canUndo: editor.UndoManager.hasUndo(),\n canRedo: editor.UndoManager.hasRedo(),\n saveStatus: saveStatusRef.current,\n zoom: Math.round((editor.Canvas.getZoom?.() as number | undefined) ?? 100),\n contentWidth: bodyWidth(),\n });\n const notifyState = () => {\n const s = snapshot();\n stateListeners.current.forEach((l) => l(s));\n };\n const setSave = (s: SaveStatus) => {\n saveStatusRef.current = s;\n notifyState();\n };\n\n // Comment target for a component: its section + (if it's not the section\n // itself) the specific element. Assigns stable IDs (sec-/obj-) when needed.\n const targetOf = (c: Component | undefined): CommentTarget | null => {\n const section = closestSection(c);\n if (!section || !c) return null;\n const sectionId = addIdClass(section, \"sec\");\n if (isSection(c)) {\n return { sectionId, objectId: null, objectLabel: null };\n }\n const objectId = addIdClass(c, \"obj\");\n return { sectionId, objectId, objectLabel: objectLabel(c) };\n };\n\n // Gives the section a sec-<id> and adds a comment button to the toolbar of\n // every commentable element (section + text/button/image/column).\n const decorate = (c: Component) => {\n if (isSection(c)) addIdClass(c, \"sec\");\n if (!isCommentable(c)) return;\n const toolbar = [...((c.get(\"toolbar\") as { command?: string }[]) ?? [])];\n if (!toolbar.some((t) => t.command === \"open-comments\")) {\n toolbar.push({\n command: \"open-comments\",\n label: SPARKLES_SVG,\n attributes: { title: \"Comment on element / section\", \"data-role\": \"sparkles\" },\n } as never);\n c.set(\"toolbar\", toolbar as never);\n }\n };\n\n editor.Commands.add(\"open-comments\", {\n run(ed: Editor) {\n const target = targetOf(ed.getSelected() ?? undefined);\n if (target) setComposeTarget(target);\n },\n });\n\n setupRichText(editor);\n\n // Group the palette blocks into categories (the plugin ships them flat).\n const blockCategory = (label: string): string => {\n const l = label.toLowerCase();\n if (/(column|section)/.test(l)) return \"Layout\";\n if (/(text|image|button|divider|spacer|social)/.test(l)) return \"Basic\";\n return \"Advanced\";\n };\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const bm = editor.BlockManager as any;\n bm.getAll().forEach(\n (b: { get: (k: string) => string; set: (k: string, v: unknown) => void }) => {\n b.set(\"category\", blockCategory(b.get(\"label\") || \"\"));\n },\n );\n bm.render();\n\n editor.on(\"component:add\", decorate);\n // Track selection origin: a mousedown inside the canvas iframe marks the\n // next selection as coming from the canvas (→ open Settings). Selecting via\n // the Layers tree leaves the source as \"layers\" (set by the sidebar).\n editor.on(\"load\", () => {\n const body = editor.Canvas.getBody();\n body?.addEventListener(\n \"mousedown\",\n () => {\n selectionSource.current = \"canvas\";\n },\n true,\n );\n });\n editor.on(\"component:selected\", (c: Component) => {\n if (selectionSource.current === \"canvas\") setSidebarView(\"settings\");\n selectionSource.current = \"other\";\n buildCrumbs(c);\n // mj-image has no src trait by default (src changes via the Asset\n // Manager) — add a URL field so the image can be set from the panel.\n if (c?.get(\"type\") === \"mj-image\" && !c.getTrait(\"src\")) {\n c.addTrait(\n {\n type: \"text\",\n name: \"src\",\n label: \"Image (URL)\",\n placeholder: \"https://…\",\n changeProp: true,\n } as never,\n { at: 0 },\n );\n }\n });\n editor.on(\"component:deselected\", () => setCrumbs([]));\n\n const save = async () => {\n if (loadingRef.current) return;\n setSave(\"saving\");\n try {\n await documents.save(docId, {\n mjml: editor.getHtml(),\n projectData: editor.getProjectData(),\n });\n setSave(\"saved\");\n } catch (e) {\n setSave(\"error\");\n toast.error(\"Failed to save changes.\");\n throw e;\n }\n };\n\n editor.on(\"update\", () => {\n notifyState();\n if (loadingRef.current) return;\n if (saveTimer.current) clearTimeout(saveTimer.current);\n saveTimer.current = setTimeout(() => void save().catch(console.error), 1200);\n });\n editor.on(\"change:device\", notifyState);\n\n const loadMjml = (mjml: string) => {\n // Mute autosave during loading and for a moment after — setComponents\n // can fire the \"update\" event asynchronously, which would otherwise\n // overwrite the agent's fresh change with the editor's normalized version.\n loadingRef.current = true;\n if (saveTimer.current) clearTimeout(saveTimer.current);\n editor.setComponents(mjml || STARTER_MJML);\n editor.getWrapper()?.find(\"mj-section\").forEach(decorate);\n for (const t of Object.keys(TYPE_LABEL)) {\n editor.getWrapper()?.find(t).forEach(decorate);\n }\n setTimeout(() => {\n loadingRef.current = false;\n }, 400);\n };\n\n // Highlight for the section the agent is editing. The canvas is an iframe with its\n // own document, so the host's stylesheet does not reach it and these rules have to be\n // injected. The colour is still read from the shared token rather than written out\n // again — the literal that used to live here was the pre-redesign violet and had\n // silently drifted from the brand for as long as the redesign had been in place.\n const ensureHighlightStyles = () => {\n const cdoc = editor.Canvas.getDocument();\n if (!cdoc || cdoc.getElementById(\"agent-edit-style\")) return;\n\n const accent =\n getComputedStyle(document.documentElement)\n .getPropertyValue(\"--mjml-editor-accent\")\n .trim() || \"#7c5cfc\";\n\n const style = cdoc.createElement(\"style\");\n style.id = \"agent-edit-style\";\n style.textContent = `\n @keyframes agentEditPulse {\n 0%, 100% { outline-color: color-mix(in srgb, ${accent} 25%, transparent); }\n 50% { outline-color: color-mix(in srgb, ${accent} 95%, transparent); }\n }\n .agent-editing {\n outline: 3px solid color-mix(in srgb, ${accent} 90%, transparent) !important;\n outline-offset: -3px;\n animation: agentEditPulse 1s ease-in-out infinite;\n transition: outline-color 0.2s;\n }`;\n cdoc.head.appendChild(style);\n };\n\n const sectionEl = (sectionId: string): HTMLElement | undefined => {\n const comp = editor\n .getWrapper()\n ?.find(\"mj-section\")\n .find((c) => sectionIdOf(c) === sectionId);\n return (comp?.getEl?.() as HTMLElement | undefined) ?? undefined;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const compiledHtml = (): string => {\n try {\n // grapesjs-mjml compiles MJML → email HTML via this command ({ html, errors }).\n const res = editor.runCommand(\"mjml-code-to-html\") as { html?: string } | undefined;\n return res?.html ?? editor.getHtml();\n } catch {\n return editor.getHtml();\n }\n };\n\n try {\n const doc = await documents.get(docId);\n loadMjml(doc.mjml);\n } catch (e) {\n toast.error(\"Failed to load the document.\");\n console.error(e);\n } finally {\n setLoading(false);\n }\n\n onReady({\n getMjml: () => editor.getHtml(),\n getCompiledHtml: compiledHtml,\n flushSave: async () => {\n if (saveTimer.current) clearTimeout(saveTimer.current);\n await save();\n },\n reloadFromDb: async () => {\n const fresh = await documents.get(docId);\n if (fresh.mjml !== editor.getHtml()) loadMjml(fresh.mjml);\n },\n highlightSection: (sectionId, on) => {\n ensureHighlightStyles();\n const el = sectionEl(sectionId);\n if (!el) return;\n el.classList.toggle(\"agent-editing\", on);\n },\n getDevices: () =>\n editor.Devices.getDevices().map((d) => ({\n id: String(d.id),\n name: d.getName() || String(d.id),\n })),\n setDevice: (name) => {\n editor.setDevice(name);\n notifyState();\n },\n undo: () => {\n editor.UndoManager.undo();\n notifyState();\n },\n redo: () => {\n editor.UndoManager.redo();\n notifyState();\n },\n setZoom: (z) => {\n editor.Canvas.setZoom?.(Math.max(25, Math.min(200, z)));\n notifyState();\n },\n setContentWidth: (w) => {\n findByTag(\"mj-body\")?.addAttributes({ width: w });\n notifyState();\n },\n onEditorState: (cb) => {\n stateListeners.current.add(cb);\n cb(snapshot());\n return () => stateListeners.current.delete(cb);\n },\n });\n };\n\n return (\n <GjsEditor\n grapesjs={grapesjs}\n className=\"h-full\"\n options={{\n height: \"100%\",\n storageManager: false,\n fromElement: false,\n panels: { defaults: [] },\n blockManager: { appendTo: \"#gjs-blocks\" },\n styleManager: { appendTo: \"#gjs-styles\" },\n traitManager: { appendTo: \"#gjs-traits\" },\n layerManager: { appendTo: \"#gjs-layers\" },\n deviceManager: {\n devices: [\n { id: \"desktop\", name: \"Desktop\", width: \"\" },\n { id: \"mobile\", name: \"Mobile\", width: \"375px\", widthMedia: \"480px\" },\n ],\n },\n plugins: [grapesjsMJML],\n }}\n onEditor={onEditor}\n >\n <div className=\"flex h-full min-h-0 flex-1\">\n <LeftSidebar\n view={sidebarView}\n onViewChange={setSidebarView}\n markLayersSource={() => (selectionSource.current = \"layers\")}\n />\n <div className=\"flex min-w-0 flex-1 flex-col bg-surface-muted\">\n <div className=\"relative min-h-0 flex-1\">\n <Canvas className=\"h-full\" />\n {/* Canvas comment layer (pins + thread popovers) overlays the canvas. */}\n <CanvasComments\n docId={docId}\n composeTarget={composeTarget}\n onComposeConsumed={() => setComposeTarget(null)}\n refreshSignal={commentsRefresh}\n onOpenCountChange={onOpenCountChange}\n />\n {loading && (\n <div className=\"absolute inset-0 z-10 flex items-center justify-center gap-2 bg-white/70 text-sm text-zinc-500\">\n <Spinner /> Loading editor…\n </div>\n )}\n </div>\n <Breadcrumb crumbs={crumbs} onSelect={(c) => editorRef.current?.select(c)} />\n </div>\n </div>\n </GjsEditor>\n );\n}\n\ntype SidebarView = \"blocks\" | \"settings\" | \"layers\";\n\n// Collapsible section — content ALWAYS mounted (appendTo target), hidden via `hidden`.\nfunction CollapseSection({\n title,\n defaultOpen = true,\n children,\n}: {\n title: string;\n defaultOpen?: boolean;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(defaultOpen);\n return (\n <div className=\"border-b border-panel-border\">\n <button\n type=\"button\"\n onClick={() => setOpen((o) => !o)}\n className=\"flex w-full items-center gap-1.5 px-3 py-2 text-xs font-semibold tracking-wide text-panel-muted-fg uppercase hover:text-panel-fg\"\n >\n <ChevronRight className={cn(\"size-3.5 transition-transform\", open && \"rotate-90\")} />\n {title}\n </button>\n <div className={cn(!open && \"hidden\")}>{children}</div>\n </div>\n );\n}\n\n// Left sidebar (dark): Blocks / Settings / Layers. All managers are always\n// mounted (appendTo targets for GrapesJS) — visibility toggled via `hidden`.\nfunction LeftSidebar({\n view,\n onViewChange,\n markLayersSource,\n}: {\n view: SidebarView;\n onViewChange: (v: SidebarView) => void;\n markLayersSource: () => void;\n}) {\n const editor = useEditorMaybe();\n const [layersExpanded, setLayersExpanded] = useState(false);\n const [blockSearch, setBlockSearch] = useState(\"\");\n\n const changeView = (v: SidebarView) => {\n if (v === \"settings\" && editor && !editor.getSelected()) {\n const wrapper = editor.getWrapper();\n const body = wrapper?.find(\"mj-body\")[0] ?? wrapper;\n if (body) editor.select(body);\n }\n onViewChange(v);\n };\n\n const toggleLayers = (expand: boolean) => {\n setLayersExpanded(expand);\n editor?.getWrapper()?.onAll((c) => c.set(\"open\", expand));\n };\n\n // Filter the GrapesJS-rendered blocks (DOM lives outside React) by label;\n // hide category groups that end up empty.\n const filterBlocks = (q: string) => {\n setBlockSearch(q);\n const root = document.getElementById(\"gjs-blocks\");\n if (!root) return;\n const term = q.trim().toLowerCase();\n root.querySelectorAll<HTMLElement>(\".gjs-block\").forEach((b) => {\n const label = (b.querySelector(\".gjs-block-label\")?.textContent ?? b.textContent ?? \"\")\n .toLowerCase()\n .trim();\n b.style.display = !term || label.includes(term) ? \"\" : \"none\";\n });\n root.querySelectorAll<HTMLElement>(\".gjs-block-category\").forEach((cat) => {\n const anyVisible = [...cat.querySelectorAll<HTMLElement>(\".gjs-block\")].some(\n (b) => b.style.display !== \"none\",\n );\n cat.style.display = anyVisible ? \"\" : \"none\";\n });\n };\n\n return (\n <div className=\"editor-dark flex w-64 shrink-0 flex-col border-r border-panel-border bg-panel text-panel-fg\">\n <div className=\"flex border-b border-panel-border\">\n {(\n [\n [\"blocks\", \"Blocks\"],\n [\"settings\", \"Settings\"],\n [\"layers\", \"Layers\"],\n ] as const\n ).map(([value, label]) => (\n <button\n key={value}\n type=\"button\"\n onClick={() => changeView(value)}\n className={cn(\n \"relative flex-1 px-3 py-2.5 text-sm transition-colors\",\n \"after:absolute after:inset-x-0 after:-bottom-px after:h-0.5 after:transition-colors\",\n view === value\n ? \"font-medium text-panel-fg after:bg-brand\"\n : \"text-panel-muted-fg after:bg-transparent hover:text-panel-fg\",\n )}\n >\n {label}\n </button>\n ))}\n </div>\n\n {/* Blocks: search + categorized block palette */}\n <div className={cn(\"flex min-h-0 flex-1 flex-col\", view !== \"blocks\" && \"hidden\")}>\n <div className=\"relative border-b border-panel-border p-2\">\n <Search className=\"pointer-events-none absolute top-1/2 left-4 size-3.5 -translate-y-1/2 text-panel-muted-fg\" />\n <Input\n value={blockSearch}\n onChange={(e) => filterBlocks(e.target.value)}\n placeholder=\"Search blocks…\"\n className=\"h-8 border-panel-border bg-panel-elevated pr-10 pl-7 text-sm text-panel-fg placeholder:text-panel-muted-fg\"\n />\n <kbd className=\"pointer-events-none absolute top-1/2 right-4 -translate-y-1/2 rounded border border-panel-border bg-panel px-1 py-0.5 font-mono text-[10px] text-panel-muted-fg\">\n ⌘K\n </kbd>\n </div>\n <div id=\"gjs-blocks\" className=\"min-h-0 flex-1 overflow-y-auto\" />\n </div>\n\n {/* Settings: Attributes + Style (collapsible, stacked) */}\n <div className={cn(\"min-h-0 flex-1 overflow-y-auto\", view !== \"settings\" && \"hidden\")}>\n <CollapseSection title=\"Attributes\">\n <div id=\"gjs-traits\" />\n </CollapseSection>\n <CollapseSection title=\"Style\">\n <div id=\"gjs-styles\" />\n </CollapseSection>\n </div>\n\n {/* Layers — with an expand/collapse-all switch. A pointer-down here marks\n the next selection as coming from the tree (→ do NOT open Settings). */}\n <div\n className={cn(\"flex min-h-0 flex-1 flex-col\", view !== \"layers\" && \"hidden\")}\n onMouseDownCapture={markLayersSource}\n >\n <label className=\"flex items-center justify-between gap-2 border-b border-panel-border px-3 py-2 text-xs text-panel-muted-fg\">\n <span>Expand all</span>\n <Switch\n checked={layersExpanded}\n onCheckedChange={toggleLayers}\n className=\"data-[state=checked]:bg-brand data-[state=unchecked]:bg-panel-border\"\n />\n </label>\n <div id=\"gjs-layers\" className=\"min-h-0 flex-1 overflow-y-auto\" />\n </div>\n </div>\n );\n}\n\n// Breadcrumb under the canvas: the selected component's ancestry (clickable).\nfunction Breadcrumb({\n crumbs,\n onSelect,\n}: {\n crumbs: Component[];\n onSelect: (c: Component) => void;\n}) {\n return (\n <div className=\"flex h-9 shrink-0 items-center gap-0.5 border-t border-border bg-surface px-3 text-xs text-muted-foreground\">\n {crumbs.length === 0 ? (\n <span className=\"text-muted-foreground/60\">Select an element…</span>\n ) : (\n crumbs.map((c, i) => (\n <span key={i} className=\"flex items-center gap-0.5\">\n {i > 0 && <ChevronRight className=\"size-3 opacity-40\" />}\n <button\n type=\"button\"\n onClick={() => onSelect(c)}\n className={cn(\n \"rounded px-1.5 py-0.5 hover:bg-muted hover:text-foreground\",\n i === crumbs.length - 1 && \"font-medium text-brand\",\n )}\n >\n {crumbName(c)}\n </button>\n </span>\n ))\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { Switch as SwitchPrimitive } from \"radix-ui\";\n\nimport { cn } from \"../../lib/utils\";\n\nfunction Switch({\n className,\n size = \"default\",\n ...props\n}: React.ComponentProps<typeof SwitchPrimitive.Root> & {\n size?: \"sm\" | \"default\";\n}) {\n return (\n <SwitchPrimitive.Root\n data-slot=\"switch\"\n data-size={size}\n className={cn(\n \"peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n <SwitchPrimitive.Thumb\n data-slot=\"switch-thumb\"\n className=\"pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground\"\n />\n </SwitchPrimitive.Root>\n );\n}\n\nexport { Switch };\n"],"mappings":"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","names":["jsx"]}
@@ -43,20 +43,8 @@ function useCommentStore() {
43
43
  return useStores().comments;
44
44
  }
45
45
 
46
- // src/starter.ts
47
- var STARTER_MJML = `<mjml>
48
- <mj-body background-color="#f4f4f5">
49
- <mj-section background-color="#ffffff" padding="32px 24px">
50
- <mj-column>
51
- <mj-text font-size="22px" font-weight="bold">New email</mj-text>
52
- <mj-text color="#555555">
53
- Describe the email you need in the chat on the right \u2014 the agent
54
- will design the sections, content and images.
55
- </mj-text>
56
- </mj-column>
57
- </mj-section>
58
- </mj-body>
59
- </mjml>`;
46
+ // src/index.ts
47
+ import { STARTER_MJML } from "@mjml-agent-editor/core";
60
48
 
61
49
  // src/components/editor/EditorHeader.tsx
62
50
  import { useEffect, useState } from "react";
@@ -1153,6 +1141,7 @@ function ToolActivity({ tools }) {
1153
1141
  function ChatPanel({
1154
1142
  docId,
1155
1143
  initialMessages,
1144
+ transport,
1156
1145
  onBeforeSend,
1157
1146
  onAgentFinish,
1158
1147
  onLiveUpdate,
@@ -1173,7 +1162,7 @@ function ChatPanel({
1173
1162
  };
1174
1163
  const { messages, sendMessage, status, stop } = useChat({
1175
1164
  messages: initialMessages,
1176
- transport: new DefaultChatTransport({
1165
+ transport: transport ?? new DefaultChatTransport({
1177
1166
  // Same-origin: the agent is a route handler in this app, not a separate service.
1178
1167
  api: "/api/chat",
1179
1168
  body: { docId }
@@ -1642,10 +1631,10 @@ export {
1642
1631
  EditorStoreProvider,
1643
1632
  useDocumentStore,
1644
1633
  useCommentStore,
1645
- STARTER_MJML,
1646
1634
  EditorHeader,
1647
1635
  Markdown,
1648
1636
  ChatPanel,
1649
- CanvasComments
1637
+ CanvasComments,
1638
+ STARTER_MJML
1650
1639
  };
1651
- //# sourceMappingURL=chunk-IO4AKLYJ.js.map
1640
+ //# sourceMappingURL=chunk-74EUKHXJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stores.tsx","../src/index.ts","../src/components/editor/EditorHeader.tsx","../src/components/ui/toggle-group.tsx","../src/components/ui/toggle.tsx","../src/components/ui/popover.tsx","../src/components/ui/tabs.tsx","../src/components/ui/dialog.tsx","../src/components/chat/ChatPanel.tsx","../src/components/ui/message.tsx","../src/components/ui/bubble.tsx","../src/components/chat/Markdown.tsx","../src/components/ui/marker.tsx","../src/components/ui/collapsible.tsx","../src/components/ui/message-scroller.tsx","../src/components/comments/CanvasComments.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * How the editor reaches its data.\n *\n * In the spike every component imported `@/lib/documents`, which imported a Supabase\n * client — so adopting the editor meant adopting Supabase, and the components could not\n * be tested without a database. They now read whatever the host provides through this\n * context, and the host is free to back it with Supabase, plain Postgres, an HTTP API or\n * an in-memory object.\n *\n * The shapes are the same `DocumentStore` and `CommentStore` the agent uses\n * (`@mjml-agent-editor/core`), so one adapter serves both sides.\n */\n\nimport type { CommentStore, DocumentStore } from \"@mjml-agent-editor/core\";\nimport { createContext, useContext, type ReactNode } from \"react\";\n\nexport interface EditorStores {\n readonly documents: DocumentStore;\n readonly comments: CommentStore;\n}\n\nconst StoreContext = createContext<EditorStores | null>(null);\n\nexport function EditorStoreProvider({\n stores,\n children,\n}: {\n stores: EditorStores;\n children: ReactNode;\n}) {\n return <StoreContext.Provider value={stores}>{children}</StoreContext.Provider>;\n}\n\nfunction useStores(): EditorStores {\n const stores = useContext(StoreContext);\n if (!stores) {\n throw new Error(\n \"The editor needs an <EditorStoreProvider>. Wrap the editor and pass a DocumentStore \" +\n \"and a CommentStore — see packages/editor/README.md.\",\n );\n }\n return stores;\n}\n\nexport function useDocumentStore(): DocumentStore {\n return useStores().documents;\n}\n\nexport function useCommentStore(): CommentStore {\n return useStores().comments;\n}\n","export {\n EditorStoreProvider,\n useCommentStore,\n useDocumentStore,\n type EditorStores,\n} from \"./stores.js\";\n\n/**\n * Re-exported from `core`, where it moved so a server could import it. Kept here because\n * removing an export is a breaking change for no gain — but a route handler should reach\n * for `@mjml-agent-editor/core`, since everything in this entry point is client-only.\n */\nexport { STARTER_MJML } from \"@mjml-agent-editor/core\";\n\nexport { default as EditorHeader } from \"./components/editor/EditorHeader.js\";\nexport { default as ChatPanel } from \"./components/chat/ChatPanel.js\";\nexport { default as CanvasComments } from \"./components/comments/CanvasComments.js\";\nexport { Markdown } from \"./components/chat/Markdown.js\";\n\n// Types only — erased at build time, so this does not pull the canvas in.\nexport type { EditorApi, EditorState, SaveStatus } from \"./components/editor/EmailEditor.js\";\n\nexport type {\n CommentStore,\n CommentTarget,\n DocumentPatch,\n DocumentStore,\n EmailDocument,\n SectionComment,\n} from \"@mjml-agent-editor/core\";\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { toast } from \"sonner\";\nimport {\n Undo2,\n Redo2,\n Code2,\n Copy,\n Eye,\n Download,\n MessageSquare,\n Mail,\n ChevronDown,\n Minus,\n Plus,\n Monitor,\n Smartphone,\n MoreVertical,\n X,\n} from \"lucide-react\";\nimport type { ReactNode } from \"react\";\n\nimport { useDocumentStore } from \"../../index.js\";\nimport type { EditorApi, EditorState, SaveStatus } from \"../editor/EmailEditor.js\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../ui/button\";\nimport { Input } from \"../ui/input\";\nimport { ToggleGroup, ToggleGroupItem } from \"../ui/toggle-group\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"../ui/tooltip\";\nimport { Badge } from \"../ui/badge\";\nimport { Spinner } from \"../ui/spinner\";\nimport { Separator } from \"../ui/separator\";\nimport { Popover, PopoverTrigger, PopoverContent } from \"../ui/popover\";\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from \"../ui/tabs\";\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"../ui/dialog\";\n\nconst SAVE_LABEL: Record<SaveStatus, string> = {\n idle: \"\",\n saving: \"Saving…\",\n saved: \"Saved\",\n error: \"Save failed\",\n};\n\nconst WIDTHS = [\"600px\", \"640px\", \"680px\", \"720px\"];\n\nconst DEVICE_ICON: Record<string, ReactNode> = {\n Desktop: <Monitor className=\"size-3.5\" />,\n Mobile: <Smartphone className=\"size-3.5\" />,\n};\n\nfunction SaveBadge({ status }: { status: SaveStatus }) {\n if (status === \"idle\") return null;\n if (status === \"saving\")\n return (\n <span className=\"flex items-center gap-1 text-xs text-panel-muted-fg\">\n <Spinner className=\"size-3\" /> {SAVE_LABEL.saving}\n </span>\n );\n if (status === \"error\") return <Badge variant=\"destructive\">{SAVE_LABEL.error}</Badge>;\n return <span className=\"text-xs text-emerald-400\">✓ {SAVE_LABEL.saved}</span>;\n}\n\nfunction slugify(name: string): string {\n return (\n name\n .trim()\n .replace(/[^\\p{L}\\p{N}]+/gu, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase() || \"email\"\n );\n}\n\nfunction download(filename: string, content: string, mime: string) {\n const blob = new Blob([content], { type: mime });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = filename;\n a.click();\n URL.revokeObjectURL(url);\n}\n\nconst darkGhost = \"text-panel-muted-fg hover:bg-panel-hover hover:text-panel-fg\";\n\nexport default function EditorHeader({\n docId,\n api,\n openCount,\n homeLink,\n}: {\n docId: string;\n api: EditorApi | null;\n openCount: number;\n /**\n * Rendered in the overflow menu as the way back out of the editor. Routing belongs to\n * the host — a Next.js app passes `<Link href=\"/\">`, anything else passes an anchor —\n * so the package does not depend on a router.\n */\n homeLink?: ReactNode;\n}) {\n // Injected by the host rather than imported, so the header carries no database.\n const documents = useDocumentStore();\n const [name, setName] = useState(\"\");\n const [state, setState] = useState<EditorState>({\n device: \"Desktop\",\n canUndo: false,\n canRedo: false,\n saveStatus: \"idle\",\n zoom: 100,\n contentWidth: \"600px\",\n });\n const [code, setCode] = useState({ mjml: \"\", html: \"\" });\n const [preview, setPreview] = useState(\"\");\n\n useEffect(() => {\n documents\n .get(docId)\n .then((d) => setName(d.name))\n .catch(() => {});\n }, [docId, documents]);\n\n useEffect(() => {\n if (!api) return;\n return api.onEditorState(setState);\n }, [api]);\n\n const commitName = async () => {\n const n = name.trim() || \"Untitled\";\n setName(n);\n try {\n await documents.save(docId, { name: n });\n } catch {\n toast.error(\"Failed to rename.\");\n }\n };\n\n const devices = api?.getDevices() ?? [];\n const base = slugify(name);\n\n const openCode = () =>\n setCode({ mjml: api?.getMjml() ?? \"\", html: api?.getCompiledHtml() ?? \"\" });\n\n return (\n <header className=\"flex h-14 shrink-0 items-center gap-2 border-b border-panel-border bg-panel px-3 text-panel-fg\">\n {/* Logo + document name */}\n <span className=\"flex size-8 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-brand to-indigo-400 text-brand-fg shadow-sm\">\n <Mail className=\"size-4\" />\n </span>\n <span className=\"hidden text-sm font-semibold sm:inline\">MJML Editor</span>\n <Separator orientation=\"vertical\" className=\"mx-1 !h-5 bg-panel-border\" />\n <Input\n value={name}\n onChange={(e) => setName(e.target.value)}\n onBlur={() => void commitName()}\n onKeyDown={(e) => e.key === \"Enter\" && e.currentTarget.blur()}\n className=\"h-8 w-44 border-transparent bg-transparent text-sm font-medium text-panel-fg hover:border-panel-border focus-visible:border-panel-border\"\n aria-label=\"Email name\"\n />\n\n <Separator orientation=\"vertical\" className=\"mx-1 !h-5 bg-panel-border\" />\n\n {devices.length > 0 && (\n <ToggleGroup\n type=\"single\"\n size=\"sm\"\n value={state.device}\n onValueChange={(v) => v && api?.setDevice(v)}\n className=\"rounded-md border border-panel-border\"\n >\n {devices.map((d) => (\n <ToggleGroupItem\n key={d.id}\n value={d.name}\n className=\"gap-1.5 px-2.5 text-panel-muted-fg data-[state=on]:bg-panel-elevated data-[state=on]:text-panel-fg\"\n >\n {DEVICE_ICON[d.name]}\n {d.name}\n </ToggleGroupItem>\n ))}\n </ToggleGroup>\n )}\n\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={darkGhost}\n disabled={!state.canUndo}\n onClick={() => api?.undo()}\n >\n <Undo2 />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Undo</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={darkGhost}\n disabled={!state.canRedo}\n onClick={() => api?.redo()}\n >\n <Redo2 />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Redo</TooltipContent>\n </Tooltip>\n\n {/* Content width */}\n <Separator orientation=\"vertical\" className=\"mx-1 !h-5 bg-panel-border max-xl:hidden\" />\n <Popover>\n <PopoverTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className={cn(darkGhost, \"gap-1.5 rounded-md border border-panel-border max-xl:hidden\")}\n >\n <span className=\"text-panel-muted-fg\">Content width</span>\n {state.contentWidth}\n <ChevronDown className=\"size-3.5\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-40 p-1\">\n {WIDTHS.map((w) => (\n <button\n key={w}\n onClick={() => api?.setContentWidth(w)}\n className={cn(\n \"flex w-full items-center justify-between rounded px-2 py-1.5 text-sm hover:bg-muted\",\n state.contentWidth === w && \"font-medium text-brand\",\n )}\n >\n {w}\n </button>\n ))}\n </PopoverContent>\n </Popover>\n\n {/* Zoom */}\n <div className=\"flex items-center gap-0.5 rounded-md border border-panel-border px-0.5 max-xl:hidden\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={cn(darkGhost, \"size-7\")}\n onClick={() => api?.setZoom(state.zoom - 10)}\n >\n <Minus className=\"size-3.5\" />\n </Button>\n <span className=\"w-10 text-center text-xs tabular-nums text-panel-muted-fg\">\n {state.zoom}%\n </span>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className={cn(darkGhost, \"size-7\")}\n onClick={() => api?.setZoom(state.zoom + 10)}\n >\n <Plus className=\"size-3.5\" />\n </Button>\n </div>\n\n {/* Right group */}\n <div className=\"ml-auto flex items-center gap-2\">\n {openCount > 0 && (\n <span className=\"flex items-center gap-1 text-xs text-panel-muted-fg\">\n <MessageSquare className=\"size-3.5\" /> {openCount}\n </span>\n )}\n <SaveBadge status={state.saveStatus} />\n\n {/* Full-screen preview */}\n <Dialog>\n <DialogTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className={cn(darkGhost, \"gap-1.5\")}\n onClick={() => setPreview(api?.getCompiledHtml() ?? \"\")}\n >\n <Eye /> Preview\n </Button>\n </DialogTrigger>\n <DialogContent\n // The dialog's own close button is absolutely positioned top-right, where it\n // sits on top of \"Export HTML\". Replaced by one inside the toolbar flow.\n showCloseButton={false}\n className=\"flex !max-w-none h-screen w-screen flex-col gap-0 rounded-none border-0 bg-zinc-100 p-0 sm:rounded-none\"\n >\n <div className=\"flex h-12 shrink-0 items-center justify-between border-b bg-white px-4\">\n <DialogTitle className=\"text-sm\">Preview — {name}</DialogTitle>\n <div className=\"flex items-center gap-2\">\n {devices.length > 0 && (\n <ToggleGroup\n type=\"single\"\n size=\"sm\"\n value={state.device}\n onValueChange={(v) => v && api?.setDevice(v)}\n variant=\"outline\"\n >\n {devices.map((d) => (\n <ToggleGroupItem key={d.id} value={d.name} className=\"px-2.5\">\n {d.name}\n </ToggleGroupItem>\n ))}\n </ToggleGroup>\n )}\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => download(`${base}.html`, preview, \"text/html\")}\n >\n <Download /> Export HTML\n </Button>\n <DialogClose asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label=\"Close preview\">\n <X />\n </Button>\n </DialogClose>\n </div>\n </div>\n <div className=\"min-h-0 flex-1 overflow-auto p-6\">\n <iframe\n title=\"Email preview\"\n srcDoc={preview}\n className={cn(\n \"mx-auto block h-full min-h-[80vh] rounded-md border bg-white shadow-sm\",\n state.device === \"Mobile\" ? \"w-[375px]\" : \"w-full max-w-[720px]\",\n )}\n />\n </div>\n </DialogContent>\n </Dialog>\n\n {/* Code (MJML + HTML) */}\n <Dialog>\n <DialogTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className={cn(darkGhost, \"gap-1.5\")}\n onClick={openCode}\n >\n <Code2 /> Code\n </Button>\n </DialogTrigger>\n <DialogContent className=\"flex !max-w-4xl flex-col\">\n <DialogHeader>\n <DialogTitle>Source code</DialogTitle>\n </DialogHeader>\n <Tabs defaultValue=\"mjml\" className=\"min-h-0 flex-1\">\n <TabsList>\n <TabsTrigger value=\"mjml\">MJML</TabsTrigger>\n <TabsTrigger value=\"html\">HTML</TabsTrigger>\n </TabsList>\n {([\"mjml\", \"html\"] as const).map((kind) => (\n <TabsContent key={kind} value={kind} className=\"mt-2\">\n <pre className=\"max-h-[62vh] overflow-auto rounded-md border bg-muted/40 p-3 text-xs leading-relaxed break-all whitespace-pre-wrap\">\n {code[kind]}\n </pre>\n <div className=\"mt-2 flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() =>\n download(\n `${base}.${kind}`,\n code[kind],\n kind === \"html\" ? \"text/html\" : \"text/plain\",\n )\n }\n >\n <Download /> Download .{kind}\n </Button>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => {\n void navigator.clipboard?.writeText(code[kind]);\n toast.success(`${kind.toUpperCase()} copied.`);\n }}\n >\n <Copy /> Copy\n </Button>\n </div>\n </TabsContent>\n ))}\n </Tabs>\n </DialogContent>\n </Dialog>\n\n {/* Export split-button (HTML / MJML), file named from the project */}\n <Popover>\n <PopoverTrigger asChild>\n <Button size=\"sm\" className=\"gap-1.5 bg-brand text-brand-fg hover:bg-brand/90\">\n <Download /> Export\n <ChevronDown className=\"size-3.5\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-52 p-1\">\n <button\n onClick={() => download(`${base}.html`, api?.getCompiledHtml() ?? \"\", \"text/html\")}\n className=\"flex w-full flex-col rounded px-2 py-1.5 text-left text-sm hover:bg-muted\"\n >\n <span className=\"font-medium\">Export HTML</span>\n <span className=\"text-xs text-muted-foreground\">{base}.html</span>\n </button>\n <button\n onClick={() => download(`${base}.mjml`, api?.getMjml() ?? \"\", \"text/plain\")}\n className=\"flex w-full flex-col rounded px-2 py-1.5 text-left text-sm hover:bg-muted\"\n >\n <span className=\"font-medium\">Export MJML</span>\n <span className=\"text-xs text-muted-foreground\">{base}.mjml</span>\n </button>\n </PopoverContent>\n </Popover>\n\n {/* Overflow menu */}\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className={darkGhost}>\n <MoreVertical />\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-44 p-1\">\n {homeLink}\n </PopoverContent>\n </Popover>\n </div>\n </header>\n );\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { type VariantProps } from \"class-variance-authority\";\nimport { ToggleGroup as ToggleGroupPrimitive } from \"radix-ui\";\n\nimport { cn } from \"../../lib/utils\";\nimport { toggleVariants } from \"./toggle\";\n\nconst ToggleGroupContext = React.createContext<\n VariantProps<typeof toggleVariants> & {\n spacing?: number;\n orientation?: \"horizontal\" | \"vertical\";\n }\n>({\n size: \"default\",\n variant: \"default\",\n spacing: 2,\n orientation: \"horizontal\",\n});\n\nfunction ToggleGroup({\n className,\n variant,\n size,\n spacing = 2,\n orientation = \"horizontal\",\n children,\n ...props\n}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &\n VariantProps<typeof toggleVariants> & {\n spacing?: number;\n orientation?: \"horizontal\" | \"vertical\";\n }) {\n return (\n <ToggleGroupPrimitive.Root\n data-slot=\"toggle-group\"\n data-variant={variant}\n data-size={size}\n data-spacing={spacing}\n data-orientation={orientation}\n style={{ \"--gap\": spacing } as React.CSSProperties}\n className={cn(\n \"group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] rounded-lg data-[size=sm]:rounded-[min(var(--radius-md),10px)] data-vertical:flex-col data-vertical:items-stretch\",\n className,\n )}\n {...props}\n >\n <ToggleGroupContext.Provider value={{ variant, size, spacing, orientation }}>\n {children}\n </ToggleGroupContext.Provider>\n </ToggleGroupPrimitive.Root>\n );\n}\n\nfunction ToggleGroupItem({\n className,\n children,\n variant = \"default\",\n size = \"default\",\n ...props\n}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> & VariantProps<typeof toggleVariants>) {\n const context = React.useContext(ToggleGroupContext);\n\n return (\n <ToggleGroupPrimitive.Item\n data-slot=\"toggle-group-item\"\n data-variant={context.variant || variant}\n data-size={context.size || size}\n data-spacing={context.spacing}\n className={cn(\n \"shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 focus:z-10 focus-visible:z-10 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-lg group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t\",\n toggleVariants({\n variant: context.variant || variant,\n size: context.size || size,\n }),\n className,\n )}\n {...props}\n >\n {children}\n </ToggleGroupPrimitive.Item>\n );\n}\n\nexport { ToggleGroup, ToggleGroupItem };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Toggle as TogglePrimitive } from \"radix-ui\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst toggleVariants = cva(\n \"group/toggle inline-flex items-center justify-center gap-1 rounded-lg text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n outline: \"border border-input bg-transparent hover:bg-muted\",\n },\n size: {\n default:\n \"h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n sm: \"h-7 min-w-7 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n lg: \"h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nfunction Toggle({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: React.ComponentProps<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants>) {\n return (\n <TogglePrimitive.Root\n data-slot=\"toggle\"\n className={cn(toggleVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nexport { Toggle, toggleVariants };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { Popover as PopoverPrimitive } from \"radix-ui\";\n\nimport { cn } from \"../../lib/utils\";\n\nfunction Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />;\n}\n\nfunction PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />;\n}\n\nfunction PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />;\n}\n\nfunction PopoverContent({\n className,\n align = \"center\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content>) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden\",\n className,\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n );\n}\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Tabs as TabsPrimitive } from \"radix-ui\";\n\nimport { cn } from \"../../lib/utils\";\n\nfunction Tabs({\n className,\n orientation = \"horizontal\",\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Root>) {\n return (\n <TabsPrimitive.Root\n data-slot=\"tabs\"\n data-orientation={orientation}\n className={cn(\"group/tabs flex gap-2 data-horizontal:flex-col\", className)}\n {...props}\n />\n );\n}\n\nconst tabsListVariants = cva(\n \"group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none\",\n {\n variants: {\n variant: {\n default: \"bg-muted\",\n line: \"gap-1 bg-transparent\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nfunction TabsList({\n className,\n variant = \"default\",\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.List> & VariantProps<typeof tabsListVariants>) {\n return (\n <TabsPrimitive.List\n data-slot=\"tabs-list\"\n data-variant={variant}\n className={cn(tabsListVariants({ variant }), className)}\n {...props}\n />\n );\n}\n\nfunction TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n return (\n <TabsPrimitive.Trigger\n data-slot=\"tabs-trigger\"\n className={cn(\n \"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n \"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent\",\n \"data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground\",\n \"after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Content>) {\n return (\n <TabsPrimitive.Content\n data-slot=\"tabs-content\"\n className={cn(\"flex-1 text-sm outline-none\", className)}\n {...props}\n />\n );\n}\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { Dialog as DialogPrimitive } from \"radix-ui\";\n\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"./button\";\nimport { XIcon } from \"lucide-react\";\n\nfunction Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n return (\n <DialogPrimitive.Overlay\n data-slot=\"dialog-overlay\"\n className={cn(\n \"fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n}) {\n return (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n className={cn(\n \"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close data-slot=\"dialog-close\" asChild>\n <Button variant=\"ghost\" className=\"absolute top-2 right-2\" size=\"icon-sm\">\n <XIcon />\n <span className=\"sr-only\">Close</span>\n </Button>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div data-slot=\"dialog-header\" className={cn(\"flex flex-col gap-2\", className)} {...props} />\n );\n}\n\nfunction DialogFooter({\n className,\n showCloseButton = false,\n children,\n ...props\n}: React.ComponentProps<\"div\"> & {\n showCloseButton?: boolean;\n}) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n \"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end\",\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close asChild>\n <Button variant=\"outline\">Close</Button>\n </DialogPrimitive.Close>\n )}\n </div>\n );\n}\n\nfunction DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn(\"font-heading text-base leading-none font-medium\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\n \"text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n","\"use client\";\n\nimport { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport, type ChatTransport, type ToolUIPart, type UIMessage } from \"ai\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { toast } from \"sonner\";\nimport {\n Check,\n Loader2,\n TriangleAlert,\n Send,\n Square,\n Sparkles,\n MessageSquare,\n ChevronRight,\n} from \"lucide-react\";\n\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../ui/button\";\nimport { Textarea } from \"../ui/textarea\";\nimport { Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription } from \"../ui/empty\";\nimport { Message, MessageContent } from \"../ui/message\";\nimport { Bubble, BubbleContent } from \"../ui/bubble\";\nimport { Markdown } from \"../chat/Markdown.js\";\nimport { Marker, MarkerIcon, MarkerContent } from \"../ui/marker\";\nimport { Collapsible, CollapsibleTrigger, CollapsibleContent } from \"../ui/collapsible\";\nimport {\n MessageScrollerProvider,\n MessageScroller,\n MessageScrollerViewport,\n MessageScrollerContent,\n MessageScrollerItem,\n MessageScrollerButton,\n} from \"../ui/message-scroller\";\n\nconst TOOL_LABELS: Record<string, string> = {\n get_document: \"Reading document\",\n get_section: \"Reading section\",\n set_document: \"Saving whole email\",\n set_section: \"Replacing section\",\n insert_section: \"Adding section\",\n remove_section: \"Removing section\",\n generate_image: \"Generating image\",\n list_open_comments: \"Reading comments\",\n resolve_comment: \"Resolving comment\",\n};\n\nconst APPLY_COMMENTS_PROMPT =\n \"Apply changes based on all open section comments. \" +\n \"After each successful change mark the comment as resolved and summarize what you changed.\";\n\n// Tools that mutate the document or comments — after each of them we refresh\n// the preview/panel live, without waiting for the agent's turn to finish.\nconst MUTATING_TOOLS = new Set([\n \"set_document\",\n \"set_section\",\n \"insert_section\",\n \"remove_section\",\n \"resolve_comment\",\n]);\n\n// Tools that edit a specific section → name of the argument holding its section_id.\n// Used to highlight that section while it is being edited.\nconst SECTION_ARG: Record<string, string> = {\n set_section: \"section_id\",\n remove_section: \"section_id\",\n insert_section: \"after_section_id\",\n};\n\ntype Props = {\n docId: string;\n /**\n * Conversation to start from, oldest first.\n *\n * Only useful to a host that stores the conversation server-side. Without it the panel\n * mounts empty, which is right when the browser is the only place the history ever\n * lived — and wrong, invisibly, when it is not: the agent still receives the stored\n * history on the next turn, so the model remembers a conversation the visitor is\n * looking at an empty panel for.\n */\n initialMessages?: UIMessage[];\n /**\n * Where the panel sends turns. Defaults to `POST /api/chat` in this application.\n *\n * Supplying one replaces the endpoint entirely, which is how a host reaches an agent that\n * is not a same-origin route — and how the scripted demo drives this panel from a\n * recorded transcript without making any request at all.\n *\n * Memoize it. A transport carrying state — a playback position, an open connection —\n * restarts if it is rebuilt on every render.\n */\n transport?: ChatTransport<UIMessage>;\n /** Flushes unsaved editor changes before the agent starts. */\n onBeforeSend: () => Promise<void>;\n /** After the agent's turn finishes (refresh the editor and comments). */\n onAgentFinish: () => void;\n /** After each single agent edit (mutating tool call) — live reload. */\n onLiveUpdate: () => void;\n /** Agent started editing a section (highlight it). */\n onSectionEditStart: (sectionId: string) => void;\n /** Agent finished editing a section (remove the highlight). */\n onSectionEditEnd: (sectionId: string) => void;\n};\n\nfunction ToolMarker({ tool }: { tool: ToolUIPart }) {\n const name = tool.type.slice(5);\n const done = tool.state === \"output-available\";\n const failed = tool.state === \"output-error\";\n return (\n <Marker className={cn(failed ? \"text-destructive\" : \"text-panel-fg\")}>\n <MarkerIcon>\n {failed ? (\n <TriangleAlert />\n ) : done ? (\n <Check className=\"text-emerald-400\" />\n ) : (\n <Loader2 className=\"animate-spin\" />\n )}\n </MarkerIcon>\n <MarkerContent>\n {TOOL_LABELS[name] ?? name}\n {failed && tool.errorText ? `: ${tool.errorText}` : \"\"}\n </MarkerContent>\n </Marker>\n );\n}\n\n// \"Agent is working…\" indicator — rendered either inside the current assistant\n// message (tight under the steps) or standalone when the assistant hasn't started writing yet.\nfunction BusyMarker() {\n return (\n <Marker className=\"text-panel-fg\">\n <MarkerIcon>\n <Loader2 className=\"animate-spin\" />\n </MarkerIcon>\n <MarkerContent>Agent is working…</MarkerContent>\n </Marker>\n );\n}\n\n// Tool activity: in-progress tasks visible; finished and failed ones collapsed underneath.\nfunction ToolActivity({ tools }: { tools: ToolUIPart[] }) {\n const running = tools.filter((t) => t.state !== \"output-available\" && t.state !== \"output-error\");\n const finished = tools.filter(\n (t) => t.state === \"output-available\" || t.state === \"output-error\",\n );\n const failedCount = finished.filter((t) => t.state === \"output-error\").length;\n\n return (\n <div className=\"space-y-1 rounded-lg border border-panel-border bg-panel-elevated/60 p-2\">\n {finished.length > 0 && (\n <Collapsible defaultOpen>\n <CollapsibleTrigger className=\"group/col flex w-full items-center gap-1.5 text-left text-xs font-medium text-panel-fg hover:text-panel-fg\">\n <ChevronRight className=\"size-3.5 shrink-0 transition-transform group-data-[state=open]/col:rotate-90\" />\n <span>\n {failedCount > 0\n ? `Completed steps (${finished.length}, ${failedCount} failed)`\n : `Completed steps (${finished.length})`}\n </span>\n </CollapsibleTrigger>\n <CollapsibleContent className=\"mt-1 space-y-0.5 pl-1\">\n {finished.map((t, i) => (\n <ToolMarker key={`f${i}`} tool={t} />\n ))}\n </CollapsibleContent>\n </Collapsible>\n )}\n {running.map((t, i) => (\n <ToolMarker key={`r${i}`} tool={t} />\n ))}\n </div>\n );\n}\n\nexport default function ChatPanel({\n docId,\n initialMessages,\n transport,\n onBeforeSend,\n onAgentFinish,\n onLiveUpdate,\n onSectionEditStart,\n onSectionEditEnd,\n}: Props) {\n const [input, setInput] = useState(\"\");\n const taRef = useRef<HTMLTextAreaElement>(null);\n // Per-message timestamp, stamped when the message first renders.\n const times = useRef<Map<string, string>>(new Map());\n const timeFor = (id: string) => {\n if (!times.current.has(id)) {\n times.current.set(\n id,\n new Date().toLocaleTimeString([], { hour: \"2-digit\", minute: \"2-digit\" }),\n );\n }\n return times.current.get(id)!;\n };\n const { messages, sendMessage, status, stop } = useChat({\n messages: initialMessages,\n transport:\n transport ??\n new DefaultChatTransport({\n // Same-origin: the agent is a route handler in this app, not a separate service.\n api: \"/api/chat\",\n body: { docId },\n }),\n onFinish: onAgentFinish,\n onError: (e) => {\n console.error(\"chat error:\", e);\n toast.error(\"Agent chat error.\");\n },\n });\n\n // Reactions to the agent's tool calls (deduped by message:part key):\n // - section edit started (section_id known, tool not finished yet) → highlight\n // - mutating tool call finished → live-reload the preview + remove the highlight\n const firedTools = useRef<Set<string>>(new Set());\n const highlightStarted = useRef<Map<string, string>>(new Map());\n const highlightEnded = useRef<Set<string>>(new Set());\n useEffect(() => {\n for (const message of messages) {\n if (message.role !== \"assistant\") continue;\n message.parts.forEach((part, i) => {\n if (!part.type.startsWith(\"tool-\")) return;\n const tool = part as ToolUIPart;\n const name = tool.type.slice(5);\n const key = `${message.id}:${i}`;\n const done = tool.state === \"output-available\" || tool.state === \"output-error\";\n\n // start the highlight — when we know the section_id and the tool is still running\n const argName = SECTION_ARG[name];\n if (argName && !done && !highlightStarted.current.has(key)) {\n const sid = (tool.input as Record<string, unknown> | undefined)?.[argName];\n if (typeof sid === \"string\" && sid) {\n highlightStarted.current.set(key, sid);\n onSectionEditStart(sid);\n }\n }\n\n if (!done) return;\n\n // remove the section highlight (before the reload, which rebuilds the canvas anyway)\n const startedSid = highlightStarted.current.get(key);\n if (startedSid && !highlightEnded.current.has(key)) {\n highlightEnded.current.add(key);\n onSectionEditEnd(startedSid);\n }\n // mutating tool call finished → live reload\n if (MUTATING_TOOLS.has(name) && !firedTools.current.has(key)) {\n firedTools.current.add(key);\n onLiveUpdate();\n }\n });\n }\n }, [messages, onLiveUpdate, onSectionEditStart, onSectionEditEnd]);\n\n const busy = status === \"submitted\" || status === \"streaming\";\n\n // Whether any tool is in progress (to avoid duplicating the global \"Agent is working…\").\n const lastMsg = messages[messages.length - 1];\n const toolRunning =\n lastMsg?.role === \"assistant\" &&\n lastMsg.parts.some((p) => {\n if (!p.type.startsWith(\"tool-\")) return false;\n const s = (p as ToolUIPart).state;\n return s !== \"output-available\" && s !== \"output-error\";\n });\n\n const grow = () => {\n const el = taRef.current;\n if (!el) return;\n el.style.height = \"auto\";\n el.style.height = `${Math.min(el.scrollHeight, 160)}px`;\n };\n\n const send = async (text: string) => {\n const trimmed = text.trim();\n if (!trimmed || busy) return;\n await onBeforeSend().catch(console.error);\n void sendMessage({ text: trimmed });\n setInput(\"\");\n if (taRef.current) taRef.current.style.height = \"auto\";\n };\n\n return (\n <div className=\"flex h-full flex-col\">\n <MessageScrollerProvider autoScroll>\n <MessageScroller className=\"flex-1\">\n <MessageScrollerViewport>\n <MessageScrollerContent className=\"p-3\">\n {messages.length === 0 ? (\n <Empty className=\"h-full\">\n <EmptyHeader>\n <EmptyMedia variant=\"icon\">\n <MessageSquare />\n </EmptyMedia>\n <EmptyTitle>Start a conversation with the agent</EmptyTitle>\n <EmptyDescription>\n Describe the email (goal, tone, content) and paste your data — the agent will\n design the sections and images.\n </EmptyDescription>\n </EmptyHeader>\n </Empty>\n ) : (\n messages.map((message, mi) => {\n const isUser = message.role === \"user\";\n const isLast = mi === messages.length - 1;\n const toolParts = message.parts.filter((p) =>\n p.type.startsWith(\"tool-\"),\n ) as ToolUIPart[];\n // Skip empty text parts — while streaming, the SDK appends an\n // empty text part that used to render as an empty bubble\n // (an unwanted gap above \"Agent is working…\").\n const textParts = message.parts.filter(\n (p) => p.type === \"text\" && p.text.trim() !== \"\",\n );\n return (\n <MessageScrollerItem key={message.id} messageId={message.id}>\n <div className={cn(\"flex w-full gap-2\", isUser && \"flex-row-reverse\")}>\n {!isUser && (\n <span className=\"mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-full bg-brand/15 text-brand\">\n <Sparkles className=\"size-3.5\" />\n </span>\n )}\n <div\n className={cn(\n \"flex min-w-0 flex-1 flex-col gap-1\",\n isUser ? \"items-end\" : \"items-start\",\n )}\n >\n <Message align={isUser ? \"end\" : \"start\"}>\n <MessageContent>\n {toolParts.length > 0 && <ToolActivity tools={toolParts} />}\n {textParts.map((part, i) => (\n <Bubble\n key={i}\n variant={isUser ? \"default\" : \"muted\"}\n align={isUser ? \"end\" : \"start\"}\n className={cn(\n isUser\n ? \"[&_[data-slot=bubble-content]]:bg-brand [&_[data-slot=bubble-content]]:text-brand-fg\"\n : \"[&_[data-slot=bubble-content]]:border [&_[data-slot=bubble-content]]:border-panel-border [&_[data-slot=bubble-content]]:bg-panel-elevated [&_[data-slot=bubble-content]]:text-panel-fg [&_code]:!bg-white/12 [&_pre]:!bg-white/10 [&_a]:text-brand\",\n )}\n >\n <BubbleContent\n className={isUser ? \"whitespace-pre-wrap\" : undefined}\n >\n {isUser && part.type === \"text\" ? (\n part.text\n ) : part.type === \"text\" ? (\n <Markdown>{part.text}</Markdown>\n ) : null}\n </BubbleContent>\n </Bubble>\n ))}\n {/* Busy indicator as part of the assistant's current turn —\n tight spacing (gap-2.5). Hidden once text is already\n streaming (textParts not empty) — keeps things clean. */}\n {isLast &&\n !isUser &&\n busy &&\n !toolRunning &&\n textParts.length === 0 && <BusyMarker />}\n </MessageContent>\n </Message>\n {(textParts.length > 0 || toolParts.length > 0) && (\n <span className=\"px-1 text-[10px] text-panel-muted-fg\">\n {timeFor(message.id)}\n </span>\n )}\n </div>\n </div>\n </MessageScrollerItem>\n );\n })\n )}\n {/* Fallback: the agent hasn't created a message yet (last one is the user's). */}\n {busy && !toolRunning && lastMsg?.role !== \"assistant\" && <BusyMarker />}\n </MessageScrollerContent>\n </MessageScrollerViewport>\n <MessageScrollerButton direction=\"end\" />\n </MessageScroller>\n </MessageScrollerProvider>\n\n <div className=\"border-t border-panel-border p-3\">\n <Button\n className=\"mb-2 w-full bg-brand text-brand-fg hover:bg-brand/90\"\n disabled={busy}\n onClick={() => void send(APPLY_COMMENTS_PROMPT)}\n >\n <Sparkles /> Apply changes from comments\n </Button>\n <form\n onSubmit={(e) => {\n e.preventDefault();\n void send(input);\n }}\n className=\"rounded-xl border border-panel-border bg-panel-elevated transition-colors focus-within:border-brand/60\"\n >\n <Textarea\n ref={taRef}\n rows={2}\n className=\"max-h-40 min-h-14 resize-none border-0 bg-transparent px-3 pt-2.5 text-panel-fg shadow-none placeholder:text-panel-muted-fg focus-visible:ring-0\"\n placeholder=\"Describe what you want to change… (Enter = send, Shift+Enter = new line)\"\n value={input}\n onChange={(e) => {\n setInput(e.target.value);\n grow();\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n void send(input);\n }\n }}\n />\n <div className=\"flex items-center justify-end gap-2 px-2 pb-2\">\n {busy && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"border-panel-border bg-transparent text-panel-fg hover:bg-panel-hover hover:text-panel-fg\"\n onClick={() => void stop()}\n >\n <Square /> Stop\n </Button>\n )}\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={busy || !input.trim()}\n className=\"bg-brand text-brand-fg hover:bg-brand/90\"\n >\n <Send /> Send\n </Button>\n </div>\n </form>\n </div>\n </div>\n );\n}\n","import * as React from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nfunction MessageGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"message-group\"\n className={cn(\"flex min-w-0 flex-col gap-2\", className)}\n {...props}\n />\n );\n}\n\nfunction Message({\n className,\n align = \"start\",\n ...props\n}: React.ComponentProps<\"div\"> & { align?: \"start\" | \"end\" }) {\n return (\n <div\n data-slot=\"message\"\n data-align={align}\n className={cn(\n \"group/message relative flex w-full min-w-0 gap-2 text-sm data-[align=end]:flex-row-reverse\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MessageAvatar({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"message-avatar\"\n className={cn(\n \"flex w-fit min-w-8 shrink-0 items-center justify-center self-end overflow-hidden rounded-full bg-muted group-has-data-[slot=message-footer]/message:-translate-y-8\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MessageContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"message-content\"\n className={cn(\n \"flex w-full min-w-0 flex-col gap-2.5 wrap-break-word group-data-[align=end]/message:*:data-slot:self-end\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MessageHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"message-header\"\n className={cn(\n \"flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MessageFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"message-footer\"\n className={cn(\n \"flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0 group-data-[align=end]/message:justify-end\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { MessageGroup, Message, MessageAvatar, MessageContent, MessageFooter, MessageHeader };\n","import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Slot } from \"radix-ui\";\n\nimport { cn } from \"../../lib/utils\";\n\nfunction BubbleGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"bubble-group\"\n className={cn(\"flex min-w-0 flex-col gap-2\", className)}\n {...props}\n />\n );\n}\n\nconst bubbleVariants = cva(\n \"group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full\",\n {\n variants: {\n variant: {\n default:\n \"*:data-[slot=bubble-content]:bg-primary *:data-[slot=bubble-content]:text-primary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-primary/80\",\n secondary:\n \"*:data-[slot=bubble-content]:bg-secondary *:data-[slot=bubble-content]:text-secondary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]\",\n muted:\n \"*:data-[slot=bubble-content]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--muted),var(--foreground)_5%)]\",\n tinted:\n \"*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.93_calc(c*0.4)_h)] *:data-[slot=bubble-content]:text-foreground dark:*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.3_calc(c*0.4)_h)] [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.88_calc(c*0.5)_h)] dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.35_calc(c*0.5)_h)]\",\n outline:\n \"*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-background [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-input/30\",\n ghost:\n \"border-none *:data-[slot=bubble-content]:rounded-none *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted/50\",\n destructive:\n \"*:data-[slot=bubble-content]:bg-destructive/10 *:data-[slot=bubble-content]:text-destructive dark:*:data-[slot=bubble-content]:bg-destructive/20 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/20 dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/30\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nfunction Bubble({\n variant = \"default\",\n align = \"start\",\n className,\n ...props\n}: React.ComponentProps<\"div\"> &\n VariantProps<typeof bubbleVariants> & {\n align?: \"start\" | \"end\";\n }) {\n return (\n <div\n data-slot=\"bubble\"\n data-variant={variant}\n data-align={align}\n className={cn(bubbleVariants({ variant }), className)}\n {...props}\n />\n );\n}\n\nfunction BubbleContent({\n asChild = false,\n className,\n ...props\n}: React.ComponentProps<\"div\"> & {\n asChild?: boolean;\n}) {\n const Comp = asChild ? Slot.Root : \"div\";\n\n return (\n <Comp\n data-slot=\"bubble-content\"\n className={cn(\n \"w-fit max-w-full min-w-0 overflow-hidden rounded-xl border border-transparent px-3 py-2 text-sm leading-relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:border-ring [button,a]:focus-visible:ring-3 [button,a]:focus-visible:ring-ring/50\",\n className,\n )}\n {...props}\n />\n );\n}\n\nconst bubbleReactionsVariants = cva(\n \"absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-sm ring-3 ring-card has-[button]:p-0\",\n {\n variants: {\n side: {\n top: \"top-0 -translate-y-3/4\",\n bottom: \"bottom-0 translate-y-3/4\",\n },\n align: {\n start: \"left-3\",\n end: \"right-3\",\n },\n },\n defaultVariants: {\n side: \"bottom\",\n align: \"end\",\n },\n },\n);\n\nfunction BubbleReactions({\n side = \"bottom\",\n align = \"end\",\n className,\n ...props\n}: React.ComponentProps<\"div\"> & {\n align?: \"start\" | \"end\";\n side?: \"top\" | \"bottom\";\n}) {\n return (\n <div\n data-slot=\"bubble-reactions\"\n data-align={align}\n data-side={side}\n className={cn(bubbleReactionsVariants({ side, align }), className)}\n {...props}\n />\n );\n}\n\nexport { BubbleGroup, Bubble, BubbleContent, BubbleReactions };\n","\"use client\";\n\nimport { memo } from \"react\";\nimport ReactMarkdown, { type Components } from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\n\nimport { cn } from \"../../lib/utils\";\n\n// Agent links open in a new tab (don't navigate away from the editor).\nconst components: Components = {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n a: ({ node, ...props }) => <a target=\"_blank\" rel=\"noopener noreferrer\" {...props} />,\n};\n\nfunction MarkdownImpl({ children }: { children: string }) {\n return (\n <div\n className={cn(\n \"text-sm leading-relaxed break-words\",\n \"[&>:first-child]:mt-0 [&>:last-child]:mb-0\",\n \"[&_p]:my-1.5\",\n \"[&_ul]:my-1.5 [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:my-1.5 [&_ol]:list-decimal [&_ol]:pl-5\",\n \"[&_li]:my-0.5 [&_li>ul]:my-0.5 [&_li>ol]:my-0.5\",\n \"[&_strong]:font-semibold [&_em]:italic\",\n \"[&_a]:underline [&_a]:underline-offset-2\",\n \"[&_h1]:mt-2 [&_h1]:mb-1 [&_h1]:text-base [&_h1]:font-semibold\",\n \"[&_h2]:mt-2 [&_h2]:mb-1 [&_h2]:text-sm [&_h2]:font-semibold\",\n \"[&_h3]:mt-2 [&_h3]:mb-1 [&_h3]:text-sm [&_h3]:font-semibold\",\n \"[&_code]:rounded [&_code]:bg-black/5 [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.85em]\",\n \"[&_pre]:my-1.5 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-black/5 [&_pre]:p-2 [&_pre]:text-xs\",\n \"[&_pre_code]:bg-transparent [&_pre_code]:p-0\",\n \"[&_blockquote]:my-1.5 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground\",\n \"[&_hr]:my-2 [&_hr]:border-border\",\n \"[&_table]:my-1.5 [&_table]:w-full [&_table]:border-collapse [&_table]:text-xs\",\n \"[&_th]:border [&_th]:border-border [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-semibold\",\n \"[&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1\",\n )}\n >\n <ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>\n {children}\n </ReactMarkdown>\n </div>\n );\n}\n\nexport const Markdown = memo(MarkdownImpl);\n","import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Slot } from \"radix-ui\";\n\nimport { cn } from \"../../lib/utils\";\n\nconst markerVariants = cva(\n \"group/marker relative flex min-h-4 w-full items-center gap-2 text-left text-sm text-muted-foreground [&_svg:not([class*='size-'])]:size-4 [a]:underline [a]:underline-offset-3 [a]:hover:text-foreground\",\n {\n variants: {\n variant: {\n default: \"\",\n separator:\n \"before:mr-1 before:h-px before:min-w-0 before:flex-1 before:bg-border after:ml-1 after:h-px after:min-w-0 after:flex-1 after:bg-border\",\n border: \"border-b border-border pb-2\",\n },\n },\n },\n);\n\nfunction Marker({\n className,\n variant = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> &\n VariantProps<typeof markerVariants> & {\n asChild?: boolean;\n }) {\n const Comp = asChild ? Slot.Root : \"div\";\n\n return (\n <Comp\n data-slot=\"marker\"\n data-variant={variant}\n className={cn(markerVariants({ variant, className }))}\n {...props}\n />\n );\n}\n\nfunction MarkerIcon({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"marker-icon\"\n aria-hidden=\"true\"\n className={cn(\"size-4 shrink-0 [&_svg:not([class*='size-'])]:size-4\", className)}\n {...props}\n />\n );\n}\n\nfunction MarkerContent({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"marker-content\"\n className={cn(\n \"min-w-0 wrap-break-word group-data-[variant=separator]/marker:flex-none group-data-[variant=separator]/marker:text-center *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { Marker, MarkerIcon, MarkerContent, markerVariants };\n","\"use client\";\n\nimport { Collapsible as CollapsiblePrimitive } from \"radix-ui\";\n\nfunction Collapsible({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {\n return <CollapsiblePrimitive.Root data-slot=\"collapsible\" {...props} />;\n}\n\nfunction CollapsibleTrigger({\n ...props\n}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {\n return <CollapsiblePrimitive.CollapsibleTrigger data-slot=\"collapsible-trigger\" {...props} />;\n}\n\nfunction CollapsibleContent({\n ...props\n}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {\n return <CollapsiblePrimitive.CollapsibleContent data-slot=\"collapsible-content\" {...props} />;\n}\n\nexport { Collapsible, CollapsibleTrigger, CollapsibleContent };\n","\"use client\";\n\nimport * as React from \"react\";\nimport {\n MessageScroller as MessageScrollerPrimitive,\n useMessageScroller,\n useMessageScrollerScrollable,\n useMessageScrollerVisibility,\n} from \"@shadcn/react/message-scroller\";\n\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"./button\";\nimport { ArrowDownIcon } from \"lucide-react\";\n\nfunction MessageScrollerProvider(\n props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,\n) {\n return <MessageScrollerPrimitive.Provider {...props} />;\n}\n\nfunction MessageScroller({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) {\n return (\n <MessageScrollerPrimitive.Root\n data-slot=\"message-scroller\"\n className={cn(\n \"group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MessageScrollerViewport({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) {\n return (\n <MessageScrollerPrimitive.Viewport\n data-slot=\"message-scroller-viewport\"\n className={cn(\n \"size-full min-h-0 min-w-0 scroll-fade-b scrollbar-thin scrollbar-gutter-stable overflow-y-auto overscroll-contain contain-content data-autoscrolling:scrollbar-thumb-transparent data-autoscrolling:scrollbar-track-transparent\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MessageScrollerContent({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) {\n return (\n <MessageScrollerPrimitive.Content\n data-slot=\"message-scroller-content\"\n className={cn(\"flex h-max min-h-full flex-col gap-6\", className)}\n {...props}\n />\n );\n}\n\nfunction MessageScrollerItem({\n className,\n scrollAnchor = false,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Item>) {\n return (\n <MessageScrollerPrimitive.Item\n data-slot=\"message-scroller-item\"\n scrollAnchor={scrollAnchor}\n className={cn(\n \"min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MessageScrollerButton({\n direction = \"end\",\n className,\n children,\n render,\n variant = \"secondary\",\n size = \"icon-sm\",\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Button> &\n Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\">) {\n return (\n <MessageScrollerPrimitive.Button\n data-slot=\"message-scroller-button\"\n data-direction={direction}\n data-variant={variant}\n data-size={size}\n direction={direction}\n className={cn(\n \"absolute inset-s-1/2 -translate-x-1/2 border-border bg-background text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180\",\n className,\n )}\n render={render ?? <Button variant={variant} size={size} />}\n {...props}\n >\n {children ?? (\n <>\n <ArrowDownIcon />\n <span className=\"sr-only\">\n {direction === \"end\" ? \"Scroll to end\" : \"Scroll to start\"}\n </span>\n </>\n )}\n </MessageScrollerPrimitive.Button>\n );\n}\n\nexport {\n MessageScrollerProvider,\n MessageScroller,\n MessageScrollerViewport,\n MessageScrollerContent,\n MessageScrollerItem,\n MessageScrollerButton,\n useMessageScroller,\n useMessageScrollerScrollable,\n useMessageScrollerVisibility,\n};\n","\"use client\";\n\nimport { useEditorMaybe } from \"@grapesjs/react\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Check, MessageSquarePlus, X } from \"lucide-react\";\n\nimport { useCommentStore, type CommentTarget, type SectionComment } from \"../../index.js\";\nimport { Popover, PopoverAnchor, PopoverContent } from \"../ui/popover\";\nimport { Button } from \"../ui/button\";\nimport { Textarea } from \"../ui/textarea\";\n\ntype Props = {\n docId: string;\n /** Sparkles-button target → opens the compose popover for that element. */\n composeTarget: CommentTarget | null;\n onComposeConsumed: () => void;\n /** Bump to refetch comments (after agent turns). */\n refreshSignal: number;\n onOpenCountChange: (n: number) => void;\n};\n\ntype Pos = { top: number; left: number };\n\n// Anchor key = the stable css-class the comment is attached to.\nconst keyOf = (c: Pick<SectionComment, \"objectId\" | \"sectionId\">) =>\n c.objectId ? `obj-${c.objectId}` : `sec-${c.sectionId}`;\nconst keyOfTarget = (t: CommentTarget) => (t.objectId ? `obj-${t.objectId}` : `sec-${t.sectionId}`);\n\nexport default function CanvasComments({\n docId,\n composeTarget,\n onComposeConsumed,\n refreshSignal,\n onOpenCountChange,\n}: Props) {\n // Injected by the host rather than imported, so comments carry no database.\n const commentStore = useCommentStore();\n const editor = useEditorMaybe();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [comments, setComments] = useState<SectionComment[]>([]);\n const [positions, setPositions] = useState<Record<string, Pos>>({});\n const [activeKey, setActiveKey] = useState<string | null>(null);\n const [composeInfo, setComposeInfo] = useState<CommentTarget | null>(null);\n const [body, setBody] = useState(\"\");\n\n const reload = useCallback(() => {\n commentStore.list(docId).then(setComments).catch(console.error);\n }, [docId]);\n\n useEffect(() => {\n reload();\n }, [reload, refreshSignal]);\n\n const open = useMemo(() => comments.filter((c) => c.status === \"open\"), [comments]);\n\n useEffect(() => {\n onOpenCountChange(open.length);\n }, [open.length, onOpenCountChange]);\n\n // One pin per commented anchor (element or section), with its open comments.\n const pins = useMemo(() => {\n const map = new Map<string, SectionComment[]>();\n for (const c of open) {\n const k = keyOf(c);\n const arr = map.get(k) ?? [];\n arr.push(c);\n map.set(k, arr);\n }\n return [...map.entries()].map(([key, list]) => ({ key, list }));\n }, [open]);\n\n // Refs so the event-driven recompute reads fresh values without re-subscribing.\n const openRef = useRef(open);\n openRef.current = open;\n const activeRef = useRef(activeKey);\n activeRef.current = activeKey;\n const positionsRef = useRef<Record<string, Pos>>({});\n\n // Positions of pins/popover, computed from the elements' rects in the canvas iframe.\n const recompute = useCallback(() => {\n const ed = editor;\n const container = containerRef.current;\n if (!ed || !container) return;\n const frame = ed.Canvas.getFrameEl?.();\n const cdoc = ed.Canvas.getDocument?.();\n if (!frame || !cdoc) return;\n const cRect = container.getBoundingClientRect();\n const fRect = frame.getBoundingClientRect();\n // The iframe is scaled by GrapesJS zoom (transform), so its on-screen rect\n // (fRect) is scaled while elements INSIDE it report unscaled coordinates.\n // Map an inner coordinate to screen by this zoom factor.\n const zoom = frame.offsetWidth ? fRect.width / frame.offsetWidth : 1;\n const keys = new Set<string>(openRef.current.map(keyOf));\n if (activeRef.current) keys.add(activeRef.current);\n const next: Record<string, Pos> = {};\n keys.forEach((k) => {\n const el = cdoc.querySelector(`.${k}`) as HTMLElement | null;\n if (!el) return;\n const r = el.getBoundingClientRect();\n // Element's top-right corner mapped from iframe coords to screen (× zoom),\n // then a small constant offset so the pin sits just past the right edge.\n next[k] = {\n top: fRect.top - cRect.top + r.top * zoom + 4,\n left: fRect.left - cRect.left + (r.left + r.width) * zoom + 8,\n };\n });\n if (JSON.stringify(positionsRef.current) !== JSON.stringify(next)) {\n positionsRef.current = next;\n setPositions(next);\n }\n }, [editor]);\n\n // Recompute on canvas activity (edits, scroll, device change, resize) + a\n // low-frequency safety net for layout shifts the events miss.\n useEffect(() => {\n const ed = editor;\n if (!ed) return;\n const evts = [\n \"canvas:update\",\n \"update\",\n \"change:device\",\n \"load\",\n \"component:update\",\n \"component:mount\",\n ];\n evts.forEach((e) => ed.on(e, recompute));\n const win = ed.Canvas.getWindow?.();\n win?.addEventListener(\"scroll\", recompute, true);\n window.addEventListener(\"resize\", recompute);\n const id = window.setInterval(recompute, 500);\n return () => {\n evts.forEach((e) => ed.off(e, recompute));\n win?.removeEventListener(\"scroll\", recompute, true);\n window.removeEventListener(\"resize\", recompute);\n window.clearInterval(id);\n };\n }, [editor, recompute]);\n\n useEffect(() => {\n recompute();\n }, [comments, activeKey, recompute]);\n\n // Sparkles button → open the compose popover anchored to that element.\n useEffect(() => {\n if (!composeTarget) return;\n setComposeInfo(composeTarget);\n setActiveKey(keyOfTarget(composeTarget));\n setBody(\"\");\n requestAnimationFrame(recompute);\n }, [composeTarget, recompute]);\n\n const activeComments = activeKey ? open.filter((c) => keyOf(c) === activeKey) : [];\n const activeTarget: CommentTarget | null = (() => {\n if (!activeKey) return null;\n const c = activeComments[0];\n if (c) return { sectionId: c.sectionId, objectId: c.objectId, objectLabel: c.objectLabel };\n if (composeInfo && keyOfTarget(composeInfo) === activeKey) return composeInfo;\n return null;\n })();\n const activePos = activeKey ? positions[activeKey] : undefined;\n // Keep the last real anchor position through the popover's close animation.\n // On close activeKey→null makes activePos undefined; without this the anchor\n // would snap to (0,0) and the still-animating popover would flash there.\n const lastAnchorPos = useRef<Pos>({ top: 0, left: 0 });\n if (activePos) lastAnchorPos.current = activePos;\n const anchorPos = activePos ?? lastAnchorPos.current;\n\n const closePopover = useCallback(() => {\n setActiveKey(null);\n setBody(\"\");\n if (composeInfo) {\n setComposeInfo(null);\n onComposeConsumed();\n }\n }, [composeInfo, onComposeConsumed]);\n\n // Close the popover on a click inside the canvas iframe (Radix's outside-click\n // detection lives in the top document and misses iframe clicks).\n useEffect(() => {\n if (!activeKey || !editor) return;\n const doc = editor.Canvas.getDocument?.();\n if (!doc) return;\n const onDown = () => closePopover();\n doc.addEventListener(\"mousedown\", onDown, true);\n return () => doc.removeEventListener(\"mousedown\", onDown, true);\n }, [activeKey, editor, closePopover]);\n\n const submit = async () => {\n if (!activeTarget || !body.trim()) return;\n try {\n await commentStore.add(docId, activeTarget, body.trim());\n setBody(\"\");\n if (composeInfo) {\n setComposeInfo(null);\n onComposeConsumed();\n }\n reload();\n } catch (e) {\n console.error(e);\n }\n };\n\n const resolve = async (id: string) => {\n try {\n await commentStore.resolve(id);\n reload();\n } catch (e) {\n console.error(e);\n }\n };\n\n return (\n <div ref={containerRef} className=\"pointer-events-none absolute inset-0 z-20 overflow-hidden\">\n {pins.map(({ key, list }) => {\n const pos = positions[key];\n if (!pos) return null;\n return (\n <button\n key={key}\n type=\"button\"\n onClick={() => {\n setActiveKey((k) => (k === key ? null : key));\n setBody(\"\");\n }}\n style={{ top: pos.top, left: pos.left }}\n className=\"pointer-events-auto absolute flex h-6 min-w-6 items-center justify-center rounded-full rounded-bl-none bg-brand px-1.5 text-xs font-semibold text-brand-fg shadow-md ring-2 ring-white transition-transform hover:scale-110\"\n title={`${list.length} comment(s)`}\n >\n {list.length}\n </button>\n );\n })}\n\n <Popover open={!!activeKey && !!activePos} onOpenChange={(o) => !o && closePopover()}>\n <PopoverAnchor asChild>\n <div\n style={{\n position: \"absolute\",\n top: anchorPos.top,\n left: anchorPos.left,\n width: 1,\n height: 1,\n }}\n />\n </PopoverAnchor>\n <PopoverContent\n side=\"right\"\n align=\"start\"\n // Disable the close animation: while it plays, Radix keeps the content\n // mounted but floating-ui drops its positioning for a frame, flashing\n // the popover at (0,0). No exit animation → instant unmount, no flash.\n className=\"pointer-events-auto w-80 p-0 data-[state=closed]:!animate-none data-[state=closed]:!duration-0\"\n >\n <div className=\"flex items-start justify-between gap-2 border-b px-3 py-2 text-xs text-muted-foreground\">\n <span className=\"min-w-0\">\n {activeTarget?.objectId ? (\n <>\n Comment on{\" \"}\n <span className=\"font-medium text-foreground\">{activeTarget.objectLabel}</span>\n </>\n ) : (\n <>\n Comment on the whole section{\" \"}\n <code className=\"font-mono\">{activeTarget?.sectionId}</code>\n </>\n )}\n </span>\n <button\n type=\"button\"\n onClick={closePopover}\n aria-label=\"Close\"\n className=\"-mr-1 -mt-0.5 shrink-0 rounded p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n <div className=\"max-h-64 space-y-2 overflow-y-auto p-3\">\n {activeComments.length === 0 && (\n <p className=\"text-xs text-muted-foreground\">No comments yet — add the first one.</p>\n )}\n {activeComments.map((c) => (\n <div key={c.id} className=\"rounded-md border bg-muted/40 p-2 text-sm\">\n <p className=\"whitespace-pre-wrap\">{c.body}</p>\n <button\n onClick={() => void resolve(c.id)}\n className=\"mt-1 inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground\"\n >\n <Check className=\"size-3\" /> Resolve\n </button>\n </div>\n ))}\n </div>\n <div className=\"border-t p-3\">\n <Textarea\n autoFocus\n value={body}\n onChange={(e) => setBody(e.target.value)}\n placeholder=\"Add a comment… (⌘/Ctrl+Enter to send)\"\n className=\"min-h-14 resize-none text-sm\"\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n void submit();\n }\n }}\n />\n <div className=\"mt-2 flex justify-end\">\n <Button size=\"sm\" disabled={!body.trim()} onClick={() => void submit()}>\n <MessageSquarePlus /> Add\n </Button>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n </div>\n );\n}\n"],"mappings":"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","names":["React","jsx","jsx","jsx","cva","jsx","cva","jsx","jsx","jsx","jsxs","useEffect","useState","toast","MessageSquare","jsx","jsx","jsx","cva","jsx","cva","jsx","jsx","cva","Slot","jsx","cva","Slot","jsx","jsx","jsxs","jsx","jsxs","useState","toast","useEffect","MessageSquare","useEffect","useRef","useState","Check","X","Fragment","jsx","jsxs","useRef","useState","useEffect","X","Check"]}