dpk-editor 0.1.0 → 0.1.1

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 CHANGED
@@ -1,12 +1,12 @@
1
1
  # dpk-editor
2
2
 
3
- A React rich-text editor built on **TipTap v3**, purpose-built for composing **HTML emails**.
3
+ A React feature-rich **HTML rich-text editor** built on **TipTap v3**. Use it anywhere you need a WYSIWYG editor that produces clean, portable, inline-styled HTML — CMS bodies, comment boxes, document editors, marketing pages, or email composers.
4
4
 
5
- Editing email HTML is not like editing article HTML. This package is designed around three constraints that ordinary rich-text editors get wrong:
5
+ Unlike editors that emit class-based or framework-coupled markup, this one is designed around three constraints that keep the output portable and paste-anywhere safe:
6
6
 
7
- 1. **Emails are full documents** — `<!doctype html><html><body style="…"><table>…`. A `contentEditable`/ProseMirror surface cannot host `<html>`/`<head>`/`<body>`; it silently strips them. So this editor edits only the **body fragment** and preserves the surrounding document shell verbatim (the *document-shell bridge*).
8
- 2. **Emails rely on inline styles** — `style="padding:…;background:…"` on buttons, colored headings, table layouts. TipTap strips the `style` attribute by default. The bundled `PreserveStyles` extension keeps it.
9
- 3. **Email clients need bulletproof markup** — CTA buttons are `<a style="display:inline-block;…">` wrapped in an aligned `<p>`, not `<button>`.
7
+ 1. **Full documents are supported** — `<!doctype html><html><body style="…">…`. A `contentEditable`/ProseMirror surface cannot host `<html>`/`<head>`/`<body>`; it silently strips them. So the editor edits only the **body fragment** and preserves the surrounding document shell verbatim (the *document-shell bridge*). Pass it a full document or a bare fragment — it round-trips either.
8
+ 2. **Inline styles are preserved** — `style="padding:…;background:…"` on buttons, colored headings, table layouts. TipTap strips the `style` attribute by default. The bundled `PreserveStyles` extension keeps it, so styled content survives the round-trip.
9
+ 3. **Output is portable, bulletproof markup** — call-to-action buttons are `<a style="display:inline-block;…">` wrapped in an aligned `<p>`, not `<button>` — markup that renders consistently across browsers, CMSes, and even email clients.
10
10
 
11
11
  - ✅ Ships **ESM + CJS + type declarations**
12
12
  - ✅ Works in **Next.js App Router** and plain **Vite/CRA** (`immediatelyRender:false` set internally for SSR)
@@ -26,11 +26,13 @@ import { EmailEditor } from "dpk-editor";
26
26
  import "dpk-editor/styles.css"; // required
27
27
  ```
28
28
 
29
+ > The main component is exported as `EmailEditor` (and as the default export) for historical reasons — it is a fully general HTML editor and works for any content, not just email.
30
+
29
31
  ## Usage
30
32
 
31
33
  ### `<EmailEditor>` — batteries included (default export)
32
34
 
33
- Handles the document-shell bridge, placeholder chips, and image upload wiring. `value` may be a full `<!doctype><html><body>…` document **or** a bare fragment; `onChange` always emits in the same shape it received.
35
+ The full editor: toolbar, editable surface, document-shell bridge, optional insertable token chips, and image-upload wiring. `value` may be a full `<!doctype><html><body>…` document **or** a bare fragment; `onChange` always emits in the same shape it received.
34
36
 
35
37
  ```tsx
36
38
  import { useState } from "react";
@@ -38,17 +40,16 @@ import { EmailEditor } from "dpk-editor";
38
40
  import "dpk-editor/styles.css";
39
41
 
