@mjml-agent-editor/editor 0.1.5 → 0.1.6
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.
- package/README.md +25 -0
- package/dist/canvas.cjs +97 -19
- package/dist/canvas.cjs.map +1 -1
- package/dist/canvas.js +19 -15
- package/dist/canvas.js.map +1 -1
- package/dist/{chunk-2SXJHEF5.js → chunk-XAEUCHL4.js} +132 -57
- package/dist/chunk-XAEUCHL4.js.map +1 -0
- package/dist/index.cjs +132 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -2
- package/dist/index.d.ts +87 -2
- package/dist/index.js +9 -3
- package/package.json +2 -2
- package/dist/chunk-2SXJHEF5.js.map +0 -1
package/dist/canvas.js.map
CHANGED
|
@@ -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 } 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"]}
|
|
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, useLabels, type CommentTarget, type EditorLabels } 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, labels: EditorLabels) {\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=\"${labels.rteFont}\"><option value=\"\">${labels.rteFont}</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=\"${labels.rteSize}\"><option value=\"\">${labels.rteSize}</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=\"${labels.rteTextColor}\" 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=\"${labels.rteBackgroundColor}\" 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 const labels = useLabels();\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, labels);\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(labels.documentSaveFailed);\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(labels.documentLoadFailed);\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 labels = useLabels();\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={labels.searchBlocks}\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={labels.attributes}>\n <div id=\"gjs-traits\" />\n </CollapseSection>\n <CollapseSection title={labels.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>{labels.expandAll}</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 const labels = useLabels();\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\">{labels.selectAnElement}</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"]}
|