rich-html-editor 0.2.1 → 0.2.2

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/events.ts","../src/core/constants.ts","../src/utils/sanitize.ts","../src/core/state.ts","../src/index.ts","../src/core/editor.ts","../src/dom/styles.ts","../src/toolbar/toolbar.ts","../src/dom/handlers.ts","../src/dom/candidates.ts","../src/dom/format.ts","../src/core/sanitizeURL.ts","../src/core/history.ts","../src/core/formatActions.ts"],"sourcesContent":["import type { EditorEventType, EditorEvent, EditorEventHandler } from \"./types\";\r\n\r\nexport class EditorEventEmitter {\r\n private listeners: Map<EditorEventType, Set<EditorEventHandler>> = new Map();\r\n\r\n on(type: EditorEventType, handler: EditorEventHandler): () => void {\r\n if (!this.listeners.has(type)) {\r\n this.listeners.set(type, new Set());\r\n }\r\n this.listeners.get(type)!.add(handler);\r\n return () => this.off(type, handler);\r\n }\r\n\r\n once(type: EditorEventType, handler: EditorEventHandler): void {\r\n const unsubscribe = this.on(type, (event) => {\r\n handler(event);\r\n unsubscribe();\r\n });\r\n }\r\n\r\n off(type: EditorEventType, handler: EditorEventHandler): void {\r\n const handlers = this.listeners.get(type);\r\n if (handlers) {\r\n handlers.delete(handler);\r\n if (handlers.size === 0) this.listeners.delete(type);\r\n }\r\n }\r\n\r\n emit(event: EditorEvent): void {\r\n const handlers = this.listeners.get(event.type);\r\n if (handlers) {\r\n handlers.forEach((handler) => {\r\n try {\r\n handler(event);\r\n } catch (error) {\r\n console.error(\r\n `[rich-html-editor] Error in event handler for ${event.type}:`,\r\n error\r\n );\r\n }\r\n });\r\n }\r\n }\r\n\r\n removeAllListeners(type?: EditorEventType): void {\r\n if (type) this.listeners.delete(type);\r\n else this.listeners.clear();\r\n }\r\n\r\n listenerCount(type: EditorEventType): number {\r\n return this.listeners.get(type)?.size ?? 0;\r\n }\r\n}\r\n\r\nexport const editorEventEmitter = new EditorEventEmitter();\r\n\r\nexport function getEditorEventEmitter(): EditorEventEmitter {\r\n return editorEventEmitter;\r\n}\r\n","// Shared constants for the rich-html-editor (moved to core)\r\nexport const TOOLBAR_ID = \"editor-toolbar\";\r\nexport const STYLE_ID = \"editor-styles\";\r\nexport const CLASS_EDITABLE = \"editor-editable-element\";\r\nexport const CLASS_ACTIVE = \"editor-active-element\";\r\n\r\n// Default undo/redo stack size\r\nexport const DEFAULT_MAX_STACK = 60;\r\n\r\n// Toolbar styling constants\r\nexport const TOOLBAR_BG = \"#f8fafc\";\r\nexport const TOOLBAR_BORDER = \"#e5e7eb\";\r\nexport const BUTTON_BORDER = \"#d1d5db\";\r\nexport const BUTTON_ACTIVE_BG = \"#e0e7ff\";\r\nexport const BUTTON_BG = \"#fff\";\r\nexport const BUTTON_COLOR = \"#222\";\r\nexport const INFO_COLOR = \"#888\";\r\n\r\n// Outline colors used by injected styles\r\nexport const HOVER_OUTLINE = \"#2563eb\";\r\nexport const ACTIVE_OUTLINE = \"#16a34a\";\r\n\r\n// Toolbar label/icon constants (kept in core for reuse)\r\nexport const LABEL_BOLD = \"<b>B</b>\";\r\nexport const LABEL_ITALIC = \"<i>I</i>\";\r\nexport const LABEL_UNDERLINE = \"<u>U</u>\";\r\nexport const LABEL_STRIKETHROUGH = \"<s>S</s>\";\r\nexport const LABEL_UNDO = \"↺\";\r\nexport const LABEL_REDO = \"↻\";\r\nexport const LABEL_LINK = \"🔗\";\r\nexport const LABEL_ALIGN_LEFT = `\r\n\t<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\r\n\t\t<rect x=\"1\" y=\"2\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"6\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"10\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"14\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t</svg>\r\n`;\r\nexport const LABEL_ALIGN_CENTER = `\r\n\t<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\r\n\t\t<rect x=\"3\" y=\"2\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"6\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"3\" y=\"10\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"14\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t</svg>\r\n`;\r\nexport const LABEL_ALIGN_RIGHT = `\r\n\t<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\r\n\t\t<rect x=\"5\" y=\"2\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"6\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"5\" y=\"10\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"14\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t</svg>\r\n`;\r\n\r\n// Font and size option lists used by the toolbar\r\nexport const FONT_OPTIONS: { label: string; value: string }[] = [\r\n { label: \"Arial\", value: \"Arial\" },\r\n { label: \"Helvetica\", value: \"Helvetica, Arial, sans-serif\" },\r\n { label: \"Verdana\", value: \"Verdana, Geneva, sans-serif\" },\r\n { label: \"Tahoma\", value: \"Tahoma, Geneva, sans-serif\" },\r\n { label: \"Trebuchet MS\", value: \"Trebuchet MS, Helvetica, sans-serif\" },\r\n { label: \"Georgia\", value: \"Georgia, serif\" },\r\n { label: \"Times New Roman\", value: \"Times New Roman, Times, serif\" },\r\n { label: \"Palatino\", value: \"Palatino, 'Palatino Linotype', serif\" },\r\n { label: \"Garamond\", value: \"Garamond, serif\" },\r\n { label: \"Book Antiqua\", value: \"'Book Antiqua', Palatino, serif\" },\r\n { label: \"Courier New\", value: \"'Courier New', Courier, monospace\" },\r\n { label: \"Lucida Console\", value: \"'Lucida Console', Monaco, monospace\" },\r\n { label: \"Impact\", value: \"Impact, Charcoal, sans-serif\" },\r\n { label: \"Comic Sans MS\", value: \"'Comic Sans MS', 'Comic Sans', cursive\" },\r\n { label: \"Segoe UI\", value: \"'Segoe UI', Tahoma, Geneva, sans-serif\" },\r\n {\r\n label: \"Roboto\",\r\n value: \"Roboto, 'Helvetica Neue', Helvetica, Arial, sans-serif\",\r\n },\r\n { label: \"Open Sans\", value: \"'Open Sans', Arial, sans-serif\" },\r\n { label: \"Lato\", value: \"Lato, 'Helvetica Neue', Arial, sans-serif\" },\r\n { label: \"Montserrat\", value: \"Montserrat, Arial, sans-serif\" },\r\n { label: \"Source Sans Pro\", value: \"'Source Sans Pro', Arial, sans-serif\" },\r\n { label: \"Fira Sans\", value: \"'Fira Sans', Arial, sans-serif\" },\r\n { label: \"Ubuntu\", value: \"Ubuntu, Arial, sans-serif\" },\r\n { label: \"Noto Sans\", value: \"'Noto Sans', Arial, sans-serif\" },\r\n { label: \"Droid Sans\", value: \"'Droid Sans', Arial, sans-serif\" },\r\n {\r\n label: \"Helvetica Neue\",\r\n value: \"'Helvetica Neue', Helvetica, Arial, sans-serif\",\r\n },\r\n {\r\n label: \"System UI\",\r\n value:\r\n \"system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\",\r\n },\r\n];\r\n\r\nexport const SIZE_OPTIONS: { label: string; value: string }[] = [\r\n { label: \"8\", value: \"8\" },\r\n { label: \"9\", value: \"9\" },\r\n { label: \"10\", value: \"10\" },\r\n { label: \"11\", value: \"11\" },\r\n { label: \"12\", value: \"12\" },\r\n { label: \"14\", value: \"14\" },\r\n { label: \"16\", value: \"16\" },\r\n { label: \"18\", value: \"18\" },\r\n { label: \"20\", value: \"20\" },\r\n { label: \"22\", value: \"22\" },\r\n { label: \"24\", value: \"24\" },\r\n { label: \"26\", value: \"26\" },\r\n { label: \"28\", value: \"28\" },\r\n { label: \"36\", value: \"36\" },\r\n { label: \"48\", value: \"48\" },\r\n { label: \"72\", value: \"72\" },\r\n];\r\n\r\n// Block format options (Paragraph + Headings)\r\nexport const FORMAT_OPTIONS: { label: string; value: string }[] = [\r\n { label: \"Heading 1\", value: \"h1\" },\r\n { label: \"Heading 2\", value: \"h2\" },\r\n { label: \"Heading 3\", value: \"h3\" },\r\n { label: \"Heading 4\", value: \"h4\" },\r\n { label: \"Heading 5\", value: \"h5\" },\r\n { label: \"Heading 6\", value: \"h6\" },\r\n];\r\n\r\n// Shared SVG used by toolbar color inputs (palette icon)\r\nexport const PALETTE_SVG = `\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\r\n <path d=\"M12 2C7 2 3 6 3 11c0 2.8 1.4 5.3 3.7 6.8.9.6 2 .9 3.3.9 1.6 0 3.1-.5 4.3-1.4.6-.4.9-1.1.6-1.8-.3-.7-1-1-1.7-.8-1.1.3-2.3.2-3.4-.3C10.3 14.6 9 13.6 9 12c0-1.7 1.3-3 3-3 .8 0 1.5.3 2.1.8.5.4 1.2.3 1.6-.2.9-1.1 1.4-2.4 1.4-3.8C20.9 6 16.9 2 12 2z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n <circle cx=\"7.5\" cy=\"10.5\" r=\"1\" fill=\"currentColor\"/>\r\n <circle cx=\"11.5\" cy=\"8.5\" r=\"1\" fill=\"currentColor\"/>\r\n <circle cx=\"14.5\" cy=\"11.5\" r=\"1\" fill=\"currentColor\"/>\r\n </svg>\r\n`;\r\n\r\n// MS Word-like icons for color controls\r\nexport const TEXT_COLOR_ICON_HTML = `\r\n <span class=\"text-color-wrapper\" aria-hidden=\"true\">\r\n <span class=\"text-A\">A</span>\r\n </span>\r\n`;\r\n\r\nexport const HIGHLIGHT_ICON_HTML = `\r\n <span class=\"highlight-wrapper\" aria-hidden=\"true\">\r\n <span class=\"highlight-bar\" data-role=\"highlight\"></span>\r\n <span class=\"text-A\">A</span>\r\n </span>\r\n`;\r\n","import createDOMPurify from \"dompurify\";\r\n\r\n/**\r\n * Sanitize HTML using DOMPurify.\r\n *\r\n * Works in browser and in jsdom (tests) by accepting either a `Window`\r\n * or a `Document` (from which `defaultView` is used).\r\n */\r\nexport function sanitizeHtml(\r\n html: string,\r\n ctx?: Window | Document | null\r\n): string {\r\n if (!html) return \"\";\r\n // Try to get a Window reference\r\n let win: Window | null = null;\r\n if (ctx && (ctx as Document).defaultView) {\r\n win = (ctx as Document).defaultView as Window;\r\n } else if (ctx && (ctx as Window).document) {\r\n win = ctx as Window;\r\n } else if (typeof window !== \"undefined\") {\r\n win = window as Window;\r\n }\r\n\r\n // If we have a window, use DOMPurify\r\n if (win) {\r\n try {\r\n const DOMPurify = createDOMPurify(win as any);\r\n // Preserve element ids and data-* attributes so restoring snapshots\r\n // during undo/redo does not break page scripts or CSS that rely on\r\n // those attributes. Still strip <script> and all inline event\r\n // handlers (on*) to avoid executing arbitrary script.\r\n // Use ADD_ATTR to allow `id`, and a hook to preserve any `data-` attrs.\r\n try {\r\n DOMPurify.addHook(\"uponSanitizeAttribute\", (node: any, data: any) => {\r\n try {\r\n if (data && data.attrName && data.attrName.startsWith(\"data-\")) {\r\n // Keep data-* attributes\r\n (data as any).keepAttr = true;\r\n }\r\n } catch (e) {\r\n /* ignore hook errors */\r\n }\r\n });\r\n } catch (e) {\r\n /* addHook may not be available in some environments; ignore */\r\n }\r\n\r\n return DOMPurify.sanitize(html, {\r\n // Use sensible defaults: allow common formatting tags but strip scripts\r\n ALLOWED_TAGS: [\r\n \"a\",\r\n \"b\",\r\n \"i\",\r\n \"em\",\r\n \"strong\",\r\n \"u\",\r\n \"p\",\r\n \"div\",\r\n \"span\",\r\n // Common semantic elements: preserve document structure so undo/redo\r\n // does not flatten header/section/nav into plain content.\r\n \"header\",\r\n \"nav\",\r\n \"section\",\r\n \"main\",\r\n \"footer\",\r\n \"article\",\r\n \"aside\",\r\n \"figure\",\r\n \"figcaption\",\r\n \"time\",\r\n // Interactive / form elements that may appear in content\r\n \"button\",\r\n \"input\",\r\n \"label\",\r\n \"select\",\r\n \"option\",\r\n \"textarea\",\r\n \"details\",\r\n \"summary\",\r\n // Allow <style> tags so user/content-provided CSS is preserved\r\n // when taking snapshots and during undo/redo operations.\r\n // DOMPurify will still sanitize the contents of style blocks.\r\n \"style\",\r\n // Preserve linked stylesheets so page/editor styling isn't lost\r\n \"link\",\r\n \"ul\",\r\n \"ol\",\r\n \"li\",\r\n \"br\",\r\n \"hr\",\r\n \"blockquote\",\r\n \"pre\",\r\n \"code\",\r\n \"h1\",\r\n \"h2\",\r\n \"h3\",\r\n \"h4\",\r\n \"h5\",\r\n \"h6\",\r\n \"img\",\r\n ],\r\n ALLOWED_ATTR: [\r\n \"href\",\r\n \"title\",\r\n \"alt\",\r\n \"src\",\r\n \"class\",\r\n \"style\",\r\n // Attributes used by <link> tags\r\n \"rel\",\r\n \"type\",\r\n \"media\",\r\n ],\r\n // Also allow `id` attributes so element ids survive sanitization.\r\n ADD_ATTR: [\"id\"],\r\n });\r\n } catch (e) {\r\n // If DOMPurify initialization fails, fall through to minimal stripping\r\n }\r\n }\r\n\r\n // Minimal fallback: remove <script> tags and on* attributes\r\n return html\r\n .replace(/<script[\\s\\S]*?>[\\s\\S]*?<\\/script>/gi, \"\")\r\n .replace(/on[a-z]+=\\\"[^\"]*\\\"/gi, \"\");\r\n}\r\n\r\nexport default sanitizeHtml;\r\n","import { editorEventEmitter } from \"./events\";\r\nimport {\r\n DEFAULT_MAX_STACK,\r\n TOOLBAR_ID,\r\n STYLE_ID,\r\n CLASS_EDITABLE,\r\n CLASS_ACTIVE,\r\n} from \"./constants\";\r\nimport { sanitizeHtml } from \"../utils/sanitize\";\r\n\r\nlet _doc: Document | null = null;\r\nlet _undoStack: string[] = [];\r\nlet _redoStack: string[] = [];\r\nlet _currentEditable: HTMLElement | null = null;\r\nlet _maxStackSize = DEFAULT_MAX_STACK;\r\n\r\nexport function _setDoc(doc: Document | null) {\r\n _doc = doc;\r\n}\r\nexport function _getDoc() {\r\n return _doc;\r\n}\r\nexport function _setUndoStack(stack: string[]) {\r\n _undoStack = stack;\r\n editorEventEmitter.emit({\r\n type: \"undoStateChanged\",\r\n timestamp: Date.now(),\r\n data: { canUndo: _undoStack.length > 1 },\r\n });\r\n}\r\nexport function _getUndoStack() {\r\n return _undoStack;\r\n}\r\nexport function _setRedoStack(stack: string[]) {\r\n _redoStack = stack;\r\n editorEventEmitter.emit({\r\n type: \"redoStateChanged\",\r\n timestamp: Date.now(),\r\n data: { canRedo: _redoStack.length > 0 },\r\n });\r\n}\r\nexport function _getRedoStack() {\r\n return _redoStack;\r\n}\r\nexport function _setCurrentEditable(el: HTMLElement | null) {\r\n _currentEditable = el;\r\n editorEventEmitter.emit({\r\n type: \"selectionChanged\",\r\n timestamp: Date.now(),\r\n data: { element: el?.tagName },\r\n });\r\n}\r\nexport function _getCurrentEditable() {\r\n return _currentEditable;\r\n}\r\nexport function pushStandaloneSnapshot(clearRedo = true) {\r\n if (!_doc) return;\r\n // Clone the documentElement and remove injected UI (toolbar/style)\r\n // so snapshots capture only the user's content.\r\n const clone = _doc.documentElement.cloneNode(true) as HTMLElement;\r\n const toolbarNode = clone.querySelector(`#${TOOLBAR_ID}`);\r\n if (toolbarNode && toolbarNode.parentNode)\r\n toolbarNode.parentNode.removeChild(toolbarNode);\r\n const styleNode = clone.querySelector(`#${STYLE_ID}`);\r\n if (styleNode && styleNode.parentNode)\r\n styleNode.parentNode.removeChild(styleNode);\r\n // Remove editor-specific attributes/classes so snapshots don't persist\r\n // transient editing state (contenteditable, toolbar classes, tabindex).\r\n try {\r\n const editableNodes = clone.querySelectorAll(\r\n \"[contenteditable], .\" + CLASS_EDITABLE + \", .\" + CLASS_ACTIVE\r\n );\r\n editableNodes.forEach((el) => {\r\n try {\r\n if (el instanceof Element) {\r\n if (el.hasAttribute(\"contenteditable\"))\r\n el.removeAttribute(\"contenteditable\");\r\n if (el.hasAttribute(\"tabindex\")) el.removeAttribute(\"tabindex\");\r\n el.classList.remove(CLASS_EDITABLE, CLASS_ACTIVE);\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n });\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n // Preserve scripts by replacing them with a harmless placeholder\r\n // that contains the encoded script source/attributes. This allows the\r\n // sanitizer to run (which strips <script> tags) while keeping the\r\n // script content available to re-insert and execute on restore.\r\n try {\r\n const scripts = Array.from(\r\n clone.querySelectorAll<HTMLScriptElement>(\"script\")\r\n );\r\n scripts.forEach((s) => {\r\n try {\r\n const code = s.textContent || \"\";\r\n const attrs: Record<string, string> = {};\r\n Array.from(s.attributes).forEach((a) => (attrs[a.name] = a.value));\r\n const placeholder = clone.ownerDocument!.createElement(\"span\");\r\n // encode script body in base64 to survive sanitization\r\n try {\r\n // btoa may throw on Unicode; encodeURIComponent first\r\n const safe =\r\n typeof btoa !== \"undefined\"\r\n ? btoa(unescape(encodeURIComponent(code)))\r\n : encodeURIComponent(code);\r\n placeholder.setAttribute(\"data-rhe-script\", safe);\r\n } catch (e) {\r\n placeholder.setAttribute(\"data-rhe-script\", encodeURIComponent(code));\r\n }\r\n if (Object.keys(attrs).length) {\r\n placeholder.setAttribute(\r\n \"data-rhe-script-attrs\",\r\n encodeURIComponent(JSON.stringify(attrs))\r\n );\r\n }\r\n // mark parent editable region if present so we can reinsert in-place\r\n const parentMarker = s.closest(\"[data-rhe-id]\") as HTMLElement | null;\r\n if (parentMarker && parentMarker.getAttribute(\"data-rhe-id\")) {\r\n placeholder.setAttribute(\r\n \"data-rhe-script-parent\",\r\n parentMarker.getAttribute(\"data-rhe-id\")!\r\n );\r\n } else {\r\n placeholder.setAttribute(\"data-rhe-script-parent\", \"head\");\r\n }\r\n s.parentNode?.replaceChild(placeholder, s);\r\n } catch (e) {\r\n /* ignore per-script errors */\r\n }\r\n });\r\n } catch (e) {\r\n /* ignore script extraction errors */\r\n }\r\n const snapRaw = clone.outerHTML;\r\n const snap = sanitizeHtml(snapRaw, _doc);\r\n if (!_undoStack.length || _undoStack[_undoStack.length - 1] !== snap) {\r\n _undoStack.push(snap);\r\n if (_undoStack.length > _maxStackSize) _undoStack.shift();\r\n editorEventEmitter.emit({\r\n type: \"contentChanged\",\r\n timestamp: Date.now(),\r\n data: { htmlLength: snap.length },\r\n });\r\n }\r\n if (clearRedo) {\r\n _redoStack = [];\r\n editorEventEmitter.emit({\r\n type: \"redoStateChanged\",\r\n timestamp: Date.now(),\r\n data: { canRedo: false },\r\n });\r\n }\r\n}\r\nexport function setMaxStackSize(size: number) {\r\n _maxStackSize = Math.max(1, size);\r\n}\r\n","// Main entry point for the rich-html-editor util\r\n// Plug-and-play HTML editor API\r\n\r\n// Core functions\r\nexport { initRichEditor, getCleanHTML } from \"./core/editor\";\r\n\r\n// Types\r\nexport type {\r\n FormatState,\r\n ToolbarOptions,\r\n EditorEvent,\r\n EditorEventType,\r\n EditorEventHandler,\r\n FormattingCommand,\r\n TextAlignment,\r\n FontSizeMap,\r\n EditorConfig,\r\n} from \"./core/types\";\r\n\r\n// Event system\r\nexport { editorEventEmitter, getEditorEventEmitter } from \"./core/events\";\r\nexport type { EditorEventEmitter } from \"./core/events\";\r\n","import {\r\n _setDoc,\r\n _getDoc,\r\n _setUndoStack,\r\n _getUndoStack,\r\n _setRedoStack,\r\n _getRedoStack,\r\n _setCurrentEditable,\r\n _getCurrentEditable,\r\n pushStandaloneSnapshot,\r\n} from \"./state\";\r\nimport { injectStyles } from \"../dom/styles\";\r\nimport { injectToolbar } from \"../toolbar/toolbar\";\r\nimport { attachStandaloneHandlers } from \"../dom/handlers\";\r\nimport { computeFormatState, getElementLabel } from \"../dom/format\";\r\nimport { handleUndo, handleRedo, handleToolbarCommand } from \"./commands\";\r\nimport type { EditorConfig } from \"./types\";\r\nimport { sanitizeHtml } from \"../utils/sanitize\";\r\nimport {\r\n TOOLBAR_ID,\r\n STYLE_ID,\r\n CLASS_EDITABLE,\r\n CLASS_ACTIVE,\r\n} from \"./constants\";\r\n\r\n/**\r\n * Initialize the rich HTML editor on an iframe element\r\n */\r\nexport function initRichEditor(\r\n iframe: HTMLIFrameElement,\r\n config?: EditorConfig\r\n) {\r\n try {\r\n if (!iframe || !(iframe instanceof HTMLIFrameElement)) {\r\n throw new Error(\"Invalid iframe element provided to initRichEditor\");\r\n }\r\n\r\n const doc = iframe.contentDocument;\r\n if (!doc) {\r\n throw new Error(\r\n \"Unable to access iframe contentDocument. Ensure iframe src is same-origin.\"\r\n );\r\n }\r\n\r\n _setDoc(doc);\r\n injectStyles(doc);\r\n _setUndoStack([]);\r\n _setRedoStack([]);\r\n _setCurrentEditable(null);\r\n if (config?.maxStackSize) {\r\n import(\"./state\")\r\n .then((m) => m.setMaxStackSize(config.maxStackSize!))\r\n .catch(() => {\r\n /* ignore */\r\n });\r\n }\r\n attachStandaloneHandlers(doc);\r\n pushStandaloneSnapshot();\r\n injectToolbar(doc, {\r\n onCommand: handleToolbarCommand,\r\n canUndo: () => _getUndoStack().length > 1,\r\n canRedo: () => _getRedoStack().length > 0,\r\n onUndo: handleUndo,\r\n onRedo: handleRedo,\r\n getFormatState: () => computeFormatState(doc),\r\n getSelectedElementInfo: () => getElementLabel(_getCurrentEditable()),\r\n });\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Failed to initialize editor:\", message);\r\n throw error;\r\n }\r\n}\r\n\r\nexport function getCleanHTML(): string {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) {\r\n console.warn(\r\n \"[rich-html-editor] getCleanHTML called before editor initialization\"\r\n );\r\n return \"\";\r\n }\r\n if (!doc.documentElement) {\r\n throw new Error(\"Document is missing documentElement\");\r\n }\r\n\r\n const clone = doc.documentElement.cloneNode(true) as HTMLElement;\r\n\r\n // Remove injected toolbar and style elements if present\r\n const toolbarNode = clone.querySelector(`#${TOOLBAR_ID}`);\r\n if (toolbarNode && toolbarNode.parentNode)\r\n toolbarNode.parentNode.removeChild(toolbarNode);\r\n const styleNode = clone.querySelector(`#${STYLE_ID}`);\r\n if (styleNode && styleNode.parentNode)\r\n styleNode.parentNode.removeChild(styleNode);\r\n\r\n // Recursively clean root and descendants\r\n try {\r\n const cleanElement = (el: Element) => {\r\n try {\r\n // remove boolean/content attributes explicitly\r\n if (el.hasAttribute(\"contenteditable\"))\r\n el.removeAttribute(\"contenteditable\");\r\n if (el.hasAttribute(\"tabindex\")) el.removeAttribute(\"tabindex\");\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n\r\n try {\r\n const attrs = Array.from(el.attributes || []);\r\n attrs.forEach((a) => {\r\n const rawName = a.name;\r\n const name = rawName.toLowerCase();\r\n\r\n // remove inline event handlers\r\n if (name.startsWith(\"on\")) {\r\n try {\r\n el.removeAttribute(rawName);\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n return;\r\n }\r\n\r\n // remove any data-rhe-* attributes (including data-rhe-id)\r\n if (\r\n name === \"data-rhe-id\" ||\r\n name.startsWith(\"data-rhe-\") ||\r\n name === \"data-rhe\"\r\n ) {\r\n try {\r\n el.removeAttribute(rawName);\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n return;\r\n }\r\n });\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n\r\n try {\r\n if (el.id) {\r\n const id = el.id;\r\n if (\r\n id === TOOLBAR_ID ||\r\n id === STYLE_ID ||\r\n id.startsWith(\"editor-\") ||\r\n id.startsWith(\"rhe-\")\r\n ) {\r\n el.removeAttribute(\"id\");\r\n }\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n\r\n try {\r\n const cls = Array.from(el.classList || []);\r\n cls.forEach((c) => {\r\n if (\r\n c === CLASS_EDITABLE ||\r\n c === CLASS_ACTIVE ||\r\n c.startsWith(\"editor-\") ||\r\n c.startsWith(\"rhe-\")\r\n ) {\r\n try {\r\n el.classList.remove(c);\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n }\r\n });\r\n\r\n // remove empty class attributes left behind\r\n if (\r\n el.hasAttribute(\"class\") &&\r\n (el.getAttribute(\"class\") || \"\").trim() === \"\"\r\n ) {\r\n try {\r\n el.removeAttribute(\"class\");\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n\r\n try {\r\n const children = Array.from(el.children || []);\r\n children.forEach((child) => cleanElement(child as Element));\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n };\r\n\r\n // `instanceof Element` can fail across window/iframe boundaries\r\n // because each iframe has its own global `Element` constructor.\r\n // Use a cross-realm-safe check instead.\r\n if ((clone as Node).nodeType === Node.ELEMENT_NODE) {\r\n cleanElement(clone as Element);\r\n }\r\n } catch (e) {\r\n /* ignore traversal errors */\r\n }\r\n\r\n // Preserve original scripts intentionally.\r\n return \"<!doctype html>\\n\" + clone.outerHTML;\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Failed to get clean HTML:\", message);\r\n throw error;\r\n }\r\n}\r\n\r\nexport function getSanitizedHTML(): string {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) return \"\";\r\n if (!doc.documentElement)\r\n throw new Error(\"Document is missing documentElement\");\r\n const raw = \"<!doctype html>\\n\" + doc.documentElement.outerHTML;\r\n return sanitizeHtml(raw, doc);\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Failed to get sanitized HTML:\", message);\r\n throw error;\r\n }\r\n}\r\n","/**\r\n * Inject CSS styles into the document for editor UI\r\n *\r\n * Adds styling for:\r\n * - `.editor-editable-element`: Dashed outline for hoverable elements\r\n * - `.editor-active-element`: Solid green outline for active editing element\r\n *\r\n * Uses a style ID to prevent duplicate injections\r\n *\r\n * @param doc - Document to inject styles into\r\n */\r\nimport {\r\n STYLE_ID,\r\n CLASS_EDITABLE,\r\n CLASS_ACTIVE,\r\n HOVER_OUTLINE,\r\n ACTIVE_OUTLINE,\r\n TOOLBAR_ID,\r\n TOOLBAR_BG,\r\n TOOLBAR_BORDER,\r\n BUTTON_BORDER,\r\n BUTTON_ACTIVE_BG,\r\n BUTTON_BG,\r\n BUTTON_COLOR,\r\n INFO_COLOR,\r\n} from \"../core/constants\";\r\n\r\nexport function injectStyles(doc: Document): void {\r\n const styleId = STYLE_ID;\r\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\r\n const css = `\r\n.${CLASS_EDITABLE}{outline:2px dashed ${HOVER_OUTLINE};cursor:text}\r\n.${CLASS_ACTIVE}{outline:2px solid ${ACTIVE_OUTLINE};cursor:text}\r\n#${TOOLBAR_ID}{\r\n position: sticky;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n z-index: 9999;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n background: ${TOOLBAR_BG};\r\n border-bottom: 1px solid ${TOOLBAR_BORDER};\r\n font-family: inherit;\r\n box-shadow: 0 6px 18px rgba(2,6,23,0.08);\r\n backdrop-filter: blur(6px);\r\n /* Allow toolbar items to wrap onto multiple lines on narrow screens */\r\n flex-wrap: wrap;\r\n justify-content: flex-start;\r\n}\r\n#${TOOLBAR_ID} button{\r\n padding: 6px 8px;\r\n border: 1px solid ${BUTTON_BORDER};\r\n background: ${BUTTON_BG};\r\n color: ${BUTTON_COLOR};\r\n border-radius: 8px;\r\n font-weight: 500;\r\n cursor: pointer;\r\n transition: transform .12s ease, box-shadow .12s ease, background .12s ease;\r\n outline: none;\r\n margin-right: 2px;\r\n}\r\n#${TOOLBAR_ID} button[aria-pressed=\"true\"]{\r\n background: ${BUTTON_ACTIVE_BG};\r\n font-weight: 600;\r\n box-shadow: 0 6px 12px rgba(99,102,241,0.12);\r\n}\r\n#${TOOLBAR_ID} button:hover:not(:disabled){\r\n transform: translateY(-2px);\r\n box-shadow: 0 8px 20px rgba(2,6,23,0.08);\r\n}\r\n#${TOOLBAR_ID} select{\r\n padding: 6px 8px;\r\n border-radius: 8px;\r\n border: 1px solid ${BUTTON_BORDER};\r\n background: #fff;\r\n font-family: inherit;\r\n}\r\n#${TOOLBAR_ID} input[type=\"color\"]{\r\n border-radius: 8px;\r\n border: 1px solid ${BUTTON_BORDER};\r\n background: #fff;\r\n font-family: inherit;\r\n}\r\n#${TOOLBAR_ID} .color-input-label{\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 0;\r\n background: transparent;\r\n border: none;\r\n}\r\n\r\n/* Labeled color inputs (e.g. \"Text Color <input type=color>\") */\r\n#${TOOLBAR_ID} .color-label{\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 0;\r\n background: transparent;\r\n border: none;\r\n}\r\n#${TOOLBAR_ID} .color-input-label .color-icon{\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n#${TOOLBAR_ID} .text-color-icon{\r\n font-weight: 700;\r\n font-size: 14px;\r\n line-height: 1;\r\n display: inline-block;\r\n padding-bottom: 2px;\r\n border-bottom: 3px solid currentColor;\r\n transform-origin: center;\r\n}\r\n#${TOOLBAR_ID} .highlight-icon{\r\n width: 16px;\r\n height: 16px;\r\n display: inline-block;\r\n}\r\n#${TOOLBAR_ID} .color-icon svg{\r\n width: 16px;\r\n height: 16px;\r\n display: block;\r\n}\r\n/* Text color wrapper: A with a small swatch on the right */\r\n#${TOOLBAR_ID} .text-color-wrapper{\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n}\r\n#${TOOLBAR_ID} .text-color-wrapper .text-A{\r\n font-weight: 700;\r\n font-size: 14px;\r\n line-height: 1;\r\n}\r\n#${TOOLBAR_ID} .text-color-wrapper .color-swatch{\r\n width: 12px;\r\n height: 12px;\r\n border-radius: 3px;\r\n border: 1px solid rgba(0,0,0,0.12);\r\n box-shadow: 0 1px 0 rgba(255,255,255,0.5) inset;\r\n background: currentColor;\r\n}\r\n\r\n/* Highlight wrapper: small colored bar under/behind the A to mimic highlighter */\r\n#${TOOLBAR_ID} .highlight-wrapper{\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n position: relative;\r\n}\r\n#${TOOLBAR_ID} .highlight-wrapper .highlight-bar{\r\n position: absolute;\r\n left: 0;\r\n right: 0;\r\n bottom: 2px;\r\n height: 8px;\r\n border-radius: 3px;\r\n background: #ffeb3b; /* default yellow */\r\n z-index: 0;\r\n}\r\n#${TOOLBAR_ID} .highlight-wrapper .text-A{\r\n position: relative;\r\n z-index: 1;\r\n font-weight: 700;\r\n font-size: 14px;\r\n line-height: 1;\r\n padding: 0 4px;\r\n}\r\n#${TOOLBAR_ID} span{\r\n color: ${INFO_COLOR};\r\n font-size: 90%;\r\n}\r\n\r\n/* Grouping and separators */\r\n#${TOOLBAR_ID} .toolbar-group{\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n}\r\n#${TOOLBAR_ID} .toolbar-group{\r\n /* groups may wrap internally to avoid overflow on narrow screens */\r\n flex-wrap: wrap;\r\n}\r\n/* Overflow button + menu styling */\r\n#${TOOLBAR_ID} .toolbar-overflow-btn{\r\n display: none;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 6px 8px;\r\n border-radius: 8px;\r\n border: 1px solid ${BUTTON_BORDER};\r\n background: ${BUTTON_BG};\r\n color: ${BUTTON_COLOR};\r\n font-weight: 600;\r\n}\r\n#${TOOLBAR_ID} .toolbar-overflow-menu{\r\n position: absolute;\r\n top: calc(100% + 6px);\r\n right: 12px;\r\n min-width: 160px;\r\n background: #fff;\r\n border: 1px solid rgba(15,23,42,0.06);\r\n border-radius: 8px;\r\n padding: 8px;\r\n box-shadow: 0 12px 40px rgba(2,6,23,0.12);\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n z-index: 10000;\r\n}\r\n#${TOOLBAR_ID} .toolbar-overflow-menu[hidden]{\r\n display: none;\r\n}\r\n#${TOOLBAR_ID} .toolbar-sep{\r\n width: 1px;\r\n height: 28px;\r\n background: rgba(15,23,42,0.06);\r\n margin: 0 8px;\r\n border-radius: 1px;\r\n}\r\n#${TOOLBAR_ID} .toolbar-spacer{\r\n flex: 1 1 auto;\r\n}\r\n#${TOOLBAR_ID} button svg{\r\n width: 16px;\r\n height: 16px;\r\n display: block;\r\n /* Default icon appearance */\r\n fill: none;\r\n}\r\n\r\n/* Active/pressed: switch to filled appearance */\r\n#${TOOLBAR_ID} button[aria-pressed=\"true\"] svg{\r\n fill: currentColor;\r\n}\r\n\r\n/* Focus and accessibility */\r\n#${TOOLBAR_ID} button:focus{\r\n outline: none;\r\n box-shadow: 0 0 0 4px rgba(99,102,241,0.12);\r\n}\r\n\r\n/* Disabled state */\r\n#${TOOLBAR_ID} button:disabled{\r\n opacity: 0.48;\r\n cursor: not-allowed;\r\n}\r\n/* Responsive tweaks: reduce spacing and allow horizontal scroll on very small screens */\r\n@media (max-width: 720px){\r\n #${TOOLBAR_ID}{\r\n padding: 6px 8px;\r\n gap: 6px;\r\n }\r\n #${TOOLBAR_ID} button,\r\n #${TOOLBAR_ID} select,\r\n #${TOOLBAR_ID} input[type=\"color\"]{\r\n padding: 4px 6px;\r\n border-radius: 6px;\r\n }\r\n /* Hide visual separators to save horizontal space */\r\n #${TOOLBAR_ID} .toolbar-sep{\r\n display: none;\r\n }\r\n /* Collapse labeled color text visually but preserve accessibility on the input */\r\n #${TOOLBAR_ID} .color-label{\r\n font-size: 0;\r\n }\r\n #${TOOLBAR_ID} .color-label input{\r\n font-size: initial;\r\n }\r\n}\r\n@media (max-width: 420px){\r\n /* On very small screens prefer a single-line scrollable toolbar */\r\n #${TOOLBAR_ID}{\r\n flex-wrap: nowrap;\r\n overflow-x: auto;\r\n -webkit-overflow-scrolling: touch;\r\n }\r\n #${TOOLBAR_ID} .toolbar-group{\r\n flex: 0 0 auto;\r\n }\r\n #${TOOLBAR_ID} button{ margin-right: 6px; }\r\n /* Show overflow button and hide the groups marked for collapse */\r\n #${TOOLBAR_ID} .toolbar-overflow-btn{\r\n display: inline-flex;\r\n }\r\n #${TOOLBAR_ID} .collapse-on-small{\r\n display: none;\r\n }\r\n}\r\n`;\r\n if (!styleEl) {\r\n styleEl = doc.createElement(\"style\");\r\n styleEl.id = styleId;\r\n doc.head.appendChild(styleEl);\r\n }\r\n styleEl.textContent = css;\r\n}\r\n","/**\r\n * Inject and render the formatting toolbar into the document\r\n *\r\n * Creates a sticky toolbar with:\r\n * - Text formatting buttons (Bold, Italic, Underline)\r\n * - Font and size selectors\r\n * - Undo/Redo buttons\r\n * - Link insertion button\r\n * - Color pickers (text and highlight)\r\n * - Text alignment buttons\r\n * - Selected element info display\r\n *\r\n * The toolbar is re-injected on every selection change to update state\r\n * (this is optimized for small toolbar size and few state changes)\r\n *\r\n * @param doc - Document to inject toolbar into\r\n * @param options - Toolbar configuration and callbacks\r\n */\r\nimport {\r\n TOOLBAR_ID,\r\n LABEL_BOLD,\r\n LABEL_ITALIC,\r\n LABEL_UNDERLINE,\r\n LABEL_STRIKETHROUGH,\r\n LABEL_UNDO,\r\n LABEL_REDO,\r\n LABEL_LINK,\r\n LABEL_ALIGN_LEFT,\r\n LABEL_ALIGN_CENTER,\r\n LABEL_ALIGN_RIGHT,\r\n FONT_OPTIONS,\r\n SIZE_OPTIONS,\r\n FORMAT_OPTIONS,\r\n PALETTE_SVG,\r\n TEXT_COLOR_ICON_HTML,\r\n HIGHLIGHT_ICON_HTML,\r\n} from \"../core/constants\";\r\n\r\nexport function injectToolbar(\r\n doc: Document,\r\n options: {\r\n onCommand: (command: string, value?: string) => void;\r\n canUndo: () => boolean;\r\n canRedo: () => boolean;\r\n onUndo: () => void;\r\n onRedo: () => void;\r\n getFormatState: () => {\r\n bold: boolean;\r\n italic: boolean;\r\n underline: boolean;\r\n foreColor?: string | null;\r\n hiliteColor?: string | null;\r\n fontName?: string | null;\r\n fontSize?: string | null;\r\n formatBlock?: string | null;\r\n };\r\n getSelectedElementInfo: () => string | null;\r\n }\r\n) {\r\n const existing = doc.getElementById(TOOLBAR_ID);\r\n if (existing) existing.remove();\r\n\r\n const toolbar = doc.createElement(\"div\");\r\n toolbar.id = TOOLBAR_ID;\r\n // Accessibility: expose as a toolbar region and provide a readable label\r\n toolbar.setAttribute(\"role\", \"toolbar\");\r\n toolbar.setAttribute(\"aria-label\", \"Rich text editor toolbar\");\r\n\r\n // Styling moved to injected stylesheet (see src/dom/styles.ts)\r\n\r\n function makeButton(\r\n label: string,\r\n title: string,\r\n command: string,\r\n value?: string,\r\n isActive?: boolean,\r\n disabled?: boolean\r\n ) {\r\n const btn = doc.createElement(\"button\");\r\n btn.type = \"button\";\r\n // If caller provided an HTML label (e.g. \"<i>I</i>\"), render it as HTML.\r\n // Otherwise set textContent for safety.\r\n if (label && label.trim().startsWith(\"<\")) {\r\n btn.innerHTML = label;\r\n } else {\r\n btn.textContent = label;\r\n }\r\n btn.title = title;\r\n // Accessibility: aria-label + keyboard focusability + pressed state\r\n btn.setAttribute(\"aria-label\", title);\r\n if (typeof isActive !== \"undefined\")\r\n btn.setAttribute(\"aria-pressed\", String(!!isActive));\r\n btn.tabIndex = 0;\r\n // Visual appearance handled by stylesheet; use ARIA pressed for active state\r\n if (disabled) btn.disabled = true;\r\n btn.onclick = () => options.onCommand(command, value);\r\n // Keyboard activation: Enter or Space should trigger\r\n btn.addEventListener(\"keydown\", (ev) => {\r\n if (ev.key === \"Enter\" || ev.key === \" \") {\r\n ev.preventDefault();\r\n btn.click();\r\n }\r\n });\r\n return btn;\r\n }\r\n\r\n function makeSelect(\r\n title: string,\r\n command: string,\r\n optionsList: { label: string; value: string }[],\r\n initialValue?: string | null\r\n ) {\r\n const select = doc.createElement(\"select\");\r\n select.title = title;\r\n select.setAttribute(\"aria-label\", title);\r\n // Select styling handled in stylesheet\r\n select.appendChild(new Option(title, \"\", true, true));\r\n for (const opt of optionsList) {\r\n select.appendChild(new Option(opt.label, opt.value));\r\n }\r\n // set initial value if provided\r\n try {\r\n if (initialValue) select.value = initialValue;\r\n } catch (e) {\r\n /* ignore invalid value */\r\n }\r\n\r\n select.onchange = (e) => {\r\n const val = (e.target as HTMLSelectElement).value;\r\n options.onCommand(command, val);\r\n select.selectedIndex = 0;\r\n };\r\n return select;\r\n }\r\n\r\n function makeColorInput(\r\n title: string,\r\n command: string,\r\n initialColor?: string\r\n ) {\r\n /*\r\n const label = doc.createElement(\"label\");\r\n label.title = title;\r\n label.setAttribute(\"aria-label\", title);\r\n label.className = \"color-input-label\";\r\n // Icon element shown before the native color input. Use MS Word-like icons\r\n const iconWrap = doc.createElement(\"span\");\r\n iconWrap.className = \"color-icon\";\r\n iconWrap.setAttribute(\"aria-hidden\", \"true\");\r\n if (command === \"foreColor\") {\r\n iconWrap.innerHTML = TEXT_COLOR_ICON_HTML;\r\n } else if (command === \"hiliteColor\") {\r\n iconWrap.innerHTML = HIGHLIGHT_ICON_HTML;\r\n } else {\r\n iconWrap.innerHTML = PALETTE_SVG;\r\n }\r\n */\r\n\r\n const input = doc.createElement(\"input\");\r\n input.type = \"color\";\r\n input.className = \"toolbar-color-input\";\r\n // Wrap the native color input with a visible label so users can see\r\n // which control is for text color vs highlight.\r\n const wrapper = doc.createElement(\"label\");\r\n wrapper.className = \"color-label\";\r\n // Use the provided title as the label text (e.g. \"Text Color\")\r\n wrapper.appendChild(doc.createTextNode(title + \" \"));\r\n wrapper.appendChild(input);\r\n // Preserve the user's selection when the color picker opens (input steals focus)\r\n let savedRange: Range | null = null;\r\n input.addEventListener(\"pointerdown\", () => {\r\n const s = doc.getSelection();\r\n if (s && s.rangeCount) savedRange = s.getRangeAt(0).cloneRange();\r\n });\r\n input.onchange = (e) => {\r\n // Restore selection before applying the command\r\n try {\r\n const s = doc.getSelection();\r\n if (savedRange && s) {\r\n s.removeAllRanges();\r\n s.addRange(savedRange);\r\n }\r\n } catch (err) {\r\n // ignore restore errors\r\n }\r\n options.onCommand(command, (e.target as HTMLInputElement).value);\r\n // clear saved range after applying\r\n savedRange = null;\r\n };\r\n // Note: iconWrap/label are currently commented out above; operate on the\r\n // native color `input` only and set its value to match detected colors.\r\n function rgbToHex(input?: string | null): string | null {\r\n if (!input) return null;\r\n const v = input.trim();\r\n if (v.startsWith(\"#\")) {\r\n // Normalize short hex #abc -> #aabbcc\r\n if (v.length === 4) {\r\n return (\"#\" + v[1] + v[1] + v[2] + v[2] + v[3] + v[3]).toLowerCase();\r\n }\r\n return v.toLowerCase();\r\n }\r\n const rgbMatch = v.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/i);\r\n if (rgbMatch) {\r\n const r = Number(rgbMatch[1]);\r\n const g = Number(rgbMatch[2]);\r\n const b = Number(rgbMatch[3]);\r\n const hex =\r\n \"#\" +\r\n [r, g, b]\r\n .map((n) => n.toString(16).padStart(2, \"0\"))\r\n .join(\"\")\r\n .toLowerCase();\r\n return hex;\r\n }\r\n return null;\r\n }\r\n\r\n const setColor = (val?: string) => {\r\n if (!val) return;\r\n const hex = rgbToHex(val) || val;\r\n // set native input value if we have a hex color\r\n try {\r\n if (\r\n hex &&\r\n hex.startsWith(\"#\") &&\r\n (input as HTMLInputElement).value !== hex\r\n ) {\r\n (input as HTMLInputElement).value = hex;\r\n }\r\n } catch (e) {\r\n // ignore invalid value assignment\r\n }\r\n };\r\n // initialize from provided initialColor when available\r\n if (initialColor) setColor(initialColor);\r\n input.addEventListener(\"input\", (e) => {\r\n const val = (e.target as HTMLInputElement).value;\r\n setColor(val);\r\n });\r\n // Instead of using a label+icon, return the native input directly.\r\n // Forward title and ARIA to the input so accessibility is preserved.\r\n input.title = title;\r\n input.setAttribute(\"aria-label\", title);\r\n return wrapper;\r\n }\r\n\r\n const format = options.getFormatState();\r\n // Helpers: group wrapper and separator element\r\n function makeGroup() {\r\n const g = doc.createElement(\"div\");\r\n g.className = \"toolbar-group\";\r\n return g;\r\n }\r\n\r\n function makeSep() {\r\n const s = doc.createElement(\"div\");\r\n s.className = \"toolbar-sep\";\r\n return s;\r\n }\r\n\r\n // Section 1: Undo / Redo\r\n const undoBtn = makeButton(\r\n LABEL_UNDO,\r\n \"Undo\",\r\n \"undo\",\r\n undefined,\r\n false,\r\n !options.canUndo()\r\n );\r\n // Undo/Redo are handled by the history module — call handlers directly\r\n undoBtn.onclick = () => options.onUndo();\r\n\r\n const redoBtn = makeButton(\r\n LABEL_REDO,\r\n \"Redo\",\r\n \"redo\",\r\n undefined,\r\n false,\r\n !options.canRedo()\r\n );\r\n redoBtn.onclick = () => options.onRedo();\r\n\r\n const grp1 = makeGroup();\r\n grp1.appendChild(undoBtn);\r\n grp1.appendChild(redoBtn);\r\n toolbar.appendChild(grp1);\r\n toolbar.appendChild(makeSep());\r\n\r\n // Section 2: Format, Font & Size\r\n const grp2 = makeGroup();\r\n grp2.className = \"toolbar-group collapse-on-small\";\r\n grp2.appendChild(\r\n makeSelect(\r\n \"Format\",\r\n \"formatBlock\",\r\n FORMAT_OPTIONS,\r\n (format as any).formatBlock\r\n )\r\n );\r\n grp2.appendChild(\r\n makeSelect(\"Font\", \"fontName\", FONT_OPTIONS, (format as any).fontName)\r\n );\r\n grp2.appendChild(\r\n makeSelect(\"Size\", \"fontSize\", SIZE_OPTIONS, (format as any).fontSize)\r\n );\r\n toolbar.appendChild(grp2);\r\n toolbar.appendChild(makeSep());\r\n\r\n // Section 3: Bold, Italic, Underline, Strikethrough\r\n const grp3 = makeGroup();\r\n grp3.appendChild(\r\n makeButton(LABEL_BOLD, \"Bold\", \"bold\", undefined, format.bold)\r\n );\r\n grp3.appendChild(\r\n makeButton(LABEL_ITALIC, \"Italic\", \"italic\", undefined, format.italic)\r\n );\r\n grp3.appendChild(\r\n makeButton(\r\n LABEL_UNDERLINE,\r\n \"Underline\",\r\n \"underline\",\r\n undefined,\r\n format.underline\r\n )\r\n );\r\n grp3.appendChild(makeButton(LABEL_STRIKETHROUGH, \"Strikethrough\", \"strike\"));\r\n toolbar.appendChild(grp3);\r\n toolbar.appendChild(makeSep());\r\n\r\n // Section 4: Alignment\r\n const grp4 = makeGroup();\r\n grp4.appendChild(makeButton(LABEL_ALIGN_LEFT, \"Align left\", \"align\", \"left\"));\r\n grp4.appendChild(\r\n makeButton(LABEL_ALIGN_CENTER, \"Align center\", \"align\", \"center\")\r\n );\r\n grp4.appendChild(\r\n makeButton(LABEL_ALIGN_RIGHT, \"Align right\", \"align\", \"right\")\r\n );\r\n toolbar.appendChild(grp4);\r\n toolbar.appendChild(makeSep());\r\n\r\n // Section 5: Colors\r\n const grp5 = makeGroup();\r\n grp5.className = \"toolbar-group collapse-on-small\";\r\n grp5.appendChild(\r\n makeColorInput(\"Text color\", \"foreColor\", (format as any).foreColor)\r\n );\r\n grp5.appendChild(\r\n makeColorInput(\r\n \"Highlight color\",\r\n \"hiliteColor\",\r\n (format as any).hiliteColor\r\n )\r\n );\r\n toolbar.appendChild(grp5);\r\n toolbar.appendChild(makeSep());\r\n\r\n // Section 6: Link\r\n const grp6 = makeGroup();\r\n grp6.className = \"toolbar-group collapse-on-small\";\r\n grp6.appendChild(makeButton(LABEL_LINK, \"Insert link\", \"link\"));\r\n toolbar.appendChild(grp6);\r\n\r\n // Overflow menu button and floating menu for small screens\r\n const overflowBtn = doc.createElement(\"button\");\r\n overflowBtn.type = \"button\";\r\n overflowBtn.className = \"toolbar-overflow-btn\";\r\n overflowBtn.title = \"More\";\r\n overflowBtn.setAttribute(\"aria-label\", \"More toolbar actions\");\r\n overflowBtn.setAttribute(\"aria-haspopup\", \"true\");\r\n overflowBtn.setAttribute(\"aria-expanded\", \"false\");\r\n overflowBtn.tabIndex = 0;\r\n overflowBtn.innerHTML = \"⋯\";\r\n\r\n const overflowMenu = doc.createElement(\"div\");\r\n overflowMenu.className = \"toolbar-overflow-menu\";\r\n overflowMenu.setAttribute(\"role\", \"menu\");\r\n overflowMenu.hidden = true;\r\n\r\n function openOverflow() {\r\n overflowMenu.hidden = false;\r\n overflowBtn.setAttribute(\"aria-expanded\", \"true\");\r\n const first = overflowMenu.querySelector<HTMLElement>(\r\n \"button, select, input\"\r\n );\r\n first?.focus();\r\n }\r\n function closeOverflow() {\r\n overflowMenu.hidden = true;\r\n overflowBtn.setAttribute(\"aria-expanded\", \"false\");\r\n overflowBtn.focus();\r\n }\r\n\r\n overflowBtn.addEventListener(\"click\", (e) => {\r\n if (overflowMenu.hidden) openOverflow();\r\n else closeOverflow();\r\n });\r\n overflowBtn.addEventListener(\"keydown\", (e) => {\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n if (overflowMenu.hidden) openOverflow();\r\n else closeOverflow();\r\n }\r\n if (e.key === \"ArrowDown\") {\r\n e.preventDefault();\r\n if (overflowMenu.hidden) openOverflow();\r\n }\r\n });\r\n\r\n overflowMenu.addEventListener(\"keydown\", (e) => {\r\n if (e.key === \"Escape\") {\r\n e.preventDefault();\r\n closeOverflow();\r\n }\r\n });\r\n doc.addEventListener(\"pointerdown\", (ev) => {\r\n if (\r\n !overflowMenu.hidden &&\r\n !overflowMenu.contains(ev.target as Node) &&\r\n ev.target !== overflowBtn\r\n ) {\r\n closeOverflow();\r\n }\r\n });\r\n\r\n // Populate overflow menu with duplicates of the collapsed controls\r\n overflowMenu.appendChild(\r\n makeSelect(\r\n \"Format\",\r\n \"formatBlock\",\r\n FORMAT_OPTIONS,\r\n (format as any).formatBlock\r\n )\r\n );\r\n overflowMenu.appendChild(\r\n makeSelect(\"Font\", \"fontName\", FONT_OPTIONS, (format as any).fontName)\r\n );\r\n overflowMenu.appendChild(\r\n makeSelect(\"Size\", \"fontSize\", SIZE_OPTIONS, (format as any).fontSize)\r\n );\r\n overflowMenu.appendChild(\r\n makeColorInput(\"Text color\", \"foreColor\", (format as any).foreColor)\r\n );\r\n overflowMenu.appendChild(\r\n makeColorInput(\r\n \"Highlight color\",\r\n \"hiliteColor\",\r\n (format as any).hiliteColor\r\n )\r\n );\r\n overflowMenu.appendChild(makeButton(LABEL_LINK, \"Insert link\", \"link\"));\r\n\r\n const overflowWrap = makeGroup();\r\n overflowWrap.className = \"toolbar-group toolbar-overflow-wrap\";\r\n overflowWrap.appendChild(overflowBtn);\r\n overflowWrap.appendChild(overflowMenu);\r\n toolbar.appendChild(overflowWrap);\r\n\r\n // const info = doc.createElement(\"span\");\r\n // // Info styles moved to stylesheet\r\n // info.textContent = options.getSelectedElementInfo()\r\n // ? `Selected: ${options.getSelectedElementInfo()}`\r\n // : \"Click any highlighted element to edit\";\r\n // toolbar.appendChild(info);\r\n\r\n // Keyboard navigation for toolbar (ArrowLeft/ArrowRight/Home/End)\r\n toolbar.addEventListener(\"keydown\", (e) => {\r\n const focusable = Array.from(\r\n toolbar.querySelectorAll<HTMLElement>(\"button, select, input, [tabindex]\")\r\n ).filter((el) => !el.hasAttribute(\"disabled\"));\r\n if (!focusable.length) return;\r\n const idx = focusable.indexOf(document.activeElement as HTMLElement);\r\n if (e.key === \"ArrowRight\") {\r\n e.preventDefault();\r\n const next =\r\n focusable[Math.min(focusable.length - 1, Math.max(0, idx + 1))];\r\n next?.focus();\r\n } else if (e.key === \"ArrowLeft\") {\r\n e.preventDefault();\r\n const prev = focusable[Math.max(0, idx - 1)] || focusable[0];\r\n prev?.focus();\r\n } else if (e.key === \"Home\") {\r\n e.preventDefault();\r\n focusable[0].focus();\r\n } else if (e.key === \"End\") {\r\n e.preventDefault();\r\n focusable[focusable.length - 1].focus();\r\n }\r\n });\r\n\r\n doc.body.insertBefore(toolbar, doc.body.firstChild);\r\n}\r\n","import {\r\n _getCurrentEditable,\r\n _setCurrentEditable,\r\n pushStandaloneSnapshot,\r\n _getUndoStack,\r\n _getRedoStack,\r\n} from \"../core/state\";\r\nimport { isEditableCandidate } from \"./candidates\";\r\nimport { injectToolbar } from \"../toolbar/toolbar\";\r\nimport { computeFormatState, getElementLabel } from \"./format\";\r\nimport { handleToolbarCommand, handleUndo, handleRedo } from \"../core/commands\";\r\nimport { CLASS_ACTIVE } from \"../core/constants\";\r\n\r\n/**\r\n * Attach DOM event handlers to the document\r\n *\r\n * Handles:\r\n * - Click: Enables editing on valid elements\r\n * - Selection change: Updates toolbar state\r\n * - Input: Creates undo/redo snapshots\r\n *\r\n * @param doc - Document to attach handlers to\r\n */\r\nexport function attachStandaloneHandlers(doc: Document) {\r\n // Assign stable data-rhe-id markers to likely editable candidates so\r\n // snapshots include identifiers for selective restoration. Limit the\r\n // selector to common content containers to avoid a full DOM walk.\r\n try {\r\n const selector = [\r\n \"p\",\r\n \"div\",\r\n \"section\",\r\n \"article\",\r\n \"header\",\r\n \"footer\",\r\n \"aside\",\r\n \"nav\",\r\n \"span\",\r\n \"h1\",\r\n \"h2\",\r\n \"h3\",\r\n \"h4\",\r\n \"h5\",\r\n \"h6\",\r\n \"li\",\r\n \"figure\",\r\n \"figcaption\",\r\n \"blockquote\",\r\n \"pre\",\r\n \"code\",\r\n ].join(\",\");\r\n const candidates = Array.from(\r\n doc.querySelectorAll<HTMLElement>(selector)\r\n ).filter((el) => isEditableCandidate(el));\r\n candidates.forEach((target) => {\r\n if (!target.hasAttribute(\"data-rhe-id\")) {\r\n const uid = `rhe-init-${Date.now()}-${Math.random()\r\n .toString(36)\r\n .slice(2, 7)}`;\r\n try {\r\n target.setAttribute(\"data-rhe-id\", uid);\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n }\r\n });\r\n } catch (err) {\r\n /* ignore initialization errors */\r\n }\r\n\r\n doc.addEventListener(\r\n \"click\",\r\n (e) => {\r\n const target = e.target as HTMLElement;\r\n if (!isEditableCandidate(target)) return;\r\n if (_getCurrentEditable() && _getCurrentEditable() !== target) {\r\n _getCurrentEditable()?.removeAttribute(\"contenteditable\");\r\n _getCurrentEditable()?.classList.remove(CLASS_ACTIVE);\r\n }\r\n // Ensure the editable element has a stable identifier so snapshots\r\n // can restore only the editable region without touching the rest\r\n // of the page (header, nav, scripts, etc.). Use a data attribute\r\n // to avoid clashing with page ids.\r\n if (!target.hasAttribute(\"data-rhe-id\")) {\r\n const uid = `rhe-${Date.now()}-${Math.random()\r\n .toString(36)\r\n .slice(2, 7)}`;\r\n try {\r\n target.setAttribute(\"data-rhe-id\", uid);\r\n } catch (err) {\r\n /* ignore attribute set errors */\r\n }\r\n }\r\n _setCurrentEditable(target);\r\n target.classList.add(CLASS_ACTIVE);\r\n target.setAttribute(\"contenteditable\", \"true\");\r\n target.focus();\r\n },\r\n true\r\n );\r\n doc.addEventListener(\"selectionchange\", () => {\r\n injectToolbar(doc, {\r\n onCommand: handleToolbarCommand,\r\n canUndo: () => _getUndoStack().length > 1,\r\n canRedo: () => _getRedoStack().length > 0,\r\n onUndo: handleUndo,\r\n onRedo: handleRedo,\r\n getFormatState: () => computeFormatState(doc),\r\n getSelectedElementInfo: () => getElementLabel(_getCurrentEditable()),\r\n });\r\n });\r\n doc.addEventListener(\"input\", () => pushStandaloneSnapshot(), true);\r\n\r\n // Keyboard shortcuts for common formatting and undo/redo\r\n doc.addEventListener(\r\n \"keydown\",\r\n (e) => {\r\n const meta = e.ctrlKey || e.metaKey;\r\n if (!meta) return;\r\n const key = e.key.toLowerCase();\r\n // Bold: Ctrl/Cmd+B\r\n if (key === \"b\") {\r\n e.preventDefault();\r\n handleToolbarCommand(\"bold\");\r\n return;\r\n }\r\n // Italic: Ctrl/Cmd+I\r\n if (key === \"i\") {\r\n e.preventDefault();\r\n handleToolbarCommand(\"italic\");\r\n return;\r\n }\r\n // Underline: Ctrl/Cmd+U\r\n if (key === \"u\") {\r\n e.preventDefault();\r\n handleToolbarCommand(\"underline\");\r\n return;\r\n }\r\n // Undo: Ctrl/Cmd+Z\r\n if (key === \"z\") {\r\n e.preventDefault();\r\n // If Shift is pressed, treat as redo\r\n if (e.shiftKey) {\r\n handleRedo();\r\n } else {\r\n handleUndo();\r\n }\r\n return;\r\n }\r\n // Redo: Ctrl/Cmd+Y\r\n if (key === \"y\") {\r\n e.preventDefault();\r\n handleRedo();\r\n return;\r\n }\r\n },\r\n true\r\n );\r\n}\r\n","/**\r\n * Check if an element can be edited\r\n *\r\n * Valid elements: Text container tags (p, div, section, etc.)\r\n * Invalid elements: HTML structure tags, inputs, scripts, styles\r\n *\r\n * @param el - Element to check\r\n * @returns True if element is a valid editable candidate\r\n */\r\nexport function isEditableCandidate(el: HTMLElement | null): boolean {\r\n if (!el) return false;\r\n const tag = el.tagName;\r\n const DISALLOWED = [\r\n \"HTML\",\r\n \"HEAD\",\r\n \"BODY\",\r\n \"SCRIPT\",\r\n \"STYLE\",\r\n \"LINK\",\r\n \"META\",\r\n \"NOSCRIPT\",\r\n ];\r\n if (DISALLOWED.includes(tag)) return false;\r\n if (tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\") return false;\r\n return true;\r\n}\r\n","/**\r\n * Compute the current formatting state of selected text\r\n *\r\n * Detects bold, italic, and underline formatting based on:\r\n * - DOM element tags (strong, em, u)\r\n * - CSS computed styles (fontWeight, fontStyle, textDecoration)\r\n *\r\n * @param doc - Document context\r\n * @returns Object with boolean flags for bold, italic, underline\r\n */\r\nexport function computeFormatState(doc: Document): {\r\n bold: boolean;\r\n italic: boolean;\r\n underline: boolean;\r\n foreColor: string | null;\r\n hiliteColor: string | null;\r\n fontName: string | null;\r\n fontSize: string | null;\r\n formatBlock: string | null;\r\n} {\r\n try {\r\n const s = doc.getSelection();\r\n let el: HTMLElement | null = null;\r\n if (s && s.anchorNode)\r\n el =\r\n s.anchorNode.nodeType === Node.ELEMENT_NODE\r\n ? (s.anchorNode as HTMLElement)\r\n : (s.anchorNode.parentElement as HTMLElement);\r\n if (!el)\r\n return {\r\n bold: false,\r\n italic: false,\r\n underline: false,\r\n foreColor: null,\r\n hiliteColor: null,\r\n fontName: null,\r\n fontSize: null,\r\n formatBlock: null,\r\n };\r\n const computed = doc.defaultView?.getComputedStyle(el) as\r\n | CSSStyleDeclaration\r\n | undefined;\r\n const bold = !!(\r\n el.closest(\"strong, b\") ||\r\n (computed &&\r\n (computed.fontWeight === \"700\" || Number(computed.fontWeight) >= 700))\r\n );\r\n const italic = !!(\r\n el.closest(\"em, i\") ||\r\n (computed && computed.fontStyle === \"italic\")\r\n );\r\n const underline = !!(\r\n el.closest(\"u\") ||\r\n (computed && (computed.textDecorationLine || \"\").includes(\"underline\"))\r\n );\r\n // Try to detect text color and highlight (background) color at the selection\r\n const foreColor =\r\n (el.closest(\"font[color]\") as HTMLElement | null)?.getAttribute(\r\n \"color\"\r\n ) ||\r\n (computed && computed.color) ||\r\n null;\r\n // Background color may come from a <mark> element or computed background-color\r\n const mark = el.closest(\"mark\") as HTMLElement | null;\r\n const hiliteColor =\r\n (mark && (mark.getAttribute(\"style\") || \"\")) ||\r\n (computed &&\r\n computed.backgroundColor &&\r\n computed.backgroundColor !== \"rgba(0, 0, 0, 0)\"\r\n ? computed.backgroundColor\r\n : null);\r\n\r\n // detect font name + size from computed style\r\n const fontName = (computed && computed.fontFamily) || null;\r\n const fontSize = (computed && computed.fontSize) || null;\r\n // detect block ancestor (paragraph, heading etc.)\r\n let blockEl: HTMLElement | null = el;\r\n while (blockEl && blockEl.parentElement) {\r\n const tag = blockEl.tagName;\r\n if (\r\n [\r\n \"P\",\r\n \"DIV\",\r\n \"SECTION\",\r\n \"ARTICLE\",\r\n \"LI\",\r\n \"TD\",\r\n \"BLOCKQUOTE\",\r\n \"H1\",\r\n \"H2\",\r\n \"H3\",\r\n \"H4\",\r\n \"H5\",\r\n \"H6\",\r\n ].includes(tag)\r\n ) {\r\n break;\r\n }\r\n blockEl = blockEl.parentElement as HTMLElement | null;\r\n }\r\n const formatBlock = blockEl ? blockEl.tagName.toLowerCase() : null;\r\n\r\n return {\r\n bold,\r\n italic,\r\n underline,\r\n foreColor,\r\n hiliteColor,\r\n fontName,\r\n fontSize,\r\n formatBlock,\r\n };\r\n } catch (err) {\r\n return {\r\n bold: false,\r\n italic: false,\r\n underline: false,\r\n foreColor: null,\r\n hiliteColor: null,\r\n fontName: null,\r\n fontSize: null,\r\n formatBlock: null,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Get a human-readable label for an element\r\n *\r\n * Format: `tagname#id.class`\r\n * Example: `p#intro.highlight` or `div.container`\r\n *\r\n * @param el - HTML element to label\r\n * @returns Label string or null if element is null\r\n */\r\nexport function getElementLabel(el: HTMLElement | null): string | null {\r\n if (!el) return null;\r\n const id = el.id ? `#${el.id}` : \"\";\r\n const cls = el.className ? `.${String(el.className).split(\" \")[0]}` : \"\";\r\n const tag = el.tagName.toLowerCase();\r\n return `${tag}${id}${cls}`;\r\n}\r\n","export function sanitizeURL(url: string): string {\r\n if (!url) return \"\";\r\n const trimmed = url.trim();\r\n if (!trimmed) return \"\";\r\n if (\r\n trimmed.toLowerCase().startsWith(\"javascript:\") ||\r\n trimmed.toLowerCase().startsWith(\"data:\")\r\n ) {\r\n console.warn(\"Blocked potentially dangerous URL protocol\");\r\n return \"\";\r\n }\r\n if (!trimmed.startsWith(\"http\") && !trimmed.startsWith(\"#\")) {\r\n return \"https://\" + trimmed;\r\n }\r\n return trimmed;\r\n}\r\n","import {\r\n _getDoc,\r\n _getUndoStack,\r\n _getRedoStack,\r\n _setUndoStack,\r\n _setRedoStack,\r\n} from \"./state\";\r\n\r\nimport { sanitizeHtml } from \"../utils/sanitize\";\r\nimport { injectStyles } from \"../dom/styles\";\r\n\r\nexport function handleUndo() {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) {\r\n console.warn(\r\n \"[rich-html-editor] handleUndo called before initialization\"\r\n );\r\n return;\r\n }\r\n if (_getUndoStack().length < 2) return;\r\n const undoStack = _getUndoStack();\r\n const redoStack = _getRedoStack();\r\n const current = undoStack.pop()!;\r\n redoStack.push(current);\r\n const prev = undoStack[undoStack.length - 1];\r\n if (!doc.documentElement) {\r\n throw new Error(\"Document is missing documentElement\");\r\n }\r\n // Sanitize the snapshot and extract only the body content so we\r\n // avoid overwriting head/link/style nodes that may contain page\r\n // or editor styles. Replacing only `document.body` preserves those\r\n // nodes while still restoring user content.\r\n const safe = sanitizeHtml(prev.replace(/^<!doctype html>\\n?/i, \"\"), doc);\r\n try {\r\n const parser = new DOMParser();\r\n const parsed = parser.parseFromString(safe, \"text/html\");\r\n if (parsed && parsed.body && doc.body) {\r\n // Prefer selective restoration: if the snapshot contains elements\r\n // marked with `data-rhe-id`, restore only those elements so we do\r\n // not clobber page-level UI (headers, tabs, carousel scripts).\r\n const parsedEls = parsed.body.querySelectorAll(\"[data-rhe-id]\");\r\n if (parsedEls && parsedEls.length) {\r\n const loadPromises: Promise<void>[] = [];\r\n parsedEls.forEach((pe) => {\r\n const id = pe.getAttribute(\"data-rhe-id\");\r\n if (!id) return;\r\n const local = doc.body.querySelector(`[data-rhe-id=\"${id}\"]`);\r\n if (!local) return;\r\n // Copy non-identifying attributes from parsed element to local\r\n try {\r\n Array.from(local.attributes).forEach((a) => {\r\n if (a.name !== \"data-rhe-id\") local.removeAttribute(a.name);\r\n });\r\n Array.from(pe.attributes).forEach((a) => {\r\n if (a.name !== \"data-rhe-id\")\r\n local.setAttribute(a.name, a.value);\r\n });\r\n } catch (err) {\r\n /* ignore attribute copy errors */\r\n }\r\n // Replace innerHTML of the editable region only\r\n try {\r\n local.innerHTML = pe.innerHTML;\r\n } catch (err) {\r\n /* ignore innerHTML set errors */\r\n }\r\n // Recreate preserved script placeholders inside the parsed element\r\n try {\r\n const placeholders = pe.querySelectorAll(\"[data-rhe-script]\");\r\n placeholders.forEach((ph) => {\r\n const encoded = ph.getAttribute(\"data-rhe-script\") || \"\";\r\n let code = \"\";\r\n try {\r\n code =\r\n typeof atob !== \"undefined\"\r\n ? decodeURIComponent(escape(atob(encoded)))\r\n : decodeURIComponent(encoded);\r\n } catch (e) {\r\n try {\r\n code = decodeURIComponent(encoded);\r\n } catch (er) {\r\n code = \"\";\r\n }\r\n }\r\n const attrsRaw = ph.getAttribute(\"data-rhe-script-attrs\");\r\n let attrs: Record<string, string> = {};\r\n if (attrsRaw) {\r\n try {\r\n attrs = JSON.parse(decodeURIComponent(attrsRaw));\r\n } catch (e) {\r\n attrs = {};\r\n }\r\n }\r\n const parentId = ph.getAttribute(\"data-rhe-script-parent\");\r\n try {\r\n const s = doc.createElement(\"script\");\r\n try {\r\n s.type = \"text/javascript\";\r\n (s as any).async = false;\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n Object.keys(attrs).forEach((k) =>\r\n s.setAttribute(k, attrs[k])\r\n );\r\n if (attrs.src) {\r\n const p = new Promise<void>((resolve) => {\r\n s.addEventListener(\"load\", () => resolve());\r\n s.addEventListener(\"error\", () => resolve());\r\n });\r\n loadPromises.push(p);\r\n s.src = attrs.src;\r\n } else {\r\n s.textContent = code;\r\n }\r\n if (parentId === \"head\") {\r\n doc.head.appendChild(s);\r\n } else {\r\n const target = doc.body.querySelector(\r\n `[data-rhe-id=\"${parentId}\"]`\r\n );\r\n if (target) target.appendChild(s);\r\n else doc.body.appendChild(s);\r\n }\r\n } catch (e) {\r\n /* ignore script injection errors */\r\n }\r\n });\r\n } catch (e) {\r\n /* ignore placeholder processing errors */\r\n }\r\n });\r\n try {\r\n if (loadPromises.length) {\r\n const waiter = (Promise as any).allSettled\r\n ? (Promise as any).allSettled(loadPromises)\r\n : Promise.all(\r\n loadPromises.map((p) => p.catch(() => undefined))\r\n );\r\n waiter.then(() => {\r\n try {\r\n doc.dispatchEvent(new Event(\"rhe:scripts-restored\"));\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n });\r\n } else {\r\n try {\r\n doc.dispatchEvent(new Event(\"rhe:scripts-restored\"));\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n } else {\r\n // No markers present — fallback to previous behavior of replacing\r\n // the body contents. This preserves backward compatibility.\r\n doc.body.innerHTML = parsed.body.innerHTML;\r\n }\r\n } else {\r\n // Fallback to replacing the whole documentElement if body is missing\r\n doc.documentElement.innerHTML = safe;\r\n }\r\n } catch (err) {\r\n // On any parse error, fall back to previous behavior\r\n doc.documentElement.innerHTML = safe;\r\n }\r\n\r\n // Re-inject editor styles (toolbar/style) and notify listeners so the\r\n // toolbar is restored and selectionchange handlers run.\r\n injectStyles(doc);\r\n try {\r\n doc.dispatchEvent(new Event(\"selectionchange\"));\r\n } catch (err) {\r\n /* ignore dispatch errors */\r\n }\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Undo failed:\", message);\r\n }\r\n}\r\n\r\nexport function handleRedo() {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) {\r\n console.warn(\r\n \"[rich-html-editor] handleRedo called before initialization\"\r\n );\r\n return;\r\n }\r\n if (!_getRedoStack().length) return;\r\n const undoStack = _getUndoStack();\r\n const redoStack = _getRedoStack();\r\n const next = redoStack.pop()!;\r\n undoStack.push(next);\r\n if (!doc.documentElement) {\r\n throw new Error(\"Document is missing documentElement\");\r\n }\r\n const safeNext = sanitizeHtml(\r\n next.replace(/^<!doctype html>\\n?/i, \"\"),\r\n doc\r\n );\r\n try {\r\n const parser = new DOMParser();\r\n const parsed = parser.parseFromString(safeNext, \"text/html\");\r\n if (parsed && parsed.body && doc.body) {\r\n const parsedEls = parsed.body.querySelectorAll(\"[data-rhe-id]\");\r\n if (parsedEls && parsedEls.length) {\r\n const loadPromises: Promise<void>[] = [];\r\n parsedEls.forEach((pe) => {\r\n const id = pe.getAttribute(\"data-rhe-id\");\r\n if (!id) return;\r\n const local = doc.body.querySelector(`[data-rhe-id=\"${id}\"]`);\r\n if (!local) return;\r\n try {\r\n Array.from(local.attributes).forEach((a) => {\r\n if (a.name !== \"data-rhe-id\") local.removeAttribute(a.name);\r\n });\r\n Array.from(pe.attributes).forEach((a) => {\r\n if (a.name !== \"data-rhe-id\")\r\n local.setAttribute(a.name, a.value);\r\n });\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n try {\r\n local.innerHTML = pe.innerHTML;\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n try {\r\n const placeholders = pe.querySelectorAll(\"[data-rhe-script]\");\r\n placeholders.forEach((ph) => {\r\n const encoded = ph.getAttribute(\"data-rhe-script\") || \"\";\r\n let code = \"\";\r\n try {\r\n code =\r\n typeof atob !== \"undefined\"\r\n ? decodeURIComponent(escape(atob(encoded)))\r\n : decodeURIComponent(encoded);\r\n } catch (e) {\r\n try {\r\n code = decodeURIComponent(encoded);\r\n } catch (er) {\r\n code = \"\";\r\n }\r\n }\r\n const attrsRaw = ph.getAttribute(\"data-rhe-script-attrs\");\r\n let attrs: Record<string, string> = {};\r\n if (attrsRaw) {\r\n try {\r\n attrs = JSON.parse(decodeURIComponent(attrsRaw));\r\n } catch (e) {\r\n attrs = {};\r\n }\r\n }\r\n const parentId = ph.getAttribute(\"data-rhe-script-parent\");\r\n try {\r\n const s = doc.createElement(\"script\");\r\n try {\r\n s.type = \"text/javascript\";\r\n (s as any).async = false;\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n Object.keys(attrs).forEach((k) =>\r\n s.setAttribute(k, attrs[k])\r\n );\r\n if (attrs.src) {\r\n const p = new Promise<void>((resolve) => {\r\n s.addEventListener(\"load\", () => resolve());\r\n s.addEventListener(\"error\", () => resolve());\r\n });\r\n loadPromises.push(p);\r\n s.src = attrs.src;\r\n } else {\r\n s.textContent = code;\r\n }\r\n if (parentId === \"head\") {\r\n doc.head.appendChild(s);\r\n } else {\r\n const target = doc.body.querySelector(\r\n `[data-rhe-id=\"${parentId}\"]`\r\n );\r\n if (target) target.appendChild(s);\r\n else doc.body.appendChild(s);\r\n }\r\n } catch (e) {\r\n /* ignore script injection errors */\r\n }\r\n });\r\n } catch (e) {\r\n /* ignore placeholder processing errors */\r\n }\r\n });\r\n try {\r\n if (loadPromises.length) {\r\n const waiter = (Promise as any).allSettled\r\n ? (Promise as any).allSettled(loadPromises)\r\n : Promise.all(\r\n loadPromises.map((p) => p.catch(() => undefined))\r\n );\r\n waiter.then(() => {\r\n try {\r\n doc.dispatchEvent(new Event(\"rhe:scripts-restored\"));\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n });\r\n } else {\r\n try {\r\n doc.dispatchEvent(new Event(\"rhe:scripts-restored\"));\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n } else {\r\n doc.body.innerHTML = parsed.body.innerHTML;\r\n }\r\n } else {\r\n doc.documentElement.innerHTML = safeNext;\r\n }\r\n } catch (err) {\r\n doc.documentElement.innerHTML = safeNext;\r\n }\r\n\r\n // Re-inject styles and notify listeners so toolbar/styles are restored\r\n injectStyles(doc);\r\n try {\r\n doc.dispatchEvent(new Event(\"selectionchange\"));\r\n } catch (err) {\r\n /* ignore dispatch errors */\r\n }\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Redo failed:\", message);\r\n }\r\n}\r\n","import { _getDoc, pushStandaloneSnapshot } from \"./state\";\r\nimport { sanitizeHtml } from \"../utils/sanitize\";\r\nimport { sanitizeURL } from \"./sanitizeURL\";\r\n\r\nexport function handleToolbarCommand(command: string, value?: string) {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) {\r\n console.warn(\r\n \"[rich-html-editor] handleToolbarCommand called before initialization\"\r\n );\r\n return;\r\n }\r\n if (command === \"undo\") return; // delegated to history module\r\n if (command === \"redo\") return; // delegated to history module\r\n if (command === \"link\") {\r\n const url = window.prompt(\"Enter URL (https://...):\", \"https://\");\r\n if (url) {\r\n const sanitized = sanitizeURL(url);\r\n if (sanitized) applyStandaloneCommand(\"link\", sanitized);\r\n }\r\n return;\r\n }\r\n applyStandaloneCommand(command, value);\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Command handler failed:\", message);\r\n }\r\n}\r\n\r\nexport function applyStandaloneCommand(command: string, value?: string) {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) {\r\n console.warn(\r\n \"[rich-html-editor] applyStandaloneCommand called before initialization\"\r\n );\r\n return;\r\n }\r\n\r\n if (command === \"bold\") wrapSelectionWithElement(doc, \"strong\");\r\n else if (command === \"italic\") wrapSelectionWithElement(doc, \"em\");\r\n else if (command === \"underline\") wrapSelectionWithElement(doc, \"u\");\r\n else if (command === \"strike\") wrapSelectionWithElement(doc, \"s\");\r\n else if (command === \"fontName\")\r\n wrapSelectionWithElement(doc, \"span\", { fontFamily: value as any });\r\n else if (command === \"fontSize\") {\r\n // Accept numeric font-size values (e.g. \"12\", \"16\") and apply as px.\r\n const raw = value || \"14\";\r\n const n = parseInt(raw, 10);\r\n const sz = Number.isFinite(n) ? `${n}px` : raw;\r\n wrapSelectionWithElement(doc, \"span\", { fontSize: sz as any });\r\n } else if (command === \"link\") {\r\n const sel = doc.getSelection();\r\n if (!sel || !sel.rangeCount) return;\r\n const range = sel.getRangeAt(0);\r\n const content = range.extractContents();\r\n const a = doc.createElement(\"a\");\r\n a.href = sanitizeURL(value || \"#\");\r\n a.appendChild(content);\r\n range.insertNode(a);\r\n } else if (command === \"foreColor\")\r\n wrapSelectionWithElement(doc, \"span\", { color: value as any });\r\n else if (command === \"hiliteColor\")\r\n wrapSelectionWithElement(doc, \"span\", { backgroundColor: value as any });\r\n else if (command === \"align\") {\r\n const sel = doc.getSelection();\r\n const node = sel?.anchorNode || null;\r\n const block = findBlockAncestor(node);\r\n if (block) block.style.textAlign = value || \"left\";\r\n else wrapSelectionWithElement(doc, \"div\", { textAlign: value as any });\r\n } else if (command === \"formatBlock\") {\r\n // Change block-level element to selected tag (p, h1..h6)\r\n const sel = doc.getSelection();\r\n const node = sel?.anchorNode || null;\r\n const block = findBlockAncestor(node);\r\n const tag = (value || \"p\").toLowerCase();\r\n if (block && block.parentElement) {\r\n // Replace existing block with new block of desired tag\r\n const newEl = doc.createElement(tag);\r\n // Preserve inline styles?\r\n newEl.className = (block as HTMLElement).className || \"\";\r\n while (block.firstChild) newEl.appendChild(block.firstChild);\r\n block.parentElement.replaceChild(newEl, block);\r\n } else {\r\n // Wrap selection in the block tag\r\n wrapSelectionWithElement(doc, tag);\r\n }\r\n }\r\n pushStandaloneSnapshot();\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Apply command failed:\", message);\r\n }\r\n}\r\n\r\nfunction wrapSelectionWithElement(\r\n doc: Document,\r\n tagName: string,\r\n style?: Partial<CSSStyleDeclaration>\r\n): void {\r\n const sel = doc.getSelection();\r\n if (!sel) return;\r\n if (!sel.rangeCount) return;\r\n const range = sel.getRangeAt(0);\r\n if (range.collapsed) {\r\n const el = doc.createElement(tagName);\r\n if (style) Object.assign(el.style, style as any);\r\n const zw = doc.createTextNode(\"\\u200B\");\r\n el.appendChild(zw);\r\n range.insertNode(el);\r\n const newRange = doc.createRange();\r\n newRange.setStart(zw, 1);\r\n newRange.collapse(true);\r\n sel.removeAllRanges();\r\n sel.addRange(newRange);\r\n return;\r\n }\r\n const content = range.extractContents();\r\n const wrapper = doc.createElement(tagName);\r\n if (style) Object.assign(wrapper.style, style as any);\r\n wrapper.appendChild(content);\r\n range.insertNode(wrapper);\r\n sel.removeAllRanges();\r\n const newRange = doc.createRange();\r\n newRange.selectNodeContents(wrapper);\r\n sel.addRange(newRange);\r\n}\r\n\r\nfunction findBlockAncestor(node: Node | null): HTMLElement | null {\r\n let n = node as Node | null;\r\n const BLOCKS = [\r\n \"P\",\r\n \"DIV\",\r\n \"SECTION\",\r\n \"ARTICLE\",\r\n \"LI\",\r\n \"TD\",\r\n \"BLOCKQUOTE\",\r\n \"H1\",\r\n \"H2\",\r\n \"H3\",\r\n \"H4\",\r\n \"H5\",\r\n \"H6\",\r\n ];\r\n while (n) {\r\n if (n.nodeType === Node.ELEMENT_NODE) {\r\n const el = n as HTMLElement;\r\n if (BLOCKS.includes(el.tagName)) return el;\r\n }\r\n n = n.parentNode;\r\n }\r\n return null;\r\n}\r\n"],"mappings":"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","names":["createDOMPurify","input","newRange"]}
1
+ {"version":3,"sources":["../src/core/events.ts","../src/core/constants.ts","../src/utils/sanitize.ts","../src/core/state.ts","../src/index.ts","../src/core/editor.ts","../src/dom/styles.ts","../src/toolbar/render.ts","../src/toolbar/color.ts","../src/toolbar/overflow.ts","../src/toolbar/buttons.ts","../src/toolbar/selects.ts","../src/toolbar/navigation.ts","../src/dom/handlers.ts","../src/dom/candidates.ts","../src/dom/format.ts","../src/core/sanitizeURL.ts","../src/core/history.ts","../src/core/formatActions.ts"],"sourcesContent":["import type { EditorEventType, EditorEvent, EditorEventHandler } from \"./types\";\r\n\r\nexport class EditorEventEmitter {\r\n private listeners: Map<EditorEventType, Set<EditorEventHandler>> = new Map();\r\n\r\n on(type: EditorEventType, handler: EditorEventHandler): () => void {\r\n if (!this.listeners.has(type)) {\r\n this.listeners.set(type, new Set());\r\n }\r\n this.listeners.get(type)!.add(handler);\r\n return () => this.off(type, handler);\r\n }\r\n\r\n once(type: EditorEventType, handler: EditorEventHandler): void {\r\n const unsubscribe = this.on(type, (event) => {\r\n handler(event);\r\n unsubscribe();\r\n });\r\n }\r\n\r\n off(type: EditorEventType, handler: EditorEventHandler): void {\r\n const handlers = this.listeners.get(type);\r\n if (handlers) {\r\n handlers.delete(handler);\r\n if (handlers.size === 0) this.listeners.delete(type);\r\n }\r\n }\r\n\r\n emit(event: EditorEvent): void {\r\n const handlers = this.listeners.get(event.type);\r\n if (handlers) {\r\n handlers.forEach((handler) => {\r\n try {\r\n handler(event);\r\n } catch (error) {\r\n console.error(\r\n `[rich-html-editor] Error in event handler for ${event.type}:`,\r\n error\r\n );\r\n }\r\n });\r\n }\r\n }\r\n\r\n removeAllListeners(type?: EditorEventType): void {\r\n if (type) this.listeners.delete(type);\r\n else this.listeners.clear();\r\n }\r\n\r\n listenerCount(type: EditorEventType): number {\r\n return this.listeners.get(type)?.size ?? 0;\r\n }\r\n}\r\n\r\nexport const editorEventEmitter = new EditorEventEmitter();\r\n\r\nexport function getEditorEventEmitter(): EditorEventEmitter {\r\n return editorEventEmitter;\r\n}\r\n","// Shared constants for the rich-html-editor (moved to core)\r\nexport const TOOLBAR_ID = \"editor-toolbar\";\r\nexport const STYLE_ID = \"editor-styles\";\r\nexport const CLASS_EDITABLE = \"editor-editable-element\";\r\nexport const CLASS_ACTIVE = \"editor-active-element\";\r\n\r\n// Default undo/redo stack size\r\nexport const DEFAULT_MAX_STACK = 60;\r\n\r\n// Toolbar styling constants\r\nexport const TOOLBAR_BG = \"#f8fafc\";\r\nexport const TOOLBAR_BORDER = \"#e5e7eb\";\r\nexport const BUTTON_BORDER = \"#d1d5db\";\r\nexport const BUTTON_ACTIVE_BG = \"#e0e7ff\";\r\nexport const BUTTON_BG = \"#fff\";\r\nexport const BUTTON_COLOR = \"#222\";\r\nexport const INFO_COLOR = \"#888\";\r\n\r\n// Outline colors used by injected styles\r\nexport const HOVER_OUTLINE = \"#2563eb\";\r\nexport const ACTIVE_OUTLINE = \"#16a34a\";\r\n\r\n// Toolbar label/icon constants (kept in core for reuse)\r\nexport const LABEL_BOLD = \"<b>B</b>\";\r\nexport const LABEL_ITALIC = \"<i>I</i>\";\r\nexport const LABEL_UNDERLINE = \"<u>U</u>\";\r\nexport const LABEL_STRIKETHROUGH = \"<s>S</s>\";\r\nexport const LABEL_UNDO = \"↺\";\r\nexport const LABEL_REDO = \"↻\";\r\nexport const LABEL_LINK = \"🔗\";\r\nexport const LABEL_ALIGN_LEFT = `\r\n\t<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\r\n\t\t<rect x=\"1\" y=\"2\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"6\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"10\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"14\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t</svg>\r\n`;\r\nexport const LABEL_ALIGN_CENTER = `\r\n\t<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\r\n\t\t<rect x=\"3\" y=\"2\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"6\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"3\" y=\"10\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"14\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t</svg>\r\n`;\r\nexport const LABEL_ALIGN_RIGHT = `\r\n\t<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\r\n\t\t<rect x=\"5\" y=\"2\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"6\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"5\" y=\"10\" width=\"10\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t\t<rect x=\"1\" y=\"14\" width=\"14\" height=\"2\" rx=\"0.5\" fill=\"currentColor\" />\r\n\t</svg>\r\n`;\r\n\r\n// Font and size option lists used by the toolbar\r\nexport const FONT_OPTIONS: { label: string; value: string }[] = [\r\n { label: \"Arial\", value: \"Arial\" },\r\n { label: \"Helvetica\", value: \"Helvetica, Arial, sans-serif\" },\r\n { label: \"Verdana\", value: \"Verdana, Geneva, sans-serif\" },\r\n { label: \"Tahoma\", value: \"Tahoma, Geneva, sans-serif\" },\r\n { label: \"Trebuchet MS\", value: \"Trebuchet MS, Helvetica, sans-serif\" },\r\n { label: \"Georgia\", value: \"Georgia, serif\" },\r\n { label: \"Times New Roman\", value: \"Times New Roman, Times, serif\" },\r\n { label: \"Palatino\", value: \"Palatino, 'Palatino Linotype', serif\" },\r\n { label: \"Garamond\", value: \"Garamond, serif\" },\r\n { label: \"Book Antiqua\", value: \"'Book Antiqua', Palatino, serif\" },\r\n { label: \"Courier New\", value: \"'Courier New', Courier, monospace\" },\r\n { label: \"Lucida Console\", value: \"'Lucida Console', Monaco, monospace\" },\r\n { label: \"Impact\", value: \"Impact, Charcoal, sans-serif\" },\r\n { label: \"Comic Sans MS\", value: \"'Comic Sans MS', 'Comic Sans', cursive\" },\r\n { label: \"Segoe UI\", value: \"'Segoe UI', Tahoma, Geneva, sans-serif\" },\r\n {\r\n label: \"Roboto\",\r\n value: \"Roboto, 'Helvetica Neue', Helvetica, Arial, sans-serif\",\r\n },\r\n { label: \"Open Sans\", value: \"'Open Sans', Arial, sans-serif\" },\r\n { label: \"Lato\", value: \"Lato, 'Helvetica Neue', Arial, sans-serif\" },\r\n { label: \"Montserrat\", value: \"Montserrat, Arial, sans-serif\" },\r\n { label: \"Source Sans Pro\", value: \"'Source Sans Pro', Arial, sans-serif\" },\r\n { label: \"Fira Sans\", value: \"'Fira Sans', Arial, sans-serif\" },\r\n { label: \"Ubuntu\", value: \"Ubuntu, Arial, sans-serif\" },\r\n { label: \"Noto Sans\", value: \"'Noto Sans', Arial, sans-serif\" },\r\n { label: \"Droid Sans\", value: \"'Droid Sans', Arial, sans-serif\" },\r\n {\r\n label: \"Helvetica Neue\",\r\n value: \"'Helvetica Neue', Helvetica, Arial, sans-serif\",\r\n },\r\n {\r\n label: \"System UI\",\r\n value:\r\n \"system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\",\r\n },\r\n];\r\n\r\nexport const SIZE_OPTIONS: { label: string; value: string }[] = [\r\n { label: \"8\", value: \"8\" },\r\n { label: \"9\", value: \"9\" },\r\n { label: \"10\", value: \"10\" },\r\n { label: \"11\", value: \"11\" },\r\n { label: \"12\", value: \"12\" },\r\n { label: \"14\", value: \"14\" },\r\n { label: \"16\", value: \"16\" },\r\n { label: \"18\", value: \"18\" },\r\n { label: \"20\", value: \"20\" },\r\n { label: \"22\", value: \"22\" },\r\n { label: \"24\", value: \"24\" },\r\n { label: \"26\", value: \"26\" },\r\n { label: \"28\", value: \"28\" },\r\n { label: \"36\", value: \"36\" },\r\n { label: \"48\", value: \"48\" },\r\n { label: \"72\", value: \"72\" },\r\n];\r\n\r\n// Block format options (Paragraph + Headings)\r\nexport const FORMAT_OPTIONS: { label: string; value: string }[] = [\r\n { label: \"Heading 1\", value: \"h1\" },\r\n { label: \"Heading 2\", value: \"h2\" },\r\n { label: \"Heading 3\", value: \"h3\" },\r\n { label: \"Heading 4\", value: \"h4\" },\r\n { label: \"Heading 5\", value: \"h5\" },\r\n { label: \"Heading 6\", value: \"h6\" },\r\n];\r\n\r\n// Shared SVG used by toolbar color inputs (palette icon)\r\nexport const PALETTE_SVG = `\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\r\n <path d=\"M12 2C7 2 3 6 3 11c0 2.8 1.4 5.3 3.7 6.8.9.6 2 .9 3.3.9 1.6 0 3.1-.5 4.3-1.4.6-.4.9-1.1.6-1.8-.3-.7-1-1-1.7-.8-1.1.3-2.3.2-3.4-.3C10.3 14.6 9 13.6 9 12c0-1.7 1.3-3 3-3 .8 0 1.5.3 2.1.8.5.4 1.2.3 1.6-.2.9-1.1 1.4-2.4 1.4-3.8C20.9 6 16.9 2 12 2z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\r\n <circle cx=\"7.5\" cy=\"10.5\" r=\"1\" fill=\"currentColor\"/>\r\n <circle cx=\"11.5\" cy=\"8.5\" r=\"1\" fill=\"currentColor\"/>\r\n <circle cx=\"14.5\" cy=\"11.5\" r=\"1\" fill=\"currentColor\"/>\r\n </svg>\r\n`;\r\n\r\n// MS Word-like icons for color controls\r\nexport const TEXT_COLOR_ICON_HTML = `\r\n <span class=\"text-color-wrapper\" aria-hidden=\"true\">\r\n <span class=\"text-A\">A</span>\r\n </span>\r\n`;\r\n\r\nexport const HIGHLIGHT_ICON_HTML = `\r\n <span class=\"highlight-wrapper\" aria-hidden=\"true\">\r\n <span class=\"highlight-bar\" data-role=\"highlight\"></span>\r\n <span class=\"text-A\">A</span>\r\n </span>\r\n`;\r\n","import createDOMPurify from \"dompurify\";\r\n\r\n/**\r\n * Sanitize HTML using DOMPurify.\r\n *\r\n * Works in browser and in jsdom (tests) by accepting either a `Window`\r\n * or a `Document` (from which `defaultView` is used).\r\n */\r\nexport function sanitizeHtml(\r\n html: string,\r\n ctx?: Window | Document | null\r\n): string {\r\n if (!html) return \"\";\r\n // Try to get a Window reference\r\n let win: Window | null = null;\r\n if (ctx && (ctx as Document).defaultView) {\r\n win = (ctx as Document).defaultView as Window;\r\n } else if (ctx && (ctx as Window).document) {\r\n win = ctx as Window;\r\n } else if (typeof window !== \"undefined\") {\r\n win = window as Window;\r\n }\r\n\r\n // If we have a window, use DOMPurify\r\n if (win) {\r\n try {\r\n const DOMPurify = createDOMPurify(win as any);\r\n // Preserve element ids and data-* attributes so restoring snapshots\r\n // during undo/redo does not break page scripts or CSS that rely on\r\n // those attributes. Still strip <script> and all inline event\r\n // handlers (on*) to avoid executing arbitrary script.\r\n // Use ADD_ATTR to allow `id`, and a hook to preserve any `data-` attrs.\r\n try {\r\n DOMPurify.addHook(\"uponSanitizeAttribute\", (node: any, data: any) => {\r\n try {\r\n if (data && data.attrName && data.attrName.startsWith(\"data-\")) {\r\n // Keep data-* attributes\r\n (data as any).keepAttr = true;\r\n }\r\n } catch (e) {\r\n /* ignore hook errors */\r\n }\r\n });\r\n } catch (e) {\r\n /* addHook may not be available in some environments; ignore */\r\n }\r\n\r\n return DOMPurify.sanitize(html, {\r\n // Use sensible defaults: allow common formatting tags but strip scripts\r\n ALLOWED_TAGS: [\r\n \"a\",\r\n \"b\",\r\n \"i\",\r\n \"em\",\r\n \"strong\",\r\n \"u\",\r\n \"p\",\r\n \"div\",\r\n \"span\",\r\n // Common semantic elements: preserve document structure so undo/redo\r\n // does not flatten header/section/nav into plain content.\r\n \"header\",\r\n \"nav\",\r\n \"section\",\r\n \"main\",\r\n \"footer\",\r\n \"article\",\r\n \"aside\",\r\n \"figure\",\r\n \"figcaption\",\r\n \"time\",\r\n // Interactive / form elements that may appear in content\r\n \"button\",\r\n \"input\",\r\n \"label\",\r\n \"select\",\r\n \"option\",\r\n \"textarea\",\r\n \"details\",\r\n \"summary\",\r\n // Allow <style> tags so user/content-provided CSS is preserved\r\n // when taking snapshots and during undo/redo operations.\r\n // DOMPurify will still sanitize the contents of style blocks.\r\n \"style\",\r\n // Preserve linked stylesheets so page/editor styling isn't lost\r\n \"link\",\r\n \"ul\",\r\n \"ol\",\r\n \"li\",\r\n \"br\",\r\n \"hr\",\r\n \"blockquote\",\r\n \"pre\",\r\n \"code\",\r\n \"h1\",\r\n \"h2\",\r\n \"h3\",\r\n \"h4\",\r\n \"h5\",\r\n \"h6\",\r\n \"img\",\r\n ],\r\n ALLOWED_ATTR: [\r\n \"href\",\r\n \"title\",\r\n \"alt\",\r\n \"src\",\r\n \"class\",\r\n \"style\",\r\n // Attributes used by <link> tags\r\n \"rel\",\r\n \"type\",\r\n \"media\",\r\n ],\r\n // Also allow `id` attributes so element ids survive sanitization.\r\n ADD_ATTR: [\"id\"],\r\n });\r\n } catch (e) {\r\n // If DOMPurify initialization fails, fall through to minimal stripping\r\n }\r\n }\r\n\r\n // Minimal fallback: remove <script> tags and on* attributes\r\n return html\r\n .replace(/<script[\\s\\S]*?>[\\s\\S]*?<\\/script>/gi, \"\")\r\n .replace(/on[a-z]+=\\\"[^\"]*\\\"/gi, \"\");\r\n}\r\n\r\nexport default sanitizeHtml;\r\n","import { editorEventEmitter } from \"./events\";\r\nimport {\r\n DEFAULT_MAX_STACK,\r\n TOOLBAR_ID,\r\n STYLE_ID,\r\n CLASS_EDITABLE,\r\n CLASS_ACTIVE,\r\n} from \"./constants\";\r\nimport { sanitizeHtml } from \"../utils/sanitize\";\r\n\r\nlet _doc: Document | null = null;\r\nlet _undoStack: string[] = [];\r\nlet _redoStack: string[] = [];\r\nlet _currentEditable: HTMLElement | null = null;\r\nlet _maxStackSize = DEFAULT_MAX_STACK;\r\n\r\nexport function _setDoc(doc: Document | null) {\r\n _doc = doc;\r\n}\r\nexport function _getDoc() {\r\n return _doc;\r\n}\r\nexport function _setUndoStack(stack: string[]) {\r\n _undoStack = stack;\r\n editorEventEmitter.emit({\r\n type: \"undoStateChanged\",\r\n timestamp: Date.now(),\r\n data: { canUndo: _undoStack.length > 1 },\r\n });\r\n}\r\nexport function _getUndoStack() {\r\n return _undoStack;\r\n}\r\nexport function _setRedoStack(stack: string[]) {\r\n _redoStack = stack;\r\n editorEventEmitter.emit({\r\n type: \"redoStateChanged\",\r\n timestamp: Date.now(),\r\n data: { canRedo: _redoStack.length > 0 },\r\n });\r\n}\r\nexport function _getRedoStack() {\r\n return _redoStack;\r\n}\r\nexport function _setCurrentEditable(el: HTMLElement | null) {\r\n _currentEditable = el;\r\n editorEventEmitter.emit({\r\n type: \"selectionChanged\",\r\n timestamp: Date.now(),\r\n data: { element: el?.tagName },\r\n });\r\n}\r\nexport function _getCurrentEditable() {\r\n return _currentEditable;\r\n}\r\nexport function pushStandaloneSnapshot(clearRedo = true) {\r\n if (!_doc) return;\r\n // Clone the documentElement and remove injected UI (toolbar/style)\r\n // so snapshots capture only the user's content.\r\n const clone = _doc.documentElement.cloneNode(true) as HTMLElement;\r\n const toolbarNode = clone.querySelector(`#${TOOLBAR_ID}`);\r\n if (toolbarNode && toolbarNode.parentNode)\r\n toolbarNode.parentNode.removeChild(toolbarNode);\r\n const styleNode = clone.querySelector(`#${STYLE_ID}`);\r\n if (styleNode && styleNode.parentNode)\r\n styleNode.parentNode.removeChild(styleNode);\r\n // Remove editor-specific attributes/classes so snapshots don't persist\r\n // transient editing state (contenteditable, toolbar classes, tabindex).\r\n try {\r\n const editableNodes = clone.querySelectorAll(\r\n \"[contenteditable], .\" + CLASS_EDITABLE + \", .\" + CLASS_ACTIVE\r\n );\r\n editableNodes.forEach((el) => {\r\n try {\r\n if (el instanceof Element) {\r\n if (el.hasAttribute(\"contenteditable\"))\r\n el.removeAttribute(\"contenteditable\");\r\n if (el.hasAttribute(\"tabindex\")) el.removeAttribute(\"tabindex\");\r\n el.classList.remove(CLASS_EDITABLE, CLASS_ACTIVE);\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n });\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n // Preserve scripts by replacing them with a harmless placeholder\r\n // that contains the encoded script source/attributes. This allows the\r\n // sanitizer to run (which strips <script> tags) while keeping the\r\n // script content available to re-insert and execute on restore.\r\n try {\r\n const scripts = Array.from(\r\n clone.querySelectorAll<HTMLScriptElement>(\"script\")\r\n );\r\n scripts.forEach((s) => {\r\n try {\r\n const code = s.textContent || \"\";\r\n const attrs: Record<string, string> = {};\r\n Array.from(s.attributes).forEach((a) => (attrs[a.name] = a.value));\r\n const placeholder = clone.ownerDocument!.createElement(\"span\");\r\n // encode script body in base64 to survive sanitization\r\n try {\r\n // btoa may throw on Unicode; encodeURIComponent first\r\n const safe =\r\n typeof btoa !== \"undefined\"\r\n ? btoa(unescape(encodeURIComponent(code)))\r\n : encodeURIComponent(code);\r\n placeholder.setAttribute(\"data-rhe-script\", safe);\r\n } catch (e) {\r\n placeholder.setAttribute(\"data-rhe-script\", encodeURIComponent(code));\r\n }\r\n if (Object.keys(attrs).length) {\r\n placeholder.setAttribute(\r\n \"data-rhe-script-attrs\",\r\n encodeURIComponent(JSON.stringify(attrs))\r\n );\r\n }\r\n // mark parent editable region if present so we can reinsert in-place\r\n const parentMarker = s.closest(\"[data-rhe-id]\") as HTMLElement | null;\r\n if (parentMarker && parentMarker.getAttribute(\"data-rhe-id\")) {\r\n placeholder.setAttribute(\r\n \"data-rhe-script-parent\",\r\n parentMarker.getAttribute(\"data-rhe-id\")!\r\n );\r\n } else {\r\n placeholder.setAttribute(\"data-rhe-script-parent\", \"head\");\r\n }\r\n s.parentNode?.replaceChild(placeholder, s);\r\n } catch (e) {\r\n /* ignore per-script errors */\r\n }\r\n });\r\n } catch (e) {\r\n /* ignore script extraction errors */\r\n }\r\n const snapRaw = clone.outerHTML;\r\n const snap = sanitizeHtml(snapRaw, _doc);\r\n if (!_undoStack.length || _undoStack[_undoStack.length - 1] !== snap) {\r\n _undoStack.push(snap);\r\n if (_undoStack.length > _maxStackSize) _undoStack.shift();\r\n editorEventEmitter.emit({\r\n type: \"contentChanged\",\r\n timestamp: Date.now(),\r\n data: { htmlLength: snap.length },\r\n });\r\n }\r\n if (clearRedo) {\r\n _redoStack = [];\r\n editorEventEmitter.emit({\r\n type: \"redoStateChanged\",\r\n timestamp: Date.now(),\r\n data: { canRedo: false },\r\n });\r\n }\r\n}\r\nexport function setMaxStackSize(size: number) {\r\n _maxStackSize = Math.max(1, size);\r\n}\r\n","// Main entry point for the rich-html-editor util\r\n// Plug-and-play HTML editor API\r\n\r\n// Core functions\r\nexport { initRichEditor, getCleanHTML } from \"./core/editor\";\r\n\r\n// Types\r\nexport type {\r\n FormatState,\r\n ToolbarOptions,\r\n EditorEvent,\r\n EditorEventType,\r\n EditorEventHandler,\r\n FormattingCommand,\r\n TextAlignment,\r\n FontSizeMap,\r\n EditorConfig,\r\n} from \"./core/types\";\r\n\r\n// Event system\r\nexport { editorEventEmitter, getEditorEventEmitter } from \"./core/events\";\r\nexport type { EditorEventEmitter } from \"./core/events\";\r\n","import {\r\n _setDoc,\r\n _getDoc,\r\n _setUndoStack,\r\n _getUndoStack,\r\n _setRedoStack,\r\n _getRedoStack,\r\n _setCurrentEditable,\r\n _getCurrentEditable,\r\n pushStandaloneSnapshot,\r\n} from \"./state\";\r\nimport { injectStyles } from \"../dom/styles\";\r\nimport { injectToolbar } from \"../toolbar/toolbar\";\r\nimport { attachStandaloneHandlers } from \"../dom/handlers\";\r\nimport { computeFormatState, getElementLabel } from \"../dom/format\";\r\nimport { handleUndo, handleRedo, handleToolbarCommand } from \"./commands\";\r\nimport type { EditorConfig } from \"./types\";\r\nimport { sanitizeHtml } from \"../utils/sanitize\";\r\nimport {\r\n TOOLBAR_ID,\r\n STYLE_ID,\r\n CLASS_EDITABLE,\r\n CLASS_ACTIVE,\r\n} from \"./constants\";\r\n\r\n/**\r\n * Initialize the rich HTML editor on an iframe element\r\n */\r\nexport function initRichEditor(\r\n iframe: HTMLIFrameElement,\r\n config?: EditorConfig\r\n) {\r\n try {\r\n if (!iframe || !(iframe instanceof HTMLIFrameElement)) {\r\n throw new Error(\"Invalid iframe element provided to initRichEditor\");\r\n }\r\n\r\n const doc = iframe.contentDocument;\r\n if (!doc) {\r\n throw new Error(\r\n \"Unable to access iframe contentDocument. Ensure iframe src is same-origin.\"\r\n );\r\n }\r\n\r\n _setDoc(doc);\r\n injectStyles(doc);\r\n _setUndoStack([]);\r\n _setRedoStack([]);\r\n _setCurrentEditable(null);\r\n if (config?.maxStackSize) {\r\n import(\"./state\")\r\n .then((m) => m.setMaxStackSize(config.maxStackSize!))\r\n .catch(() => {\r\n /* ignore */\r\n });\r\n }\r\n attachStandaloneHandlers(doc);\r\n pushStandaloneSnapshot();\r\n injectToolbar(doc, {\r\n onCommand: handleToolbarCommand,\r\n canUndo: () => _getUndoStack().length > 1,\r\n canRedo: () => _getRedoStack().length > 0,\r\n onUndo: handleUndo,\r\n onRedo: handleRedo,\r\n getFormatState: () => computeFormatState(doc),\r\n getSelectedElementInfo: () => getElementLabel(_getCurrentEditable()),\r\n });\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Failed to initialize editor:\", message);\r\n throw error;\r\n }\r\n}\r\n\r\nexport function getCleanHTML(): string {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) {\r\n console.warn(\r\n \"[rich-html-editor] getCleanHTML called before editor initialization\"\r\n );\r\n return \"\";\r\n }\r\n if (!doc.documentElement) {\r\n throw new Error(\"Document is missing documentElement\");\r\n }\r\n\r\n const clone = doc.documentElement.cloneNode(true) as HTMLElement;\r\n\r\n // Remove injected toolbar and style elements if present\r\n const toolbarNode = clone.querySelector(`#${TOOLBAR_ID}`);\r\n if (toolbarNode && toolbarNode.parentNode)\r\n toolbarNode.parentNode.removeChild(toolbarNode);\r\n const styleNode = clone.querySelector(`#${STYLE_ID}`);\r\n if (styleNode && styleNode.parentNode)\r\n styleNode.parentNode.removeChild(styleNode);\r\n\r\n // Recursively clean root and descendants\r\n try {\r\n const cleanElement = (el: Element) => {\r\n try {\r\n // remove boolean/content attributes explicitly\r\n if (el.hasAttribute(\"contenteditable\"))\r\n el.removeAttribute(\"contenteditable\");\r\n if (el.hasAttribute(\"tabindex\")) el.removeAttribute(\"tabindex\");\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n\r\n try {\r\n const attrs = Array.from(el.attributes || []);\r\n attrs.forEach((a) => {\r\n const rawName = a.name;\r\n const name = rawName.toLowerCase();\r\n\r\n // remove inline event handlers\r\n if (name.startsWith(\"on\")) {\r\n try {\r\n el.removeAttribute(rawName);\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n return;\r\n }\r\n\r\n // remove any data-rhe-* attributes (including data-rhe-id)\r\n if (\r\n name === \"data-rhe-id\" ||\r\n name.startsWith(\"data-rhe-\") ||\r\n name === \"data-rhe\"\r\n ) {\r\n try {\r\n el.removeAttribute(rawName);\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n return;\r\n }\r\n });\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n\r\n try {\r\n if (el.id) {\r\n const id = el.id;\r\n if (\r\n id === TOOLBAR_ID ||\r\n id === STYLE_ID ||\r\n id.startsWith(\"editor-\") ||\r\n id.startsWith(\"rhe-\")\r\n ) {\r\n el.removeAttribute(\"id\");\r\n }\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n\r\n try {\r\n const cls = Array.from(el.classList || []);\r\n cls.forEach((c) => {\r\n if (\r\n c === CLASS_EDITABLE ||\r\n c === CLASS_ACTIVE ||\r\n c.startsWith(\"editor-\") ||\r\n c.startsWith(\"rhe-\")\r\n ) {\r\n try {\r\n el.classList.remove(c);\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n }\r\n });\r\n\r\n // remove empty class attributes left behind\r\n if (\r\n el.hasAttribute(\"class\") &&\r\n (el.getAttribute(\"class\") || \"\").trim() === \"\"\r\n ) {\r\n try {\r\n el.removeAttribute(\"class\");\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n\r\n try {\r\n const children = Array.from(el.children || []);\r\n children.forEach((child) => cleanElement(child as Element));\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n };\r\n\r\n // `instanceof Element` can fail across window/iframe boundaries\r\n // because each iframe has its own global `Element` constructor.\r\n // Use a cross-realm-safe check instead.\r\n if ((clone as Node).nodeType === Node.ELEMENT_NODE) {\r\n cleanElement(clone as Element);\r\n }\r\n } catch (e) {\r\n /* ignore traversal errors */\r\n }\r\n\r\n // Preserve original scripts intentionally.\r\n return \"<!doctype html>\\n\" + clone.outerHTML;\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Failed to get clean HTML:\", message);\r\n throw error;\r\n }\r\n}\r\n\r\nexport function getSanitizedHTML(): string {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) return \"\";\r\n if (!doc.documentElement)\r\n throw new Error(\"Document is missing documentElement\");\r\n const raw = \"<!doctype html>\\n\" + doc.documentElement.outerHTML;\r\n return sanitizeHtml(raw, doc);\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Failed to get sanitized HTML:\", message);\r\n throw error;\r\n }\r\n}\r\n","/**\r\n * Inject CSS styles into the document for editor UI\r\n *\r\n * Adds styling for:\r\n * - `.editor-editable-element`: Dashed outline for hoverable elements\r\n * - `.editor-active-element`: Solid green outline for active editing element\r\n *\r\n * Uses a style ID to prevent duplicate injections\r\n *\r\n * @param doc - Document to inject styles into\r\n */\r\nimport {\r\n STYLE_ID,\r\n CLASS_EDITABLE,\r\n CLASS_ACTIVE,\r\n HOVER_OUTLINE,\r\n ACTIVE_OUTLINE,\r\n TOOLBAR_ID,\r\n TOOLBAR_BG,\r\n TOOLBAR_BORDER,\r\n BUTTON_BORDER,\r\n BUTTON_ACTIVE_BG,\r\n BUTTON_BG,\r\n BUTTON_COLOR,\r\n INFO_COLOR,\r\n} from \"../core/constants\";\r\n\r\nexport function injectStyles(doc: Document): void {\r\n const styleId = STYLE_ID;\r\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\r\n const css = `\r\n.${CLASS_EDITABLE}{outline:2px dashed ${HOVER_OUTLINE};cursor:text}\r\n.${CLASS_ACTIVE}{outline:2px solid ${ACTIVE_OUTLINE};cursor:text}\r\n#${TOOLBAR_ID}{\r\n position: sticky;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n z-index: 9999;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n background: ${TOOLBAR_BG};\r\n border-bottom: 1px solid ${TOOLBAR_BORDER};\r\n font-family: inherit;\r\n box-shadow: 0 6px 18px rgba(2,6,23,0.08);\r\n backdrop-filter: blur(6px);\r\n /* Allow toolbar items to wrap onto multiple lines on narrow screens */\r\n flex-wrap: wrap;\r\n justify-content: flex-start;\r\n}\r\n#${TOOLBAR_ID} button{\r\n padding: 6px 8px;\r\n border: 1px solid ${BUTTON_BORDER};\r\n background: ${BUTTON_BG};\r\n color: ${BUTTON_COLOR};\r\n border-radius: 8px;\r\n font-weight: 500;\r\n cursor: pointer;\r\n transition: transform .12s ease, box-shadow .12s ease, background .12s ease;\r\n outline: none;\r\n margin-right: 2px;\r\n}\r\n#${TOOLBAR_ID} button[aria-pressed=\"true\"]{\r\n background: ${BUTTON_ACTIVE_BG};\r\n font-weight: 600;\r\n box-shadow: 0 6px 12px rgba(99,102,241,0.12);\r\n}\r\n#${TOOLBAR_ID} button:hover:not(:disabled){\r\n transform: translateY(-2px);\r\n box-shadow: 0 8px 20px rgba(2,6,23,0.08);\r\n}\r\n#${TOOLBAR_ID} select{\r\n padding: 6px 8px;\r\n border-radius: 8px;\r\n border: 1px solid ${BUTTON_BORDER};\r\n background: #fff;\r\n font-family: inherit;\r\n}\r\n#${TOOLBAR_ID} input[type=\"color\"]{\r\n border-radius: 8px;\r\n border: 1px solid ${BUTTON_BORDER};\r\n background: #fff;\r\n font-family: inherit;\r\n}\r\n#${TOOLBAR_ID} .color-input-label{\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 0;\r\n background: transparent;\r\n border: none;\r\n}\r\n\r\n/* Labeled color inputs (e.g. \"Text Color <input type=color>\") */\r\n#${TOOLBAR_ID} .color-label{\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 0;\r\n background: transparent;\r\n border: none;\r\n}\r\n#${TOOLBAR_ID} .color-input-label .color-icon{\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n#${TOOLBAR_ID} .text-color-icon{\r\n font-weight: 700;\r\n font-size: 14px;\r\n line-height: 1;\r\n display: inline-block;\r\n padding-bottom: 2px;\r\n border-bottom: 3px solid currentColor;\r\n transform-origin: center;\r\n}\r\n#${TOOLBAR_ID} .highlight-icon{\r\n width: 16px;\r\n height: 16px;\r\n display: inline-block;\r\n}\r\n#${TOOLBAR_ID} .color-icon svg{\r\n width: 16px;\r\n height: 16px;\r\n display: block;\r\n}\r\n/* Text color wrapper: A with a small swatch on the right */\r\n#${TOOLBAR_ID} .text-color-wrapper{\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n}\r\n#${TOOLBAR_ID} .text-color-wrapper .text-A{\r\n font-weight: 700;\r\n font-size: 14px;\r\n line-height: 1;\r\n}\r\n#${TOOLBAR_ID} .text-color-wrapper .color-swatch{\r\n width: 12px;\r\n height: 12px;\r\n border-radius: 3px;\r\n border: 1px solid rgba(0,0,0,0.12);\r\n box-shadow: 0 1px 0 rgba(255,255,255,0.5) inset;\r\n background: currentColor;\r\n}\r\n\r\n/* Highlight wrapper: small colored bar under/behind the A to mimic highlighter */\r\n#${TOOLBAR_ID} .highlight-wrapper{\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n position: relative;\r\n}\r\n#${TOOLBAR_ID} .highlight-wrapper .highlight-bar{\r\n position: absolute;\r\n left: 0;\r\n right: 0;\r\n bottom: 2px;\r\n height: 8px;\r\n border-radius: 3px;\r\n background: #ffeb3b; /* default yellow */\r\n z-index: 0;\r\n}\r\n#${TOOLBAR_ID} .highlight-wrapper .text-A{\r\n position: relative;\r\n z-index: 1;\r\n font-weight: 700;\r\n font-size: 14px;\r\n line-height: 1;\r\n padding: 0 4px;\r\n}\r\n#${TOOLBAR_ID} span{\r\n color: ${INFO_COLOR};\r\n font-size: 90%;\r\n}\r\n\r\n/* Grouping and separators */\r\n#${TOOLBAR_ID} .toolbar-group{\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n}\r\n#${TOOLBAR_ID} .toolbar-group{\r\n /* groups may wrap internally to avoid overflow on narrow screens */\r\n flex-wrap: wrap;\r\n}\r\n/* Overflow button + menu styling */\r\n#${TOOLBAR_ID} .toolbar-overflow-btn{\r\n display: none;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 6px 8px;\r\n border-radius: 8px;\r\n border: 1px solid ${BUTTON_BORDER};\r\n background: ${BUTTON_BG};\r\n color: ${BUTTON_COLOR};\r\n font-weight: 600;\r\n}\r\n#${TOOLBAR_ID} .toolbar-overflow-menu{\r\n position: absolute;\r\n top: calc(100% + 6px);\r\n right: 12px;\r\n min-width: 160px;\r\n background: #fff;\r\n border: 1px solid rgba(15,23,42,0.06);\r\n border-radius: 8px;\r\n padding: 8px;\r\n box-shadow: 0 12px 40px rgba(2,6,23,0.12);\r\n display: flex;\r\n flex-direction: column;\r\n gap: 6px;\r\n z-index: 10000;\r\n}\r\n#${TOOLBAR_ID} .toolbar-overflow-menu[hidden]{\r\n display: none;\r\n}\r\n#${TOOLBAR_ID} .toolbar-sep{\r\n width: 1px;\r\n height: 28px;\r\n background: rgba(15,23,42,0.06);\r\n margin: 0 8px;\r\n border-radius: 1px;\r\n}\r\n#${TOOLBAR_ID} .toolbar-spacer{\r\n flex: 1 1 auto;\r\n}\r\n#${TOOLBAR_ID} button svg{\r\n width: 16px;\r\n height: 16px;\r\n display: block;\r\n /* Default icon appearance */\r\n fill: none;\r\n}\r\n\r\n/* Active/pressed: switch to filled appearance */\r\n#${TOOLBAR_ID} button[aria-pressed=\"true\"] svg{\r\n fill: currentColor;\r\n}\r\n\r\n/* Focus and accessibility */\r\n#${TOOLBAR_ID} button:focus{\r\n outline: none;\r\n box-shadow: 0 0 0 4px rgba(99,102,241,0.12);\r\n}\r\n\r\n/* Disabled state */\r\n#${TOOLBAR_ID} button:disabled{\r\n opacity: 0.48;\r\n cursor: not-allowed;\r\n}\r\n/* Responsive tweaks: reduce spacing and allow horizontal scroll on very small screens */\r\n@media (max-width: 720px){\r\n #${TOOLBAR_ID}{\r\n padding: 6px 8px;\r\n gap: 6px;\r\n }\r\n #${TOOLBAR_ID} button,\r\n #${TOOLBAR_ID} select,\r\n #${TOOLBAR_ID} input[type=\"color\"]{\r\n padding: 4px 6px;\r\n border-radius: 6px;\r\n }\r\n /* Hide visual separators to save horizontal space */\r\n #${TOOLBAR_ID} .toolbar-sep{\r\n display: none;\r\n }\r\n /* Collapse labeled color text visually but preserve accessibility on the input */\r\n #${TOOLBAR_ID} .color-label{\r\n font-size: 0;\r\n }\r\n #${TOOLBAR_ID} .color-label input{\r\n font-size: initial;\r\n }\r\n}\r\n@media (max-width: 420px){\r\n /* On very small screens prefer a single-line scrollable toolbar */\r\n #${TOOLBAR_ID}{\r\n flex-wrap: nowrap;\r\n overflow-x: auto;\r\n -webkit-overflow-scrolling: touch;\r\n }\r\n #${TOOLBAR_ID} .toolbar-group{\r\n flex: 0 0 auto;\r\n }\r\n #${TOOLBAR_ID} button{ margin-right: 6px; }\r\n /* Show overflow button and hide the groups marked for collapse */\r\n #${TOOLBAR_ID} .toolbar-overflow-btn{\r\n display: inline-flex;\r\n }\r\n #${TOOLBAR_ID} .collapse-on-small{\r\n display: none;\r\n }\r\n}\r\n`;\r\n if (!styleEl) {\r\n styleEl = doc.createElement(\"style\");\r\n styleEl.id = styleId;\r\n doc.head.appendChild(styleEl);\r\n }\r\n styleEl.textContent = css;\r\n}\r\n","/**\r\n * Inject and render the formatting toolbar into the document\r\n *\r\n * Creates a sticky toolbar with:\r\n * - Text formatting buttons (Bold, Italic, Underline)\r\n * - Font and size selectors\r\n * - Undo/Redo buttons\r\n * - Link insertion button\r\n * - Color pickers (text and highlight)\r\n * - Text alignment buttons\r\n * - Selected element info display\r\n *\r\n * The toolbar is re-injected on every selection change to update state\r\n * (this is optimized for small toolbar size and few state changes)\r\n *\r\n * @param doc - Document to inject toolbar into\r\n * @param options - Toolbar configuration and callbacks\r\n */\r\nimport {\r\n TOOLBAR_ID,\r\n LABEL_BOLD,\r\n LABEL_ITALIC,\r\n LABEL_UNDERLINE,\r\n LABEL_STRIKETHROUGH,\r\n LABEL_UNDO,\r\n LABEL_REDO,\r\n LABEL_LINK,\r\n LABEL_ALIGN_LEFT,\r\n LABEL_ALIGN_CENTER,\r\n LABEL_ALIGN_RIGHT,\r\n FONT_OPTIONS,\r\n SIZE_OPTIONS,\r\n FORMAT_OPTIONS,\r\n} from \"../core/constants\";\r\nimport { makeColorInput } from \"./color\";\r\nimport { setupOverflow } from \"./overflow\";\r\nimport {\r\n makeButton as _makeButton,\r\n makeGroup as _makeGroup,\r\n makeSep as _makeSep,\r\n} from \"./buttons\";\r\nimport { makeSelect as _makeSelect } from \"./selects\";\r\nimport { setupNavigation } from \"./navigation\";\r\n\r\nexport function injectToolbar(\r\n doc: Document,\r\n options: {\r\n onCommand: (command: string, value?: string) => void;\r\n canUndo: () => boolean;\r\n canRedo: () => boolean;\r\n onUndo: () => void;\r\n onRedo: () => void;\r\n getFormatState: () => {\r\n bold: boolean;\r\n italic: boolean;\r\n underline: boolean;\r\n foreColor?: string | null;\r\n hiliteColor?: string | null;\r\n fontName?: string | null;\r\n fontSize?: string | null;\r\n formatBlock?: string | null;\r\n };\r\n getSelectedElementInfo: () => string | null;\r\n }\r\n) {\r\n const existing = doc.getElementById(TOOLBAR_ID);\r\n if (existing) existing.remove();\r\n\r\n const toolbar = doc.createElement(\"div\");\r\n toolbar.id = TOOLBAR_ID;\r\n // Accessibility: expose as a toolbar region and provide a readable label\r\n toolbar.setAttribute(\"role\", \"toolbar\");\r\n toolbar.setAttribute(\"aria-label\", \"Rich text editor toolbar\");\r\n\r\n // Styling moved to injected stylesheet (see src/dom/styles.ts)\r\n\r\n const makeButton = (\r\n label: string,\r\n title: string,\r\n command: string,\r\n value?: string,\r\n isActive?: boolean,\r\n disabled?: boolean\r\n ) =>\r\n _makeButton(\r\n doc,\r\n { onCommand: options.onCommand },\r\n label,\r\n title,\r\n command,\r\n value,\r\n isActive,\r\n disabled\r\n );\r\n\r\n const makeSelect = (\r\n title: string,\r\n command: string,\r\n optionsList: { label: string; value: string }[],\r\n initialValue?: string | null\r\n ) =>\r\n _makeSelect(\r\n doc,\r\n { onCommand: options.onCommand },\r\n title,\r\n command,\r\n optionsList,\r\n initialValue\r\n );\r\n\r\n // Color input helper moved to ./color.ts\r\n\r\n const format = options.getFormatState();\r\n // Helpers: group wrapper and separator element\r\n const makeGroup = () => _makeGroup(doc);\r\n const makeSep = () => _makeSep(doc);\r\n\r\n // Section 1: Undo / Redo\r\n const undoBtn = makeButton(\r\n LABEL_UNDO,\r\n \"Undo\",\r\n \"undo\",\r\n undefined,\r\n false,\r\n !options.canUndo()\r\n );\r\n // Undo/Redo are handled by the history module — call handlers directly\r\n undoBtn.onclick = () => options.onUndo();\r\n\r\n const redoBtn = makeButton(\r\n LABEL_REDO,\r\n \"Redo\",\r\n \"redo\",\r\n undefined,\r\n false,\r\n !options.canRedo()\r\n );\r\n redoBtn.onclick = () => options.onRedo();\r\n\r\n const grp1 = makeGroup();\r\n grp1.appendChild(undoBtn);\r\n grp1.appendChild(redoBtn);\r\n toolbar.appendChild(grp1);\r\n toolbar.appendChild(makeSep());\r\n\r\n // Section 2: Format, Font & Size\r\n const grp2 = makeGroup();\r\n grp2.className = \"toolbar-group collapse-on-small\";\r\n grp2.appendChild(\r\n makeSelect(\r\n \"Format\",\r\n \"formatBlock\",\r\n FORMAT_OPTIONS,\r\n (format as any).formatBlock\r\n )\r\n );\r\n grp2.appendChild(\r\n makeSelect(\"Font\", \"fontName\", FONT_OPTIONS, (format as any).fontName)\r\n );\r\n grp2.appendChild(\r\n makeSelect(\"Size\", \"fontSize\", SIZE_OPTIONS, (format as any).fontSize)\r\n );\r\n toolbar.appendChild(grp2);\r\n toolbar.appendChild(makeSep());\r\n\r\n // Section 3: Bold, Italic, Underline, Strikethrough\r\n const grp3 = makeGroup();\r\n grp3.appendChild(\r\n makeButton(LABEL_BOLD, \"Bold\", \"bold\", undefined, format.bold)\r\n );\r\n grp3.appendChild(\r\n makeButton(LABEL_ITALIC, \"Italic\", \"italic\", undefined, format.italic)\r\n );\r\n grp3.appendChild(\r\n makeButton(\r\n LABEL_UNDERLINE,\r\n \"Underline\",\r\n \"underline\",\r\n undefined,\r\n format.underline\r\n )\r\n );\r\n grp3.appendChild(makeButton(LABEL_STRIKETHROUGH, \"Strikethrough\", \"strike\"));\r\n toolbar.appendChild(grp3);\r\n toolbar.appendChild(makeSep());\r\n\r\n // Section 4: Alignment\r\n const grp4 = makeGroup();\r\n grp4.appendChild(makeButton(LABEL_ALIGN_LEFT, \"Align left\", \"align\", \"left\"));\r\n grp4.appendChild(\r\n makeButton(LABEL_ALIGN_CENTER, \"Align center\", \"align\", \"center\")\r\n );\r\n grp4.appendChild(\r\n makeButton(LABEL_ALIGN_RIGHT, \"Align right\", \"align\", \"right\")\r\n );\r\n toolbar.appendChild(grp4);\r\n toolbar.appendChild(makeSep());\r\n\r\n // Section 5: Colors\r\n const grp5 = makeGroup();\r\n grp5.className = \"toolbar-group collapse-on-small\";\r\n grp5.appendChild(\r\n makeColorInput(\r\n doc,\r\n options,\r\n \"Text color\",\r\n \"foreColor\",\r\n (format as any).foreColor\r\n )\r\n );\r\n grp5.appendChild(\r\n makeColorInput(\r\n doc,\r\n options,\r\n \"Highlight color\",\r\n \"hiliteColor\",\r\n (format as any).hiliteColor\r\n )\r\n );\r\n toolbar.appendChild(grp5);\r\n toolbar.appendChild(makeSep());\r\n\r\n // Section 6: Link\r\n const grp6 = makeGroup();\r\n grp6.className = \"toolbar-group collapse-on-small\";\r\n grp6.appendChild(makeButton(LABEL_LINK, \"Insert link\", \"link\"));\r\n toolbar.appendChild(grp6);\r\n\r\n // Overflow UI extracted to ./overflow.ts — set up with helper functions\r\n setupOverflow(doc, toolbar, options, format, {\r\n makeSelect,\r\n makeColorInput: (title: string, command: string, initial?: string) =>\r\n makeColorInput(doc, options, title, command, initial),\r\n makeButton,\r\n makeGroup,\r\n });\r\n\r\n // const info = doc.createElement(\"span\");\r\n // // Info styles moved to stylesheet\r\n // info.textContent = options.getSelectedElementInfo()\r\n // ? `Selected: ${options.getSelectedElementInfo()}`\r\n // : \"Click any highlighted element to edit\";\r\n // toolbar.appendChild(info);\r\n\r\n // Keyboard navigation for toolbar\r\n setupNavigation(toolbar);\r\n\r\n doc.body.insertBefore(toolbar, doc.body.firstChild);\r\n}\r\n","export function makeColorInput(\r\n doc: Document,\r\n options: { onCommand: (command: string, value?: string) => void },\r\n title: string,\r\n command: string,\r\n initialColor?: string\r\n) {\r\n const input = doc.createElement(\"input\");\r\n input.type = \"color\";\r\n input.className = \"toolbar-color-input\";\r\n const wrapper = doc.createElement(\"label\");\r\n wrapper.className = \"color-label\";\r\n wrapper.appendChild(doc.createTextNode(title + \" \"));\r\n wrapper.appendChild(input);\r\n let savedRange: Range | null = null;\r\n input.addEventListener(\"pointerdown\", () => {\r\n const s = doc.getSelection();\r\n if (s && s.rangeCount) savedRange = s.getRangeAt(0).cloneRange();\r\n });\r\n input.onchange = (e: Event) => {\r\n try {\r\n const s = doc.getSelection();\r\n if (savedRange && s) {\r\n s.removeAllRanges();\r\n s.addRange(savedRange);\r\n }\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n options.onCommand(command, (e.target as HTMLInputElement).value);\r\n savedRange = null;\r\n };\r\n\r\n function rgbToHex(input?: string | null): string | null {\r\n if (!input) return null;\r\n const v = input.trim();\r\n if (v.startsWith(\"#\")) {\r\n if (v.length === 4) {\r\n return (\"#\" + v[1] + v[1] + v[2] + v[2] + v[3] + v[3]).toLowerCase();\r\n }\r\n return v.toLowerCase();\r\n }\r\n const rgbMatch = v.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/i);\r\n if (rgbMatch) {\r\n const r = Number(rgbMatch[1]);\r\n const g = Number(rgbMatch[2]);\r\n const b = Number(rgbMatch[3]);\r\n const hex =\r\n \"#\" +\r\n [r, g, b]\r\n .map((n) => n.toString(16).padStart(2, \"0\"))\r\n .join(\"\")\r\n .toLowerCase();\r\n return hex;\r\n }\r\n return null;\r\n }\r\n\r\n const setColor = (val?: string) => {\r\n if (!val) return;\r\n const hex = rgbToHex(val) || val;\r\n try {\r\n if (\r\n hex &&\r\n hex.startsWith(\"#\") &&\r\n (input as HTMLInputElement).value !== hex\r\n ) {\r\n (input as HTMLInputElement).value = hex;\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n };\r\n\r\n if (initialColor) setColor(initialColor);\r\n input.addEventListener(\"input\", (e: Event) => {\r\n const val = (e.target as HTMLInputElement).value;\r\n setColor(val);\r\n });\r\n input.title = title;\r\n input.setAttribute(\"aria-label\", title);\r\n return wrapper;\r\n}\r\n","export function setupOverflow(\r\n doc: Document,\r\n toolbar: HTMLElement,\r\n options: {\r\n onCommand: (command: string, value?: string) => void;\r\n onUndo: () => void;\r\n onRedo: () => void;\r\n canUndo: () => boolean;\r\n canRedo: () => boolean;\r\n },\r\n format: any,\r\n helpers: {\r\n makeSelect: (\r\n title: string,\r\n command: string,\r\n optionsList: { label: string; value: string }[],\r\n initialValue?: string | null\r\n ) => HTMLElement;\r\n makeColorInput: (\r\n title: string,\r\n command: string,\r\n initialColor?: string\r\n ) => HTMLElement;\r\n makeButton: (\r\n label: string,\r\n title: string,\r\n command: string,\r\n value?: string,\r\n isActive?: boolean,\r\n disabled?: boolean\r\n ) => HTMLElement;\r\n makeGroup: () => HTMLElement;\r\n }\r\n) {\r\n const overflowBtn = doc.createElement(\"button\");\r\n overflowBtn.type = \"button\";\r\n overflowBtn.className = \"toolbar-overflow-btn\";\r\n overflowBtn.title = \"More\";\r\n overflowBtn.setAttribute(\"aria-label\", \"More toolbar actions\");\r\n overflowBtn.setAttribute(\"aria-haspopup\", \"true\");\r\n overflowBtn.setAttribute(\"aria-expanded\", \"false\");\r\n overflowBtn.tabIndex = 0;\r\n overflowBtn.innerHTML = \"⋯\";\r\n\r\n const overflowMenu = doc.createElement(\"div\");\r\n overflowMenu.className = \"toolbar-overflow-menu\";\r\n overflowMenu.setAttribute(\"role\", \"menu\");\r\n overflowMenu.hidden = true;\r\n\r\n function openOverflow() {\r\n overflowMenu.hidden = false;\r\n overflowBtn.setAttribute(\"aria-expanded\", \"true\");\r\n const first = overflowMenu.querySelector<HTMLElement>(\r\n \"button, select, input\"\r\n );\r\n first?.focus();\r\n }\r\n function closeOverflow() {\r\n overflowMenu.hidden = true;\r\n overflowBtn.setAttribute(\"aria-expanded\", \"false\");\r\n overflowBtn.focus();\r\n }\r\n\r\n overflowBtn.addEventListener(\"click\", () => {\r\n if (overflowMenu.hidden) openOverflow();\r\n else closeOverflow();\r\n });\r\n overflowBtn.addEventListener(\"keydown\", (e: KeyboardEvent) => {\r\n if (e.key === \"Enter\" || e.key === \" \") {\r\n e.preventDefault();\r\n if (overflowMenu.hidden) openOverflow();\r\n else closeOverflow();\r\n }\r\n if (e.key === \"ArrowDown\") {\r\n e.preventDefault();\r\n if (overflowMenu.hidden) openOverflow();\r\n }\r\n });\r\n\r\n overflowMenu.addEventListener(\"keydown\", (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") {\r\n e.preventDefault();\r\n closeOverflow();\r\n }\r\n });\r\n doc.addEventListener(\"pointerdown\", (ev: PointerEvent) => {\r\n if (\r\n !overflowMenu.hidden &&\r\n !overflowMenu.contains(ev.target as Node) &&\r\n ev.target !== overflowBtn\r\n ) {\r\n closeOverflow();\r\n }\r\n });\r\n\r\n // Populate overflow menu with duplicates of the collapsed controls\r\n overflowMenu.appendChild(\r\n helpers.makeSelect(\r\n \"Format\",\r\n \"formatBlock\",\r\n (window as any).RHE_FORMAT_OPTIONS || [],\r\n (format as any).formatBlock\r\n )\r\n );\r\n overflowMenu.appendChild(\r\n helpers.makeSelect(\r\n \"Font\",\r\n \"fontName\",\r\n (window as any).RHE_FONT_OPTIONS || [],\r\n (format as any).fontName\r\n )\r\n );\r\n overflowMenu.appendChild(\r\n helpers.makeSelect(\r\n \"Size\",\r\n \"fontSize\",\r\n (window as any).RHE_SIZE_OPTIONS || [],\r\n (format as any).fontSize\r\n )\r\n );\r\n overflowMenu.appendChild(\r\n helpers.makeColorInput(\"Text color\", \"foreColor\", (format as any).foreColor)\r\n );\r\n overflowMenu.appendChild(\r\n helpers.makeColorInput(\r\n \"Highlight color\",\r\n \"hiliteColor\",\r\n (format as any).hiliteColor\r\n )\r\n );\r\n overflowMenu.appendChild(helpers.makeButton(\"Link\", \"Insert link\", \"link\"));\r\n\r\n const overflowWrap = helpers.makeGroup();\r\n overflowWrap.className = \"toolbar-group toolbar-overflow-wrap\";\r\n overflowWrap.appendChild(overflowBtn);\r\n overflowWrap.appendChild(overflowMenu);\r\n toolbar.appendChild(overflowWrap);\r\n}\r\n","export function makeButton(\r\n doc: Document,\r\n options: { onCommand: (command: string, value?: string) => void },\r\n label: string,\r\n title: string,\r\n command: string,\r\n value?: string,\r\n isActive?: boolean,\r\n disabled?: boolean\r\n) {\r\n const btn = doc.createElement(\"button\");\r\n btn.type = \"button\";\r\n if (label && label.trim().startsWith(\"<\")) {\r\n btn.innerHTML = label;\r\n } else {\r\n btn.textContent = label;\r\n }\r\n btn.title = title;\r\n btn.setAttribute(\"aria-label\", title);\r\n if (typeof isActive !== \"undefined\")\r\n btn.setAttribute(\"aria-pressed\", String(!!isActive));\r\n btn.tabIndex = 0;\r\n if (disabled) btn.disabled = true;\r\n btn.onclick = () => options.onCommand(command, value);\r\n btn.addEventListener(\"keydown\", (ev: KeyboardEvent) => {\r\n if (ev.key === \"Enter\" || ev.key === \" \") {\r\n ev.preventDefault();\r\n btn.click();\r\n }\r\n });\r\n return btn;\r\n}\r\n\r\nexport function makeGroup(doc: Document) {\r\n const g = doc.createElement(\"div\");\r\n g.className = \"toolbar-group\";\r\n return g;\r\n}\r\n\r\nexport function makeSep(doc: Document) {\r\n const s = doc.createElement(\"div\");\r\n s.className = \"toolbar-sep\";\r\n return s;\r\n}\r\n","export function makeSelect(\r\n doc: Document,\r\n options: { onCommand: (command: string, value?: string) => void },\r\n title: string,\r\n command: string,\r\n optionsList: { label: string; value: string }[],\r\n initialValue?: string | null\r\n) {\r\n const select = doc.createElement(\"select\");\r\n select.title = title;\r\n select.setAttribute(\"aria-label\", title);\r\n select.appendChild(new Option(title, \"\", true, true));\r\n for (const opt of optionsList) {\r\n select.appendChild(new Option(opt.label, opt.value));\r\n }\r\n try {\r\n if (initialValue) select.value = initialValue;\r\n } catch (e) {\r\n /* ignore invalid value */\r\n }\r\n select.onchange = (e: Event) => {\r\n const val = (e.target as HTMLSelectElement).value;\r\n options.onCommand(command, val);\r\n select.selectedIndex = 0;\r\n };\r\n return select;\r\n}\r\n","export function setupNavigation(toolbar: HTMLElement) {\r\n toolbar.addEventListener(\"keydown\", (e: KeyboardEvent) => {\r\n const focusable = Array.from(\r\n toolbar.querySelectorAll<HTMLElement>(\"button, select, input, [tabindex]\")\r\n ).filter((el) => !el.hasAttribute(\"disabled\"));\r\n if (!focusable.length) return;\r\n const idx = focusable.indexOf(document.activeElement as HTMLElement);\r\n if (e.key === \"ArrowRight\") {\r\n e.preventDefault();\r\n const next =\r\n focusable[Math.min(focusable.length - 1, Math.max(0, idx + 1))];\r\n next?.focus();\r\n } else if (e.key === \"ArrowLeft\") {\r\n e.preventDefault();\r\n const prev = focusable[Math.max(0, idx - 1)] || focusable[0];\r\n prev?.focus();\r\n } else if (e.key === \"Home\") {\r\n e.preventDefault();\r\n focusable[0].focus();\r\n } else if (e.key === \"End\") {\r\n e.preventDefault();\r\n focusable[focusable.length - 1].focus();\r\n }\r\n });\r\n}\r\n","import {\r\n _getCurrentEditable,\r\n _setCurrentEditable,\r\n pushStandaloneSnapshot,\r\n _getUndoStack,\r\n _getRedoStack,\r\n} from \"../core/state\";\r\nimport { isEditableCandidate } from \"./candidates\";\r\nimport { injectToolbar } from \"../toolbar/toolbar\";\r\nimport { computeFormatState, getElementLabel } from \"./format\";\r\nimport { handleToolbarCommand, handleUndo, handleRedo } from \"../core/commands\";\r\nimport { CLASS_ACTIVE } from \"../core/constants\";\r\n\r\n/**\r\n * Attach DOM event handlers to the document\r\n *\r\n * Handles:\r\n * - Click: Enables editing on valid elements\r\n * - Selection change: Updates toolbar state\r\n * - Input: Creates undo/redo snapshots\r\n *\r\n * @param doc - Document to attach handlers to\r\n */\r\nexport function attachStandaloneHandlers(doc: Document) {\r\n // Assign stable data-rhe-id markers to likely editable candidates so\r\n // snapshots include identifiers for selective restoration. Limit the\r\n // selector to common content containers to avoid a full DOM walk.\r\n try {\r\n const selector = [\r\n \"p\",\r\n \"div\",\r\n \"section\",\r\n \"article\",\r\n \"header\",\r\n \"footer\",\r\n \"aside\",\r\n \"nav\",\r\n \"span\",\r\n \"h1\",\r\n \"h2\",\r\n \"h3\",\r\n \"h4\",\r\n \"h5\",\r\n \"h6\",\r\n \"li\",\r\n \"figure\",\r\n \"figcaption\",\r\n \"blockquote\",\r\n \"pre\",\r\n \"code\",\r\n ].join(\",\");\r\n const candidates = Array.from(\r\n doc.querySelectorAll<HTMLElement>(selector)\r\n ).filter((el) => isEditableCandidate(el));\r\n candidates.forEach((target) => {\r\n if (!target.hasAttribute(\"data-rhe-id\")) {\r\n const uid = `rhe-init-${Date.now()}-${Math.random()\r\n .toString(36)\r\n .slice(2, 7)}`;\r\n try {\r\n target.setAttribute(\"data-rhe-id\", uid);\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n }\r\n });\r\n } catch (err) {\r\n /* ignore initialization errors */\r\n }\r\n\r\n doc.addEventListener(\r\n \"click\",\r\n (e) => {\r\n const target = e.target as HTMLElement;\r\n if (!isEditableCandidate(target)) return;\r\n if (_getCurrentEditable() && _getCurrentEditable() !== target) {\r\n _getCurrentEditable()?.removeAttribute(\"contenteditable\");\r\n _getCurrentEditable()?.classList.remove(CLASS_ACTIVE);\r\n }\r\n // Ensure the editable element has a stable identifier so snapshots\r\n // can restore only the editable region without touching the rest\r\n // of the page (header, nav, scripts, etc.). Use a data attribute\r\n // to avoid clashing with page ids.\r\n if (!target.hasAttribute(\"data-rhe-id\")) {\r\n const uid = `rhe-${Date.now()}-${Math.random()\r\n .toString(36)\r\n .slice(2, 7)}`;\r\n try {\r\n target.setAttribute(\"data-rhe-id\", uid);\r\n } catch (err) {\r\n /* ignore attribute set errors */\r\n }\r\n }\r\n _setCurrentEditable(target);\r\n target.classList.add(CLASS_ACTIVE);\r\n target.setAttribute(\"contenteditable\", \"true\");\r\n target.focus();\r\n },\r\n true\r\n );\r\n doc.addEventListener(\"selectionchange\", () => {\r\n injectToolbar(doc, {\r\n onCommand: handleToolbarCommand,\r\n canUndo: () => _getUndoStack().length > 1,\r\n canRedo: () => _getRedoStack().length > 0,\r\n onUndo: handleUndo,\r\n onRedo: handleRedo,\r\n getFormatState: () => computeFormatState(doc),\r\n getSelectedElementInfo: () => getElementLabel(_getCurrentEditable()),\r\n });\r\n });\r\n doc.addEventListener(\"input\", () => pushStandaloneSnapshot(), true);\r\n\r\n // Keyboard shortcuts for common formatting and undo/redo\r\n doc.addEventListener(\r\n \"keydown\",\r\n (e) => {\r\n const meta = e.ctrlKey || e.metaKey;\r\n if (!meta) return;\r\n const key = e.key.toLowerCase();\r\n // Bold: Ctrl/Cmd+B\r\n if (key === \"b\") {\r\n e.preventDefault();\r\n handleToolbarCommand(\"bold\");\r\n return;\r\n }\r\n // Italic: Ctrl/Cmd+I\r\n if (key === \"i\") {\r\n e.preventDefault();\r\n handleToolbarCommand(\"italic\");\r\n return;\r\n }\r\n // Underline: Ctrl/Cmd+U\r\n if (key === \"u\") {\r\n e.preventDefault();\r\n handleToolbarCommand(\"underline\");\r\n return;\r\n }\r\n // Undo: Ctrl/Cmd+Z\r\n if (key === \"z\") {\r\n e.preventDefault();\r\n // If Shift is pressed, treat as redo\r\n if (e.shiftKey) {\r\n handleRedo();\r\n } else {\r\n handleUndo();\r\n }\r\n return;\r\n }\r\n // Redo: Ctrl/Cmd+Y\r\n if (key === \"y\") {\r\n e.preventDefault();\r\n handleRedo();\r\n return;\r\n }\r\n },\r\n true\r\n );\r\n}\r\n","/**\r\n * Check if an element can be edited\r\n *\r\n * Valid elements: Text container tags (p, div, section, etc.)\r\n * Invalid elements: HTML structure tags, inputs, scripts, styles\r\n *\r\n * @param el - Element to check\r\n * @returns True if element is a valid editable candidate\r\n */\r\nexport function isEditableCandidate(el: HTMLElement | null): boolean {\r\n if (!el) return false;\r\n const tag = el.tagName;\r\n const DISALLOWED = [\r\n \"HTML\",\r\n \"HEAD\",\r\n \"BODY\",\r\n \"SCRIPT\",\r\n \"STYLE\",\r\n \"LINK\",\r\n \"META\",\r\n \"NOSCRIPT\",\r\n ];\r\n if (DISALLOWED.includes(tag)) return false;\r\n if (tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\") return false;\r\n return true;\r\n}\r\n","/**\r\n * Compute the current formatting state of selected text\r\n *\r\n * Detects bold, italic, and underline formatting based on:\r\n * - DOM element tags (strong, em, u)\r\n * - CSS computed styles (fontWeight, fontStyle, textDecoration)\r\n *\r\n * @param doc - Document context\r\n * @returns Object with boolean flags for bold, italic, underline\r\n */\r\nexport function computeFormatState(doc: Document): {\r\n bold: boolean;\r\n italic: boolean;\r\n underline: boolean;\r\n foreColor: string | null;\r\n hiliteColor: string | null;\r\n fontName: string | null;\r\n fontSize: string | null;\r\n formatBlock: string | null;\r\n} {\r\n try {\r\n const s = doc.getSelection();\r\n let el: HTMLElement | null = null;\r\n if (s && s.anchorNode)\r\n el =\r\n s.anchorNode.nodeType === Node.ELEMENT_NODE\r\n ? (s.anchorNode as HTMLElement)\r\n : (s.anchorNode.parentElement as HTMLElement);\r\n if (!el)\r\n return {\r\n bold: false,\r\n italic: false,\r\n underline: false,\r\n foreColor: null,\r\n hiliteColor: null,\r\n fontName: null,\r\n fontSize: null,\r\n formatBlock: null,\r\n };\r\n const computed = doc.defaultView?.getComputedStyle(el) as\r\n | CSSStyleDeclaration\r\n | undefined;\r\n const bold = !!(\r\n el.closest(\"strong, b\") ||\r\n (computed &&\r\n (computed.fontWeight === \"700\" || Number(computed.fontWeight) >= 700))\r\n );\r\n const italic = !!(\r\n el.closest(\"em, i\") ||\r\n (computed && computed.fontStyle === \"italic\")\r\n );\r\n const underline = !!(\r\n el.closest(\"u\") ||\r\n (computed && (computed.textDecorationLine || \"\").includes(\"underline\"))\r\n );\r\n // Try to detect text color and highlight (background) color at the selection\r\n const foreColor =\r\n (el.closest(\"font[color]\") as HTMLElement | null)?.getAttribute(\r\n \"color\"\r\n ) ||\r\n (computed && computed.color) ||\r\n null;\r\n // Background color may come from a <mark> element or computed background-color\r\n const mark = el.closest(\"mark\") as HTMLElement | null;\r\n const hiliteColor =\r\n (mark && (mark.getAttribute(\"style\") || \"\")) ||\r\n (computed &&\r\n computed.backgroundColor &&\r\n computed.backgroundColor !== \"rgba(0, 0, 0, 0)\"\r\n ? computed.backgroundColor\r\n : null);\r\n\r\n // detect font name + size from computed style\r\n const fontName = (computed && computed.fontFamily) || null;\r\n const fontSize = (computed && computed.fontSize) || null;\r\n // detect block ancestor (paragraph, heading etc.)\r\n let blockEl: HTMLElement | null = el;\r\n while (blockEl && blockEl.parentElement) {\r\n const tag = blockEl.tagName;\r\n if (\r\n [\r\n \"P\",\r\n \"DIV\",\r\n \"SECTION\",\r\n \"ARTICLE\",\r\n \"LI\",\r\n \"TD\",\r\n \"BLOCKQUOTE\",\r\n \"H1\",\r\n \"H2\",\r\n \"H3\",\r\n \"H4\",\r\n \"H5\",\r\n \"H6\",\r\n ].includes(tag)\r\n ) {\r\n break;\r\n }\r\n blockEl = blockEl.parentElement as HTMLElement | null;\r\n }\r\n const formatBlock = blockEl ? blockEl.tagName.toLowerCase() : null;\r\n\r\n return {\r\n bold,\r\n italic,\r\n underline,\r\n foreColor,\r\n hiliteColor,\r\n fontName,\r\n fontSize,\r\n formatBlock,\r\n };\r\n } catch (err) {\r\n return {\r\n bold: false,\r\n italic: false,\r\n underline: false,\r\n foreColor: null,\r\n hiliteColor: null,\r\n fontName: null,\r\n fontSize: null,\r\n formatBlock: null,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Get a human-readable label for an element\r\n *\r\n * Format: `tagname#id.class`\r\n * Example: `p#intro.highlight` or `div.container`\r\n *\r\n * @param el - HTML element to label\r\n * @returns Label string or null if element is null\r\n */\r\nexport function getElementLabel(el: HTMLElement | null): string | null {\r\n if (!el) return null;\r\n const id = el.id ? `#${el.id}` : \"\";\r\n const cls = el.className ? `.${String(el.className).split(\" \")[0]}` : \"\";\r\n const tag = el.tagName.toLowerCase();\r\n return `${tag}${id}${cls}`;\r\n}\r\n","export function sanitizeURL(url: string): string {\r\n if (!url) return \"\";\r\n const trimmed = url.trim();\r\n if (!trimmed) return \"\";\r\n if (\r\n trimmed.toLowerCase().startsWith(\"javascript:\") ||\r\n trimmed.toLowerCase().startsWith(\"data:\")\r\n ) {\r\n console.warn(\"Blocked potentially dangerous URL protocol\");\r\n return \"\";\r\n }\r\n if (!trimmed.startsWith(\"http\") && !trimmed.startsWith(\"#\")) {\r\n return \"https://\" + trimmed;\r\n }\r\n return trimmed;\r\n}\r\n","import {\r\n _getDoc,\r\n _getUndoStack,\r\n _getRedoStack,\r\n _setUndoStack,\r\n _setRedoStack,\r\n} from \"./state\";\r\n\r\nimport { sanitizeHtml } from \"../utils/sanitize\";\r\nimport { injectStyles } from \"../dom/styles\";\r\n\r\nexport function handleUndo() {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) {\r\n console.warn(\r\n \"[rich-html-editor] handleUndo called before initialization\"\r\n );\r\n return;\r\n }\r\n if (_getUndoStack().length < 2) return;\r\n const undoStack = _getUndoStack();\r\n const redoStack = _getRedoStack();\r\n const current = undoStack.pop()!;\r\n redoStack.push(current);\r\n const prev = undoStack[undoStack.length - 1];\r\n if (!doc.documentElement) {\r\n throw new Error(\"Document is missing documentElement\");\r\n }\r\n // Sanitize the snapshot and extract only the body content so we\r\n // avoid overwriting head/link/style nodes that may contain page\r\n // or editor styles. Replacing only `document.body` preserves those\r\n // nodes while still restoring user content.\r\n const safe = sanitizeHtml(prev.replace(/^<!doctype html>\\n?/i, \"\"), doc);\r\n try {\r\n const parser = new DOMParser();\r\n const parsed = parser.parseFromString(safe, \"text/html\");\r\n if (parsed && parsed.body && doc.body) {\r\n // Prefer selective restoration: if the snapshot contains elements\r\n // marked with `data-rhe-id`, restore only those elements so we do\r\n // not clobber page-level UI (headers, tabs, carousel scripts).\r\n const parsedEls = parsed.body.querySelectorAll(\"[data-rhe-id]\");\r\n if (parsedEls && parsedEls.length) {\r\n const loadPromises: Promise<void>[] = [];\r\n parsedEls.forEach((pe) => {\r\n const id = pe.getAttribute(\"data-rhe-id\");\r\n if (!id) return;\r\n const local = doc.body.querySelector(`[data-rhe-id=\"${id}\"]`);\r\n if (!local) return;\r\n // Copy non-identifying attributes from parsed element to local\r\n try {\r\n Array.from(local.attributes).forEach((a) => {\r\n if (a.name !== \"data-rhe-id\") local.removeAttribute(a.name);\r\n });\r\n Array.from(pe.attributes).forEach((a) => {\r\n if (a.name !== \"data-rhe-id\")\r\n local.setAttribute(a.name, a.value);\r\n });\r\n } catch (err) {\r\n /* ignore attribute copy errors */\r\n }\r\n // Replace innerHTML of the editable region only\r\n try {\r\n local.innerHTML = pe.innerHTML;\r\n } catch (err) {\r\n /* ignore innerHTML set errors */\r\n }\r\n // Recreate preserved script placeholders inside the parsed element\r\n try {\r\n const placeholders = pe.querySelectorAll(\"[data-rhe-script]\");\r\n placeholders.forEach((ph) => {\r\n const encoded = ph.getAttribute(\"data-rhe-script\") || \"\";\r\n let code = \"\";\r\n try {\r\n code =\r\n typeof atob !== \"undefined\"\r\n ? decodeURIComponent(escape(atob(encoded)))\r\n : decodeURIComponent(encoded);\r\n } catch (e) {\r\n try {\r\n code = decodeURIComponent(encoded);\r\n } catch (er) {\r\n code = \"\";\r\n }\r\n }\r\n const attrsRaw = ph.getAttribute(\"data-rhe-script-attrs\");\r\n let attrs: Record<string, string> = {};\r\n if (attrsRaw) {\r\n try {\r\n attrs = JSON.parse(decodeURIComponent(attrsRaw));\r\n } catch (e) {\r\n attrs = {};\r\n }\r\n }\r\n const parentId = ph.getAttribute(\"data-rhe-script-parent\");\r\n try {\r\n const s = doc.createElement(\"script\");\r\n try {\r\n s.type = \"text/javascript\";\r\n (s as any).async = false;\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n Object.keys(attrs).forEach((k) =>\r\n s.setAttribute(k, attrs[k])\r\n );\r\n if (attrs.src) {\r\n const p = new Promise<void>((resolve) => {\r\n s.addEventListener(\"load\", () => resolve());\r\n s.addEventListener(\"error\", () => resolve());\r\n });\r\n loadPromises.push(p);\r\n s.src = attrs.src;\r\n } else {\r\n s.textContent = code;\r\n }\r\n if (parentId === \"head\") {\r\n doc.head.appendChild(s);\r\n } else {\r\n const target = doc.body.querySelector(\r\n `[data-rhe-id=\"${parentId}\"]`\r\n );\r\n if (target) target.appendChild(s);\r\n else doc.body.appendChild(s);\r\n }\r\n } catch (e) {\r\n /* ignore script injection errors */\r\n }\r\n });\r\n } catch (e) {\r\n /* ignore placeholder processing errors */\r\n }\r\n });\r\n try {\r\n if (loadPromises.length) {\r\n const waiter = (Promise as any).allSettled\r\n ? (Promise as any).allSettled(loadPromises)\r\n : Promise.all(\r\n loadPromises.map((p) => p.catch(() => undefined))\r\n );\r\n waiter.then(() => {\r\n try {\r\n doc.dispatchEvent(new Event(\"rhe:scripts-restored\"));\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n });\r\n } else {\r\n try {\r\n doc.dispatchEvent(new Event(\"rhe:scripts-restored\"));\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n } else {\r\n // No markers present — fallback to previous behavior of replacing\r\n // the body contents. This preserves backward compatibility.\r\n doc.body.innerHTML = parsed.body.innerHTML;\r\n }\r\n } else {\r\n // Fallback to replacing the whole documentElement if body is missing\r\n doc.documentElement.innerHTML = safe;\r\n }\r\n } catch (err) {\r\n // On any parse error, fall back to previous behavior\r\n doc.documentElement.innerHTML = safe;\r\n }\r\n\r\n // Re-inject editor styles (toolbar/style) and notify listeners so the\r\n // toolbar is restored and selectionchange handlers run.\r\n injectStyles(doc);\r\n try {\r\n doc.dispatchEvent(new Event(\"selectionchange\"));\r\n } catch (err) {\r\n /* ignore dispatch errors */\r\n }\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Undo failed:\", message);\r\n }\r\n}\r\n\r\nexport function handleRedo() {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) {\r\n console.warn(\r\n \"[rich-html-editor] handleRedo called before initialization\"\r\n );\r\n return;\r\n }\r\n if (!_getRedoStack().length) return;\r\n const undoStack = _getUndoStack();\r\n const redoStack = _getRedoStack();\r\n const next = redoStack.pop()!;\r\n undoStack.push(next);\r\n if (!doc.documentElement) {\r\n throw new Error(\"Document is missing documentElement\");\r\n }\r\n const safeNext = sanitizeHtml(\r\n next.replace(/^<!doctype html>\\n?/i, \"\"),\r\n doc\r\n );\r\n try {\r\n const parser = new DOMParser();\r\n const parsed = parser.parseFromString(safeNext, \"text/html\");\r\n if (parsed && parsed.body && doc.body) {\r\n const parsedEls = parsed.body.querySelectorAll(\"[data-rhe-id]\");\r\n if (parsedEls && parsedEls.length) {\r\n const loadPromises: Promise<void>[] = [];\r\n parsedEls.forEach((pe) => {\r\n const id = pe.getAttribute(\"data-rhe-id\");\r\n if (!id) return;\r\n const local = doc.body.querySelector(`[data-rhe-id=\"${id}\"]`);\r\n if (!local) return;\r\n try {\r\n Array.from(local.attributes).forEach((a) => {\r\n if (a.name !== \"data-rhe-id\") local.removeAttribute(a.name);\r\n });\r\n Array.from(pe.attributes).forEach((a) => {\r\n if (a.name !== \"data-rhe-id\")\r\n local.setAttribute(a.name, a.value);\r\n });\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n try {\r\n local.innerHTML = pe.innerHTML;\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n try {\r\n const placeholders = pe.querySelectorAll(\"[data-rhe-script]\");\r\n placeholders.forEach((ph) => {\r\n const encoded = ph.getAttribute(\"data-rhe-script\") || \"\";\r\n let code = \"\";\r\n try {\r\n code =\r\n typeof atob !== \"undefined\"\r\n ? decodeURIComponent(escape(atob(encoded)))\r\n : decodeURIComponent(encoded);\r\n } catch (e) {\r\n try {\r\n code = decodeURIComponent(encoded);\r\n } catch (er) {\r\n code = \"\";\r\n }\r\n }\r\n const attrsRaw = ph.getAttribute(\"data-rhe-script-attrs\");\r\n let attrs: Record<string, string> = {};\r\n if (attrsRaw) {\r\n try {\r\n attrs = JSON.parse(decodeURIComponent(attrsRaw));\r\n } catch (e) {\r\n attrs = {};\r\n }\r\n }\r\n const parentId = ph.getAttribute(\"data-rhe-script-parent\");\r\n try {\r\n const s = doc.createElement(\"script\");\r\n try {\r\n s.type = \"text/javascript\";\r\n (s as any).async = false;\r\n } catch (err) {\r\n /* ignore */\r\n }\r\n Object.keys(attrs).forEach((k) =>\r\n s.setAttribute(k, attrs[k])\r\n );\r\n if (attrs.src) {\r\n const p = new Promise<void>((resolve) => {\r\n s.addEventListener(\"load\", () => resolve());\r\n s.addEventListener(\"error\", () => resolve());\r\n });\r\n loadPromises.push(p);\r\n s.src = attrs.src;\r\n } else {\r\n s.textContent = code;\r\n }\r\n if (parentId === \"head\") {\r\n doc.head.appendChild(s);\r\n } else {\r\n const target = doc.body.querySelector(\r\n `[data-rhe-id=\"${parentId}\"]`\r\n );\r\n if (target) target.appendChild(s);\r\n else doc.body.appendChild(s);\r\n }\r\n } catch (e) {\r\n /* ignore script injection errors */\r\n }\r\n });\r\n } catch (e) {\r\n /* ignore placeholder processing errors */\r\n }\r\n });\r\n try {\r\n if (loadPromises.length) {\r\n const waiter = (Promise as any).allSettled\r\n ? (Promise as any).allSettled(loadPromises)\r\n : Promise.all(\r\n loadPromises.map((p) => p.catch(() => undefined))\r\n );\r\n waiter.then(() => {\r\n try {\r\n doc.dispatchEvent(new Event(\"rhe:scripts-restored\"));\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n });\r\n } else {\r\n try {\r\n doc.dispatchEvent(new Event(\"rhe:scripts-restored\"));\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n }\r\n } catch (e) {\r\n /* ignore */\r\n }\r\n } else {\r\n doc.body.innerHTML = parsed.body.innerHTML;\r\n }\r\n } else {\r\n doc.documentElement.innerHTML = safeNext;\r\n }\r\n } catch (err) {\r\n doc.documentElement.innerHTML = safeNext;\r\n }\r\n\r\n // Re-inject styles and notify listeners so toolbar/styles are restored\r\n injectStyles(doc);\r\n try {\r\n doc.dispatchEvent(new Event(\"selectionchange\"));\r\n } catch (err) {\r\n /* ignore dispatch errors */\r\n }\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Redo failed:\", message);\r\n }\r\n}\r\n","import { _getDoc, pushStandaloneSnapshot } from \"./state\";\r\nimport { sanitizeHtml } from \"../utils/sanitize\";\r\nimport { sanitizeURL } from \"./sanitizeURL\";\r\n\r\nexport function handleToolbarCommand(command: string, value?: string) {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) {\r\n console.warn(\r\n \"[rich-html-editor] handleToolbarCommand called before initialization\"\r\n );\r\n return;\r\n }\r\n if (command === \"undo\") return; // delegated to history module\r\n if (command === \"redo\") return; // delegated to history module\r\n if (command === \"link\") {\r\n const url = window.prompt(\"Enter URL (https://...):\", \"https://\");\r\n if (url) {\r\n const sanitized = sanitizeURL(url);\r\n if (sanitized) applyStandaloneCommand(\"link\", sanitized);\r\n }\r\n return;\r\n }\r\n applyStandaloneCommand(command, value);\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Command handler failed:\", message);\r\n }\r\n}\r\n\r\nexport function applyStandaloneCommand(command: string, value?: string) {\r\n try {\r\n const doc = _getDoc();\r\n if (!doc) {\r\n console.warn(\r\n \"[rich-html-editor] applyStandaloneCommand called before initialization\"\r\n );\r\n return;\r\n }\r\n\r\n if (command === \"bold\") wrapSelectionWithElement(doc, \"strong\");\r\n else if (command === \"italic\") wrapSelectionWithElement(doc, \"em\");\r\n else if (command === \"underline\") wrapSelectionWithElement(doc, \"u\");\r\n else if (command === \"strike\") wrapSelectionWithElement(doc, \"s\");\r\n else if (command === \"fontName\")\r\n wrapSelectionWithElement(doc, \"span\", { fontFamily: value as any });\r\n else if (command === \"fontSize\") {\r\n // Accept numeric font-size values (e.g. \"12\", \"16\") and apply as px.\r\n const raw = value || \"14\";\r\n const n = parseInt(raw, 10);\r\n const sz = Number.isFinite(n) ? `${n}px` : raw;\r\n wrapSelectionWithElement(doc, \"span\", { fontSize: sz as any });\r\n } else if (command === \"link\") {\r\n const sel = doc.getSelection();\r\n if (!sel || !sel.rangeCount) return;\r\n const range = sel.getRangeAt(0);\r\n const content = range.extractContents();\r\n const a = doc.createElement(\"a\");\r\n a.href = sanitizeURL(value || \"#\");\r\n a.appendChild(content);\r\n range.insertNode(a);\r\n } else if (command === \"foreColor\")\r\n wrapSelectionWithElement(doc, \"span\", { color: value as any });\r\n else if (command === \"hiliteColor\")\r\n wrapSelectionWithElement(doc, \"span\", { backgroundColor: value as any });\r\n else if (command === \"align\") {\r\n const sel = doc.getSelection();\r\n const node = sel?.anchorNode || null;\r\n const block = findBlockAncestor(node);\r\n if (block) block.style.textAlign = value || \"left\";\r\n else wrapSelectionWithElement(doc, \"div\", { textAlign: value as any });\r\n } else if (command === \"formatBlock\") {\r\n // Change block-level element to selected tag (p, h1..h6)\r\n const sel = doc.getSelection();\r\n const node = sel?.anchorNode || null;\r\n const block = findBlockAncestor(node);\r\n const tag = (value || \"p\").toLowerCase();\r\n if (block && block.parentElement) {\r\n // Replace existing block with new block of desired tag\r\n const newEl = doc.createElement(tag);\r\n // Preserve inline styles?\r\n newEl.className = (block as HTMLElement).className || \"\";\r\n while (block.firstChild) newEl.appendChild(block.firstChild);\r\n block.parentElement.replaceChild(newEl, block);\r\n } else {\r\n // Wrap selection in the block tag\r\n wrapSelectionWithElement(doc, tag);\r\n }\r\n }\r\n pushStandaloneSnapshot();\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(\"[rich-html-editor] Apply command failed:\", message);\r\n }\r\n}\r\n\r\nfunction wrapSelectionWithElement(\r\n doc: Document,\r\n tagName: string,\r\n style?: Partial<CSSStyleDeclaration>\r\n): void {\r\n const sel = doc.getSelection();\r\n if (!sel) return;\r\n if (!sel.rangeCount) return;\r\n const range = sel.getRangeAt(0);\r\n if (range.collapsed) {\r\n const el = doc.createElement(tagName);\r\n if (style) Object.assign(el.style, style as any);\r\n const zw = doc.createTextNode(\"\\u200B\");\r\n el.appendChild(zw);\r\n range.insertNode(el);\r\n const newRange = doc.createRange();\r\n newRange.setStart(zw, 1);\r\n newRange.collapse(true);\r\n sel.removeAllRanges();\r\n sel.addRange(newRange);\r\n return;\r\n }\r\n const content = range.extractContents();\r\n const wrapper = doc.createElement(tagName);\r\n if (style) Object.assign(wrapper.style, style as any);\r\n wrapper.appendChild(content);\r\n range.insertNode(wrapper);\r\n sel.removeAllRanges();\r\n const newRange = doc.createRange();\r\n newRange.selectNodeContents(wrapper);\r\n sel.addRange(newRange);\r\n}\r\n\r\nfunction findBlockAncestor(node: Node | null): HTMLElement | null {\r\n let n = node as Node | null;\r\n const BLOCKS = [\r\n \"P\",\r\n \"DIV\",\r\n \"SECTION\",\r\n \"ARTICLE\",\r\n \"LI\",\r\n \"TD\",\r\n \"BLOCKQUOTE\",\r\n \"H1\",\r\n \"H2\",\r\n \"H3\",\r\n \"H4\",\r\n \"H5\",\r\n \"H6\",\r\n ];\r\n while (n) {\r\n if (n.nodeType === Node.ELEMENT_NODE) {\r\n const el = n as HTMLElement;\r\n if (BLOCKS.includes(el.tagName)) return el;\r\n }\r\n n = n.parentNode;\r\n }\r\n return null;\r\n}\r\n"],"mappings":"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","names":["createDOMPurify","input","makeButton","makeSelect","makeGroup","makeSep","newRange"]}