40
42
  export default function Composer() {
41
- const [html, setHtml] = useState(
42
- "<html><body><h1>Hi {{FirstName}}</h1></body></html>",
43
- );
43
+ const [html, setHtml] = useState("<h1>Hello, world</h1><p>Start writing…</p>");
44
44
 
45
45
  return (
46
46
  <EmailEditor
47
47
  value={html}
48
48
  onChange={setHtml}
49
+ // Optional: clickable chips that insert any text/token at the caret.
49
50
  placeholders={[
50
51
  { token: "{{FirstName}}", label: "First name" },
51
- { token: "{{Email}}", label: "Email" },
52
+ { token: "{{Date}}", label: "Today's date" },
52
53
  ]}
53
54
  onUploadImage={async (file) => {
54
55
  // upload `file` somewhere and return a hosted URL
@@ -62,7 +63,7 @@ export default function Composer() {
62
63
 
63
64
  ### `<RichTextEditor>` — the generic body-HTML editor (named export)
64
65
 
65
- The toolbar + editable surface operating on a **plain HTML fragment** (no `<html>`/`<body>`). `EmailEditor` is a thin wrapper that adds the shell bridge + chips around this. Use it if you want to build your own wrapper.
66
+ The toolbar + editable surface operating on a **plain HTML fragment** (no `<html>`/`<body>`). `EmailEditor` is a thin wrapper that adds the shell bridge + token chips around this. Use it if you want to build your own wrapper or only ever deal with a body fragment.
66
67
 
67
68
  ```tsx
68
69
  import { useRef, useState } from "react";
@@ -83,7 +84,7 @@ function Body() {
83
84
  value={body}
84
85
  onChange={setBody}
85
86
  editorStyle={{ minHeight: 240 }}
86
- toolbar={{ button: false }} // hide the CTA-button control
87
+ toolbar={{ button: false }} // hide the button-builder control
87
88
  />
88
89
  </>
89
90
  );
@@ -98,10 +99,10 @@ function Body() {
98
99
  | --------------- | ----------------------------------------- | -------------- | ----------- |
99
100
  | `value` | `string` | — | Full HTML document **or** bare body fragment. |
100
101
  | `onChange` | `(value: string) => void` | — | Fires with HTML in the same shape as `value` (shell re-applied). |
101
- | `placeholders` | `EmailPlaceholder[]` | `undefined` | Merge tokens → renders a chip row that inserts at the caret. |
102
+ | `placeholders` | `EmailPlaceholder[]` | `undefined` | Insertable tokens → renders a chip row that inserts each at the caret. |
102
103
  | `onUploadImage` | `(file: File) => Promise<string>` | `undefined` | Resolve an upload to a URL. If omitted, the image button prompts for a URL. |
103
104
  | `minHeight` | `number` | `288` | Min height (px) of the editable surface. |
104
- | `placeholder` | `string` | `"Write your email…"` | Empty-state text. |
105
+ | `placeholder` | `string` | `"Write something…"` | Empty-state text. |
105
106
  | `toolbar` | `ToolbarConfig` | all on | Which controls to render. |
106
107
  | `className` | `string` | `undefined` | Extra class on the wrapper. |
107
108
 
@@ -111,7 +112,7 @@ function Body() {
111
112
  | --------------- | ----------------------------------- | ------- | ----------- |
112
113
  | `value` | `string` | — | Body-level HTML fragment. |
113
114
  | `onChange` | `(value: string) => void` | — | Fires with the body-level HTML fragment. |
114
- | `placeholder` | `string` | `"Write your email…"` | Empty-state text. |
115
+ | `placeholder` | `string` | `"Write something…"` | Empty-state text. |
115
116
  | `onUploadImage` | `(file: File) => Promise<string>` | `undefined` | Upload handler (else URL prompt). |
116
117
  | `className` | `string` | `undefined` | Extra class on the wrapper. |
117
118
  | `editorStyle` | `React.CSSProperties` | `undefined` | Applied to the editable surface (e.g. `{ minHeight }`). |
@@ -148,7 +149,7 @@ type ToolbarConfig = {
148
149
  blocks?: boolean | { paragraph?: boolean; divider?: boolean; footer?: boolean };
149
150
  link?: boolean; // Link control
150
151
  image?: boolean; // Image control
151
- button?: boolean; // Email CTA button dialog
152
+ button?: boolean; // Button-builder dialog
152
153
  html?: boolean; // Raw HTML source toggle
153
154
  };
154
155
  ```
@@ -209,6 +210,8 @@ import type {
209
210
 
210
211
  ### `buildButtonHtml`
211
212
 
213
+ Builds portable, inline-styled HTML for a clickable button (an `<a>`, so it works in any HTML context — including email clients that won't render a `<button>`):
214
+
212
215
  ```ts
213
216
  const html = buildButtonHtml({
214
217
  text: "Get started",
package/dist/index.cjs CHANGED
@@ -93,7 +93,7 @@ function createEmailExtensions(placeholder) {
93
93
  extensionTextStyle.Color,
94
94
  Highlight__default.default.configure({ multicolor: true }),
95
95
  Placeholder__default.default.configure({
96
- placeholder: placeholder ?? "Write your email\u2026",
96
+ placeholder: placeholder ?? "Write something\u2026",
97
97
  // Emit data-placeholder so styles.css can render it via attr(); also
98
98
  // keep the default is-editor-empty class for the :first-child selector.
99
99
  showOnlyWhenEditable: true
@@ -763,7 +763,7 @@ function Toolbar({
763
763
  var RichTextEditor = react$1.forwardRef(function RichTextEditor2({
764
764
  value,
765
765
  onChange,
766
- placeholder = "Write your email\u2026",
766
+ placeholder = "Write something\u2026",
767
767
  onUploadImage,
768
768
  className,
769
769
  editorStyle,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/shellBridge.ts","../src/extensions/PreserveStyles.ts","../src/extensions/editorExtensions.ts","../src/utils/presets.ts","../src/utils/resolveToolbarConfig.ts","../src/utils/escapeHtml.ts","../src/utils/buildButtonHtml.ts","../src/components/EmailButtonDialog.tsx","../src/components/Toolbar.tsx","../src/components/RichTextEditor.tsx","../src/components/EmailEditor.tsx"],"names":["Extension","StarterKit","Image","TextAlign","TextStyle","Color","Highlight","Placeholder","jsxs","jsx","useState","useRef","useEffect","useMemo","Heading2","Heading3","Heading4","Heading5","Heading6","useEditorState","Bold","Italic","Underline","Strikethrough","Code","List","ListOrdered","Quote","AlignLeft","AlignCenter","AlignRight","LinkIcon","ImageIcon","MousePointerClick","Pilcrow","Minus","PanelBottom","FileCode","Fragment","forwardRef","RichTextEditor","useEditor","useImperativeHandle","useCallback","EditorContent"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { EmailHtmlDocument } from \"../types\";\n\n/**\n * Document-shell bridge utilities.\n *\n * A `contentEditable`/ProseMirror surface cannot host `<html>`/`<head>`/\n * `<body>` — it silently strips them and keeps only body-level flow content.\n * So `<EmailEditor>` edits only the **body fragment** and preserves the\n * surrounding document shell verbatim across edits.\n *\n * These are pure string utilities (no DOM required): they operate by locating\n * the `<body ...>` tag with a regex, so they work the same in the browser,\n * during SSR, and in tests.\n */\n\n// Matches the opening <body ...> tag (case-insensitive, any attributes,\n// across newlines). Non-greedy so it stops at the first `>`.\nconst BODY_OPEN_RE = /<body\\b[^>]*>/i;\n// Matches the closing </body> tag.\nconst BODY_CLOSE_RE = /<\\/body\\s*>/i;\n\n/**\n * Split a full email HTML document into `{ prefix, body, suffix }`.\n *\n * - `prefix` = everything up to and including the opening `<body ...>` tag.\n * - `body` = the inner body HTML (the editable fragment).\n * - `suffix` = the closing `</body>` tag plus everything after it.\n *\n * If the input has no `<body>` tag it is treated as a **bare fragment**: the\n * whole input becomes `body`, and `prefix`/`suffix` are empty strings.\n */\nexport function splitEmailHtml(html: string): EmailHtmlDocument {\n const input = html ?? \"\";\n\n const openMatch = input.match(BODY_OPEN_RE);\n if (!openMatch || openMatch.index === undefined) {\n // Bare fragment — no shell to preserve.\n return { prefix: \"\", body: input, suffix: \"\" };\n }\n\n const openStart = openMatch.index;\n const openEnd = openStart + openMatch[0].length;\n const prefix = input.slice(0, openEnd);\n\n const rest = input.slice(openEnd);\n const closeMatch = rest.match(BODY_CLOSE_RE);\n\n if (!closeMatch || closeMatch.index === undefined) {\n // Opening <body> but no closing tag — treat the remainder as body and\n // synthesize an empty suffix so a rejoin still nests inside the shell.\n return { prefix, body: rest, suffix: \"\" };\n }\n\n const body = rest.slice(0, closeMatch.index);\n const suffix = rest.slice(closeMatch.index);\n\n return { prefix, body, suffix };\n}\n\n/**\n * Reassemble a document from a shell and a (possibly edited) body fragment.\n *\n * If the shell has no surrounding markup (a bare fragment was originally\n * supplied) the body is returned as-is, so `onChange` emits in the same shape\n * the consumer provided `value`.\n */\nexport function joinEmailHtml(\n shell: EmailHtmlDocument,\n newBody: string,\n): string {\n const body = newBody ?? \"\";\n if (!shell.prefix && !shell.suffix) {\n return body;\n }\n return `${shell.prefix}${body}${shell.suffix}`;\n}\n\n/**\n * Convenience: extract just the editable body fragment from a full document\n * (or return the input unchanged if it is already a bare fragment).\n */\nexport function extractEmailBody(html: string): string {\n return splitEmailHtml(html).body;\n}\n","import { Extension } from \"@tiptap/react\";\n\n/**\n * A TipTap extension that preserves the inline `style` attribute on every node\n * and mark in the schema.\n *\n * TipTap (ProseMirror) strips any HTML attribute a node/mark does not declare.\n * For article editing that is fine; for **email** HTML it is lossy — buttons\n * lose their padding/background, headings lose their color, and so on. This\n * extension declares a global `style` attribute so arbitrary inline-styled\n * email HTML round-trips.\n *\n * It preserves `style` only on elements that map to a known node or mark\n * (paragraph, heading, list, blockquote, link, image, hr, …). Raw\n * `<table>`/`<td>` layouts are still flattened by ProseMirror's schema — those\n * survive via the document-shell bridge, not here.\n */\nexport const PreserveStyles = Extension.create({\n name: \"preserveStyles\",\n\n addGlobalAttributes() {\n return [\n {\n // ⚠️ MUST be the string shorthand \"*\" (= all nodes and marks).\n // NEVER [\"*\"] — an array means \"a type literally named *\", which\n // matches nothing and silently preserves no styles. That bug passes\n // tsc/eslint/build cleanly, so it is asserted against in the tests.\n types: \"*\",\n attributes: {\n style: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"style\"),\n renderHTML: (attributes) =>\n attributes.style ? { style: attributes.style as string } : {},\n },\n },\n },\n ];\n },\n});\n\nexport default PreserveStyles;\n","import Highlight from \"@tiptap/extension-highlight\";\nimport Image from \"@tiptap/extension-image\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport TextAlign from \"@tiptap/extension-text-align\";\n// @tiptap/extension-text-style v3 re-exports both TextStyle and Color, so we\n// do NOT need @tiptap/extension-color as a separate dependency.\nimport { Color, TextStyle } from \"@tiptap/extension-text-style\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport type { Extensions } from \"@tiptap/react\";\n\nimport { PreserveStyles } from \"./PreserveStyles\";\n\n/**\n * The canonical extension set for the email editor.\n *\n * Notes / watch-outs baked in here:\n * - StarterKit v3 already bundles Link, Underline, lists, blockquote, code and\n * headings — we do NOT add @tiptap/extension-link or -underline separately\n * (that throws duplicate-extension warnings). Link is configured through\n * StarterKit.configure({ link: {...} }).\n * - Image is block-level and base64 is disabled (uploads should resolve to a\n * hosted URL, which is what email clients can render).\n * - PreserveStyles must be present so inline `style` survives the round-trip.\n * - Placeholder is NOT bundled by StarterKit v3, so it is added explicitly to\n * power the empty-state hint (it sets the `is-editor-empty` class and the\n * `data-placeholder` attribute that styles.css renders via `::before`).\n *\n * Exported as a factory so the React component and the headless tests build an\n * identical extension set. Pass the empty-state placeholder text in.\n */\nexport function createEmailExtensions(placeholder?: string): Extensions {\n return [\n StarterKit.configure({\n link: {\n openOnClick: false,\n autolink: true,\n HTMLAttributes: { rel: \"noopener noreferrer\" },\n },\n }),\n Image.configure({ inline: false, allowBase64: false }),\n TextAlign.configure({ types: [\"heading\", \"paragraph\"] }),\n TextStyle,\n Color,\n Highlight.configure({ multicolor: true }),\n Placeholder.configure({\n placeholder: placeholder ?? \"Write your email…\",\n // Emit data-placeholder so styles.css can render it via attr(); also\n // keep the default is-editor-empty class for the :first-child selector.\n showOnlyWhenEditable: true,\n }),\n PreserveStyles,\n ];\n}\n","/**\n * Preset block snippets — small, inline-styled, email-safe HTML fragments\n * inserted at the caret via `editor.chain().focus().insertContent(snippet)`.\n *\n * Every snippet uses inline styles only (no classes) so it survives both the\n * editor schema (via PreserveStyles) and downstream email clients.\n */\nexport const PRESET_PARAGRAPH =\n '<p style=\"margin:0 0 12px;color:#4b5563;line-height:1.6;\">Write your message here.</p>';\n\nexport const PRESET_DIVIDER =\n '<hr style=\"border:none;border-top:1px solid #e5e7eb;margin:20px 0;\" />';\n\nexport const PRESET_FOOTER =\n '<p style=\"margin:20px 0 0;color:#9ca3af;font-size:12px;\">© Your Company</p>';\n\nexport const PRESET_HEADING =\n '<h2 style=\"margin:0 0 12px;color:#111827;font-size:24px;line-height:1.3;\">Heading</h2>';\n\nexport const presets = {\n paragraph: PRESET_PARAGRAPH,\n divider: PRESET_DIVIDER,\n footer: PRESET_FOOTER,\n heading: PRESET_HEADING,\n} as const;\n","import type {\n AlignButtons,\n BlockButtons,\n HeadingButtons,\n InlineButtons,\n ListButtons,\n ResolvedToolbarConfig,\n ToolbarConfig,\n ToolbarGroup,\n} from \"../types\";\n\n/**\n * Resolve a loose `ToolbarConfig` into the flat `ResolvedToolbarConfig` the\n * Toolbar renders from. Rules:\n * - A group key may be a boolean or a per-button object (or omitted).\n * - Omitted / `true` / `{}` → group enabled, every button enabled.\n * - `false` → group disabled (and all its buttons disabled).\n * - An object → group enabled, each listed button overridden; unlisted buttons\n * default to `true`.\n */\nfunction resolveGroup<TButtons extends Record<string, boolean | undefined>>(\n group: ToolbarGroup<TButtons> | undefined,\n defaults: Required<TButtons>,\n): { enabled: boolean; buttons: Required<TButtons> } {\n // Omitted → all on.\n if (group === undefined || group === true) {\n return { enabled: true, buttons: { ...defaults } };\n }\n // Whole group off → disable every button too.\n if (group === false) {\n const off = {} as Required<TButtons>;\n for (const key of Object.keys(defaults) as (keyof TButtons)[]) {\n off[key] = false as Required<TButtons>[keyof TButtons];\n }\n return { enabled: false, buttons: off };\n }\n // Per-button object → group on, merge overrides over the all-on defaults.\n return { enabled: true, buttons: { ...defaults, ...group } };\n}\n\nconst INLINE_DEFAULTS: Required<InlineButtons> = {\n bold: true,\n italic: true,\n underline: true,\n strike: true,\n code: true,\n};\nconst HEADING_DEFAULTS: Required<HeadingButtons> = {\n h2: true,\n h3: true,\n h4: true,\n h5: true,\n h6: true,\n};\nconst LIST_DEFAULTS: Required<ListButtons> = {\n bullet: true,\n ordered: true,\n blockquote: true,\n};\nconst ALIGN_DEFAULTS: Required<AlignButtons> = {\n left: true,\n center: true,\n right: true,\n};\nconst BLOCK_DEFAULTS: Required<BlockButtons> = {\n paragraph: true,\n divider: true,\n footer: true,\n};\n\n/** A single-control group is on unless explicitly set to `false`. */\nfunction resolveToggle(value: boolean | undefined): boolean {\n return value !== false;\n}\n\nexport function resolveToolbarConfig(\n config?: ToolbarConfig,\n): ResolvedToolbarConfig {\n const c = config ?? {};\n return {\n inline: resolveGroup(c.inline, INLINE_DEFAULTS),\n headings: resolveGroup(c.headings, HEADING_DEFAULTS),\n lists: resolveGroup(c.lists, LIST_DEFAULTS),\n align: resolveGroup(c.align, ALIGN_DEFAULTS),\n link: resolveToggle(c.link),\n image: resolveToggle(c.image),\n button: resolveToggle(c.button),\n blocks: resolveGroup(c.blocks, BLOCK_DEFAULTS),\n html: resolveToggle(c.html),\n };\n}\n","/**\n * Escape a string for safe insertion into HTML text or a double-quoted\n * attribute value. Used by `buildButtonHtml` for the button label and href.\n */\nexport function escapeHtml(value: string): string {\n return String(value)\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n","import type { EmailButtonConfig } from \"../types\";\nimport { escapeHtml } from \"./escapeHtml\";\n\n/**\n * Build email-safe HTML for a call-to-action button.\n *\n * Two non-obvious decisions, both load-bearing:\n *\n * 1. The anchor is wrapped in a `<p style=\"...;text-align:X\">`, **never** a\n * `<div>`. TipTap has no `div` node and unwraps a `<div>` into a paragraph,\n * losing the `text-align`. A paragraph is a real node whose `text-align`\n * the TextAlign extension preserves — so the alignment round-trips.\n *\n * 2. The button is an `<a style=\"display:inline-block;...\">` (or\n * `display:block` when full-width), not a `<button>`, because email clients\n * need bulletproof, inline-styled markup.\n *\n * Both the label and the href are HTML-escaped.\n */\nexport function buildButtonHtml(config: EmailButtonConfig): string {\n const {\n text,\n href,\n bgColor,\n textColor,\n align,\n radius,\n fullWidth,\n } = config;\n\n const safeText = escapeHtml(text || \"Button\");\n const safeHref = escapeHtml(href || \"#\");\n const safeRadius = Number.isFinite(radius) ? Math.max(0, radius) : 0;\n\n // Full-width buttons span the content area as a block and center their own\n // label; otherwise they hug their content as an inline-block.\n const display = fullWidth ? \"block\" : \"inline-block\";\n const anchorTextAlign = fullWidth ? \"text-align:center;\" : \"\";\n\n const anchorStyle = [\n `display:${display}`,\n \"padding:12px 24px\",\n `background-color:${bgColor}`,\n `color:${textColor}`,\n \"text-decoration:none\",\n \"font-weight:600\",\n \"font-family:Arial,Helvetica,sans-serif\",\n \"font-size:14px\",\n \"line-height:1.4\",\n `border-radius:${safeRadius}px`,\n anchorTextAlign,\n ]\n .filter(Boolean)\n .join(\";\");\n\n const paragraphStyle = `margin:16px 0;text-align:${align}`;\n\n return (\n `<p style=\"${paragraphStyle}\">` +\n `<a href=\"${safeHref}\" target=\"_blank\" rel=\"noopener noreferrer\" ` +\n `style=\"${anchorStyle}\">${safeText}</a>` +\n `</p>`\n );\n}\n","import { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { EmailButtonConfig } from \"../types\";\nimport { buildButtonHtml } from \"../utils/buildButtonHtml\";\n\nexport type EmailButtonDialogProps = {\n /** Whether the dialog is open. */\n open: boolean;\n /** Called when the user confirms; receives the email-safe button HTML. */\n onConfirm: (html: string, config: EmailButtonConfig) => void;\n /** Called when the user dismisses the dialog (Esc / click-outside / cancel). */\n onClose: () => void;\n /** Optional initial values for the form. */\n initial?: Partial<EmailButtonConfig>;\n};\n\nconst DEFAULT_CONFIG: EmailButtonConfig = {\n text: \"Click here\",\n href: \"https://\",\n bgColor: \"#2563eb\",\n textColor: \"#ffffff\",\n align: \"left\",\n radius: 6,\n fullWidth: false,\n};\n\nconst BG_SWATCHES = [\n \"#2563eb\",\n \"#16a34a\",\n \"#dc2626\",\n \"#7c3aed\",\n \"#ea580c\",\n \"#0891b2\",\n \"#111827\",\n];\nconst TEXT_SWATCHES = [\"#ffffff\", \"#111827\", \"#f9fafb\", \"#1f2937\"];\n\n// <input type=color> only accepts #rrggbb. Named colors, #rgb shorthand, or\n// anything else must be coerced or it throws/blanks the control.\nconst HEX6_RE = /^#[0-9a-fA-F]{6}$/;\nfunction toColorInputValue(value: string): string {\n return HEX6_RE.test(value) ? value : \"#000000\";\n}\n\ntype ColorFieldProps = {\n label: string;\n value: string;\n swatches: string[];\n onChange: (value: string) => void;\n};\n\nfunction ColorField({ label, value, swatches, onChange }: ColorFieldProps) {\n return (\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">{label}</span>\n <div className=\"rte-color-row\">\n {swatches.map((swatch) => (\n <button\n key={swatch}\n type=\"button\"\n className={\n \"rte-swatch\" + (value === swatch ? \" rte-swatch--active\" : \"\")\n }\n style={{ backgroundColor: swatch }}\n aria-label={`Use ${swatch}`}\n aria-pressed={value === swatch}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onChange(swatch)}\n />\n ))}\n <input\n type=\"color\"\n className=\"rte-color-input\"\n value={toColorInputValue(value)}\n aria-label={`${label} picker`}\n onChange={(e) => onChange(e.target.value)}\n />\n <input\n type=\"text\"\n className=\"rte-hex-input\"\n value={value}\n aria-label={`${label} hex`}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n </div>\n );\n}\n\n/**\n * Modal dialog for configuring an email CTA button. Supports Esc to close,\n * body-scroll lock while open, click-outside to dismiss, and a live preview of\n * the rendered button.\n */\nexport function EmailButtonDialog({\n open,\n onConfirm,\n onClose,\n initial,\n}: EmailButtonDialogProps) {\n const [config, setConfig] = useState<EmailButtonConfig>({\n ...DEFAULT_CONFIG,\n ...initial,\n });\n const overlayRef = useRef<HTMLDivElement>(null);\n\n // Reset the form to its initial state each time the dialog opens.\n useEffect(() => {\n if (open) {\n setConfig({ ...DEFAULT_CONFIG, ...initial });\n }\n }, [open, initial]);\n\n // Esc to close + body-scroll lock while open.\n useEffect(() => {\n if (!open) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n onClose();\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.body.style.overflow = previousOverflow;\n };\n }, [open, onClose]);\n\n const previewHtml = useMemo(() => buildButtonHtml(config), [config]);\n\n if (!open) return null;\n\n const update = <K extends keyof EmailButtonConfig>(\n key: K,\n value: EmailButtonConfig[K],\n ) => setConfig((prev) => ({ ...prev, [key]: value }));\n\n const handleSubmit = () => {\n onConfirm(buildButtonHtml(config), config);\n };\n\n return (\n <div\n ref={overlayRef}\n className=\"rte-dialog-overlay\"\n role=\"presentation\"\n onMouseDown={(e) => {\n // Click-outside (on the overlay itself, not the panel) dismisses.\n if (e.target === overlayRef.current) onClose();\n }}\n >\n <div\n className=\"rte-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Insert button\"\n >\n <div className=\"rte-dialog-header\">\n <h2 className=\"rte-dialog-title\">Insert button</h2>\n <button\n type=\"button\"\n className=\"rte-dialog-close\"\n aria-label=\"Close\"\n onClick={onClose}\n >\n ×\n </button>\n </div>\n\n <div className=\"rte-dialog-body\">\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Text</span>\n <input\n type=\"text\"\n className=\"rte-text-input\"\n value={config.text}\n onChange={(e) => update(\"text\", e.target.value)}\n />\n </label>\n\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Link URL</span>\n <input\n type=\"text\"\n className=\"rte-text-input\"\n value={config.href}\n onChange={(e) => update(\"href\", e.target.value)}\n />\n </label>\n\n <ColorField\n label=\"Background color\"\n value={config.bgColor}\n swatches={BG_SWATCHES}\n onChange={(v) => update(\"bgColor\", v)}\n />\n\n <ColorField\n label=\"Text color\"\n value={config.textColor}\n swatches={TEXT_SWATCHES}\n onChange={(v) => update(\"textColor\", v)}\n />\n\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Alignment</span>\n <div className=\"rte-align-row\">\n {([\"left\", \"center\", \"right\"] as const).map((a) => (\n <button\n key={a}\n type=\"button\"\n className={\n \"rte-align-btn\" +\n (config.align === a ? \" rte-align-btn--active\" : \"\")\n }\n aria-pressed={config.align === a}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => update(\"align\", a)}\n >\n {a}\n </button>\n ))}\n </div>\n </div>\n\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">\n Corner radius: {config.radius}px\n </span>\n <input\n type=\"range\"\n min={0}\n max={32}\n value={config.radius}\n onChange={(e) => update(\"radius\", Number(e.target.value))}\n />\n </label>\n\n <label className=\"rte-checkbox-field\">\n <input\n type=\"checkbox\"\n checked={config.fullWidth}\n onChange={(e) => update(\"fullWidth\", e.target.checked)}\n />\n <span>Full width</span>\n </label>\n\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Preview</span>\n <div\n className=\"rte-button-preview\"\n // Preview only — content is built from the same escaped builder.\n dangerouslySetInnerHTML={{ __html: previewHtml }}\n />\n </div>\n </div>\n\n <div className=\"rte-dialog-footer\">\n <button\n type=\"button\"\n className=\"rte-btn rte-btn--ghost\"\n onClick={onClose}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"rte-btn rte-btn--primary\"\n onClick={handleSubmit}\n >\n Insert\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport default EmailButtonDialog;\n","import type { Editor } from \"@tiptap/react\";\nimport { useEditorState } from \"@tiptap/react\";\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n Bold,\n Code,\n FileCode,\n Heading2,\n Heading3,\n Heading4,\n Heading5,\n Heading6,\n Image as ImageIcon,\n Italic,\n Link as LinkIcon,\n List,\n ListOrdered,\n Minus,\n MousePointerClick,\n PanelBottom,\n Pilcrow,\n Quote,\n Strikethrough,\n Underline,\n} from \"lucide-react\";\nimport { Fragment, type ReactNode } from \"react\";\n\nimport type { ResolvedToolbarConfig } from \"../types\";\n\ntype HeadingLevel = 2 | 3 | 4 | 5 | 6;\n\nexport type ToolbarProps = {\n editor: Editor;\n config: ResolvedToolbarConfig;\n /** Toggle the raw HTML source view. */\n htmlMode: boolean;\n onToggleHtml: () => void;\n /** Caller-provided handlers for the controls that need extra UI. */\n onLink: () => void;\n onImage: () => void;\n onButton: () => void;\n onInsertParagraph: () => void;\n onInsertDivider: () => void;\n onInsertFooter: () => void;\n};\n\ntype TbButtonProps = {\n onClick: () => void;\n active?: boolean;\n label: string;\n disabled?: boolean;\n children: ReactNode;\n};\n\nfunction TbButton({ onClick, active, label, disabled, children }: TbButtonProps) {\n return (\n <button\n type=\"button\"\n className={\"rte-tb-btn\" + (active ? \" rte-tb-btn--active\" : \"\")}\n // Prevent the button from stealing the editor's selection on press.\n onMouseDown={(e) => e.preventDefault()}\n onClick={onClick}\n aria-pressed={!!active}\n aria-label={label}\n title={label}\n disabled={disabled}\n >\n {children}\n </button>\n );\n}\n\nfunction Divider() {\n return <span className=\"rte-tb-divider\" aria-hidden=\"true\" />;\n}\n\nconst HEADING_ICONS: Record<HeadingLevel, ReactNode> = {\n 2: <Heading2 size={16} />,\n 3: <Heading3 size={16} />,\n 4: <Heading4 size={16} />,\n 5: <Heading5 size={16} />,\n 6: <Heading6 size={16} />,\n};\n\nexport function Toolbar({\n editor,\n config,\n htmlMode,\n onToggleHtml,\n onLink,\n onImage,\n onButton,\n onInsertParagraph,\n onInsertDivider,\n onInsertFooter,\n}: ToolbarProps) {\n // useEditorState re-renders only when the selected slice changes, keeping\n // active-state computation cheap even on large documents.\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) => ({\n bold: e.isActive(\"bold\"),\n italic: e.isActive(\"italic\"),\n underline: e.isActive(\"underline\"),\n strike: e.isActive(\"strike\"),\n code: e.isActive(\"code\"),\n h2: e.isActive(\"heading\", { level: 2 }),\n h3: e.isActive(\"heading\", { level: 3 }),\n h4: e.isActive(\"heading\", { level: 4 }),\n h5: e.isActive(\"heading\", { level: 5 }),\n h6: e.isActive(\"heading\", { level: 6 }),\n bulletList: e.isActive(\"bulletList\"),\n orderedList: e.isActive(\"orderedList\"),\n blockquote: e.isActive(\"blockquote\"),\n alignLeft: e.isActive({ textAlign: \"left\" }),\n alignCenter: e.isActive({ textAlign: \"center\" }),\n alignRight: e.isActive({ textAlign: \"right\" }),\n link: e.isActive(\"link\"),\n image: e.isActive(\"image\"),\n }),\n });\n\n const headingActive: Record<HeadingLevel, boolean> = {\n 2: state.h2,\n 3: state.h3,\n 4: state.h4,\n 5: state.h5,\n 6: state.h6,\n };\n\n // In HTML source mode only the source toggle is interactive.\n const disabled = htmlMode;\n\n // Build each group as an array of rendered buttons, gated by both the group\n // `enabled` flag and the per-button flag. A group with zero visible buttons\n // contributes nothing (and gets no divider).\n const inline = config.inline.enabled\n ? [\n config.inline.buttons.bold && (\n <TbButton\n key=\"bold\"\n label=\"Bold\"\n active={state.bold}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBold().run()}\n >\n <Bold size={16} />\n </TbButton>\n ),\n config.inline.buttons.italic && (\n <TbButton\n key=\"italic\"\n label=\"Italic\"\n active={state.italic}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleItalic().run()}\n >\n <Italic size={16} />\n </TbButton>\n ),\n config.inline.buttons.underline && (\n <TbButton\n key=\"underline\"\n label=\"Underline\"\n active={state.underline}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n >\n <Underline size={16} />\n </TbButton>\n ),\n config.inline.buttons.strike && (\n <TbButton\n key=\"strike\"\n label=\"Strikethrough\"\n active={state.strike}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleStrike().run()}\n >\n <Strikethrough size={16} />\n </TbButton>\n ),\n config.inline.buttons.code && (\n <TbButton\n key=\"code\"\n label=\"Inline code\"\n active={state.code}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleCode().run()}\n >\n <Code size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const headings = config.headings.enabled\n ? ([2, 3, 4, 5, 6] as const).map((level) =>\n config.headings.buttons[`h${level}` as keyof typeof config.headings.buttons] ? (\n <TbButton\n key={`h${level}`}\n label={`Heading ${level}`}\n active={headingActive[level]}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleHeading({ level }).run()}\n >\n {HEADING_ICONS[level]}\n </TbButton>\n ) : (\n false\n ),\n )\n : [];\n\n const lists = config.lists.enabled\n ? [\n config.lists.buttons.bullet && (\n <TbButton\n key=\"bullet\"\n label=\"Bullet list\"\n active={state.bulletList}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n >\n <List size={16} />\n </TbButton>\n ),\n config.lists.buttons.ordered && (\n <TbButton\n key=\"ordered\"\n label=\"Ordered list\"\n active={state.orderedList}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n >\n <ListOrdered size={16} />\n </TbButton>\n ),\n config.lists.buttons.blockquote && (\n <TbButton\n key=\"quote\"\n label=\"Quote\"\n active={state.blockquote}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBlockquote().run()}\n >\n <Quote size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const align = config.align.enabled\n ? [\n config.align.buttons.left && (\n <TbButton\n key=\"left\"\n label=\"Align left\"\n active={state.alignLeft}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"left\").run()}\n >\n <AlignLeft size={16} />\n </TbButton>\n ),\n config.align.buttons.center && (\n <TbButton\n key=\"center\"\n label=\"Align center\"\n active={state.alignCenter}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"center\").run()}\n >\n <AlignCenter size={16} />\n </TbButton>\n ),\n config.align.buttons.right && (\n <TbButton\n key=\"right\"\n label=\"Align right\"\n active={state.alignRight}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"right\").run()}\n >\n <AlignRight size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const inserts = [\n config.link && (\n <TbButton\n key=\"link\"\n label=\"Link\"\n active={state.link}\n disabled={disabled}\n onClick={onLink}\n >\n <LinkIcon size={16} />\n </TbButton>\n ),\n config.image && (\n <TbButton\n key=\"image\"\n label=\"Image\"\n active={state.image}\n disabled={disabled}\n onClick={onImage}\n >\n <ImageIcon size={16} />\n </TbButton>\n ),\n config.button && (\n <TbButton\n key=\"button\"\n label=\"Button\"\n disabled={disabled}\n onClick={onButton}\n >\n <MousePointerClick size={16} />\n </TbButton>\n ),\n ];\n\n const blocks = config.blocks.enabled\n ? [\n config.blocks.buttons.paragraph && (\n <TbButton\n key=\"paragraph\"\n label=\"Insert paragraph\"\n disabled={disabled}\n onClick={onInsertParagraph}\n >\n <Pilcrow size={16} />\n </TbButton>\n ),\n config.blocks.buttons.divider && (\n <TbButton\n key=\"divider\"\n label=\"Insert divider\"\n disabled={disabled}\n onClick={onInsertDivider}\n >\n <Minus size={16} />\n </TbButton>\n ),\n config.blocks.buttons.footer && (\n <TbButton\n key=\"footer\"\n label=\"Insert footer\"\n disabled={disabled}\n onClick={onInsertFooter}\n >\n <PanelBottom size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const html = config.html\n ? [\n <TbButton\n key=\"html\"\n label=\"HTML source\"\n active={htmlMode}\n onClick={onToggleHtml}\n >\n <FileCode size={16} />\n </TbButton>,\n ]\n : [];\n\n // Keep only groups that have at least one visible button, then render them\n // with a divider between each — so hidden groups leave no dangling dividers.\n const groups = [inline, headings, lists, align, inserts, blocks, html]\n .map((g) => g.filter(Boolean))\n .filter((g) => g.length > 0);\n\n return (\n <div className=\"rte-toolbar\" role=\"toolbar\" aria-label=\"Formatting\">\n {groups.map((buttons, i) => (\n <Fragment key={i}>\n {i > 0 && <Divider />}\n <div className=\"rte-tb-group\">{buttons}</div>\n </Fragment>\n ))}\n </div>\n );\n}\n\nexport default Toolbar;\n","import { EditorContent, useEditor } from \"@tiptap/react\";\nimport {\n forwardRef,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { createEmailExtensions } from \"../extensions/editorExtensions\";\nimport type { ToolbarConfig } from \"../types\";\nimport { PRESET_DIVIDER, PRESET_FOOTER, PRESET_PARAGRAPH } from \"../utils/presets\";\nimport { resolveToolbarConfig } from \"../utils/resolveToolbarConfig\";\nimport { EmailButtonDialog } from \"./EmailButtonDialog\";\nimport { Toolbar } from \"./Toolbar\";\n\nexport type RichTextEditorHandle = {\n /** Insert raw HTML or plain text at the current caret position. */\n insertAtCaret: (htmlOrText: string) => void;\n};\n\nexport type RichTextEditorProps = {\n /** Body-level HTML fragment (no `<html>`/`<body>`). */\n value: string;\n /** Fires with the updated body-level HTML fragment. */\n onChange: (value: string) => void;\n /** Empty-state placeholder text. */\n placeholder?: string;\n /** Resolve an uploaded file to a hosted image URL. */\n onUploadImage?: (file: File) => Promise<string>;\n /** Extra class on the editor wrapper. */\n className?: string;\n /** Inline style applied to the editable surface (e.g. minHeight/height). */\n editorStyle?: React.CSSProperties;\n /** Which toolbar controls to render (defaults to everything on). */\n toolbar?: ToolbarConfig;\n};\n\n/**\n * The generic body-HTML rich-text editor: a toolbar plus an editable surface\n * operating on a plain HTML fragment. `<EmailEditor>` wraps this to add the\n * document-shell bridge and placeholder chips.\n */\nexport const RichTextEditor = forwardRef<\n RichTextEditorHandle,\n RichTextEditorProps\n>(function RichTextEditor(\n {\n value,\n onChange,\n placeholder = \"Write your email…\",\n onUploadImage,\n className,\n editorStyle,\n toolbar,\n },\n ref,\n) {\n const toolbarConfig = useMemo(\n () => resolveToolbarConfig(toolbar),\n [toolbar],\n );\n\n const extensions = useMemo(\n () => createEmailExtensions(placeholder),\n [placeholder],\n );\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [htmlMode, setHtmlMode] = useState(false);\n const [buttonDialogOpen, setButtonDialogOpen] = useState(false);\n\n const editor = useEditor({\n extensions,\n content: value,\n // REQUIRED for SSR/Next.js — rendering immediately causes a hydration\n // mismatch because the server has no DOM.\n immediatelyRender: false,\n editorProps: {\n attributes: {\n class: \"rte-content\",\n },\n },\n onUpdate: ({ editor: e }) => {\n onChange(e.getHTML());\n },\n });\n\n // Sync external `value` changes into the editor without fighting the user's\n // typing: only when it actually differs from the editor's current HTML, and\n // with emitUpdate:false so it does not re-fire onChange.\n if (editor && !htmlMode && value !== editor.getHTML()) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n\n useImperativeHandle(\n ref,\n () => ({\n insertAtCaret: (htmlOrText: string) => {\n editor?.chain().focus().insertContent(htmlOrText).run();\n },\n }),\n [editor],\n );\n\n const insertSnippet = useCallback(\n (snippet: string) => {\n editor?.chain().focus().insertContent(snippet).run();\n },\n [editor],\n );\n\n const handleLink = useCallback(() => {\n if (!editor) return;\n const previous = editor.getAttributes(\"link\").href as string | undefined;\n const url = window.prompt(\"Link URL\", previous ?? \"https://\");\n if (url === null) return; // cancelled\n if (url.trim() === \"\") {\n editor.chain().focus().extendMarkRange(\"link\").unsetLink().run();\n return;\n }\n editor\n .chain()\n .focus()\n .extendMarkRange(\"link\")\n .setLink({ href: url.trim() })\n .run();\n }, [editor]);\n\n const handleImageClick = useCallback(() => {\n if (!editor) return;\n if (onUploadImage) {\n fileInputRef.current?.click();\n } else {\n const url = window.prompt(\"Image URL\", \"https://\");\n if (url && url.trim()) {\n editor.chain().focus().setImage({ src: url.trim() }).run();\n }\n }\n }, [editor, onUploadImage]);\n\n const handleFileSelected = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n // Reset so selecting the same file again re-triggers change.\n e.target.value = \"\";\n if (!file || !onUploadImage || !editor) return;\n try {\n const src = await onUploadImage(file);\n if (src) editor.chain().focus().setImage({ src }).run();\n } catch (err) {\n // Surface upload failures without crashing the editor.\n console.error(\"dpk-editor: image upload failed\", err);\n }\n },\n [editor, onUploadImage],\n );\n\n const handleButtonConfirm = useCallback(\n (html: string) => {\n setButtonDialogOpen(false);\n editor?.chain().focus().insertContent(html).run();\n },\n [editor],\n );\n\n if (!editor) return null;\n\n return (\n <div className={\"rte-root\" + (className ? ` ${className}` : \"\")}>\n <Toolbar\n editor={editor}\n config={toolbarConfig}\n htmlMode={htmlMode}\n onToggleHtml={() => setHtmlMode((m) => !m)}\n onLink={handleLink}\n onImage={handleImageClick}\n onButton={() => setButtonDialogOpen(true)}\n onInsertParagraph={() => insertSnippet(PRESET_PARAGRAPH)}\n onInsertDivider={() => insertSnippet(PRESET_DIVIDER)}\n onInsertFooter={() => insertSnippet(PRESET_FOOTER)}\n />\n\n {htmlMode ? (\n <textarea\n className=\"rte-source\"\n style={editorStyle}\n value={value}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n aria-label=\"HTML source\"\n />\n ) : (\n <EditorContent\n editor={editor}\n className=\"rte-editor\"\n style={editorStyle}\n />\n )}\n\n {onUploadImage && (\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={handleFileSelected}\n />\n )}\n\n <EmailButtonDialog\n open={buttonDialogOpen}\n onConfirm={handleButtonConfirm}\n onClose={() => setButtonDialogOpen(false)}\n />\n </div>\n );\n});\n\nexport default RichTextEditor;\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\n\nimport type {\n EmailHtmlDocument,\n EmailPlaceholder,\n ToolbarConfig,\n} from \"../types\";\nimport { joinEmailHtml, splitEmailHtml } from \"../utils/shellBridge\";\nimport {\n RichTextEditor,\n type RichTextEditorHandle,\n} from \"./RichTextEditor\";\n\nexport type EmailEditorProps = {\n /** Full HTML document OR a bare body fragment — both are supported. */\n value: string;\n /** Fires with HTML in the same shape `value` was provided (shell re-applied). */\n onChange: (value: string) => void;\n /** Optional merge tokens; render a chip row that inserts at the caret. */\n placeholders?: EmailPlaceholder[];\n /** Resolve an uploaded file to a hosted image URL (else a URL prompt is used). */\n onUploadImage?: (file: File) => Promise<string>;\n /** Minimum height (px) of the editable surface. */\n minHeight?: number;\n /** Empty-state placeholder text for the editable surface. */\n placeholder?: string;\n /** Which toolbar controls to render (defaults to everything on). */\n toolbar?: ToolbarConfig;\n /** Extra class on the editor wrapper. */\n className?: string;\n};\n\n/**\n * The batteries-included email editor. Owns the document-shell bridge so the\n * surrounding `<!doctype>`/`<html>`/`<body style>` (and any `<table>` layout\n * inside the body) is preserved verbatim across edits, while only the body\n * fragment is handed to the underlying `<RichTextEditor>`.\n */\nexport function EmailEditor({\n value,\n onChange,\n placeholders,\n onUploadImage,\n minHeight = 288,\n placeholder,\n toolbar,\n className,\n}: EmailEditorProps) {\n // Recompute the shell from `value` on each render.\n const shell = useMemo<EmailHtmlDocument>(() => splitEmailHtml(value), [value]);\n\n // Keep the latest shell in a ref so the onChange closure always rejoins with\n // the current prefix/suffix. Assign the ref in an EFFECT (never during\n // render) — strict react-hooks lint flags a render-time ref write.\n const shellRef = useRef<EmailHtmlDocument>(shell);\n useEffect(() => {\n shellRef.current = shell;\n }, [shell]);\n\n const editorRef = useRef<RichTextEditorHandle>(null);\n\n const handleBodyChange = useCallback(\n (newBody: string) => {\n onChange(joinEmailHtml(shellRef.current, newBody));\n },\n [onChange],\n );\n\n const editorStyle = useMemo<React.CSSProperties>(\n () => ({ minHeight }),\n [minHeight],\n );\n\n const insertToken = useCallback((token: string) => {\n editorRef.current?.insertAtCaret(token);\n }, []);\n\n return (\n <div className={\"rte-email\" + (className ? ` ${className}` : \"\")}>\n {placeholders && placeholders.length > 0 && (\n <div className=\"rte-chips\" role=\"group\" aria-label=\"Merge tokens\">\n {placeholders.map((p) => (\n <button\n key={p.token}\n type=\"button\"\n className=\"rte-chip\"\n title={`Insert ${p.token}`}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => insertToken(p.token)}\n >\n {p.label}\n </button>\n ))}\n </div>\n )}\n\n <RichTextEditor\n ref={editorRef}\n value={shell.body}\n onChange={handleBodyChange}\n onUploadImage={onUploadImage}\n placeholder={placeholder}\n editorStyle={editorStyle}\n toolbar={toolbar}\n />\n </div>\n );\n}\n\nexport default EmailEditor;\n"]}
1
+ {"version":3,"sources":["../src/utils/shellBridge.ts","../src/extensions/PreserveStyles.ts","../src/extensions/editorExtensions.ts","../src/utils/presets.ts","../src/utils/resolveToolbarConfig.ts","../src/utils/escapeHtml.ts","../src/utils/buildButtonHtml.ts","../src/components/EmailButtonDialog.tsx","../src/components/Toolbar.tsx","../src/components/RichTextEditor.tsx","../src/components/EmailEditor.tsx"],"names":["Extension","StarterKit","Image","TextAlign","TextStyle","Color","Highlight","Placeholder","jsxs","jsx","useState","useRef","useEffect","useMemo","Heading2","Heading3","Heading4","Heading5","Heading6","useEditorState","Bold","Italic","Underline","Strikethrough","Code","List","ListOrdered","Quote","AlignLeft","AlignCenter","AlignRight","LinkIcon","ImageIcon","MousePointerClick","Pilcrow","Minus","PanelBottom","FileCode","Fragment","forwardRef","RichTextEditor","useEditor","useImperativeHandle","useCallback","EditorContent"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { EmailHtmlDocument } from \"../types\";\n\n/**\n * Document-shell bridge utilities.\n *\n * A `contentEditable`/ProseMirror surface cannot host `<html>`/`<head>`/\n * `<body>` — it silently strips them and keeps only body-level flow content.\n * So `<EmailEditor>` edits only the **body fragment** and preserves the\n * surrounding document shell verbatim across edits.\n *\n * These are pure string utilities (no DOM required): they operate by locating\n * the `<body ...>` tag with a regex, so they work the same in the browser,\n * during SSR, and in tests.\n */\n\n// Matches the opening <body ...> tag (case-insensitive, any attributes,\n// across newlines). Non-greedy so it stops at the first `>`.\nconst BODY_OPEN_RE = /<body\\b[^>]*>/i;\n// Matches the closing </body> tag.\nconst BODY_CLOSE_RE = /<\\/body\\s*>/i;\n\n/**\n * Split a full email HTML document into `{ prefix, body, suffix }`.\n *\n * - `prefix` = everything up to and including the opening `<body ...>` tag.\n * - `body` = the inner body HTML (the editable fragment).\n * - `suffix` = the closing `</body>` tag plus everything after it.\n *\n * If the input has no `<body>` tag it is treated as a **bare fragment**: the\n * whole input becomes `body`, and `prefix`/`suffix` are empty strings.\n */\nexport function splitEmailHtml(html: string): EmailHtmlDocument {\n const input = html ?? \"\";\n\n const openMatch = input.match(BODY_OPEN_RE);\n if (!openMatch || openMatch.index === undefined) {\n // Bare fragment — no shell to preserve.\n return { prefix: \"\", body: input, suffix: \"\" };\n }\n\n const openStart = openMatch.index;\n const openEnd = openStart + openMatch[0].length;\n const prefix = input.slice(0, openEnd);\n\n const rest = input.slice(openEnd);\n const closeMatch = rest.match(BODY_CLOSE_RE);\n\n if (!closeMatch || closeMatch.index === undefined) {\n // Opening <body> but no closing tag — treat the remainder as body and\n // synthesize an empty suffix so a rejoin still nests inside the shell.\n return { prefix, body: rest, suffix: \"\" };\n }\n\n const body = rest.slice(0, closeMatch.index);\n const suffix = rest.slice(closeMatch.index);\n\n return { prefix, body, suffix };\n}\n\n/**\n * Reassemble a document from a shell and a (possibly edited) body fragment.\n *\n * If the shell has no surrounding markup (a bare fragment was originally\n * supplied) the body is returned as-is, so `onChange` emits in the same shape\n * the consumer provided `value`.\n */\nexport function joinEmailHtml(\n shell: EmailHtmlDocument,\n newBody: string,\n): string {\n const body = newBody ?? \"\";\n if (!shell.prefix && !shell.suffix) {\n return body;\n }\n return `${shell.prefix}${body}${shell.suffix}`;\n}\n\n/**\n * Convenience: extract just the editable body fragment from a full document\n * (or return the input unchanged if it is already a bare fragment).\n */\nexport function extractEmailBody(html: string): string {\n return splitEmailHtml(html).body;\n}\n","import { Extension } from \"@tiptap/react\";\n\n/**\n * A TipTap extension that preserves the inline `style` attribute on every node\n * and mark in the schema.\n *\n * TipTap (ProseMirror) strips any HTML attribute a node/mark does not declare.\n * For article editing that is fine; for **email** HTML it is lossy — buttons\n * lose their padding/background, headings lose their color, and so on. This\n * extension declares a global `style` attribute so arbitrary inline-styled\n * email HTML round-trips.\n *\n * It preserves `style` only on elements that map to a known node or mark\n * (paragraph, heading, list, blockquote, link, image, hr, …). Raw\n * `<table>`/`<td>` layouts are still flattened by ProseMirror's schema — those\n * survive via the document-shell bridge, not here.\n */\nexport const PreserveStyles = Extension.create({\n name: \"preserveStyles\",\n\n addGlobalAttributes() {\n return [\n {\n // ⚠️ MUST be the string shorthand \"*\" (= all nodes and marks).\n // NEVER [\"*\"] — an array means \"a type literally named *\", which\n // matches nothing and silently preserves no styles. That bug passes\n // tsc/eslint/build cleanly, so it is asserted against in the tests.\n types: \"*\",\n attributes: {\n style: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"style\"),\n renderHTML: (attributes) =>\n attributes.style ? { style: attributes.style as string } : {},\n },\n },\n },\n ];\n },\n});\n\nexport default PreserveStyles;\n","import Highlight from \"@tiptap/extension-highlight\";\nimport Image from \"@tiptap/extension-image\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport TextAlign from \"@tiptap/extension-text-align\";\n// @tiptap/extension-text-style v3 re-exports both TextStyle and Color, so we\n// do NOT need @tiptap/extension-color as a separate dependency.\nimport { Color, TextStyle } from \"@tiptap/extension-text-style\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport type { Extensions } from \"@tiptap/react\";\n\nimport { PreserveStyles } from \"./PreserveStyles\";\n\n/**\n * The canonical extension set for the email editor.\n *\n * Notes / watch-outs baked in here:\n * - StarterKit v3 already bundles Link, Underline, lists, blockquote, code and\n * headings — we do NOT add @tiptap/extension-link or -underline separately\n * (that throws duplicate-extension warnings). Link is configured through\n * StarterKit.configure({ link: {...} }).\n * - Image is block-level and base64 is disabled (uploads should resolve to a\n * hosted URL, which is what email clients can render).\n * - PreserveStyles must be present so inline `style` survives the round-trip.\n * - Placeholder is NOT bundled by StarterKit v3, so it is added explicitly to\n * power the empty-state hint (it sets the `is-editor-empty` class and the\n * `data-placeholder` attribute that styles.css renders via `::before`).\n *\n * Exported as a factory so the React component and the headless tests build an\n * identical extension set. Pass the empty-state placeholder text in.\n */\nexport function createEmailExtensions(placeholder?: string): Extensions {\n return [\n StarterKit.configure({\n link: {\n openOnClick: false,\n autolink: true,\n HTMLAttributes: { rel: \"noopener noreferrer\" },\n },\n }),\n Image.configure({ inline: false, allowBase64: false }),\n TextAlign.configure({ types: [\"heading\", \"paragraph\"] }),\n TextStyle,\n Color,\n Highlight.configure({ multicolor: true }),\n Placeholder.configure({\n placeholder: placeholder ?? \"Write something…\",\n // Emit data-placeholder so styles.css can render it via attr(); also\n // keep the default is-editor-empty class for the :first-child selector.\n showOnlyWhenEditable: true,\n }),\n PreserveStyles,\n ];\n}\n","/**\n * Preset block snippets — small, inline-styled, email-safe HTML fragments\n * inserted at the caret via `editor.chain().focus().insertContent(snippet)`.\n *\n * Every snippet uses inline styles only (no classes) so it survives both the\n * editor schema (via PreserveStyles) and downstream email clients.\n */\nexport const PRESET_PARAGRAPH =\n '<p style=\"margin:0 0 12px;color:#4b5563;line-height:1.6;\">Write your message here.</p>';\n\nexport const PRESET_DIVIDER =\n '<hr style=\"border:none;border-top:1px solid #e5e7eb;margin:20px 0;\" />';\n\nexport const PRESET_FOOTER =\n '<p style=\"margin:20px 0 0;color:#9ca3af;font-size:12px;\">© Your Company</p>';\n\nexport const PRESET_HEADING =\n '<h2 style=\"margin:0 0 12px;color:#111827;font-size:24px;line-height:1.3;\">Heading</h2>';\n\nexport const presets = {\n paragraph: PRESET_PARAGRAPH,\n divider: PRESET_DIVIDER,\n footer: PRESET_FOOTER,\n heading: PRESET_HEADING,\n} as const;\n","import type {\n AlignButtons,\n BlockButtons,\n HeadingButtons,\n InlineButtons,\n ListButtons,\n ResolvedToolbarConfig,\n ToolbarConfig,\n ToolbarGroup,\n} from \"../types\";\n\n/**\n * Resolve a loose `ToolbarConfig` into the flat `ResolvedToolbarConfig` the\n * Toolbar renders from. Rules:\n * - A group key may be a boolean or a per-button object (or omitted).\n * - Omitted / `true` / `{}` → group enabled, every button enabled.\n * - `false` → group disabled (and all its buttons disabled).\n * - An object → group enabled, each listed button overridden; unlisted buttons\n * default to `true`.\n */\nfunction resolveGroup<TButtons extends Record<string, boolean | undefined>>(\n group: ToolbarGroup<TButtons> | undefined,\n defaults: Required<TButtons>,\n): { enabled: boolean; buttons: Required<TButtons> } {\n // Omitted → all on.\n if (group === undefined || group === true) {\n return { enabled: true, buttons: { ...defaults } };\n }\n // Whole group off → disable every button too.\n if (group === false) {\n const off = {} as Required<TButtons>;\n for (const key of Object.keys(defaults) as (keyof TButtons)[]) {\n off[key] = false as Required<TButtons>[keyof TButtons];\n }\n return { enabled: false, buttons: off };\n }\n // Per-button object → group on, merge overrides over the all-on defaults.\n return { enabled: true, buttons: { ...defaults, ...group } };\n}\n\nconst INLINE_DEFAULTS: Required<InlineButtons> = {\n bold: true,\n italic: true,\n underline: true,\n strike: true,\n code: true,\n};\nconst HEADING_DEFAULTS: Required<HeadingButtons> = {\n h2: true,\n h3: true,\n h4: true,\n h5: true,\n h6: true,\n};\nconst LIST_DEFAULTS: Required<ListButtons> = {\n bullet: true,\n ordered: true,\n blockquote: true,\n};\nconst ALIGN_DEFAULTS: Required<AlignButtons> = {\n left: true,\n center: true,\n right: true,\n};\nconst BLOCK_DEFAULTS: Required<BlockButtons> = {\n paragraph: true,\n divider: true,\n footer: true,\n};\n\n/** A single-control group is on unless explicitly set to `false`. */\nfunction resolveToggle(value: boolean | undefined): boolean {\n return value !== false;\n}\n\nexport function resolveToolbarConfig(\n config?: ToolbarConfig,\n): ResolvedToolbarConfig {\n const c = config ?? {};\n return {\n inline: resolveGroup(c.inline, INLINE_DEFAULTS),\n headings: resolveGroup(c.headings, HEADING_DEFAULTS),\n lists: resolveGroup(c.lists, LIST_DEFAULTS),\n align: resolveGroup(c.align, ALIGN_DEFAULTS),\n link: resolveToggle(c.link),\n image: resolveToggle(c.image),\n button: resolveToggle(c.button),\n blocks: resolveGroup(c.blocks, BLOCK_DEFAULTS),\n html: resolveToggle(c.html),\n };\n}\n","/**\n * Escape a string for safe insertion into HTML text or a double-quoted\n * attribute value. Used by `buildButtonHtml` for the button label and href.\n */\nexport function escapeHtml(value: string): string {\n return String(value)\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n","import type { EmailButtonConfig } from \"../types\";\nimport { escapeHtml } from \"./escapeHtml\";\n\n/**\n * Build email-safe HTML for a call-to-action button.\n *\n * Two non-obvious decisions, both load-bearing:\n *\n * 1. The anchor is wrapped in a `<p style=\"...;text-align:X\">`, **never** a\n * `<div>`. TipTap has no `div` node and unwraps a `<div>` into a paragraph,\n * losing the `text-align`. A paragraph is a real node whose `text-align`\n * the TextAlign extension preserves — so the alignment round-trips.\n *\n * 2. The button is an `<a style=\"display:inline-block;...\">` (or\n * `display:block` when full-width), not a `<button>`, because email clients\n * need bulletproof, inline-styled markup.\n *\n * Both the label and the href are HTML-escaped.\n */\nexport function buildButtonHtml(config: EmailButtonConfig): string {\n const {\n text,\n href,\n bgColor,\n textColor,\n align,\n radius,\n fullWidth,\n } = config;\n\n const safeText = escapeHtml(text || \"Button\");\n const safeHref = escapeHtml(href || \"#\");\n const safeRadius = Number.isFinite(radius) ? Math.max(0, radius) : 0;\n\n // Full-width buttons span the content area as a block and center their own\n // label; otherwise they hug their content as an inline-block.\n const display = fullWidth ? \"block\" : \"inline-block\";\n const anchorTextAlign = fullWidth ? \"text-align:center;\" : \"\";\n\n const anchorStyle = [\n `display:${display}`,\n \"padding:12px 24px\",\n `background-color:${bgColor}`,\n `color:${textColor}`,\n \"text-decoration:none\",\n \"font-weight:600\",\n \"font-family:Arial,Helvetica,sans-serif\",\n \"font-size:14px\",\n \"line-height:1.4\",\n `border-radius:${safeRadius}px`,\n anchorTextAlign,\n ]\n .filter(Boolean)\n .join(\";\");\n\n const paragraphStyle = `margin:16px 0;text-align:${align}`;\n\n return (\n `<p style=\"${paragraphStyle}\">` +\n `<a href=\"${safeHref}\" target=\"_blank\" rel=\"noopener noreferrer\" ` +\n `style=\"${anchorStyle}\">${safeText}</a>` +\n `</p>`\n );\n}\n","import { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { EmailButtonConfig } from \"../types\";\nimport { buildButtonHtml } from \"../utils/buildButtonHtml\";\n\nexport type EmailButtonDialogProps = {\n /** Whether the dialog is open. */\n open: boolean;\n /** Called when the user confirms; receives the email-safe button HTML. */\n onConfirm: (html: string, config: EmailButtonConfig) => void;\n /** Called when the user dismisses the dialog (Esc / click-outside / cancel). */\n onClose: () => void;\n /** Optional initial values for the form. */\n initial?: Partial<EmailButtonConfig>;\n};\n\nconst DEFAULT_CONFIG: EmailButtonConfig = {\n text: \"Click here\",\n href: \"https://\",\n bgColor: \"#2563eb\",\n textColor: \"#ffffff\",\n align: \"left\",\n radius: 6,\n fullWidth: false,\n};\n\nconst BG_SWATCHES = [\n \"#2563eb\",\n \"#16a34a\",\n \"#dc2626\",\n \"#7c3aed\",\n \"#ea580c\",\n \"#0891b2\",\n \"#111827\",\n];\nconst TEXT_SWATCHES = [\"#ffffff\", \"#111827\", \"#f9fafb\", \"#1f2937\"];\n\n// <input type=color> only accepts #rrggbb. Named colors, #rgb shorthand, or\n// anything else must be coerced or it throws/blanks the control.\nconst HEX6_RE = /^#[0-9a-fA-F]{6}$/;\nfunction toColorInputValue(value: string): string {\n return HEX6_RE.test(value) ? value : \"#000000\";\n}\n\ntype ColorFieldProps = {\n label: string;\n value: string;\n swatches: string[];\n onChange: (value: string) => void;\n};\n\nfunction ColorField({ label, value, swatches, onChange }: ColorFieldProps) {\n return (\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">{label}</span>\n <div className=\"rte-color-row\">\n {swatches.map((swatch) => (\n <button\n key={swatch}\n type=\"button\"\n className={\n \"rte-swatch\" + (value === swatch ? \" rte-swatch--active\" : \"\")\n }\n style={{ backgroundColor: swatch }}\n aria-label={`Use ${swatch}`}\n aria-pressed={value === swatch}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onChange(swatch)}\n />\n ))}\n <input\n type=\"color\"\n className=\"rte-color-input\"\n value={toColorInputValue(value)}\n aria-label={`${label} picker`}\n onChange={(e) => onChange(e.target.value)}\n />\n <input\n type=\"text\"\n className=\"rte-hex-input\"\n value={value}\n aria-label={`${label} hex`}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n </div>\n );\n}\n\n/**\n * Modal dialog for configuring an email CTA button. Supports Esc to close,\n * body-scroll lock while open, click-outside to dismiss, and a live preview of\n * the rendered button.\n */\nexport function EmailButtonDialog({\n open,\n onConfirm,\n onClose,\n initial,\n}: EmailButtonDialogProps) {\n const [config, setConfig] = useState<EmailButtonConfig>({\n ...DEFAULT_CONFIG,\n ...initial,\n });\n const overlayRef = useRef<HTMLDivElement>(null);\n\n // Reset the form to its initial state each time the dialog opens.\n useEffect(() => {\n if (open) {\n setConfig({ ...DEFAULT_CONFIG, ...initial });\n }\n }, [open, initial]);\n\n // Esc to close + body-scroll lock while open.\n useEffect(() => {\n if (!open) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n onClose();\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.body.style.overflow = previousOverflow;\n };\n }, [open, onClose]);\n\n const previewHtml = useMemo(() => buildButtonHtml(config), [config]);\n\n if (!open) return null;\n\n const update = <K extends keyof EmailButtonConfig>(\n key: K,\n value: EmailButtonConfig[K],\n ) => setConfig((prev) => ({ ...prev, [key]: value }));\n\n const handleSubmit = () => {\n onConfirm(buildButtonHtml(config), config);\n };\n\n return (\n <div\n ref={overlayRef}\n className=\"rte-dialog-overlay\"\n role=\"presentation\"\n onMouseDown={(e) => {\n // Click-outside (on the overlay itself, not the panel) dismisses.\n if (e.target === overlayRef.current) onClose();\n }}\n >\n <div\n className=\"rte-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Insert button\"\n >\n <div className=\"rte-dialog-header\">\n <h2 className=\"rte-dialog-title\">Insert button</h2>\n <button\n type=\"button\"\n className=\"rte-dialog-close\"\n aria-label=\"Close\"\n onClick={onClose}\n >\n ×\n </button>\n </div>\n\n <div className=\"rte-dialog-body\">\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Text</span>\n <input\n type=\"text\"\n className=\"rte-text-input\"\n value={config.text}\n onChange={(e) => update(\"text\", e.target.value)}\n />\n </label>\n\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Link URL</span>\n <input\n type=\"text\"\n className=\"rte-text-input\"\n value={config.href}\n onChange={(e) => update(\"href\", e.target.value)}\n />\n </label>\n\n <ColorField\n label=\"Background color\"\n value={config.bgColor}\n swatches={BG_SWATCHES}\n onChange={(v) => update(\"bgColor\", v)}\n />\n\n <ColorField\n label=\"Text color\"\n value={config.textColor}\n swatches={TEXT_SWATCHES}\n onChange={(v) => update(\"textColor\", v)}\n />\n\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Alignment</span>\n <div className=\"rte-align-row\">\n {([\"left\", \"center\", \"right\"] as const).map((a) => (\n <button\n key={a}\n type=\"button\"\n className={\n \"rte-align-btn\" +\n (config.align === a ? \" rte-align-btn--active\" : \"\")\n }\n aria-pressed={config.align === a}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => update(\"align\", a)}\n >\n {a}\n </button>\n ))}\n </div>\n </div>\n\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">\n Corner radius: {config.radius}px\n </span>\n <input\n type=\"range\"\n min={0}\n max={32}\n value={config.radius}\n onChange={(e) => update(\"radius\", Number(e.target.value))}\n />\n </label>\n\n <label className=\"rte-checkbox-field\">\n <input\n type=\"checkbox\"\n checked={config.fullWidth}\n onChange={(e) => update(\"fullWidth\", e.target.checked)}\n />\n <span>Full width</span>\n </label>\n\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Preview</span>\n <div\n className=\"rte-button-preview\"\n // Preview only — content is built from the same escaped builder.\n dangerouslySetInnerHTML={{ __html: previewHtml }}\n />\n </div>\n </div>\n\n <div className=\"rte-dialog-footer\">\n <button\n type=\"button\"\n className=\"rte-btn rte-btn--ghost\"\n onClick={onClose}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"rte-btn rte-btn--primary\"\n onClick={handleSubmit}\n >\n Insert\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport default EmailButtonDialog;\n","import type { Editor } from \"@tiptap/react\";\nimport { useEditorState } from \"@tiptap/react\";\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n Bold,\n Code,\n FileCode,\n Heading2,\n Heading3,\n Heading4,\n Heading5,\n Heading6,\n Image as ImageIcon,\n Italic,\n Link as LinkIcon,\n List,\n ListOrdered,\n Minus,\n MousePointerClick,\n PanelBottom,\n Pilcrow,\n Quote,\n Strikethrough,\n Underline,\n} from \"lucide-react\";\nimport { Fragment, type ReactNode } from \"react\";\n\nimport type { ResolvedToolbarConfig } from \"../types\";\n\ntype HeadingLevel = 2 | 3 | 4 | 5 | 6;\n\nexport type ToolbarProps = {\n editor: Editor;\n config: ResolvedToolbarConfig;\n /** Toggle the raw HTML source view. */\n htmlMode: boolean;\n onToggleHtml: () => void;\n /** Caller-provided handlers for the controls that need extra UI. */\n onLink: () => void;\n onImage: () => void;\n onButton: () => void;\n onInsertParagraph: () => void;\n onInsertDivider: () => void;\n onInsertFooter: () => void;\n};\n\ntype TbButtonProps = {\n onClick: () => void;\n active?: boolean;\n label: string;\n disabled?: boolean;\n children: ReactNode;\n};\n\nfunction TbButton({ onClick, active, label, disabled, children }: TbButtonProps) {\n return (\n <button\n type=\"button\"\n className={\"rte-tb-btn\" + (active ? \" rte-tb-btn--active\" : \"\")}\n // Prevent the button from stealing the editor's selection on press.\n onMouseDown={(e) => e.preventDefault()}\n onClick={onClick}\n aria-pressed={!!active}\n aria-label={label}\n title={label}\n disabled={disabled}\n >\n {children}\n </button>\n );\n}\n\nfunction Divider() {\n return <span className=\"rte-tb-divider\" aria-hidden=\"true\" />;\n}\n\nconst HEADING_ICONS: Record<HeadingLevel, ReactNode> = {\n 2: <Heading2 size={16} />,\n 3: <Heading3 size={16} />,\n 4: <Heading4 size={16} />,\n 5: <Heading5 size={16} />,\n 6: <Heading6 size={16} />,\n};\n\nexport function Toolbar({\n editor,\n config,\n htmlMode,\n onToggleHtml,\n onLink,\n onImage,\n onButton,\n onInsertParagraph,\n onInsertDivider,\n onInsertFooter,\n}: ToolbarProps) {\n // useEditorState re-renders only when the selected slice changes, keeping\n // active-state computation cheap even on large documents.\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) => ({\n bold: e.isActive(\"bold\"),\n italic: e.isActive(\"italic\"),\n underline: e.isActive(\"underline\"),\n strike: e.isActive(\"strike\"),\n code: e.isActive(\"code\"),\n h2: e.isActive(\"heading\", { level: 2 }),\n h3: e.isActive(\"heading\", { level: 3 }),\n h4: e.isActive(\"heading\", { level: 4 }),\n h5: e.isActive(\"heading\", { level: 5 }),\n h6: e.isActive(\"heading\", { level: 6 }),\n bulletList: e.isActive(\"bulletList\"),\n orderedList: e.isActive(\"orderedList\"),\n blockquote: e.isActive(\"blockquote\"),\n alignLeft: e.isActive({ textAlign: \"left\" }),\n alignCenter: e.isActive({ textAlign: \"center\" }),\n alignRight: e.isActive({ textAlign: \"right\" }),\n link: e.isActive(\"link\"),\n image: e.isActive(\"image\"),\n }),\n });\n\n const headingActive: Record<HeadingLevel, boolean> = {\n 2: state.h2,\n 3: state.h3,\n 4: state.h4,\n 5: state.h5,\n 6: state.h6,\n };\n\n // In HTML source mode only the source toggle is interactive.\n const disabled = htmlMode;\n\n // Build each group as an array of rendered buttons, gated by both the group\n // `enabled` flag and the per-button flag. A group with zero visible buttons\n // contributes nothing (and gets no divider).\n const inline = config.inline.enabled\n ? [\n config.inline.buttons.bold && (\n <TbButton\n key=\"bold\"\n label=\"Bold\"\n active={state.bold}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBold().run()}\n >\n <Bold size={16} />\n </TbButton>\n ),\n config.inline.buttons.italic && (\n <TbButton\n key=\"italic\"\n label=\"Italic\"\n active={state.italic}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleItalic().run()}\n >\n <Italic size={16} />\n </TbButton>\n ),\n config.inline.buttons.underline && (\n <TbButton\n key=\"underline\"\n label=\"Underline\"\n active={state.underline}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n >\n <Underline size={16} />\n </TbButton>\n ),\n config.inline.buttons.strike && (\n <TbButton\n key=\"strike\"\n label=\"Strikethrough\"\n active={state.strike}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleStrike().run()}\n >\n <Strikethrough size={16} />\n </TbButton>\n ),\n config.inline.buttons.code && (\n <TbButton\n key=\"code\"\n label=\"Inline code\"\n active={state.code}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleCode().run()}\n >\n <Code size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const headings = config.headings.enabled\n ? ([2, 3, 4, 5, 6] as const).map((level) =>\n config.headings.buttons[`h${level}` as keyof typeof config.headings.buttons] ? (\n <TbButton\n key={`h${level}`}\n label={`Heading ${level}`}\n active={headingActive[level]}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleHeading({ level }).run()}\n >\n {HEADING_ICONS[level]}\n </TbButton>\n ) : (\n false\n ),\n )\n : [];\n\n const lists = config.lists.enabled\n ? [\n config.lists.buttons.bullet && (\n <TbButton\n key=\"bullet\"\n label=\"Bullet list\"\n active={state.bulletList}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n >\n <List size={16} />\n </TbButton>\n ),\n config.lists.buttons.ordered && (\n <TbButton\n key=\"ordered\"\n label=\"Ordered list\"\n active={state.orderedList}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n >\n <ListOrdered size={16} />\n </TbButton>\n ),\n config.lists.buttons.blockquote && (\n <TbButton\n key=\"quote\"\n label=\"Quote\"\n active={state.blockquote}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBlockquote().run()}\n >\n <Quote size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const align = config.align.enabled\n ? [\n config.align.buttons.left && (\n <TbButton\n key=\"left\"\n label=\"Align left\"\n active={state.alignLeft}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"left\").run()}\n >\n <AlignLeft size={16} />\n </TbButton>\n ),\n config.align.buttons.center && (\n <TbButton\n key=\"center\"\n label=\"Align center\"\n active={state.alignCenter}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"center\").run()}\n >\n <AlignCenter size={16} />\n </TbButton>\n ),\n config.align.buttons.right && (\n <TbButton\n key=\"right\"\n label=\"Align right\"\n active={state.alignRight}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"right\").run()}\n >\n <AlignRight size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const inserts = [\n config.link && (\n <TbButton\n key=\"link\"\n label=\"Link\"\n active={state.link}\n disabled={disabled}\n onClick={onLink}\n >\n <LinkIcon size={16} />\n </TbButton>\n ),\n config.image && (\n <TbButton\n key=\"image\"\n label=\"Image\"\n active={state.image}\n disabled={disabled}\n onClick={onImage}\n >\n <ImageIcon size={16} />\n </TbButton>\n ),\n config.button && (\n <TbButton\n key=\"button\"\n label=\"Button\"\n disabled={disabled}\n onClick={onButton}\n >\n <MousePointerClick size={16} />\n </TbButton>\n ),\n ];\n\n const blocks = config.blocks.enabled\n ? [\n config.blocks.buttons.paragraph && (\n <TbButton\n key=\"paragraph\"\n label=\"Insert paragraph\"\n disabled={disabled}\n onClick={onInsertParagraph}\n >\n <Pilcrow size={16} />\n </TbButton>\n ),\n config.blocks.buttons.divider && (\n <TbButton\n key=\"divider\"\n label=\"Insert divider\"\n disabled={disabled}\n onClick={onInsertDivider}\n >\n <Minus size={16} />\n </TbButton>\n ),\n config.blocks.buttons.footer && (\n <TbButton\n key=\"footer\"\n label=\"Insert footer\"\n disabled={disabled}\n onClick={onInsertFooter}\n >\n <PanelBottom size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const html = config.html\n ? [\n <TbButton\n key=\"html\"\n label=\"HTML source\"\n active={htmlMode}\n onClick={onToggleHtml}\n >\n <FileCode size={16} />\n </TbButton>,\n ]\n : [];\n\n // Keep only groups that have at least one visible button, then render them\n // with a divider between each — so hidden groups leave no dangling dividers.\n const groups = [inline, headings, lists, align, inserts, blocks, html]\n .map((g) => g.filter(Boolean))\n .filter((g) => g.length > 0);\n\n return (\n <div className=\"rte-toolbar\" role=\"toolbar\" aria-label=\"Formatting\">\n {groups.map((buttons, i) => (\n <Fragment key={i}>\n {i > 0 && <Divider />}\n <div className=\"rte-tb-group\">{buttons}</div>\n </Fragment>\n ))}\n </div>\n );\n}\n\nexport default Toolbar;\n","import { EditorContent, useEditor } from \"@tiptap/react\";\nimport {\n forwardRef,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { createEmailExtensions } from \"../extensions/editorExtensions\";\nimport type { ToolbarConfig } from \"../types\";\nimport { PRESET_DIVIDER, PRESET_FOOTER, PRESET_PARAGRAPH } from \"../utils/presets\";\nimport { resolveToolbarConfig } from \"../utils/resolveToolbarConfig\";\nimport { EmailButtonDialog } from \"./EmailButtonDialog\";\nimport { Toolbar } from \"./Toolbar\";\n\nexport type RichTextEditorHandle = {\n /** Insert raw HTML or plain text at the current caret position. */\n insertAtCaret: (htmlOrText: string) => void;\n};\n\nexport type RichTextEditorProps = {\n /** Body-level HTML fragment (no `<html>`/`<body>`). */\n value: string;\n /** Fires with the updated body-level HTML fragment. */\n onChange: (value: string) => void;\n /** Empty-state placeholder text. */\n placeholder?: string;\n /** Resolve an uploaded file to a hosted image URL. */\n onUploadImage?: (file: File) => Promise<string>;\n /** Extra class on the editor wrapper. */\n className?: string;\n /** Inline style applied to the editable surface (e.g. minHeight/height). */\n editorStyle?: React.CSSProperties;\n /** Which toolbar controls to render (defaults to everything on). */\n toolbar?: ToolbarConfig;\n};\n\n/**\n * The generic body-HTML rich-text editor: a toolbar plus an editable surface\n * operating on a plain HTML fragment. `<EmailEditor>` wraps this to add the\n * document-shell bridge and placeholder chips.\n */\nexport const RichTextEditor = forwardRef<\n RichTextEditorHandle,\n RichTextEditorProps\n>(function RichTextEditor(\n {\n value,\n onChange,\n placeholder = \"Write something…\",\n onUploadImage,\n className,\n editorStyle,\n toolbar,\n },\n ref,\n) {\n const toolbarConfig = useMemo(\n () => resolveToolbarConfig(toolbar),\n [toolbar],\n );\n\n const extensions = useMemo(\n () => createEmailExtensions(placeholder),\n [placeholder],\n );\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [htmlMode, setHtmlMode] = useState(false);\n const [buttonDialogOpen, setButtonDialogOpen] = useState(false);\n\n const editor = useEditor({\n extensions,\n content: value,\n // REQUIRED for SSR/Next.js — rendering immediately causes a hydration\n // mismatch because the server has no DOM.\n immediatelyRender: false,\n editorProps: {\n attributes: {\n class: \"rte-content\",\n },\n },\n onUpdate: ({ editor: e }) => {\n onChange(e.getHTML());\n },\n });\n\n // Sync external `value` changes into the editor without fighting the user's\n // typing: only when it actually differs from the editor's current HTML, and\n // with emitUpdate:false so it does not re-fire onChange.\n if (editor && !htmlMode && value !== editor.getHTML()) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n\n useImperativeHandle(\n ref,\n () => ({\n insertAtCaret: (htmlOrText: string) => {\n editor?.chain().focus().insertContent(htmlOrText).run();\n },\n }),\n [editor],\n );\n\n const insertSnippet = useCallback(\n (snippet: string) => {\n editor?.chain().focus().insertContent(snippet).run();\n },\n [editor],\n );\n\n const handleLink = useCallback(() => {\n if (!editor) return;\n const previous = editor.getAttributes(\"link\").href as string | undefined;\n const url = window.prompt(\"Link URL\", previous ?? \"https://\");\n if (url === null) return; // cancelled\n if (url.trim() === \"\") {\n editor.chain().focus().extendMarkRange(\"link\").unsetLink().run();\n return;\n }\n editor\n .chain()\n .focus()\n .extendMarkRange(\"link\")\n .setLink({ href: url.trim() })\n .run();\n }, [editor]);\n\n const handleImageClick = useCallback(() => {\n if (!editor) return;\n if (onUploadImage) {\n fileInputRef.current?.click();\n } else {\n const url = window.prompt(\"Image URL\", \"https://\");\n if (url && url.trim()) {\n editor.chain().focus().setImage({ src: url.trim() }).run();\n }\n }\n }, [editor, onUploadImage]);\n\n const handleFileSelected = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n // Reset so selecting the same file again re-triggers change.\n e.target.value = \"\";\n if (!file || !onUploadImage || !editor) return;\n try {\n const src = await onUploadImage(file);\n if (src) editor.chain().focus().setImage({ src }).run();\n } catch (err) {\n // Surface upload failures without crashing the editor.\n console.error(\"dpk-editor: image upload failed\", err);\n }\n },\n [editor, onUploadImage],\n );\n\n const handleButtonConfirm = useCallback(\n (html: string) => {\n setButtonDialogOpen(false);\n editor?.chain().focus().insertContent(html).run();\n },\n [editor],\n );\n\n if (!editor) return null;\n\n return (\n <div className={\"rte-root\" + (className ? ` ${className}` : \"\")}>\n <Toolbar\n editor={editor}\n config={toolbarConfig}\n htmlMode={htmlMode}\n onToggleHtml={() => setHtmlMode((m) => !m)}\n onLink={handleLink}\n onImage={handleImageClick}\n onButton={() => setButtonDialogOpen(true)}\n onInsertParagraph={() => insertSnippet(PRESET_PARAGRAPH)}\n onInsertDivider={() => insertSnippet(PRESET_DIVIDER)}\n onInsertFooter={() => insertSnippet(PRESET_FOOTER)}\n />\n\n {htmlMode ? (\n <textarea\n className=\"rte-source\"\n style={editorStyle}\n value={value}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n aria-label=\"HTML source\"\n />\n ) : (\n <EditorContent\n editor={editor}\n className=\"rte-editor\"\n style={editorStyle}\n />\n )}\n\n {onUploadImage && (\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={handleFileSelected}\n />\n )}\n\n <EmailButtonDialog\n open={buttonDialogOpen}\n onConfirm={handleButtonConfirm}\n onClose={() => setButtonDialogOpen(false)}\n />\n </div>\n );\n});\n\nexport default RichTextEditor;\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\n\nimport type {\n EmailHtmlDocument,\n EmailPlaceholder,\n ToolbarConfig,\n} from \"../types\";\nimport { joinEmailHtml, splitEmailHtml } from \"../utils/shellBridge\";\nimport {\n RichTextEditor,\n type RichTextEditorHandle,\n} from \"./RichTextEditor\";\n\nexport type EmailEditorProps = {\n /** Full HTML document OR a bare body fragment — both are supported. */\n value: string;\n /** Fires with HTML in the same shape `value` was provided (shell re-applied). */\n onChange: (value: string) => void;\n /** Optional merge tokens; render a chip row that inserts at the caret. */\n placeholders?: EmailPlaceholder[];\n /** Resolve an uploaded file to a hosted image URL (else a URL prompt is used). */\n onUploadImage?: (file: File) => Promise<string>;\n /** Minimum height (px) of the editable surface. */\n minHeight?: number;\n /** Empty-state placeholder text for the editable surface. */\n placeholder?: string;\n /** Which toolbar controls to render (defaults to everything on). */\n toolbar?: ToolbarConfig;\n /** Extra class on the editor wrapper. */\n className?: string;\n};\n\n/**\n * The batteries-included email editor. Owns the document-shell bridge so the\n * surrounding `<!doctype>`/`<html>`/`<body style>` (and any `<table>` layout\n * inside the body) is preserved verbatim across edits, while only the body\n * fragment is handed to the underlying `<RichTextEditor>`.\n */\nexport function EmailEditor({\n value,\n onChange,\n placeholders,\n onUploadImage,\n minHeight = 288,\n placeholder,\n toolbar,\n className,\n}: EmailEditorProps) {\n // Recompute the shell from `value` on each render.\n const shell = useMemo<EmailHtmlDocument>(() => splitEmailHtml(value), [value]);\n\n // Keep the latest shell in a ref so the onChange closure always rejoins with\n // the current prefix/suffix. Assign the ref in an EFFECT (never during\n // render) — strict react-hooks lint flags a render-time ref write.\n const shellRef = useRef<EmailHtmlDocument>(shell);\n useEffect(() => {\n shellRef.current = shell;\n }, [shell]);\n\n const editorRef = useRef<RichTextEditorHandle>(null);\n\n const handleBodyChange = useCallback(\n (newBody: string) => {\n onChange(joinEmailHtml(shellRef.current, newBody));\n },\n [onChange],\n );\n\n const editorStyle = useMemo<React.CSSProperties>(\n () => ({ minHeight }),\n [minHeight],\n );\n\n const insertToken = useCallback((token: string) => {\n editorRef.current?.insertAtCaret(token);\n }, []);\n\n return (\n <div className={\"rte-email\" + (className ? ` ${className}` : \"\")}>\n {placeholders && placeholders.length > 0 && (\n <div className=\"rte-chips\" role=\"group\" aria-label=\"Merge tokens\">\n {placeholders.map((p) => (\n <button\n key={p.token}\n type=\"button\"\n className=\"rte-chip\"\n title={`Insert ${p.token}`}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => insertToken(p.token)}\n >\n {p.label}\n </button>\n ))}\n </div>\n )}\n\n <RichTextEditor\n ref={editorRef}\n value={shell.body}\n onChange={handleBodyChange}\n onUploadImage={onUploadImage}\n placeholder={placeholder}\n editorStyle={editorStyle}\n toolbar={toolbar}\n />\n </div>\n );\n}\n\nexport default EmailEditor;\n"]}
package/dist/index.js CHANGED
@@ -81,7 +81,7 @@ function createEmailExtensions(placeholder) {
81
81
  Color,
82
82
  Highlight.configure({ multicolor: true }),
83
83
  Placeholder.configure({
84
- placeholder: placeholder ?? "Write your email\u2026",
84
+ placeholder: placeholder ?? "Write something\u2026",
85
85
  // Emit data-placeholder so styles.css can render it via attr(); also
86
86
  // keep the default is-editor-empty class for the :first-child selector.
87
87
  showOnlyWhenEditable: true
@@ -751,7 +751,7 @@ function Toolbar({
751
751
  var RichTextEditor = forwardRef(function RichTextEditor2({
752
752
  value,
753
753
  onChange,
754
- placeholder = "Write your email\u2026",
754
+ placeholder = "Write something\u2026",
755
755
  onUploadImage,
756
756
  className,
757
757
  editorStyle,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/shellBridge.ts","../src/extensions/PreserveStyles.ts","../src/extensions/editorExtensions.ts","../src/utils/presets.ts","../src/utils/resolveToolbarConfig.ts","../src/utils/escapeHtml.ts","../src/utils/buildButtonHtml.ts","../src/components/EmailButtonDialog.tsx","../src/components/Toolbar.tsx","../src/components/RichTextEditor.tsx","../src/components/EmailEditor.tsx"],"names":["jsx","LinkIcon","ImageIcon","jsxs","RichTextEditor","useMemo","useRef","useState","useEffect","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["import type { EmailHtmlDocument } from \"../types\";\n\n/**\n * Document-shell bridge utilities.\n *\n * A `contentEditable`/ProseMirror surface cannot host `<html>`/`<head>`/\n * `<body>` — it silently strips them and keeps only body-level flow content.\n * So `<EmailEditor>` edits only the **body fragment** and preserves the\n * surrounding document shell verbatim across edits.\n *\n * These are pure string utilities (no DOM required): they operate by locating\n * the `<body ...>` tag with a regex, so they work the same in the browser,\n * during SSR, and in tests.\n */\n\n// Matches the opening <body ...> tag (case-insensitive, any attributes,\n// across newlines). Non-greedy so it stops at the first `>`.\nconst BODY_OPEN_RE = /<body\\b[^>]*>/i;\n// Matches the closing </body> tag.\nconst BODY_CLOSE_RE = /<\\/body\\s*>/i;\n\n/**\n * Split a full email HTML document into `{ prefix, body, suffix }`.\n *\n * - `prefix` = everything up to and including the opening `<body ...>` tag.\n * - `body` = the inner body HTML (the editable fragment).\n * - `suffix` = the closing `</body>` tag plus everything after it.\n *\n * If the input has no `<body>` tag it is treated as a **bare fragment**: the\n * whole input becomes `body`, and `prefix`/`suffix` are empty strings.\n */\nexport function splitEmailHtml(html: string): EmailHtmlDocument {\n const input = html ?? \"\";\n\n const openMatch = input.match(BODY_OPEN_RE);\n if (!openMatch || openMatch.index === undefined) {\n // Bare fragment — no shell to preserve.\n return { prefix: \"\", body: input, suffix: \"\" };\n }\n\n const openStart = openMatch.index;\n const openEnd = openStart + openMatch[0].length;\n const prefix = input.slice(0, openEnd);\n\n const rest = input.slice(openEnd);\n const closeMatch = rest.match(BODY_CLOSE_RE);\n\n if (!closeMatch || closeMatch.index === undefined) {\n // Opening <body> but no closing tag — treat the remainder as body and\n // synthesize an empty suffix so a rejoin still nests inside the shell.\n return { prefix, body: rest, suffix: \"\" };\n }\n\n const body = rest.slice(0, closeMatch.index);\n const suffix = rest.slice(closeMatch.index);\n\n return { prefix, body, suffix };\n}\n\n/**\n * Reassemble a document from a shell and a (possibly edited) body fragment.\n *\n * If the shell has no surrounding markup (a bare fragment was originally\n * supplied) the body is returned as-is, so `onChange` emits in the same shape\n * the consumer provided `value`.\n */\nexport function joinEmailHtml(\n shell: EmailHtmlDocument,\n newBody: string,\n): string {\n const body = newBody ?? \"\";\n if (!shell.prefix && !shell.suffix) {\n return body;\n }\n return `${shell.prefix}${body}${shell.suffix}`;\n}\n\n/**\n * Convenience: extract just the editable body fragment from a full document\n * (or return the input unchanged if it is already a bare fragment).\n */\nexport function extractEmailBody(html: string): string {\n return splitEmailHtml(html).body;\n}\n","import { Extension } from \"@tiptap/react\";\n\n/**\n * A TipTap extension that preserves the inline `style` attribute on every node\n * and mark in the schema.\n *\n * TipTap (ProseMirror) strips any HTML attribute a node/mark does not declare.\n * For article editing that is fine; for **email** HTML it is lossy — buttons\n * lose their padding/background, headings lose their color, and so on. This\n * extension declares a global `style` attribute so arbitrary inline-styled\n * email HTML round-trips.\n *\n * It preserves `style` only on elements that map to a known node or mark\n * (paragraph, heading, list, blockquote, link, image, hr, …). Raw\n * `<table>`/`<td>` layouts are still flattened by ProseMirror's schema — those\n * survive via the document-shell bridge, not here.\n */\nexport const PreserveStyles = Extension.create({\n name: \"preserveStyles\",\n\n addGlobalAttributes() {\n return [\n {\n // ⚠️ MUST be the string shorthand \"*\" (= all nodes and marks).\n // NEVER [\"*\"] — an array means \"a type literally named *\", which\n // matches nothing and silently preserves no styles. That bug passes\n // tsc/eslint/build cleanly, so it is asserted against in the tests.\n types: \"*\",\n attributes: {\n style: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"style\"),\n renderHTML: (attributes) =>\n attributes.style ? { style: attributes.style as string } : {},\n },\n },\n },\n ];\n },\n});\n\nexport default PreserveStyles;\n","import Highlight from \"@tiptap/extension-highlight\";\nimport Image from \"@tiptap/extension-image\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport TextAlign from \"@tiptap/extension-text-align\";\n// @tiptap/extension-text-style v3 re-exports both TextStyle and Color, so we\n// do NOT need @tiptap/extension-color as a separate dependency.\nimport { Color, TextStyle } from \"@tiptap/extension-text-style\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport type { Extensions } from \"@tiptap/react\";\n\nimport { PreserveStyles } from \"./PreserveStyles\";\n\n/**\n * The canonical extension set for the email editor.\n *\n * Notes / watch-outs baked in here:\n * - StarterKit v3 already bundles Link, Underline, lists, blockquote, code and\n * headings — we do NOT add @tiptap/extension-link or -underline separately\n * (that throws duplicate-extension warnings). Link is configured through\n * StarterKit.configure({ link: {...} }).\n * - Image is block-level and base64 is disabled (uploads should resolve to a\n * hosted URL, which is what email clients can render).\n * - PreserveStyles must be present so inline `style` survives the round-trip.\n * - Placeholder is NOT bundled by StarterKit v3, so it is added explicitly to\n * power the empty-state hint (it sets the `is-editor-empty` class and the\n * `data-placeholder` attribute that styles.css renders via `::before`).\n *\n * Exported as a factory so the React component and the headless tests build an\n * identical extension set. Pass the empty-state placeholder text in.\n */\nexport function createEmailExtensions(placeholder?: string): Extensions {\n return [\n StarterKit.configure({\n link: {\n openOnClick: false,\n autolink: true,\n HTMLAttributes: { rel: \"noopener noreferrer\" },\n },\n }),\n Image.configure({ inline: false, allowBase64: false }),\n TextAlign.configure({ types: [\"heading\", \"paragraph\"] }),\n TextStyle,\n Color,\n Highlight.configure({ multicolor: true }),\n Placeholder.configure({\n placeholder: placeholder ?? \"Write your email…\",\n // Emit data-placeholder so styles.css can render it via attr(); also\n // keep the default is-editor-empty class for the :first-child selector.\n showOnlyWhenEditable: true,\n }),\n PreserveStyles,\n ];\n}\n","/**\n * Preset block snippets — small, inline-styled, email-safe HTML fragments\n * inserted at the caret via `editor.chain().focus().insertContent(snippet)`.\n *\n * Every snippet uses inline styles only (no classes) so it survives both the\n * editor schema (via PreserveStyles) and downstream email clients.\n */\nexport const PRESET_PARAGRAPH =\n '<p style=\"margin:0 0 12px;color:#4b5563;line-height:1.6;\">Write your message here.</p>';\n\nexport const PRESET_DIVIDER =\n '<hr style=\"border:none;border-top:1px solid #e5e7eb;margin:20px 0;\" />';\n\nexport const PRESET_FOOTER =\n '<p style=\"margin:20px 0 0;color:#9ca3af;font-size:12px;\">© Your Company</p>';\n\nexport const PRESET_HEADING =\n '<h2 style=\"margin:0 0 12px;color:#111827;font-size:24px;line-height:1.3;\">Heading</h2>';\n\nexport const presets = {\n paragraph: PRESET_PARAGRAPH,\n divider: PRESET_DIVIDER,\n footer: PRESET_FOOTER,\n heading: PRESET_HEADING,\n} as const;\n","import type {\n AlignButtons,\n BlockButtons,\n HeadingButtons,\n InlineButtons,\n ListButtons,\n ResolvedToolbarConfig,\n ToolbarConfig,\n ToolbarGroup,\n} from \"../types\";\n\n/**\n * Resolve a loose `ToolbarConfig` into the flat `ResolvedToolbarConfig` the\n * Toolbar renders from. Rules:\n * - A group key may be a boolean or a per-button object (or omitted).\n * - Omitted / `true` / `{}` → group enabled, every button enabled.\n * - `false` → group disabled (and all its buttons disabled).\n * - An object → group enabled, each listed button overridden; unlisted buttons\n * default to `true`.\n */\nfunction resolveGroup<TButtons extends Record<string, boolean | undefined>>(\n group: ToolbarGroup<TButtons> | undefined,\n defaults: Required<TButtons>,\n): { enabled: boolean; buttons: Required<TButtons> } {\n // Omitted → all on.\n if (group === undefined || group === true) {\n return { enabled: true, buttons: { ...defaults } };\n }\n // Whole group off → disable every button too.\n if (group === false) {\n const off = {} as Required<TButtons>;\n for (const key of Object.keys(defaults) as (keyof TButtons)[]) {\n off[key] = false as Required<TButtons>[keyof TButtons];\n }\n return { enabled: false, buttons: off };\n }\n // Per-button object → group on, merge overrides over the all-on defaults.\n return { enabled: true, buttons: { ...defaults, ...group } };\n}\n\nconst INLINE_DEFAULTS: Required<InlineButtons> = {\n bold: true,\n italic: true,\n underline: true,\n strike: true,\n code: true,\n};\nconst HEADING_DEFAULTS: Required<HeadingButtons> = {\n h2: true,\n h3: true,\n h4: true,\n h5: true,\n h6: true,\n};\nconst LIST_DEFAULTS: Required<ListButtons> = {\n bullet: true,\n ordered: true,\n blockquote: true,\n};\nconst ALIGN_DEFAULTS: Required<AlignButtons> = {\n left: true,\n center: true,\n right: true,\n};\nconst BLOCK_DEFAULTS: Required<BlockButtons> = {\n paragraph: true,\n divider: true,\n footer: true,\n};\n\n/** A single-control group is on unless explicitly set to `false`. */\nfunction resolveToggle(value: boolean | undefined): boolean {\n return value !== false;\n}\n\nexport function resolveToolbarConfig(\n config?: ToolbarConfig,\n): ResolvedToolbarConfig {\n const c = config ?? {};\n return {\n inline: resolveGroup(c.inline, INLINE_DEFAULTS),\n headings: resolveGroup(c.headings, HEADING_DEFAULTS),\n lists: resolveGroup(c.lists, LIST_DEFAULTS),\n align: resolveGroup(c.align, ALIGN_DEFAULTS),\n link: resolveToggle(c.link),\n image: resolveToggle(c.image),\n button: resolveToggle(c.button),\n blocks: resolveGroup(c.blocks, BLOCK_DEFAULTS),\n html: resolveToggle(c.html),\n };\n}\n","/**\n * Escape a string for safe insertion into HTML text or a double-quoted\n * attribute value. Used by `buildButtonHtml` for the button label and href.\n */\nexport function escapeHtml(value: string): string {\n return String(value)\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n","import type { EmailButtonConfig } from \"../types\";\nimport { escapeHtml } from \"./escapeHtml\";\n\n/**\n * Build email-safe HTML for a call-to-action button.\n *\n * Two non-obvious decisions, both load-bearing:\n *\n * 1. The anchor is wrapped in a `<p style=\"...;text-align:X\">`, **never** a\n * `<div>`. TipTap has no `div` node and unwraps a `<div>` into a paragraph,\n * losing the `text-align`. A paragraph is a real node whose `text-align`\n * the TextAlign extension preserves — so the alignment round-trips.\n *\n * 2. The button is an `<a style=\"display:inline-block;...\">` (or\n * `display:block` when full-width), not a `<button>`, because email clients\n * need bulletproof, inline-styled markup.\n *\n * Both the label and the href are HTML-escaped.\n */\nexport function buildButtonHtml(config: EmailButtonConfig): string {\n const {\n text,\n href,\n bgColor,\n textColor,\n align,\n radius,\n fullWidth,\n } = config;\n\n const safeText = escapeHtml(text || \"Button\");\n const safeHref = escapeHtml(href || \"#\");\n const safeRadius = Number.isFinite(radius) ? Math.max(0, radius) : 0;\n\n // Full-width buttons span the content area as a block and center their own\n // label; otherwise they hug their content as an inline-block.\n const display = fullWidth ? \"block\" : \"inline-block\";\n const anchorTextAlign = fullWidth ? \"text-align:center;\" : \"\";\n\n const anchorStyle = [\n `display:${display}`,\n \"padding:12px 24px\",\n `background-color:${bgColor}`,\n `color:${textColor}`,\n \"text-decoration:none\",\n \"font-weight:600\",\n \"font-family:Arial,Helvetica,sans-serif\",\n \"font-size:14px\",\n \"line-height:1.4\",\n `border-radius:${safeRadius}px`,\n anchorTextAlign,\n ]\n .filter(Boolean)\n .join(\";\");\n\n const paragraphStyle = `margin:16px 0;text-align:${align}`;\n\n return (\n `<p style=\"${paragraphStyle}\">` +\n `<a href=\"${safeHref}\" target=\"_blank\" rel=\"noopener noreferrer\" ` +\n `style=\"${anchorStyle}\">${safeText}</a>` +\n `</p>`\n );\n}\n","import { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { EmailButtonConfig } from \"../types\";\nimport { buildButtonHtml } from \"../utils/buildButtonHtml\";\n\nexport type EmailButtonDialogProps = {\n /** Whether the dialog is open. */\n open: boolean;\n /** Called when the user confirms; receives the email-safe button HTML. */\n onConfirm: (html: string, config: EmailButtonConfig) => void;\n /** Called when the user dismisses the dialog (Esc / click-outside / cancel). */\n onClose: () => void;\n /** Optional initial values for the form. */\n initial?: Partial<EmailButtonConfig>;\n};\n\nconst DEFAULT_CONFIG: EmailButtonConfig = {\n text: \"Click here\",\n href: \"https://\",\n bgColor: \"#2563eb\",\n textColor: \"#ffffff\",\n align: \"left\",\n radius: 6,\n fullWidth: false,\n};\n\nconst BG_SWATCHES = [\n \"#2563eb\",\n \"#16a34a\",\n \"#dc2626\",\n \"#7c3aed\",\n \"#ea580c\",\n \"#0891b2\",\n \"#111827\",\n];\nconst TEXT_SWATCHES = [\"#ffffff\", \"#111827\", \"#f9fafb\", \"#1f2937\"];\n\n// <input type=color> only accepts #rrggbb. Named colors, #rgb shorthand, or\n// anything else must be coerced or it throws/blanks the control.\nconst HEX6_RE = /^#[0-9a-fA-F]{6}$/;\nfunction toColorInputValue(value: string): string {\n return HEX6_RE.test(value) ? value : \"#000000\";\n}\n\ntype ColorFieldProps = {\n label: string;\n value: string;\n swatches: string[];\n onChange: (value: string) => void;\n};\n\nfunction ColorField({ label, value, swatches, onChange }: ColorFieldProps) {\n return (\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">{label}</span>\n <div className=\"rte-color-row\">\n {swatches.map((swatch) => (\n <button\n key={swatch}\n type=\"button\"\n className={\n \"rte-swatch\" + (value === swatch ? \" rte-swatch--active\" : \"\")\n }\n style={{ backgroundColor: swatch }}\n aria-label={`Use ${swatch}`}\n aria-pressed={value === swatch}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onChange(swatch)}\n />\n ))}\n <input\n type=\"color\"\n className=\"rte-color-input\"\n value={toColorInputValue(value)}\n aria-label={`${label} picker`}\n onChange={(e) => onChange(e.target.value)}\n />\n <input\n type=\"text\"\n className=\"rte-hex-input\"\n value={value}\n aria-label={`${label} hex`}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n </div>\n );\n}\n\n/**\n * Modal dialog for configuring an email CTA button. Supports Esc to close,\n * body-scroll lock while open, click-outside to dismiss, and a live preview of\n * the rendered button.\n */\nexport function EmailButtonDialog({\n open,\n onConfirm,\n onClose,\n initial,\n}: EmailButtonDialogProps) {\n const [config, setConfig] = useState<EmailButtonConfig>({\n ...DEFAULT_CONFIG,\n ...initial,\n });\n const overlayRef = useRef<HTMLDivElement>(null);\n\n // Reset the form to its initial state each time the dialog opens.\n useEffect(() => {\n if (open) {\n setConfig({ ...DEFAULT_CONFIG, ...initial });\n }\n }, [open, initial]);\n\n // Esc to close + body-scroll lock while open.\n useEffect(() => {\n if (!open) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n onClose();\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.body.style.overflow = previousOverflow;\n };\n }, [open, onClose]);\n\n const previewHtml = useMemo(() => buildButtonHtml(config), [config]);\n\n if (!open) return null;\n\n const update = <K extends keyof EmailButtonConfig>(\n key: K,\n value: EmailButtonConfig[K],\n ) => setConfig((prev) => ({ ...prev, [key]: value }));\n\n const handleSubmit = () => {\n onConfirm(buildButtonHtml(config), config);\n };\n\n return (\n <div\n ref={overlayRef}\n className=\"rte-dialog-overlay\"\n role=\"presentation\"\n onMouseDown={(e) => {\n // Click-outside (on the overlay itself, not the panel) dismisses.\n if (e.target === overlayRef.current) onClose();\n }}\n >\n <div\n className=\"rte-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Insert button\"\n >\n <div className=\"rte-dialog-header\">\n <h2 className=\"rte-dialog-title\">Insert button</h2>\n <button\n type=\"button\"\n className=\"rte-dialog-close\"\n aria-label=\"Close\"\n onClick={onClose}\n >\n ×\n </button>\n </div>\n\n <div className=\"rte-dialog-body\">\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Text</span>\n <input\n type=\"text\"\n className=\"rte-text-input\"\n value={config.text}\n onChange={(e) => update(\"text\", e.target.value)}\n />\n </label>\n\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Link URL</span>\n <input\n type=\"text\"\n className=\"rte-text-input\"\n value={config.href}\n onChange={(e) => update(\"href\", e.target.value)}\n />\n </label>\n\n <ColorField\n label=\"Background color\"\n value={config.bgColor}\n swatches={BG_SWATCHES}\n onChange={(v) => update(\"bgColor\", v)}\n />\n\n <ColorField\n label=\"Text color\"\n value={config.textColor}\n swatches={TEXT_SWATCHES}\n onChange={(v) => update(\"textColor\", v)}\n />\n\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Alignment</span>\n <div className=\"rte-align-row\">\n {([\"left\", \"center\", \"right\"] as const).map((a) => (\n <button\n key={a}\n type=\"button\"\n className={\n \"rte-align-btn\" +\n (config.align === a ? \" rte-align-btn--active\" : \"\")\n }\n aria-pressed={config.align === a}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => update(\"align\", a)}\n >\n {a}\n </button>\n ))}\n </div>\n </div>\n\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">\n Corner radius: {config.radius}px\n </span>\n <input\n type=\"range\"\n min={0}\n max={32}\n value={config.radius}\n onChange={(e) => update(\"radius\", Number(e.target.value))}\n />\n </label>\n\n <label className=\"rte-checkbox-field\">\n <input\n type=\"checkbox\"\n checked={config.fullWidth}\n onChange={(e) => update(\"fullWidth\", e.target.checked)}\n />\n <span>Full width</span>\n </label>\n\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Preview</span>\n <div\n className=\"rte-button-preview\"\n // Preview only — content is built from the same escaped builder.\n dangerouslySetInnerHTML={{ __html: previewHtml }}\n />\n </div>\n </div>\n\n <div className=\"rte-dialog-footer\">\n <button\n type=\"button\"\n className=\"rte-btn rte-btn--ghost\"\n onClick={onClose}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"rte-btn rte-btn--primary\"\n onClick={handleSubmit}\n >\n Insert\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport default EmailButtonDialog;\n","import type { Editor } from \"@tiptap/react\";\nimport { useEditorState } from \"@tiptap/react\";\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n Bold,\n Code,\n FileCode,\n Heading2,\n Heading3,\n Heading4,\n Heading5,\n Heading6,\n Image as ImageIcon,\n Italic,\n Link as LinkIcon,\n List,\n ListOrdered,\n Minus,\n MousePointerClick,\n PanelBottom,\n Pilcrow,\n Quote,\n Strikethrough,\n Underline,\n} from \"lucide-react\";\nimport { Fragment, type ReactNode } from \"react\";\n\nimport type { ResolvedToolbarConfig } from \"../types\";\n\ntype HeadingLevel = 2 | 3 | 4 | 5 | 6;\n\nexport type ToolbarProps = {\n editor: Editor;\n config: ResolvedToolbarConfig;\n /** Toggle the raw HTML source view. */\n htmlMode: boolean;\n onToggleHtml: () => void;\n /** Caller-provided handlers for the controls that need extra UI. */\n onLink: () => void;\n onImage: () => void;\n onButton: () => void;\n onInsertParagraph: () => void;\n onInsertDivider: () => void;\n onInsertFooter: () => void;\n};\n\ntype TbButtonProps = {\n onClick: () => void;\n active?: boolean;\n label: string;\n disabled?: boolean;\n children: ReactNode;\n};\n\nfunction TbButton({ onClick, active, label, disabled, children }: TbButtonProps) {\n return (\n <button\n type=\"button\"\n className={\"rte-tb-btn\" + (active ? \" rte-tb-btn--active\" : \"\")}\n // Prevent the button from stealing the editor's selection on press.\n onMouseDown={(e) => e.preventDefault()}\n onClick={onClick}\n aria-pressed={!!active}\n aria-label={label}\n title={label}\n disabled={disabled}\n >\n {children}\n </button>\n );\n}\n\nfunction Divider() {\n return <span className=\"rte-tb-divider\" aria-hidden=\"true\" />;\n}\n\nconst HEADING_ICONS: Record<HeadingLevel, ReactNode> = {\n 2: <Heading2 size={16} />,\n 3: <Heading3 size={16} />,\n 4: <Heading4 size={16} />,\n 5: <Heading5 size={16} />,\n 6: <Heading6 size={16} />,\n};\n\nexport function Toolbar({\n editor,\n config,\n htmlMode,\n onToggleHtml,\n onLink,\n onImage,\n onButton,\n onInsertParagraph,\n onInsertDivider,\n onInsertFooter,\n}: ToolbarProps) {\n // useEditorState re-renders only when the selected slice changes, keeping\n // active-state computation cheap even on large documents.\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) => ({\n bold: e.isActive(\"bold\"),\n italic: e.isActive(\"italic\"),\n underline: e.isActive(\"underline\"),\n strike: e.isActive(\"strike\"),\n code: e.isActive(\"code\"),\n h2: e.isActive(\"heading\", { level: 2 }),\n h3: e.isActive(\"heading\", { level: 3 }),\n h4: e.isActive(\"heading\", { level: 4 }),\n h5: e.isActive(\"heading\", { level: 5 }),\n h6: e.isActive(\"heading\", { level: 6 }),\n bulletList: e.isActive(\"bulletList\"),\n orderedList: e.isActive(\"orderedList\"),\n blockquote: e.isActive(\"blockquote\"),\n alignLeft: e.isActive({ textAlign: \"left\" }),\n alignCenter: e.isActive({ textAlign: \"center\" }),\n alignRight: e.isActive({ textAlign: \"right\" }),\n link: e.isActive(\"link\"),\n image: e.isActive(\"image\"),\n }),\n });\n\n const headingActive: Record<HeadingLevel, boolean> = {\n 2: state.h2,\n 3: state.h3,\n 4: state.h4,\n 5: state.h5,\n 6: state.h6,\n };\n\n // In HTML source mode only the source toggle is interactive.\n const disabled = htmlMode;\n\n // Build each group as an array of rendered buttons, gated by both the group\n // `enabled` flag and the per-button flag. A group with zero visible buttons\n // contributes nothing (and gets no divider).\n const inline = config.inline.enabled\n ? [\n config.inline.buttons.bold && (\n <TbButton\n key=\"bold\"\n label=\"Bold\"\n active={state.bold}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBold().run()}\n >\n <Bold size={16} />\n </TbButton>\n ),\n config.inline.buttons.italic && (\n <TbButton\n key=\"italic\"\n label=\"Italic\"\n active={state.italic}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleItalic().run()}\n >\n <Italic size={16} />\n </TbButton>\n ),\n config.inline.buttons.underline && (\n <TbButton\n key=\"underline\"\n label=\"Underline\"\n active={state.underline}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n >\n <Underline size={16} />\n </TbButton>\n ),\n config.inline.buttons.strike && (\n <TbButton\n key=\"strike\"\n label=\"Strikethrough\"\n active={state.strike}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleStrike().run()}\n >\n <Strikethrough size={16} />\n </TbButton>\n ),\n config.inline.buttons.code && (\n <TbButton\n key=\"code\"\n label=\"Inline code\"\n active={state.code}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleCode().run()}\n >\n <Code size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const headings = config.headings.enabled\n ? ([2, 3, 4, 5, 6] as const).map((level) =>\n config.headings.buttons[`h${level}` as keyof typeof config.headings.buttons] ? (\n <TbButton\n key={`h${level}`}\n label={`Heading ${level}`}\n active={headingActive[level]}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleHeading({ level }).run()}\n >\n {HEADING_ICONS[level]}\n </TbButton>\n ) : (\n false\n ),\n )\n : [];\n\n const lists = config.lists.enabled\n ? [\n config.lists.buttons.bullet && (\n <TbButton\n key=\"bullet\"\n label=\"Bullet list\"\n active={state.bulletList}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n >\n <List size={16} />\n </TbButton>\n ),\n config.lists.buttons.ordered && (\n <TbButton\n key=\"ordered\"\n label=\"Ordered list\"\n active={state.orderedList}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n >\n <ListOrdered size={16} />\n </TbButton>\n ),\n config.lists.buttons.blockquote && (\n <TbButton\n key=\"quote\"\n label=\"Quote\"\n active={state.blockquote}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBlockquote().run()}\n >\n <Quote size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const align = config.align.enabled\n ? [\n config.align.buttons.left && (\n <TbButton\n key=\"left\"\n label=\"Align left\"\n active={state.alignLeft}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"left\").run()}\n >\n <AlignLeft size={16} />\n </TbButton>\n ),\n config.align.buttons.center && (\n <TbButton\n key=\"center\"\n label=\"Align center\"\n active={state.alignCenter}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"center\").run()}\n >\n <AlignCenter size={16} />\n </TbButton>\n ),\n config.align.buttons.right && (\n <TbButton\n key=\"right\"\n label=\"Align right\"\n active={state.alignRight}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"right\").run()}\n >\n <AlignRight size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const inserts = [\n config.link && (\n <TbButton\n key=\"link\"\n label=\"Link\"\n active={state.link}\n disabled={disabled}\n onClick={onLink}\n >\n <LinkIcon size={16} />\n </TbButton>\n ),\n config.image && (\n <TbButton\n key=\"image\"\n label=\"Image\"\n active={state.image}\n disabled={disabled}\n onClick={onImage}\n >\n <ImageIcon size={16} />\n </TbButton>\n ),\n config.button && (\n <TbButton\n key=\"button\"\n label=\"Button\"\n disabled={disabled}\n onClick={onButton}\n >\n <MousePointerClick size={16} />\n </TbButton>\n ),\n ];\n\n const blocks = config.blocks.enabled\n ? [\n config.blocks.buttons.paragraph && (\n <TbButton\n key=\"paragraph\"\n label=\"Insert paragraph\"\n disabled={disabled}\n onClick={onInsertParagraph}\n >\n <Pilcrow size={16} />\n </TbButton>\n ),\n config.blocks.buttons.divider && (\n <TbButton\n key=\"divider\"\n label=\"Insert divider\"\n disabled={disabled}\n onClick={onInsertDivider}\n >\n <Minus size={16} />\n </TbButton>\n ),\n config.blocks.buttons.footer && (\n <TbButton\n key=\"footer\"\n label=\"Insert footer\"\n disabled={disabled}\n onClick={onInsertFooter}\n >\n <PanelBottom size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const html = config.html\n ? [\n <TbButton\n key=\"html\"\n label=\"HTML source\"\n active={htmlMode}\n onClick={onToggleHtml}\n >\n <FileCode size={16} />\n </TbButton>,\n ]\n : [];\n\n // Keep only groups that have at least one visible button, then render them\n // with a divider between each — so hidden groups leave no dangling dividers.\n const groups = [inline, headings, lists, align, inserts, blocks, html]\n .map((g) => g.filter(Boolean))\n .filter((g) => g.length > 0);\n\n return (\n <div className=\"rte-toolbar\" role=\"toolbar\" aria-label=\"Formatting\">\n {groups.map((buttons, i) => (\n <Fragment key={i}>\n {i > 0 && <Divider />}\n <div className=\"rte-tb-group\">{buttons}</div>\n </Fragment>\n ))}\n </div>\n );\n}\n\nexport default Toolbar;\n","import { EditorContent, useEditor } from \"@tiptap/react\";\nimport {\n forwardRef,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { createEmailExtensions } from \"../extensions/editorExtensions\";\nimport type { ToolbarConfig } from \"../types\";\nimport { PRESET_DIVIDER, PRESET_FOOTER, PRESET_PARAGRAPH } from \"../utils/presets\";\nimport { resolveToolbarConfig } from \"../utils/resolveToolbarConfig\";\nimport { EmailButtonDialog } from \"./EmailButtonDialog\";\nimport { Toolbar } from \"./Toolbar\";\n\nexport type RichTextEditorHandle = {\n /** Insert raw HTML or plain text at the current caret position. */\n insertAtCaret: (htmlOrText: string) => void;\n};\n\nexport type RichTextEditorProps = {\n /** Body-level HTML fragment (no `<html>`/`<body>`). */\n value: string;\n /** Fires with the updated body-level HTML fragment. */\n onChange: (value: string) => void;\n /** Empty-state placeholder text. */\n placeholder?: string;\n /** Resolve an uploaded file to a hosted image URL. */\n onUploadImage?: (file: File) => Promise<string>;\n /** Extra class on the editor wrapper. */\n className?: string;\n /** Inline style applied to the editable surface (e.g. minHeight/height). */\n editorStyle?: React.CSSProperties;\n /** Which toolbar controls to render (defaults to everything on). */\n toolbar?: ToolbarConfig;\n};\n\n/**\n * The generic body-HTML rich-text editor: a toolbar plus an editable surface\n * operating on a plain HTML fragment. `<EmailEditor>` wraps this to add the\n * document-shell bridge and placeholder chips.\n */\nexport const RichTextEditor = forwardRef<\n RichTextEditorHandle,\n RichTextEditorProps\n>(function RichTextEditor(\n {\n value,\n onChange,\n placeholder = \"Write your email…\",\n onUploadImage,\n className,\n editorStyle,\n toolbar,\n },\n ref,\n) {\n const toolbarConfig = useMemo(\n () => resolveToolbarConfig(toolbar),\n [toolbar],\n );\n\n const extensions = useMemo(\n () => createEmailExtensions(placeholder),\n [placeholder],\n );\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [htmlMode, setHtmlMode] = useState(false);\n const [buttonDialogOpen, setButtonDialogOpen] = useState(false);\n\n const editor = useEditor({\n extensions,\n content: value,\n // REQUIRED for SSR/Next.js — rendering immediately causes a hydration\n // mismatch because the server has no DOM.\n immediatelyRender: false,\n editorProps: {\n attributes: {\n class: \"rte-content\",\n },\n },\n onUpdate: ({ editor: e }) => {\n onChange(e.getHTML());\n },\n });\n\n // Sync external `value` changes into the editor without fighting the user's\n // typing: only when it actually differs from the editor's current HTML, and\n // with emitUpdate:false so it does not re-fire onChange.\n if (editor && !htmlMode && value !== editor.getHTML()) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n\n useImperativeHandle(\n ref,\n () => ({\n insertAtCaret: (htmlOrText: string) => {\n editor?.chain().focus().insertContent(htmlOrText).run();\n },\n }),\n [editor],\n );\n\n const insertSnippet = useCallback(\n (snippet: string) => {\n editor?.chain().focus().insertContent(snippet).run();\n },\n [editor],\n );\n\n const handleLink = useCallback(() => {\n if (!editor) return;\n const previous = editor.getAttributes(\"link\").href as string | undefined;\n const url = window.prompt(\"Link URL\", previous ?? \"https://\");\n if (url === null) return; // cancelled\n if (url.trim() === \"\") {\n editor.chain().focus().extendMarkRange(\"link\").unsetLink().run();\n return;\n }\n editor\n .chain()\n .focus()\n .extendMarkRange(\"link\")\n .setLink({ href: url.trim() })\n .run();\n }, [editor]);\n\n const handleImageClick = useCallback(() => {\n if (!editor) return;\n if (onUploadImage) {\n fileInputRef.current?.click();\n } else {\n const url = window.prompt(\"Image URL\", \"https://\");\n if (url && url.trim()) {\n editor.chain().focus().setImage({ src: url.trim() }).run();\n }\n }\n }, [editor, onUploadImage]);\n\n const handleFileSelected = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n // Reset so selecting the same file again re-triggers change.\n e.target.value = \"\";\n if (!file || !onUploadImage || !editor) return;\n try {\n const src = await onUploadImage(file);\n if (src) editor.chain().focus().setImage({ src }).run();\n } catch (err) {\n // Surface upload failures without crashing the editor.\n console.error(\"dpk-editor: image upload failed\", err);\n }\n },\n [editor, onUploadImage],\n );\n\n const handleButtonConfirm = useCallback(\n (html: string) => {\n setButtonDialogOpen(false);\n editor?.chain().focus().insertContent(html).run();\n },\n [editor],\n );\n\n if (!editor) return null;\n\n return (\n <div className={\"rte-root\" + (className ? ` ${className}` : \"\")}>\n <Toolbar\n editor={editor}\n config={toolbarConfig}\n htmlMode={htmlMode}\n onToggleHtml={() => setHtmlMode((m) => !m)}\n onLink={handleLink}\n onImage={handleImageClick}\n onButton={() => setButtonDialogOpen(true)}\n onInsertParagraph={() => insertSnippet(PRESET_PARAGRAPH)}\n onInsertDivider={() => insertSnippet(PRESET_DIVIDER)}\n onInsertFooter={() => insertSnippet(PRESET_FOOTER)}\n />\n\n {htmlMode ? (\n <textarea\n className=\"rte-source\"\n style={editorStyle}\n value={value}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n aria-label=\"HTML source\"\n />\n ) : (\n <EditorContent\n editor={editor}\n className=\"rte-editor\"\n style={editorStyle}\n />\n )}\n\n {onUploadImage && (\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={handleFileSelected}\n />\n )}\n\n <EmailButtonDialog\n open={buttonDialogOpen}\n onConfirm={handleButtonConfirm}\n onClose={() => setButtonDialogOpen(false)}\n />\n </div>\n );\n});\n\nexport default RichTextEditor;\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\n\nimport type {\n EmailHtmlDocument,\n EmailPlaceholder,\n ToolbarConfig,\n} from \"../types\";\nimport { joinEmailHtml, splitEmailHtml } from \"../utils/shellBridge\";\nimport {\n RichTextEditor,\n type RichTextEditorHandle,\n} from \"./RichTextEditor\";\n\nexport type EmailEditorProps = {\n /** Full HTML document OR a bare body fragment — both are supported. */\n value: string;\n /** Fires with HTML in the same shape `value` was provided (shell re-applied). */\n onChange: (value: string) => void;\n /** Optional merge tokens; render a chip row that inserts at the caret. */\n placeholders?: EmailPlaceholder[];\n /** Resolve an uploaded file to a hosted image URL (else a URL prompt is used). */\n onUploadImage?: (file: File) => Promise<string>;\n /** Minimum height (px) of the editable surface. */\n minHeight?: number;\n /** Empty-state placeholder text for the editable surface. */\n placeholder?: string;\n /** Which toolbar controls to render (defaults to everything on). */\n toolbar?: ToolbarConfig;\n /** Extra class on the editor wrapper. */\n className?: string;\n};\n\n/**\n * The batteries-included email editor. Owns the document-shell bridge so the\n * surrounding `<!doctype>`/`<html>`/`<body style>` (and any `<table>` layout\n * inside the body) is preserved verbatim across edits, while only the body\n * fragment is handed to the underlying `<RichTextEditor>`.\n */\nexport function EmailEditor({\n value,\n onChange,\n placeholders,\n onUploadImage,\n minHeight = 288,\n placeholder,\n toolbar,\n className,\n}: EmailEditorProps) {\n // Recompute the shell from `value` on each render.\n const shell = useMemo<EmailHtmlDocument>(() => splitEmailHtml(value), [value]);\n\n // Keep the latest shell in a ref so the onChange closure always rejoins with\n // the current prefix/suffix. Assign the ref in an EFFECT (never during\n // render) — strict react-hooks lint flags a render-time ref write.\n const shellRef = useRef<EmailHtmlDocument>(shell);\n useEffect(() => {\n shellRef.current = shell;\n }, [shell]);\n\n const editorRef = useRef<RichTextEditorHandle>(null);\n\n const handleBodyChange = useCallback(\n (newBody: string) => {\n onChange(joinEmailHtml(shellRef.current, newBody));\n },\n [onChange],\n );\n\n const editorStyle = useMemo<React.CSSProperties>(\n () => ({ minHeight }),\n [minHeight],\n );\n\n const insertToken = useCallback((token: string) => {\n editorRef.current?.insertAtCaret(token);\n }, []);\n\n return (\n <div className={\"rte-email\" + (className ? ` ${className}` : \"\")}>\n {placeholders && placeholders.length > 0 && (\n <div className=\"rte-chips\" role=\"group\" aria-label=\"Merge tokens\">\n {placeholders.map((p) => (\n <button\n key={p.token}\n type=\"button\"\n className=\"rte-chip\"\n title={`Insert ${p.token}`}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => insertToken(p.token)}\n >\n {p.label}\n </button>\n ))}\n </div>\n )}\n\n <RichTextEditor\n ref={editorRef}\n value={shell.body}\n onChange={handleBodyChange}\n onUploadImage={onUploadImage}\n placeholder={placeholder}\n editorStyle={editorStyle}\n toolbar={toolbar}\n />\n </div>\n );\n}\n\nexport default EmailEditor;\n"]}
1
+ {"version":3,"sources":["../src/utils/shellBridge.ts","../src/extensions/PreserveStyles.ts","../src/extensions/editorExtensions.ts","../src/utils/presets.ts","../src/utils/resolveToolbarConfig.ts","../src/utils/escapeHtml.ts","../src/utils/buildButtonHtml.ts","../src/components/EmailButtonDialog.tsx","../src/components/Toolbar.tsx","../src/components/RichTextEditor.tsx","../src/components/EmailEditor.tsx"],"names":["jsx","LinkIcon","ImageIcon","jsxs","RichTextEditor","useMemo","useRef","useState","useEffect","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["import type { EmailHtmlDocument } from \"../types\";\n\n/**\n * Document-shell bridge utilities.\n *\n * A `contentEditable`/ProseMirror surface cannot host `<html>`/`<head>`/\n * `<body>` — it silently strips them and keeps only body-level flow content.\n * So `<EmailEditor>` edits only the **body fragment** and preserves the\n * surrounding document shell verbatim across edits.\n *\n * These are pure string utilities (no DOM required): they operate by locating\n * the `<body ...>` tag with a regex, so they work the same in the browser,\n * during SSR, and in tests.\n */\n\n// Matches the opening <body ...> tag (case-insensitive, any attributes,\n// across newlines). Non-greedy so it stops at the first `>`.\nconst BODY_OPEN_RE = /<body\\b[^>]*>/i;\n// Matches the closing </body> tag.\nconst BODY_CLOSE_RE = /<\\/body\\s*>/i;\n\n/**\n * Split a full email HTML document into `{ prefix, body, suffix }`.\n *\n * - `prefix` = everything up to and including the opening `<body ...>` tag.\n * - `body` = the inner body HTML (the editable fragment).\n * - `suffix` = the closing `</body>` tag plus everything after it.\n *\n * If the input has no `<body>` tag it is treated as a **bare fragment**: the\n * whole input becomes `body`, and `prefix`/`suffix` are empty strings.\n */\nexport function splitEmailHtml(html: string): EmailHtmlDocument {\n const input = html ?? \"\";\n\n const openMatch = input.match(BODY_OPEN_RE);\n if (!openMatch || openMatch.index === undefined) {\n // Bare fragment — no shell to preserve.\n return { prefix: \"\", body: input, suffix: \"\" };\n }\n\n const openStart = openMatch.index;\n const openEnd = openStart + openMatch[0].length;\n const prefix = input.slice(0, openEnd);\n\n const rest = input.slice(openEnd);\n const closeMatch = rest.match(BODY_CLOSE_RE);\n\n if (!closeMatch || closeMatch.index === undefined) {\n // Opening <body> but no closing tag — treat the remainder as body and\n // synthesize an empty suffix so a rejoin still nests inside the shell.\n return { prefix, body: rest, suffix: \"\" };\n }\n\n const body = rest.slice(0, closeMatch.index);\n const suffix = rest.slice(closeMatch.index);\n\n return { prefix, body, suffix };\n}\n\n/**\n * Reassemble a document from a shell and a (possibly edited) body fragment.\n *\n * If the shell has no surrounding markup (a bare fragment was originally\n * supplied) the body is returned as-is, so `onChange` emits in the same shape\n * the consumer provided `value`.\n */\nexport function joinEmailHtml(\n shell: EmailHtmlDocument,\n newBody: string,\n): string {\n const body = newBody ?? \"\";\n if (!shell.prefix && !shell.suffix) {\n return body;\n }\n return `${shell.prefix}${body}${shell.suffix}`;\n}\n\n/**\n * Convenience: extract just the editable body fragment from a full document\n * (or return the input unchanged if it is already a bare fragment).\n */\nexport function extractEmailBody(html: string): string {\n return splitEmailHtml(html).body;\n}\n","import { Extension } from \"@tiptap/react\";\n\n/**\n * A TipTap extension that preserves the inline `style` attribute on every node\n * and mark in the schema.\n *\n * TipTap (ProseMirror) strips any HTML attribute a node/mark does not declare.\n * For article editing that is fine; for **email** HTML it is lossy — buttons\n * lose their padding/background, headings lose their color, and so on. This\n * extension declares a global `style` attribute so arbitrary inline-styled\n * email HTML round-trips.\n *\n * It preserves `style` only on elements that map to a known node or mark\n * (paragraph, heading, list, blockquote, link, image, hr, …). Raw\n * `<table>`/`<td>` layouts are still flattened by ProseMirror's schema — those\n * survive via the document-shell bridge, not here.\n */\nexport const PreserveStyles = Extension.create({\n name: \"preserveStyles\",\n\n addGlobalAttributes() {\n return [\n {\n // ⚠️ MUST be the string shorthand \"*\" (= all nodes and marks).\n // NEVER [\"*\"] — an array means \"a type literally named *\", which\n // matches nothing and silently preserves no styles. That bug passes\n // tsc/eslint/build cleanly, so it is asserted against in the tests.\n types: \"*\",\n attributes: {\n style: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"style\"),\n renderHTML: (attributes) =>\n attributes.style ? { style: attributes.style as string } : {},\n },\n },\n },\n ];\n },\n});\n\nexport default PreserveStyles;\n","import Highlight from \"@tiptap/extension-highlight\";\nimport Image from \"@tiptap/extension-image\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport TextAlign from \"@tiptap/extension-text-align\";\n// @tiptap/extension-text-style v3 re-exports both TextStyle and Color, so we\n// do NOT need @tiptap/extension-color as a separate dependency.\nimport { Color, TextStyle } from \"@tiptap/extension-text-style\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport type { Extensions } from \"@tiptap/react\";\n\nimport { PreserveStyles } from \"./PreserveStyles\";\n\n/**\n * The canonical extension set for the email editor.\n *\n * Notes / watch-outs baked in here:\n * - StarterKit v3 already bundles Link, Underline, lists, blockquote, code and\n * headings — we do NOT add @tiptap/extension-link or -underline separately\n * (that throws duplicate-extension warnings). Link is configured through\n * StarterKit.configure({ link: {...} }).\n * - Image is block-level and base64 is disabled (uploads should resolve to a\n * hosted URL, which is what email clients can render).\n * - PreserveStyles must be present so inline `style` survives the round-trip.\n * - Placeholder is NOT bundled by StarterKit v3, so it is added explicitly to\n * power the empty-state hint (it sets the `is-editor-empty` class and the\n * `data-placeholder` attribute that styles.css renders via `::before`).\n *\n * Exported as a factory so the React component and the headless tests build an\n * identical extension set. Pass the empty-state placeholder text in.\n */\nexport function createEmailExtensions(placeholder?: string): Extensions {\n return [\n StarterKit.configure({\n link: {\n openOnClick: false,\n autolink: true,\n HTMLAttributes: { rel: \"noopener noreferrer\" },\n },\n }),\n Image.configure({ inline: false, allowBase64: false }),\n TextAlign.configure({ types: [\"heading\", \"paragraph\"] }),\n TextStyle,\n Color,\n Highlight.configure({ multicolor: true }),\n Placeholder.configure({\n placeholder: placeholder ?? \"Write something…\",\n // Emit data-placeholder so styles.css can render it via attr(); also\n // keep the default is-editor-empty class for the :first-child selector.\n showOnlyWhenEditable: true,\n }),\n PreserveStyles,\n ];\n}\n","/**\n * Preset block snippets — small, inline-styled, email-safe HTML fragments\n * inserted at the caret via `editor.chain().focus().insertContent(snippet)`.\n *\n * Every snippet uses inline styles only (no classes) so it survives both the\n * editor schema (via PreserveStyles) and downstream email clients.\n */\nexport const PRESET_PARAGRAPH =\n '<p style=\"margin:0 0 12px;color:#4b5563;line-height:1.6;\">Write your message here.</p>';\n\nexport const PRESET_DIVIDER =\n '<hr style=\"border:none;border-top:1px solid #e5e7eb;margin:20px 0;\" />';\n\nexport const PRESET_FOOTER =\n '<p style=\"margin:20px 0 0;color:#9ca3af;font-size:12px;\">© Your Company</p>';\n\nexport const PRESET_HEADING =\n '<h2 style=\"margin:0 0 12px;color:#111827;font-size:24px;line-height:1.3;\">Heading</h2>';\n\nexport const presets = {\n paragraph: PRESET_PARAGRAPH,\n divider: PRESET_DIVIDER,\n footer: PRESET_FOOTER,\n heading: PRESET_HEADING,\n} as const;\n","import type {\n AlignButtons,\n BlockButtons,\n HeadingButtons,\n InlineButtons,\n ListButtons,\n ResolvedToolbarConfig,\n ToolbarConfig,\n ToolbarGroup,\n} from \"../types\";\n\n/**\n * Resolve a loose `ToolbarConfig` into the flat `ResolvedToolbarConfig` the\n * Toolbar renders from. Rules:\n * - A group key may be a boolean or a per-button object (or omitted).\n * - Omitted / `true` / `{}` → group enabled, every button enabled.\n * - `false` → group disabled (and all its buttons disabled).\n * - An object → group enabled, each listed button overridden; unlisted buttons\n * default to `true`.\n */\nfunction resolveGroup<TButtons extends Record<string, boolean | undefined>>(\n group: ToolbarGroup<TButtons> | undefined,\n defaults: Required<TButtons>,\n): { enabled: boolean; buttons: Required<TButtons> } {\n // Omitted → all on.\n if (group === undefined || group === true) {\n return { enabled: true, buttons: { ...defaults } };\n }\n // Whole group off → disable every button too.\n if (group === false) {\n const off = {} as Required<TButtons>;\n for (const key of Object.keys(defaults) as (keyof TButtons)[]) {\n off[key] = false as Required<TButtons>[keyof TButtons];\n }\n return { enabled: false, buttons: off };\n }\n // Per-button object → group on, merge overrides over the all-on defaults.\n return { enabled: true, buttons: { ...defaults, ...group } };\n}\n\nconst INLINE_DEFAULTS: Required<InlineButtons> = {\n bold: true,\n italic: true,\n underline: true,\n strike: true,\n code: true,\n};\nconst HEADING_DEFAULTS: Required<HeadingButtons> = {\n h2: true,\n h3: true,\n h4: true,\n h5: true,\n h6: true,\n};\nconst LIST_DEFAULTS: Required<ListButtons> = {\n bullet: true,\n ordered: true,\n blockquote: true,\n};\nconst ALIGN_DEFAULTS: Required<AlignButtons> = {\n left: true,\n center: true,\n right: true,\n};\nconst BLOCK_DEFAULTS: Required<BlockButtons> = {\n paragraph: true,\n divider: true,\n footer: true,\n};\n\n/** A single-control group is on unless explicitly set to `false`. */\nfunction resolveToggle(value: boolean | undefined): boolean {\n return value !== false;\n}\n\nexport function resolveToolbarConfig(\n config?: ToolbarConfig,\n): ResolvedToolbarConfig {\n const c = config ?? {};\n return {\n inline: resolveGroup(c.inline, INLINE_DEFAULTS),\n headings: resolveGroup(c.headings, HEADING_DEFAULTS),\n lists: resolveGroup(c.lists, LIST_DEFAULTS),\n align: resolveGroup(c.align, ALIGN_DEFAULTS),\n link: resolveToggle(c.link),\n image: resolveToggle(c.image),\n button: resolveToggle(c.button),\n blocks: resolveGroup(c.blocks, BLOCK_DEFAULTS),\n html: resolveToggle(c.html),\n };\n}\n","/**\n * Escape a string for safe insertion into HTML text or a double-quoted\n * attribute value. Used by `buildButtonHtml` for the button label and href.\n */\nexport function escapeHtml(value: string): string {\n return String(value)\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n","import type { EmailButtonConfig } from \"../types\";\nimport { escapeHtml } from \"./escapeHtml\";\n\n/**\n * Build email-safe HTML for a call-to-action button.\n *\n * Two non-obvious decisions, both load-bearing:\n *\n * 1. The anchor is wrapped in a `<p style=\"...;text-align:X\">`, **never** a\n * `<div>`. TipTap has no `div` node and unwraps a `<div>` into a paragraph,\n * losing the `text-align`. A paragraph is a real node whose `text-align`\n * the TextAlign extension preserves — so the alignment round-trips.\n *\n * 2. The button is an `<a style=\"display:inline-block;...\">` (or\n * `display:block` when full-width), not a `<button>`, because email clients\n * need bulletproof, inline-styled markup.\n *\n * Both the label and the href are HTML-escaped.\n */\nexport function buildButtonHtml(config: EmailButtonConfig): string {\n const {\n text,\n href,\n bgColor,\n textColor,\n align,\n radius,\n fullWidth,\n } = config;\n\n const safeText = escapeHtml(text || \"Button\");\n const safeHref = escapeHtml(href || \"#\");\n const safeRadius = Number.isFinite(radius) ? Math.max(0, radius) : 0;\n\n // Full-width buttons span the content area as a block and center their own\n // label; otherwise they hug their content as an inline-block.\n const display = fullWidth ? \"block\" : \"inline-block\";\n const anchorTextAlign = fullWidth ? \"text-align:center;\" : \"\";\n\n const anchorStyle = [\n `display:${display}`,\n \"padding:12px 24px\",\n `background-color:${bgColor}`,\n `color:${textColor}`,\n \"text-decoration:none\",\n \"font-weight:600\",\n \"font-family:Arial,Helvetica,sans-serif\",\n \"font-size:14px\",\n \"line-height:1.4\",\n `border-radius:${safeRadius}px`,\n anchorTextAlign,\n ]\n .filter(Boolean)\n .join(\";\");\n\n const paragraphStyle = `margin:16px 0;text-align:${align}`;\n\n return (\n `<p style=\"${paragraphStyle}\">` +\n `<a href=\"${safeHref}\" target=\"_blank\" rel=\"noopener noreferrer\" ` +\n `style=\"${anchorStyle}\">${safeText}</a>` +\n `</p>`\n );\n}\n","import { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { EmailButtonConfig } from \"../types\";\nimport { buildButtonHtml } from \"../utils/buildButtonHtml\";\n\nexport type EmailButtonDialogProps = {\n /** Whether the dialog is open. */\n open: boolean;\n /** Called when the user confirms; receives the email-safe button HTML. */\n onConfirm: (html: string, config: EmailButtonConfig) => void;\n /** Called when the user dismisses the dialog (Esc / click-outside / cancel). */\n onClose: () => void;\n /** Optional initial values for the form. */\n initial?: Partial<EmailButtonConfig>;\n};\n\nconst DEFAULT_CONFIG: EmailButtonConfig = {\n text: \"Click here\",\n href: \"https://\",\n bgColor: \"#2563eb\",\n textColor: \"#ffffff\",\n align: \"left\",\n radius: 6,\n fullWidth: false,\n};\n\nconst BG_SWATCHES = [\n \"#2563eb\",\n \"#16a34a\",\n \"#dc2626\",\n \"#7c3aed\",\n \"#ea580c\",\n \"#0891b2\",\n \"#111827\",\n];\nconst TEXT_SWATCHES = [\"#ffffff\", \"#111827\", \"#f9fafb\", \"#1f2937\"];\n\n// <input type=color> only accepts #rrggbb. Named colors, #rgb shorthand, or\n// anything else must be coerced or it throws/blanks the control.\nconst HEX6_RE = /^#[0-9a-fA-F]{6}$/;\nfunction toColorInputValue(value: string): string {\n return HEX6_RE.test(value) ? value : \"#000000\";\n}\n\ntype ColorFieldProps = {\n label: string;\n value: string;\n swatches: string[];\n onChange: (value: string) => void;\n};\n\nfunction ColorField({ label, value, swatches, onChange }: ColorFieldProps) {\n return (\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">{label}</span>\n <div className=\"rte-color-row\">\n {swatches.map((swatch) => (\n <button\n key={swatch}\n type=\"button\"\n className={\n \"rte-swatch\" + (value === swatch ? \" rte-swatch--active\" : \"\")\n }\n style={{ backgroundColor: swatch }}\n aria-label={`Use ${swatch}`}\n aria-pressed={value === swatch}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onChange(swatch)}\n />\n ))}\n <input\n type=\"color\"\n className=\"rte-color-input\"\n value={toColorInputValue(value)}\n aria-label={`${label} picker`}\n onChange={(e) => onChange(e.target.value)}\n />\n <input\n type=\"text\"\n className=\"rte-hex-input\"\n value={value}\n aria-label={`${label} hex`}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n />\n </div>\n </div>\n );\n}\n\n/**\n * Modal dialog for configuring an email CTA button. Supports Esc to close,\n * body-scroll lock while open, click-outside to dismiss, and a live preview of\n * the rendered button.\n */\nexport function EmailButtonDialog({\n open,\n onConfirm,\n onClose,\n initial,\n}: EmailButtonDialogProps) {\n const [config, setConfig] = useState<EmailButtonConfig>({\n ...DEFAULT_CONFIG,\n ...initial,\n });\n const overlayRef = useRef<HTMLDivElement>(null);\n\n // Reset the form to its initial state each time the dialog opens.\n useEffect(() => {\n if (open) {\n setConfig({ ...DEFAULT_CONFIG, ...initial });\n }\n }, [open, initial]);\n\n // Esc to close + body-scroll lock while open.\n useEffect(() => {\n if (!open) return;\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n onClose();\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.body.style.overflow = previousOverflow;\n };\n }, [open, onClose]);\n\n const previewHtml = useMemo(() => buildButtonHtml(config), [config]);\n\n if (!open) return null;\n\n const update = <K extends keyof EmailButtonConfig>(\n key: K,\n value: EmailButtonConfig[K],\n ) => setConfig((prev) => ({ ...prev, [key]: value }));\n\n const handleSubmit = () => {\n onConfirm(buildButtonHtml(config), config);\n };\n\n return (\n <div\n ref={overlayRef}\n className=\"rte-dialog-overlay\"\n role=\"presentation\"\n onMouseDown={(e) => {\n // Click-outside (on the overlay itself, not the panel) dismisses.\n if (e.target === overlayRef.current) onClose();\n }}\n >\n <div\n className=\"rte-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Insert button\"\n >\n <div className=\"rte-dialog-header\">\n <h2 className=\"rte-dialog-title\">Insert button</h2>\n <button\n type=\"button\"\n className=\"rte-dialog-close\"\n aria-label=\"Close\"\n onClick={onClose}\n >\n ×\n </button>\n </div>\n\n <div className=\"rte-dialog-body\">\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Text</span>\n <input\n type=\"text\"\n className=\"rte-text-input\"\n value={config.text}\n onChange={(e) => update(\"text\", e.target.value)}\n />\n </label>\n\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Link URL</span>\n <input\n type=\"text\"\n className=\"rte-text-input\"\n value={config.href}\n onChange={(e) => update(\"href\", e.target.value)}\n />\n </label>\n\n <ColorField\n label=\"Background color\"\n value={config.bgColor}\n swatches={BG_SWATCHES}\n onChange={(v) => update(\"bgColor\", v)}\n />\n\n <ColorField\n label=\"Text color\"\n value={config.textColor}\n swatches={TEXT_SWATCHES}\n onChange={(v) => update(\"textColor\", v)}\n />\n\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Alignment</span>\n <div className=\"rte-align-row\">\n {([\"left\", \"center\", \"right\"] as const).map((a) => (\n <button\n key={a}\n type=\"button\"\n className={\n \"rte-align-btn\" +\n (config.align === a ? \" rte-align-btn--active\" : \"\")\n }\n aria-pressed={config.align === a}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => update(\"align\", a)}\n >\n {a}\n </button>\n ))}\n </div>\n </div>\n\n <label className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">\n Corner radius: {config.radius}px\n </span>\n <input\n type=\"range\"\n min={0}\n max={32}\n value={config.radius}\n onChange={(e) => update(\"radius\", Number(e.target.value))}\n />\n </label>\n\n <label className=\"rte-checkbox-field\">\n <input\n type=\"checkbox\"\n checked={config.fullWidth}\n onChange={(e) => update(\"fullWidth\", e.target.checked)}\n />\n <span>Full width</span>\n </label>\n\n <div className=\"rte-dialog-field\">\n <span className=\"rte-dialog-label\">Preview</span>\n <div\n className=\"rte-button-preview\"\n // Preview only — content is built from the same escaped builder.\n dangerouslySetInnerHTML={{ __html: previewHtml }}\n />\n </div>\n </div>\n\n <div className=\"rte-dialog-footer\">\n <button\n type=\"button\"\n className=\"rte-btn rte-btn--ghost\"\n onClick={onClose}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n className=\"rte-btn rte-btn--primary\"\n onClick={handleSubmit}\n >\n Insert\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport default EmailButtonDialog;\n","import type { Editor } from \"@tiptap/react\";\nimport { useEditorState } from \"@tiptap/react\";\nimport {\n AlignCenter,\n AlignLeft,\n AlignRight,\n Bold,\n Code,\n FileCode,\n Heading2,\n Heading3,\n Heading4,\n Heading5,\n Heading6,\n Image as ImageIcon,\n Italic,\n Link as LinkIcon,\n List,\n ListOrdered,\n Minus,\n MousePointerClick,\n PanelBottom,\n Pilcrow,\n Quote,\n Strikethrough,\n Underline,\n} from \"lucide-react\";\nimport { Fragment, type ReactNode } from \"react\";\n\nimport type { ResolvedToolbarConfig } from \"../types\";\n\ntype HeadingLevel = 2 | 3 | 4 | 5 | 6;\n\nexport type ToolbarProps = {\n editor: Editor;\n config: ResolvedToolbarConfig;\n /** Toggle the raw HTML source view. */\n htmlMode: boolean;\n onToggleHtml: () => void;\n /** Caller-provided handlers for the controls that need extra UI. */\n onLink: () => void;\n onImage: () => void;\n onButton: () => void;\n onInsertParagraph: () => void;\n onInsertDivider: () => void;\n onInsertFooter: () => void;\n};\n\ntype TbButtonProps = {\n onClick: () => void;\n active?: boolean;\n label: string;\n disabled?: boolean;\n children: ReactNode;\n};\n\nfunction TbButton({ onClick, active, label, disabled, children }: TbButtonProps) {\n return (\n <button\n type=\"button\"\n className={\"rte-tb-btn\" + (active ? \" rte-tb-btn--active\" : \"\")}\n // Prevent the button from stealing the editor's selection on press.\n onMouseDown={(e) => e.preventDefault()}\n onClick={onClick}\n aria-pressed={!!active}\n aria-label={label}\n title={label}\n disabled={disabled}\n >\n {children}\n </button>\n );\n}\n\nfunction Divider() {\n return <span className=\"rte-tb-divider\" aria-hidden=\"true\" />;\n}\n\nconst HEADING_ICONS: Record<HeadingLevel, ReactNode> = {\n 2: <Heading2 size={16} />,\n 3: <Heading3 size={16} />,\n 4: <Heading4 size={16} />,\n 5: <Heading5 size={16} />,\n 6: <Heading6 size={16} />,\n};\n\nexport function Toolbar({\n editor,\n config,\n htmlMode,\n onToggleHtml,\n onLink,\n onImage,\n onButton,\n onInsertParagraph,\n onInsertDivider,\n onInsertFooter,\n}: ToolbarProps) {\n // useEditorState re-renders only when the selected slice changes, keeping\n // active-state computation cheap even on large documents.\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) => ({\n bold: e.isActive(\"bold\"),\n italic: e.isActive(\"italic\"),\n underline: e.isActive(\"underline\"),\n strike: e.isActive(\"strike\"),\n code: e.isActive(\"code\"),\n h2: e.isActive(\"heading\", { level: 2 }),\n h3: e.isActive(\"heading\", { level: 3 }),\n h4: e.isActive(\"heading\", { level: 4 }),\n h5: e.isActive(\"heading\", { level: 5 }),\n h6: e.isActive(\"heading\", { level: 6 }),\n bulletList: e.isActive(\"bulletList\"),\n orderedList: e.isActive(\"orderedList\"),\n blockquote: e.isActive(\"blockquote\"),\n alignLeft: e.isActive({ textAlign: \"left\" }),\n alignCenter: e.isActive({ textAlign: \"center\" }),\n alignRight: e.isActive({ textAlign: \"right\" }),\n link: e.isActive(\"link\"),\n image: e.isActive(\"image\"),\n }),\n });\n\n const headingActive: Record<HeadingLevel, boolean> = {\n 2: state.h2,\n 3: state.h3,\n 4: state.h4,\n 5: state.h5,\n 6: state.h6,\n };\n\n // In HTML source mode only the source toggle is interactive.\n const disabled = htmlMode;\n\n // Build each group as an array of rendered buttons, gated by both the group\n // `enabled` flag and the per-button flag. A group with zero visible buttons\n // contributes nothing (and gets no divider).\n const inline = config.inline.enabled\n ? [\n config.inline.buttons.bold && (\n <TbButton\n key=\"bold\"\n label=\"Bold\"\n active={state.bold}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBold().run()}\n >\n <Bold size={16} />\n </TbButton>\n ),\n config.inline.buttons.italic && (\n <TbButton\n key=\"italic\"\n label=\"Italic\"\n active={state.italic}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleItalic().run()}\n >\n <Italic size={16} />\n </TbButton>\n ),\n config.inline.buttons.underline && (\n <TbButton\n key=\"underline\"\n label=\"Underline\"\n active={state.underline}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n >\n <Underline size={16} />\n </TbButton>\n ),\n config.inline.buttons.strike && (\n <TbButton\n key=\"strike\"\n label=\"Strikethrough\"\n active={state.strike}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleStrike().run()}\n >\n <Strikethrough size={16} />\n </TbButton>\n ),\n config.inline.buttons.code && (\n <TbButton\n key=\"code\"\n label=\"Inline code\"\n active={state.code}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleCode().run()}\n >\n <Code size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const headings = config.headings.enabled\n ? ([2, 3, 4, 5, 6] as const).map((level) =>\n config.headings.buttons[`h${level}` as keyof typeof config.headings.buttons] ? (\n <TbButton\n key={`h${level}`}\n label={`Heading ${level}`}\n active={headingActive[level]}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleHeading({ level }).run()}\n >\n {HEADING_ICONS[level]}\n </TbButton>\n ) : (\n false\n ),\n )\n : [];\n\n const lists = config.lists.enabled\n ? [\n config.lists.buttons.bullet && (\n <TbButton\n key=\"bullet\"\n label=\"Bullet list\"\n active={state.bulletList}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n >\n <List size={16} />\n </TbButton>\n ),\n config.lists.buttons.ordered && (\n <TbButton\n key=\"ordered\"\n label=\"Ordered list\"\n active={state.orderedList}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n >\n <ListOrdered size={16} />\n </TbButton>\n ),\n config.lists.buttons.blockquote && (\n <TbButton\n key=\"quote\"\n label=\"Quote\"\n active={state.blockquote}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBlockquote().run()}\n >\n <Quote size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const align = config.align.enabled\n ? [\n config.align.buttons.left && (\n <TbButton\n key=\"left\"\n label=\"Align left\"\n active={state.alignLeft}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"left\").run()}\n >\n <AlignLeft size={16} />\n </TbButton>\n ),\n config.align.buttons.center && (\n <TbButton\n key=\"center\"\n label=\"Align center\"\n active={state.alignCenter}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"center\").run()}\n >\n <AlignCenter size={16} />\n </TbButton>\n ),\n config.align.buttons.right && (\n <TbButton\n key=\"right\"\n label=\"Align right\"\n active={state.alignRight}\n disabled={disabled}\n onClick={() => editor.chain().focus().setTextAlign(\"right\").run()}\n >\n <AlignRight size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const inserts = [\n config.link && (\n <TbButton\n key=\"link\"\n label=\"Link\"\n active={state.link}\n disabled={disabled}\n onClick={onLink}\n >\n <LinkIcon size={16} />\n </TbButton>\n ),\n config.image && (\n <TbButton\n key=\"image\"\n label=\"Image\"\n active={state.image}\n disabled={disabled}\n onClick={onImage}\n >\n <ImageIcon size={16} />\n </TbButton>\n ),\n config.button && (\n <TbButton\n key=\"button\"\n label=\"Button\"\n disabled={disabled}\n onClick={onButton}\n >\n <MousePointerClick size={16} />\n </TbButton>\n ),\n ];\n\n const blocks = config.blocks.enabled\n ? [\n config.blocks.buttons.paragraph && (\n <TbButton\n key=\"paragraph\"\n label=\"Insert paragraph\"\n disabled={disabled}\n onClick={onInsertParagraph}\n >\n <Pilcrow size={16} />\n </TbButton>\n ),\n config.blocks.buttons.divider && (\n <TbButton\n key=\"divider\"\n label=\"Insert divider\"\n disabled={disabled}\n onClick={onInsertDivider}\n >\n <Minus size={16} />\n </TbButton>\n ),\n config.blocks.buttons.footer && (\n <TbButton\n key=\"footer\"\n label=\"Insert footer\"\n disabled={disabled}\n onClick={onInsertFooter}\n >\n <PanelBottom size={16} />\n </TbButton>\n ),\n ]\n : [];\n\n const html = config.html\n ? [\n <TbButton\n key=\"html\"\n label=\"HTML source\"\n active={htmlMode}\n onClick={onToggleHtml}\n >\n <FileCode size={16} />\n </TbButton>,\n ]\n : [];\n\n // Keep only groups that have at least one visible button, then render them\n // with a divider between each — so hidden groups leave no dangling dividers.\n const groups = [inline, headings, lists, align, inserts, blocks, html]\n .map((g) => g.filter(Boolean))\n .filter((g) => g.length > 0);\n\n return (\n <div className=\"rte-toolbar\" role=\"toolbar\" aria-label=\"Formatting\">\n {groups.map((buttons, i) => (\n <Fragment key={i}>\n {i > 0 && <Divider />}\n <div className=\"rte-tb-group\">{buttons}</div>\n </Fragment>\n ))}\n </div>\n );\n}\n\nexport default Toolbar;\n","import { EditorContent, useEditor } from \"@tiptap/react\";\nimport {\n forwardRef,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { createEmailExtensions } from \"../extensions/editorExtensions\";\nimport type { ToolbarConfig } from \"../types\";\nimport { PRESET_DIVIDER, PRESET_FOOTER, PRESET_PARAGRAPH } from \"../utils/presets\";\nimport { resolveToolbarConfig } from \"../utils/resolveToolbarConfig\";\nimport { EmailButtonDialog } from \"./EmailButtonDialog\";\nimport { Toolbar } from \"./Toolbar\";\n\nexport type RichTextEditorHandle = {\n /** Insert raw HTML or plain text at the current caret position. */\n insertAtCaret: (htmlOrText: string) => void;\n};\n\nexport type RichTextEditorProps = {\n /** Body-level HTML fragment (no `<html>`/`<body>`). */\n value: string;\n /** Fires with the updated body-level HTML fragment. */\n onChange: (value: string) => void;\n /** Empty-state placeholder text. */\n placeholder?: string;\n /** Resolve an uploaded file to a hosted image URL. */\n onUploadImage?: (file: File) => Promise<string>;\n /** Extra class on the editor wrapper. */\n className?: string;\n /** Inline style applied to the editable surface (e.g. minHeight/height). */\n editorStyle?: React.CSSProperties;\n /** Which toolbar controls to render (defaults to everything on). */\n toolbar?: ToolbarConfig;\n};\n\n/**\n * The generic body-HTML rich-text editor: a toolbar plus an editable surface\n * operating on a plain HTML fragment. `<EmailEditor>` wraps this to add the\n * document-shell bridge and placeholder chips.\n */\nexport const RichTextEditor = forwardRef<\n RichTextEditorHandle,\n RichTextEditorProps\n>(function RichTextEditor(\n {\n value,\n onChange,\n placeholder = \"Write something…\",\n onUploadImage,\n className,\n editorStyle,\n toolbar,\n },\n ref,\n) {\n const toolbarConfig = useMemo(\n () => resolveToolbarConfig(toolbar),\n [toolbar],\n );\n\n const extensions = useMemo(\n () => createEmailExtensions(placeholder),\n [placeholder],\n );\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [htmlMode, setHtmlMode] = useState(false);\n const [buttonDialogOpen, setButtonDialogOpen] = useState(false);\n\n const editor = useEditor({\n extensions,\n content: value,\n // REQUIRED for SSR/Next.js — rendering immediately causes a hydration\n // mismatch because the server has no DOM.\n immediatelyRender: false,\n editorProps: {\n attributes: {\n class: \"rte-content\",\n },\n },\n onUpdate: ({ editor: e }) => {\n onChange(e.getHTML());\n },\n });\n\n // Sync external `value` changes into the editor without fighting the user's\n // typing: only when it actually differs from the editor's current HTML, and\n // with emitUpdate:false so it does not re-fire onChange.\n if (editor && !htmlMode && value !== editor.getHTML()) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n\n useImperativeHandle(\n ref,\n () => ({\n insertAtCaret: (htmlOrText: string) => {\n editor?.chain().focus().insertContent(htmlOrText).run();\n },\n }),\n [editor],\n );\n\n const insertSnippet = useCallback(\n (snippet: string) => {\n editor?.chain().focus().insertContent(snippet).run();\n },\n [editor],\n );\n\n const handleLink = useCallback(() => {\n if (!editor) return;\n const previous = editor.getAttributes(\"link\").href as string | undefined;\n const url = window.prompt(\"Link URL\", previous ?? \"https://\");\n if (url === null) return; // cancelled\n if (url.trim() === \"\") {\n editor.chain().focus().extendMarkRange(\"link\").unsetLink().run();\n return;\n }\n editor\n .chain()\n .focus()\n .extendMarkRange(\"link\")\n .setLink({ href: url.trim() })\n .run();\n }, [editor]);\n\n const handleImageClick = useCallback(() => {\n if (!editor) return;\n if (onUploadImage) {\n fileInputRef.current?.click();\n } else {\n const url = window.prompt(\"Image URL\", \"https://\");\n if (url && url.trim()) {\n editor.chain().focus().setImage({ src: url.trim() }).run();\n }\n }\n }, [editor, onUploadImage]);\n\n const handleFileSelected = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n // Reset so selecting the same file again re-triggers change.\n e.target.value = \"\";\n if (!file || !onUploadImage || !editor) return;\n try {\n const src = await onUploadImage(file);\n if (src) editor.chain().focus().setImage({ src }).run();\n } catch (err) {\n // Surface upload failures without crashing the editor.\n console.error(\"dpk-editor: image upload failed\", err);\n }\n },\n [editor, onUploadImage],\n );\n\n const handleButtonConfirm = useCallback(\n (html: string) => {\n setButtonDialogOpen(false);\n editor?.chain().focus().insertContent(html).run();\n },\n [editor],\n );\n\n if (!editor) return null;\n\n return (\n <div className={\"rte-root\" + (className ? ` ${className}` : \"\")}>\n <Toolbar\n editor={editor}\n config={toolbarConfig}\n htmlMode={htmlMode}\n onToggleHtml={() => setHtmlMode((m) => !m)}\n onLink={handleLink}\n onImage={handleImageClick}\n onButton={() => setButtonDialogOpen(true)}\n onInsertParagraph={() => insertSnippet(PRESET_PARAGRAPH)}\n onInsertDivider={() => insertSnippet(PRESET_DIVIDER)}\n onInsertFooter={() => insertSnippet(PRESET_FOOTER)}\n />\n\n {htmlMode ? (\n <textarea\n className=\"rte-source\"\n style={editorStyle}\n value={value}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n aria-label=\"HTML source\"\n />\n ) : (\n <EditorContent\n editor={editor}\n className=\"rte-editor\"\n style={editorStyle}\n />\n )}\n\n {onUploadImage && (\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={handleFileSelected}\n />\n )}\n\n <EmailButtonDialog\n open={buttonDialogOpen}\n onConfirm={handleButtonConfirm}\n onClose={() => setButtonDialogOpen(false)}\n />\n </div>\n );\n});\n\nexport default RichTextEditor;\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\n\nimport type {\n EmailHtmlDocument,\n EmailPlaceholder,\n ToolbarConfig,\n} from \"../types\";\nimport { joinEmailHtml, splitEmailHtml } from \"../utils/shellBridge\";\nimport {\n RichTextEditor,\n type RichTextEditorHandle,\n} from \"./RichTextEditor\";\n\nexport type EmailEditorProps = {\n /** Full HTML document OR a bare body fragment — both are supported. */\n value: string;\n /** Fires with HTML in the same shape `value` was provided (shell re-applied). */\n onChange: (value: string) => void;\n /** Optional merge tokens; render a chip row that inserts at the caret. */\n placeholders?: EmailPlaceholder[];\n /** Resolve an uploaded file to a hosted image URL (else a URL prompt is used). */\n onUploadImage?: (file: File) => Promise<string>;\n /** Minimum height (px) of the editable surface. */\n minHeight?: number;\n /** Empty-state placeholder text for the editable surface. */\n placeholder?: string;\n /** Which toolbar controls to render (defaults to everything on). */\n toolbar?: ToolbarConfig;\n /** Extra class on the editor wrapper. */\n className?: string;\n};\n\n/**\n * The batteries-included email editor. Owns the document-shell bridge so the\n * surrounding `<!doctype>`/`<html>`/`<body style>` (and any `<table>` layout\n * inside the body) is preserved verbatim across edits, while only the body\n * fragment is handed to the underlying `<RichTextEditor>`.\n */\nexport function EmailEditor({\n value,\n onChange,\n placeholders,\n onUploadImage,\n minHeight = 288,\n placeholder,\n toolbar,\n className,\n}: EmailEditorProps) {\n // Recompute the shell from `value` on each render.\n const shell = useMemo<EmailHtmlDocument>(() => splitEmailHtml(value), [value]);\n\n // Keep the latest shell in a ref so the onChange closure always rejoins with\n // the current prefix/suffix. Assign the ref in an EFFECT (never during\n // render) — strict react-hooks lint flags a render-time ref write.\n const shellRef = useRef<EmailHtmlDocument>(shell);\n useEffect(() => {\n shellRef.current = shell;\n }, [shell]);\n\n const editorRef = useRef<RichTextEditorHandle>(null);\n\n const handleBodyChange = useCallback(\n (newBody: string) => {\n onChange(joinEmailHtml(shellRef.current, newBody));\n },\n [onChange],\n );\n\n const editorStyle = useMemo<React.CSSProperties>(\n () => ({ minHeight }),\n [minHeight],\n );\n\n const insertToken = useCallback((token: string) => {\n editorRef.current?.insertAtCaret(token);\n }, []);\n\n return (\n <div className={\"rte-email\" + (className ? ` ${className}` : \"\")}>\n {placeholders && placeholders.length > 0 && (\n <div className=\"rte-chips\" role=\"group\" aria-label=\"Merge tokens\">\n {placeholders.map((p) => (\n <button\n key={p.token}\n type=\"button\"\n className=\"rte-chip\"\n title={`Insert ${p.token}`}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => insertToken(p.token)}\n >\n {p.label}\n </button>\n ))}\n </div>\n )}\n\n <RichTextEditor\n ref={editorRef}\n value={shell.body}\n onChange={handleBodyChange}\n onUploadImage={onUploadImage}\n placeholder={placeholder}\n editorStyle={editorStyle}\n toolbar={toolbar}\n />\n </div>\n );\n}\n\nexport default EmailEditor;\n"]}
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "dpk-editor",
3
- "version": "0.1.0",
4
- "description": "A React rich-text editor built on TipTap v3, purpose-built for composing HTML emails. Preserves inline styles, the full document shell, and produces email-safe (bulletproof) markup.",
3
+ "version": "0.1.1",
4
+ "description": "A React feature-rich HTML rich-text (WYSIWYG) editor built on TipTap v3. Use it anywhere — CMS bodies, comments, documents, marketing pages, or email. Preserves inline styles and the full document shell, and produces clean, portable, paste-anywhere markup.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": "",
8
8
  "keywords": [
9
9
  "react",
10
10
  "tiptap",
11
- "email",
12
11
  "rich-text-editor",
13
12
  "wysiwyg",
14
- "html-email",
15
- "editor"
13
+ "html-editor",
14
+ "prosemirror",
15
+ "editor",
16
+ "email"
16
17
  ],
17
18
  "sideEffects": [
18
19
  "*.css"
@@ -38,7 +39,10 @@
38
39
  "lint": "eslint \"src/**/*.{ts,tsx}\"",
39
40
  "test": "vitest run",
40
41
  "test:watch": "vitest",
41
- "prepublishOnly": "npm run build"
42
+ "prepublishOnly": "npm run typecheck && npm run test && npm run build",
43
+ "release": "npm version patch && npm publish",
44
+ "release:minor": "npm version minor && npm publish",
45
+ "release:major": "npm version major && npm publish"
42
46
  },
43
47
  "dependencies": {
44
48
  "@tiptap/extension-highlight": "^3.23.6",