autumnnote 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -1
- package/dist/autumnnote.cjs +33 -33
- package/dist/autumnnote.core.es.js +640 -533
- package/dist/autumnnote.core.es.js.map +1 -1
- package/dist/autumnnote.es.js +769 -637
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.min.js +33 -33
- package/dist/autumnnote.umd.js +33 -33
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +1 -1
- package/types/index.d.ts +8 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autumnnote.core.es.js","names":["root","BLOCK_TAGS","Style.bold","Style.italic","Style.underline","Style.strikethrough","Style.superscript","Style.subscript","Style.justifyLeft","Style.justifyCenter","Style.justifyRight","Style.justifyFull","Style.insertUnorderedList","Style.insertOrderedList","Style.indent","Style.outdent","Style.execCommand","Style.fontSize","Style.fontName","Style.formatBlock","Style.lineHeight","Style.isInlineCode","Style.isInChecklist","Style.foreColor","Style.backColor"],"sources":["../src/js/core/func.js","../src/js/core/dom.js","../src/js/core/range.js","../src/js/editing/insert.js","../src/js/editing/Style.js","../src/js/module/Buttons.js","../src/js/settings.js","../src/js/i18n/en.js","../src/js/i18n/index.js","../src/js/core/sanitise.js","../src/js/renderer.js","../src/js/Context.js","../src/js/editing/History.js","../src/js/editing/Table.js","../src/js/core/key.js","../src/js/editing/Typing.js","../src/js/core/markdown.js","../src/js/core/detectLang.js","../src/js/module/Editor.js","../src/js/module/Toolbar.js","../src/js/module/Statusbar.js","../src/js/module/Clipboard.js","../src/js/module/Placeholder.js","../src/js/presets/core.js","../src/js/core/lists.js","../src/js/core/env.js","../src/js/factory.js","../src/js/core.js"],"sourcesContent":["/**\n * func.js - General utility / functional helpers\n * Inspired by Summernote's func.js\n */\n\n/**\n * Clamp a value between min and max.\n * @param {number} val\n * @param {number} min\n * @param {number} max\n * @returns {number}\n */\nexport function clamp(val, min, max) {\n return Math.min(Math.max(val, min), max);\n}\n\n/**\n * Debounce a function call.\n * @param {Function} fn\n * @param {number} delay - milliseconds\n * @returns {Function}\n */\nexport function debounce(fn, delay) {\n let timer;\n return function (...args) {\n clearTimeout(timer);\n timer = setTimeout(() => fn.apply(this, args), delay);\n };\n}\n\n/**\n * Create a wrapper that limits how often `fn` can be invoked while ensuring the last call in a burst is executed.\n * @param {Function} fn - Function to be throttled.\n * @param {number} limit - Time globalThis in milliseconds during which at most one call is allowed.\n * @returns {Function} A wrapper function that invokes `fn` at most once per `limit` milliseconds; calls preserve `this` and original arguments and schedule a trailing invocation for the final call in a burst.\n */\nexport function throttle(fn, limit) {\n let lastCall = -Infinity;\n let trailingTimer = null;\n return function (...args) {\n const now = performance.now();\n const elapsed = now - lastCall;\n if (elapsed >= limit) {\n lastCall = now;\n clearTimeout(trailingTimer);\n trailingTimer = null;\n return fn.apply(this, args);\n }\n // Ensure the final event in a burst is not dropped\n clearTimeout(trailingTimer);\n trailingTimer = setTimeout(() => {\n lastCall = performance.now();\n trailingTimer = null;\n fn.apply(this, args);\n }, limit - elapsed);\n };\n}\n\n/**\n * Compose multiple functions right-to-left.\n * @param {...Function} fns\n * @returns {Function}\n */\nexport function compose(...fns) {\n return (x) => fns.reduceRight((v, f) => f(v), x);\n}\n\n/**\n * Identity function.\n * @template T\n * @param {T} x\n * @returns {T}\n */\nexport function identity(x) {\n return x;\n}\n\n/**\n * Determines if a value is null or undefined.\n * @param {*} val\n * @returns {boolean}\n */\nexport function isNil(val) {\n return val === null || val === undefined;\n}\n\n/**\n * Determines if a value is a string.\n * @param {*} val\n * @returns {boolean}\n */\nexport function isString(val) {\n return typeof val === 'string';\n}\n\n/**\n * Determines if a value is a function.\n * @param {*} val\n * @returns {boolean}\n */\nexport function isFunction(val) {\n return typeof val === 'function';\n}\n\n/**\n * Deep-merge two plain objects. Returns a new object.\n * Arrays are cloned (shallow copy) rather than shared by reference so that\n * mutations to the merged result do not bleed back into the source object\n * (e.g. mutating `instance.options.fontFamilies` should not affect\n * `AutumnNote.defaults.fontFamilies`).\n * @param {object} target\n * @param {object} source\n * @returns {object}\n */\nexport function mergeDeep(target, source) {\n // Start with a shallow copy of target; clone any arrays to avoid shared refs\n const output = {};\n for (const key of Object.keys(target)) {\n output[key] = Array.isArray(target[key]) ? [...target[key]] : target[key];\n }\n if (isPlainObject(target) && isPlainObject(source)) {\n for (const key of Object.keys(source)) {\n if (isPlainObject(source[key])) {\n // When target[key] is null / undefined / a non-object (e.g. the `mention: null`\n // default), merge into an empty object instead of passing null to the next\n // recursive call — which would silently drop all source properties.\n const base = isPlainObject(target[key]) ? target[key] : {};\n output[key] = mergeDeep(base, source[key]);\n } else if (Array.isArray(source[key])) {\n output[key] = [...source[key]];\n } else {\n output[key] = source[key];\n }\n }\n }\n return output;\n}\n\n/**\n * Checks if value is a plain object.\n * @param {*} val\n * @returns {boolean}\n */\nexport function isPlainObject(val) {\n return val !== null && typeof val === 'object' && !Array.isArray(val);\n}\n\n/**\n * Convert a DOMRect (or similar bounding object) to a plain object bounding box.\n * Guards against missing/null rect (e.g. in AirMode).\n * @param {DOMRect|null|undefined} rect\n * @returns {{ top: number, left: number, width: number, height: number, bottom: number, right: number }|null}\n */\nexport function rect2bnd(rect) {\n if (!rect) return null;\n return {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n bottom: rect.bottom,\n right: rect.right,\n };\n}\n","/**\n * dom.js - DOM manipulation utilities\n * Inspired by Summernote's dom.js — rewritten for vanilla JS without jQuery\n */\n\n// ---------------------------------------------------------------------------\n// Node type helpers\n// ---------------------------------------------------------------------------\n\nexport const ELEMENT_NODE = 1;\nexport const TEXT_NODE = 3;\n\n/** @param {Node} node */\nexport const isElement = (node) => node?.nodeType === ELEMENT_NODE;\n/** @param {Node} node */\nexport const isText = (node) => node?.nodeType === TEXT_NODE;\n/** @param {Node} node */\nexport const isVoid = (node) => isElement(node) && /^(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/i.test(node.nodeName);\n/** @param {Node} node */\nexport const isPara = (node) => isElement(node) && /^(p|div|li|h[1-6]|blockquote|td|th|pre)$/i.test(node.nodeName);\n/** @param {Node} node */\nexport const isLi = (node) => isElement(node) && /^(li)$/i.test(node.nodeName);\n/** @param {Node} node */\nexport const isList = (node) => isElement(node) && /^(ul|ol)$/i.test(node.nodeName);\n/** @param {Node} node */\nexport const isTable = (node) => isElement(node) && node.nodeName.toUpperCase() === 'TABLE';\n/** @param {Node} node */\nexport const isInline = (node) =>\n isElement(node) &&\n /^(a|abbr|acronym|b|bdo|big|br|button|cite|code|dfn|em|i|img|input|kbd|label|map|object|output|q|s|samp|select|small|span|strong|sub|sup|textarea|time|tt|u|var)$/i.test(node.nodeName);\n/** @param {Node} node */\nexport const isEditable = (node) => isElement(node) && /** @type {HTMLElement} */ (node).isContentEditable;\n/** @param {Node} node */\nexport const isAnchor = (node) => isElement(node) && node.nodeName.toUpperCase() === 'A';\n/** @param {Node} node */\nexport const isImage = (node) => isElement(node) && node.nodeName.toUpperCase() === 'IMG';\n\n// ---------------------------------------------------------------------------\n// Tree traversal\n// ---------------------------------------------------------------------------\n\n/**\n * Walk up the DOM tree from node, returning the first element matching predicate (inclusive).\n * @param {Node} node\n * @param {(node: Node) => boolean} predicate\n * @param {Node} [stopAt] - stop traversal at this ancestor (exclusive)\n * @returns {Node|null}\n */\nexport function closest(node, predicate, stopAt) {\n let cur = node;\n while (cur && cur !== stopAt) {\n if (predicate(cur)) return cur;\n cur = cur.parentNode;\n }\n return null;\n}\n\n/**\n * Returns the nearest ancestor that is a paragraph-like block.\n * @param {Node} node\n * @param {Node} [editable]\n * @returns {Node|null}\n */\nexport function closestPara(node, editable) {\n return closest(node, isPara, editable);\n}\n\n/**\n * Returns all ancestors of node up to (but not including) stopAt.\n * @param {Node} node\n * @param {Node} [stopAt]\n * @returns {Node[]}\n */\nexport function ancestors(node, stopAt) {\n const result = [];\n let cur = node.parentNode;\n while (cur && cur !== stopAt) {\n result.push(cur);\n cur = cur.parentNode;\n }\n return result;\n}\n\n/**\n * Returns all children of node as an Array.\n * @param {Node} node\n * @returns {Node[]}\n */\nexport function children(node) {\n return Array.from(node.childNodes);\n}\n\n/**\n * Returns the previous sibling element (skipping text/comment nodes).\n * @param {Node} node\n * @returns {Element|null}\n */\nexport function prevElement(node) {\n let sibling = node.previousSibling;\n while (sibling && !isElement(sibling)) {\n sibling = sibling.previousSibling;\n }\n return /** @type {Element|null} */ (sibling);\n}\n\n/**\n * Returns the next sibling element.\n * @param {Node} node\n * @returns {Element|null}\n */\nexport function nextElement(node) {\n let sibling = node.nextSibling;\n while (sibling && !isElement(sibling)) {\n sibling = sibling.nextSibling;\n }\n return /** @type {Element|null} */ (sibling);\n}\n\n// ---------------------------------------------------------------------------\n// DOM mutation helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an element with optional attributes and children.\n * @param {string} tag\n * @param {Record<string, string>} [attrs]\n * @param {(Node|string)[]} [childNodes]\n * @returns {HTMLElement}\n */\nexport function createElement(tag, attrs = {}, childNodes = []) {\n const el = document.createElement(tag);\n for (const [k, v] of Object.entries(attrs)) {\n el.setAttribute(k, v);\n }\n for (const child of childNodes) {\n if (typeof child === 'string') {\n el.appendChild(document.createTextNode(child));\n } else {\n el.appendChild(child);\n }\n }\n return el;\n}\n\n/**\n * Removes a node from its parent.\n * @param {Node} node\n */\nexport function remove(node) {\n if (node?.parentNode) {\n /** @type {ChildNode} */ (node).remove();\n }\n}\n\n/**\n * Unwraps a node — replaces the node with its children.\n * @param {Node} node\n */\nexport function unwrap(node) {\n const parent = node.parentNode;\n if (!parent) return;\n while (node.firstChild) {\n parent.insertBefore(node.firstChild, node);\n }\n /** @type {ChildNode} */ (node).remove();\n}\n\n/**\n * Wraps a node with a wrapper element.\n * @param {Node} node\n * @param {HTMLElement} wrapper\n * @returns {HTMLElement} the wrapper\n */\nexport function wrap(node, wrapper) {\n node.parentNode.insertBefore(wrapper, node);\n wrapper.appendChild(node);\n return wrapper;\n}\n\n/**\n * Insert node after reference node.\n * @param {Node} newNode\n * @param {Node} refNode\n */\nexport function insertAfter(newNode, refNode) {\n if (refNode.nextSibling) {\n refNode.parentNode.insertBefore(newNode, refNode.nextSibling);\n } else {\n refNode.parentNode.appendChild(newNode);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Content helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the text content of a node (safe).\n * @param {Node} node\n * @returns {string}\n */\nexport function nodeValue(node) {\n return isText(node) ? node.nodeValue : node.textContent || '';\n}\n\n/**\n * Determine whether a DOM node contains no visible content.\n *\n * Text nodes are considered empty when their `nodeValue` is empty. Void elements (e.g., `img`, `br`, `input`) are considered non-empty. An element with exactly one `<br>` child is treated as empty. For other elements, emptiness means trimmed `textContent` is empty and there are no descendant `img`, `video`, `hr`, or `table` elements.\n * @param {Node} node - Node to inspect for visible content.\n * @returns {boolean} `true` if the node has no visible content, `false` otherwise.\n */\nexport function isEmpty(node) {\n if (isText(node)) return !node.nodeValue;\n if (isVoid(node)) return false;\n if (node.childNodes.length === 1 && node.firstChild?.nodeName === 'BR') return true;\n return !node.textContent.trim() && !/** @type {Element} */ (node).querySelector('img, video, hr, table');\n}\n\n/**\n * Returns the outerHTML of an element.\n * @param {Element} el\n * @returns {string}\n */\nexport function outerHtml(el) {\n return el.outerHTML;\n}\n\n// ---------------------------------------------------------------------------\n// Selection / editing helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Places the caret at the end of a contenteditable element.\n * @param {HTMLElement} el\n */\nexport function placeCaret(el) {\n const range = document.createRange();\n range.selectNodeContents(el);\n range.collapse(false);\n const sel = globalThis.getSelection();\n if (sel) {\n sel.removeAllRanges();\n sel.addRange(range);\n }\n}\n\n/**\n * Returns true if the node is inside a contenteditable root.\n * @param {Node} node\n * @returns {boolean}\n */\nexport function isInsideEditable(node) {\n return !!closest(node, isEditable);\n}\n\n// ---------------------------------------------------------------------------\n// Event helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Adds an event listener and returns a disposer function.\n * @param {EventTarget} target\n * @param {string} type\n * @param {EventListener} handler\n * @param {AddEventListenerOptions} [options]\n * @returns {() => void} disposer\n */\nexport function on(target, type, handler, options) {\n target.addEventListener(type, handler, options);\n return () => target.removeEventListener(type, handler, options);\n}\n\n/**\n * Installs a keyboard focus trap inside a dialog container.\n * - Tab / Shift+Tab cycles focus within the container's focusable children.\n * - Escape calls `onEscape` and removes the trap listener.\n *\n * Returns a disposer function that removes the listener (call on dialog close).\n *\n * @param {HTMLElement} container - the dialog element to trap focus inside\n * @param {() => void} onEscape - called when Escape is pressed\n * @returns {() => void} disposer\n */\nexport function trapFocus(container, onEscape) {\n const FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\n const getFocusable = () => Array.from(container.querySelectorAll(FOCUSABLE)).filter(\n (el) => !el.closest('[style*=\"display: none\"]') && !el.closest('[style*=\"display:none\"]'),\n );\n\n const handler = (e) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n onEscape?.();\n return;\n }\n if (e.key !== 'Tab') return;\n const els = getFocusable();\n if (!els.length) return;\n const first = els[0];\n const last = els.at(-1);\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n /** @type {HTMLElement} */ (last).focus();\n }\n } else if (document.activeElement === last) {\n e.preventDefault();\n /** @type {HTMLElement} */ (first).focus();\n }\n };\n\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n}\n\n/**\n * Makes a dialog box draggable by its handle element.\n * On first drag the box is pinned to its current viewport coordinates via\n * `position:fixed`, freeing it from the parent flex container's centering.\n * The position is clamped to the visible viewport.\n *\n * @param {HTMLElement} handle Element the user grabs (title bar / header)\n * @param {HTMLElement} box Element that actually moves\n * @returns {Function} Cleanup function (removes the mousedown listener)\n */\nexport function makeDraggable(handle, box) {\n handle.style.cursor = 'grab';\n\n const onMousedown = (e) => {\n if (e.button !== 0) return;\n // Don't start drag when clicking on interactive children of the handle\n if (/** @type {Element} */ (e.target).closest('button, input, select, textarea, a')) return;\n\n e.preventDefault();\n\n // First drag: snapshot position and pin to viewport with position:fixed\n if (!box.dataset.anDragPinned) {\n const r = box.getBoundingClientRect();\n box.style.position = 'fixed';\n box.style.margin = '0';\n box.style.left = `${r.left}px`;\n box.style.top = `${r.top}px`;\n box.dataset.anDragPinned = '1';\n }\n\n const startX = e.clientX - Number.parseFloat(box.style.left);\n const startY = e.clientY - Number.parseFloat(box.style.top);\n\n handle.style.cursor = 'grabbing';\n\n const onMove = (ev) => {\n const bw = box.offsetWidth;\n const bh = box.offsetHeight;\n box.style.left = `${Math.max(0, Math.min(ev.clientX - startX, globalThis.innerWidth - bw))}px`;\n box.style.top = `${Math.max(0, Math.min(ev.clientY - startY, globalThis.innerHeight - bh))}px`;\n };\n\n const onUp = () => {\n handle.style.cursor = 'grab';\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n };\n\n handle.addEventListener('mousedown', onMousedown);\n return () => handle.removeEventListener('mousedown', onMousedown);\n}\n","/**\n * range.js - Selection and Range utilities\n * Inspired by Summernote's range.js — rewritten as vanilla JS\n */\n\nimport { isElement, closest } from './dom.js';\n\n// ---------------------------------------------------------------------------\n// WrappedRange — a convenience wrapper over the native Range API\n// ---------------------------------------------------------------------------\n\nexport class WrappedRange {\n /**\n * @param {Node} sc - start container\n * @param {number} so - start offset\n * @param {Node} ec - end container\n * @param {number} eo - end offset\n */\n constructor(sc, so, ec, eo) {\n this.sc = sc;\n this.so = so;\n this.ec = ec;\n this.eo = eo;\n }\n\n /** @returns {boolean} */\n isCollapsed() {\n return this.sc === this.ec && this.so === this.eo;\n }\n\n /** @returns {Range} */\n toNativeRange() {\n const range = document.createRange();\n try {\n range.setStart(this.sc, this.so);\n range.setEnd(this.ec, this.eo);\n } catch (_e) {\n void _e; // guard against detached nodes\n }\n return range;\n }\n\n /**\n * Select this wrapped range in the globalThis.\n */\n select() {\n const sel = globalThis.getSelection();\n if (!sel) return;\n sel.removeAllRanges();\n sel.addRange(this.toNativeRange());\n }\n\n /**\n * Returns the common ancestor element of this range.\n * @returns {Element|null}\n */\n commonAncestor() {\n const native = this.toNativeRange();\n const ancestor = native.commonAncestorContainer;\n return /** @type {Element|null} */ (isElement(ancestor) ? ancestor : ancestor.parentElement);\n }\n\n /**\n * Returns the nearest paragraph/block ancestor within the editable area.\n * @param {HTMLElement} editable\n * @returns {Element|null}\n */\n blockNode(editable) {\n return /** @type {Element|null} */ (closest(this.sc, (n) => isElement(n) && n !== editable, editable));\n }\n\n /**\n * Returns either the selected text string or empty string.\n * @returns {string}\n */\n toString() {\n return this.toNativeRange().toString();\n }\n\n /**\n * Returns the bounding DOMRect of the range (or null).\n * @returns {DOMRect|null}\n */\n getClientRects() {\n const rects = this.toNativeRange().getClientRects();\n return rects.length > 0 ? rects[rects.length - 1] : null;\n }\n\n /**\n * Inserts a node at the start of this range.\n * @param {Node} node\n */\n insertNode(node) {\n const native = this.toNativeRange();\n native.insertNode(node);\n }\n\n}\n\n// ---------------------------------------------------------------------------\n// Factory helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a WrappedRange from a native Range object.\n * @param {Range} range\n * @returns {WrappedRange}\n */\nexport function fromNativeRange(range) {\n return new WrappedRange(\n range.startContainer,\n range.startOffset,\n range.endContainer,\n range.endOffset,\n );\n}\n\n/**\n * Returns a WrappedRange for the current globalThis selection,\n * optionally restricted to a given editable element.\n * @param {HTMLElement} [editable]\n * @returns {WrappedRange|null}\n */\nexport function currentRange(editable) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const native = sel.getRangeAt(0);\n // Optionally check that the selection is inside the editable element\n if (editable && !editable.contains(native.commonAncestorContainer)) {\n return null;\n }\n return fromNativeRange(native);\n}\n\n/**\n * Creates a WrappedRange that covers the entire content of an element.\n * @param {HTMLElement} el\n * @returns {WrappedRange}\n */\nexport function rangeFromElement(el) {\n return new WrappedRange(el, 0, el, el.childNodes.length);\n}\n\n/**\n * Creates a collapsed range (cursor) at the given node / offset.\n * @param {Node} node\n * @param {number} offset\n * @returns {WrappedRange}\n */\nexport function collapsedRange(node, offset = 0) {\n return new WrappedRange(node, offset, node, offset);\n}\n\n// ---------------------------------------------------------------------------\n// Utility helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if the current selection is inside the given element.\n * @param {HTMLElement} el\n * @returns {boolean}\n */\nexport function isSelectionInside(el) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return false;\n return el.contains(sel.getRangeAt(0).commonAncestorContainer);\n}\n\n/**\n * Saves the current selection, executes fn, then restores the selection.\n * @param {Function} fn\n */\nexport function withSavedRange(fn) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) {\n fn(null);\n return;\n }\n const saved = sel.getRangeAt(0).cloneRange();\n fn(fromNativeRange(saved));\n sel.removeAllRanges();\n sel.addRange(saved);\n}\n\n/**\n * Splits the text node at the given offset and returns the two halves.\n * @param {Text} textNode\n * @param {number} offset\n * @returns {[Text, Text]}\n */\nexport function splitText(textNode, offset) {\n const after = textNode.splitText(offset);\n return [textNode, after];\n}\n","/**\n * insert.js — native replacements for the insertion `execCommand`s.\n *\n * Stage 1 of docs/EXEC_COMMAND_MIGRATION.md. `insertHTML`, `insertText` and\n * `insertHorizontalRule` are the easiest commands to leave behind: they do not\n * have to reason about overlapping inline formatting the way `bold` or\n * `fontName` do, so a Range-based implementation is a straight substitution\n * rather than a rewrite of the formatting model.\n *\n * Each function returns `false` when there is no usable selection, which is the\n * caller's signal to fall back to `document.execCommand`. That keeps the\n * compatibility adapter the migration doc asks for: nothing silently stops\n * working while the native paths are proven in browsers.\n *\n * The HTML given to `insertHTMLNative` is inserted as-is — callers sanitise\n * first, exactly as they did before.\n */\n\n/**\n * The nearest ancestor that makes `node` editable, if there is one.\n *\n * Reads the attribute and falls back to the property, rather than using\n * `isContentEditable`: jsdom implements neither `isContentEditable` nor the\n * property/attribute reflection, so an editable built with\n * `el.contentEditable = 'true'` is only visible through the property there, and\n * one built from markup only through the attribute.\n * @param {Node|null} node\n * @returns {Element|null}\n */\nfunction _editableHost(node) {\n let cur = node && node.nodeType === 1 ? /** @type {Element} */ (node) : node?.parentElement;\n while (cur) {\n const flag = cur.getAttribute?.('contenteditable') ?? /** @type {HTMLElement} */ (cur).contentEditable;\n if (flag === 'false') return null;\n // 'inherit' is the browser's answer for ordinary elements: keep climbing.\n if (flag != null && flag !== 'inherit') return cur;\n cur = cur.parentElement;\n }\n return null;\n}\n\n/**\n * The current selection range, but only when it is somewhere these functions\n * may write to.\n *\n * With an explicit `editable` that means inside it; without one it means inside\n * *some* contenteditable host. The second check matters: `Style.execCommand`\n * does not know which editor it is acting for, and `document.execCommand` is\n * itself a no-op when the selection sits outside editable content. Without the\n * check a stale selection elsewhere in the page would have the native path\n * cheerfully insert into it.\n * @param {HTMLElement|Document} [editable]\n * @returns {Range|null}\n */\nfunction _usableRange(editable) {\n const sel = globalThis.getSelection?.();\n if (!sel || sel.rangeCount === 0) return null;\n const range = sel.getRangeAt(0);\n if (editable && editable !== document) {\n const root = /** @type {HTMLElement} */ (editable);\n return root.contains(range.commonAncestorContainer) ? range : null;\n }\n return _editableHost(range.commonAncestorContainer) ? range : null;\n}\n\n/**\n * Collapses the selection immediately after `node`.\n * @param {Node} node\n */\nfunction _caretAfter(node) {\n const sel = globalThis.getSelection?.();\n if (!sel) return;\n const range = document.createRange();\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Replaces the selection with `html`.\n * @param {string} html - already sanitised by the caller\n * @param {HTMLElement} [editable] - restricts the operation to this subtree\n * @returns {boolean} false when there is no usable selection\n */\nexport function insertHTMLNative(html, editable) {\n const range = _usableRange(editable);\n if (!range) return false;\n\n const template = document.createElement('template');\n template.innerHTML = html;\n const fragment = template.content;\n // Held before insertion: appending the fragment empties it.\n const lastNode = fragment.lastChild;\n\n range.deleteContents();\n range.insertNode(fragment);\n\n if (lastNode) _caretAfter(lastNode);\n return true;\n}\n\n/**\n * Replaces the selection with literal text.\n *\n * A newline becomes a `<br>`, which is what execCommand did and what\n * contenteditable expects — a raw \"\\n\" in a text node renders as a space.\n * @param {string} text\n * @param {HTMLElement} [editable]\n * @returns {boolean} false when there is no usable selection\n */\nexport function insertTextNative(text, editable) {\n const range = _usableRange(editable);\n if (!range) return false;\n\n range.deleteContents();\n\n const value = String(text);\n const fragment = document.createDocumentFragment();\n\n // Inside preformatted content a newline is a newline; everywhere else it has\n // to become a <br>, because a raw \"\\n\" in a text node renders as a space.\n if (!value.includes('\\n') || _inPreformatted(range.startContainer, editable)) {\n fragment.appendChild(document.createTextNode(value));\n } else {\n value.split('\\n').forEach((line, i) => {\n if (i > 0) fragment.appendChild(document.createElement('br'));\n if (line) fragment.appendChild(document.createTextNode(line));\n });\n }\n\n const lastNode = fragment.lastChild;\n range.insertNode(fragment);\n if (lastNode) _caretAfter(lastNode);\n return true;\n}\n\n/**\n * True when `node` sits in content that preserves whitespace.\n *\n * Checks the tag first because jsdom does not apply the UA stylesheet's\n * `white-space: pre` to `<pre>`, so the computed style alone would miss it.\n * @param {Node} node\n * @param {HTMLElement} [editable]\n * @returns {boolean}\n */\nfunction _inPreformatted(node, editable) {\n let cur = node.nodeType === 1 ? /** @type {Element} */ (node) : node.parentElement;\n while (cur && cur !== editable) {\n if (cur.tagName === 'PRE' || cur.tagName === 'TEXTAREA') return true;\n const ws = globalThis.getComputedStyle?.(cur)?.whiteSpace;\n if (ws && ws.startsWith('pre')) return true;\n cur = cur.parentElement;\n }\n return false;\n}\n\n/**\n * Inserts a horizontal rule at the selection.\n *\n * The rule is placed after the block the caret is in rather than inside it, and\n * a paragraph follows it so there is somewhere to type — a bare `<hr>` at the\n * end of the document leaves the caret with nowhere to go.\n * @param {HTMLElement} [editable]\n * @returns {boolean} false when there is no usable selection\n */\nexport function insertHorizontalRuleNative(editable) {\n const range = _usableRange(editable);\n if (!range) return false;\n\n const hr = document.createElement('hr');\n range.deleteContents();\n\n const block = _closestBlock(range.startContainer, editable);\n if (block && block.parentNode) {\n block.parentNode.insertBefore(hr, block.nextSibling);\n } else {\n range.insertNode(hr);\n }\n\n let after = hr.nextElementSibling;\n if (!after || after.tagName === 'HR') {\n const p = document.createElement('p');\n p.appendChild(document.createElement('br'));\n hr.parentNode?.insertBefore(p, hr.nextSibling);\n after = p;\n }\n\n const sel = globalThis.getSelection?.();\n if (sel) {\n const caret = document.createRange();\n caret.setStart(after, 0);\n caret.collapse(true);\n sel.removeAllRanges();\n sel.addRange(caret);\n }\n return true;\n}\n\nconst BLOCK_TAGS = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE', 'PRE', 'LI']);\n\n/**\n * Nearest block-level ancestor of `node`, stopping at `editable`.\n * @param {Node} node\n * @param {HTMLElement} [editable]\n * @returns {Element|null}\n */\nfunction _closestBlock(node, editable) {\n let cur = node.nodeType === 1 ? /** @type {Element} */ (node) : node.parentElement;\n while (cur && cur !== editable) {\n if (BLOCK_TAGS.has(cur.tagName)) return cur;\n cur = cur.parentElement;\n }\n return null;\n}\n","/**\n * Style.js - Inline / block style detection and application utilities\n * Rewritten from Summernote's approach using vanilla JS + execCommand fallback\n */\n\nimport { closest, isElement, isPara } from '../core/dom.js';\nimport { currentRange } from '../core/range.js';\nimport { insertHTMLNative, insertTextNative, insertHorizontalRuleNative } from './insert.js';\n\n// ---------------------------------------------------------------------------\n// execCommand wrappers (still the most compatible way in contenteditable)\n// ---------------------------------------------------------------------------\n\n/**\n * Applies a document execCommand.\n * @param {string} cmd\n * @param {string} [value]\n * @returns {boolean}\n */\nexport function execCommand(cmd, value = null) {\n // Stage 1 of the execCommand migration: the three insertion commands have\n // native Range-based implementations. They are tried first and report false\n // when there is no usable selection, in which case the deprecated command\n // still runs — the compatibility adapter docs/EXEC_COMMAND_MIGRATION.md calls\n // for, so nothing stops working while the native paths are proven.\n if (cmd === 'insertHTML' && insertHTMLNative(String(value ?? ''))) return true;\n if (cmd === 'insertText' && insertTextNative(String(value ?? ''))) return true;\n if (cmd === 'insertHorizontalRule' && insertHorizontalRuleNative()) return true;\n return document.execCommand(cmd, false, value);\n}\n\n// ---------------------------------------------------------------------------\n// Inline style helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Bolds / unbolds the selection.\n */\nexport const bold = () => execCommand('bold');\n\n/**\n * Italicises / un-italicises the selection.\n */\nexport const italic = () => execCommand('italic');\n\n/**\n * Underlines / un-underlines the selection.\n * Falls back to manual DOM manipulation when inside <code> where\n * execCommand's state detection is unreliable.\n */\nexport function underline() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n let container = sel.getRangeAt(0).commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n // Check if we're inside a <u> (DOM truth), to guard against unreliable queryCommandState\n const uEl = /** @type {Element|null} */ (container)?.closest('u');\n const nativeState = document.queryCommandState('underline');\n if (uEl && !nativeState) {\n // Browser doesn't recognise the underline state (e.g. inside <code>).\n // Manually unwrap the <u> element.\n const parent = uEl.parentNode;\n while (uEl.firstChild) parent.insertBefore(uEl.firstChild, uEl);\n uEl.remove();\n return;\n }\n execCommand('underline');\n}\n\n/**\n * Strikethrough / removes strikethrough.\n * Falls back to manual DOM manipulation inside nested formats where\n * execCommand's state detection is unreliable (mirrors underline() logic).\n */\nexport function strikethrough() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n // Use startContainer for consistent detection across collapsed and range\n // selections — commonAncestorContainer can miss ancestor <s>/<strike> tags\n // when the selection spans across nested inline elements.\n let sc = sel.getRangeAt(0).startContainer;\n if (sc.nodeType === 3) sc = sc.parentElement;\n const sEl = /** @type {Element|null} */ (sc)?.closest('s') || /** @type {Element|null} */ (sc)?.closest('strike');\n const nativeState = document.queryCommandState('strikeThrough');\n if (sEl && !nativeState) {\n // Browser doesn’t recognise the strikethrough state (e.g. inside <code>\n // or deeply nested inline formats). Manually unwrap the <s>/<strike>.\n const parent = sEl.parentNode;\n while (sEl.firstChild) parent.insertBefore(sEl.firstChild, sEl);\n sEl.remove();\n return;\n }\n execCommand('strikeThrough');\n}\n\n/**\n * Superscript toggle.\n */\nexport const superscript = () => execCommand('superscript');\n\n/**\n * Subscript toggle.\n */\nexport const subscript = () => execCommand('subscript');\n\n/**\n * Sets the foreground colour of the selected text.\n * @param {string} color - CSS colour string\n */\nexport const foreColor = (color) => execCommand('foreColor', color);\n\n/**\n * Sets the background (highlight) colour of the selected text.\n * @param {string} color - CSS colour string\n */\nexport const backColor = (color) => execCommand('hiliteColor', color);\n\n/**\n * Sets the font name for the selection.\n * @param {string} name\n */\nexport const fontName = (name) => execCommand('fontName', name);\n\n/**\n * Sets the font size (in pt or with unit) for the selection.\n * Uses a span-based approach to set px sizes precisely.\n * @param {string} size - e.g. '14px'\n * @param {HTMLElement|Document} [editable] - scoping element to avoid touching nodes outside this editor\n */\nexport function fontSize(size, editable = document) {\n const sel = globalThis.getSelection();\n const wasCollapsed = !sel?.rangeCount || sel.getRangeAt(0).collapsed;\n\n // B-I-3/4: For a collapsed (caret) selection the browser's execCommand\n // 'fontSize' leaves an internal \"pending\" state of size-7 (=48px) instead of\n // creating a <font> element, so the very next typed character comes out at\n // 48px. Fix: bypass execCommand entirely for collapsed selections and directly\n // insert a span with the requested size, placing the cursor inside it.\n // Only applies when there IS an active selection (sel.rangeCount > 0); when\n // there is no selection at all (e.g. jsdom unit tests) fall through to the\n // execCommand path so the font-replacement logic still runs.\n if (wasCollapsed && sel?.rangeCount > 0) {\n try {\n const range = sel.getRangeAt(0);\n const span = document.createElement('span');\n span.style.fontSize = size;\n const zwsNode = document.createTextNode('\\u200B');\n span.appendChild(zwsNode);\n range.insertNode(span);\n const nr = document.createRange();\n nr.setStart(zwsNode, zwsNode.textContent.length);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n } catch (_) { void _; /* ignore range errors on unusual DOM structures */ }\n return;\n }\n\n // Non-collapsed selection (or no selection — handles jsdom test setup where\n // <font size=\"7\"> elements are injected directly without a live selection):\n // use execCommand placeholder approach then replace <font> with <span>.\n execCommand('fontSize', '7');\n const scope = editable instanceof HTMLElement ? editable : document;\n const newSpans = [];\n scope.querySelectorAll('font[size=\"7\"]').forEach((el) => {\n const span = document.createElement('span');\n span.style.fontSize = size;\n el.parentNode.insertBefore(span, el);\n while (el.firstChild) span.appendChild(el.firstChild);\n el.remove();\n newSpans.push(span);\n });\n\n // Re-select all replaced content so toolbar getValue() reads the new size\n // (B-I-1/2: without this re-selection the toolbar dropdown stays on the old\n // value until the next selectionchange event).\n if (!wasCollapsed && sel && newSpans.length > 0) {\n const first = newSpans[0];\n const last = newSpans.at(-1);\n try {\n const nr = document.createRange();\n const startNode = first.firstChild || first;\n const endNode = last.lastChild || last;\n nr.setStart(startNode, 0);\n nr.setEnd(endNode, endNode.nodeType === Node.TEXT_NODE ? endNode.textContent.length : endNode.childNodes.length);\n sel.removeAllRanges();\n sel.addRange(nr);\n } catch (_) { void _; /* ignore range errors on unusual DOM structures */ }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Block style helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Wraps the selection in the given block tag (p, h1-h6, blockquote, pre).\n * @param {string} tagName\n */\nexport const formatBlock = (tagName) => execCommand('formatBlock', `<${tagName}>`);\n\n/**\n * Left-aligns the current block.\n */\nexport const justifyLeft = () => execCommand('justifyLeft');\n\n/**\n * Center-aligns the current block.\n */\nexport const justifyCenter = () => execCommand('justifyCenter');\n\n/**\n * Right-aligns the current block.\n */\nexport const justifyRight = () => execCommand('justifyRight');\n\n/**\n * Fully justifies the current block.\n */\nexport const justifyFull = () => execCommand('justifyFull');\n\n/**\n * Indents the list or block.\n */\nexport const indent = () => execCommand('indent');\n\n/**\n * Outdents the list or block.\n * G.5: When cursor is inside a checklist item, \"outdent\" means converting\n * that item back to a regular <p> element rather than calling execCommand\n * (which would destroy the ul > li checklist structure).\n */\nexport function outdent() {\n const sel = globalThis.getSelection();\n if (sel?.rangeCount) {\n let container = sel.getRangeAt(0).commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n const checkLi = /** @type {Element|null} */ (container)?.closest('.an-checklist li');\n if (checkLi) {\n _checklistItemToP(/** @type {HTMLElement} */ (checkLi));\n return;\n }\n }\n execCommand('outdent');\n}\n\n/**\n * Convert a checklist <li> into a paragraph and move any following items into a new checklist.\n *\n * Preserves inline markup from the converted item, strips zero-width space anchors,\n * and replaces empty content with a non‑breaking space. If there are list items\n * after the converted item they are moved into a new <ul class=\"an-checklist\">\n * inserted immediately after the original list. The original <li> is removed and\n * the original list is removed if it becomes empty. Attempts to place the caret\n * at the start of the newly created <p>.\n * @param {HTMLElement} checkLi - The checklist `<li>` element to convert to a `<p>`.\n */\nfunction _checklistItemToP(checkLi) {\n const checkUl = checkLi.closest('.an-checklist');\n if (!checkUl) return;\n\n const allLis = Array.from(checkUl.children);\n const liIndex = allLis.indexOf(checkLi);\n const afterLis = allLis.slice(liIndex + 1);\n\n // Build <p> preserving inline formatting (bold/italic/links) from the item's content\n const p = document.createElement('p');\n for (const child of checkLi.childNodes) {\n if (child.nodeType === 1 && /** @type {Element} */ (child).tagName === 'INPUT') continue;\n p.appendChild(child.cloneNode(true));\n }\n // Strip ZWS anchors left over from checklist markup\n p.innerHTML = p.innerHTML.replaceAll('\\u200B', '');\n if (!p.hasChildNodes() || !p.textContent.trim()) {\n p.innerHTML = '';\n p.appendChild(document.createTextNode('\\u00a0'));\n }\n\n // Move items after the current li into a new checklist\n if (afterLis.length > 0) {\n const newUl = document.createElement('ul');\n newUl.className = 'an-checklist';\n afterLis.forEach(li => newUl.appendChild(li));\n checkUl.parentNode.insertBefore(newUl, checkUl.nextSibling);\n }\n\n // Insert <p> after checkUl (before any newUl)\n checkUl.parentNode.insertBefore(p, checkUl.nextSibling);\n\n // Remove current li from checkUl; delete checkUl if now empty\n checkLi.remove();\n if (checkUl.children.length === 0) checkUl.remove();\n\n // Place caret at start of the new <p>\n try {\n const nr = document.createRange();\n const firstChild = p.firstChild;\n nr.setStart(firstChild?.nodeType === 3 ? firstChild : p, 0);\n nr.collapse(true);\n const s = globalThis.getSelection();\n if (s) { s.removeAllRanges(); s.addRange(nr); }\n } catch {}\n}\n\n/**\n * Inserts an unordered (bulleted) list, or converts the current list to `<ul>`.\n *\n * When the cursor is already inside a list, direct DOM manipulation is used to\n * transition between list types — `execCommand` alone cannot handle checklist →\n * UL/OL conversions because it has no awareness of the `an-checklist` class or\n * the checkbox `<input>` elements.\n *\n * Transition paths:\n * - **Checklist → UL**: strips `an-checklist` class and all checkbox inputs;\n * converts `<ol>` container to `<ul>` via `changeTagName()` if needed.\n * - **OL → UL**: swaps the container tag via `changeTagName()`.\n * - **UL → paragraphs**: falls back to `execCommand('insertUnorderedList')`\n * which toggles the list off (browser-native behaviour).\n * - **No list → UL**: falls back to `execCommand('insertUnorderedList')`.\n */\n/**\n * Helper to get the closest ul/ol element containing the current selection.\n * @returns {Element|null}\n */\nfunction getSelectedList() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return null;\n let container = sel.getRangeAt(0).commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n return /** @type {Element|null} */ (container)?.closest('ul, ol') || null;\n}\n\n/**\n * Strips the checklist class and checkbox inputs from a list element.\n * @param {Element} listEl\n */\nfunction stripChecklist(listEl) {\n listEl.classList.remove('an-checklist');\n listEl.querySelectorAll('input[type=\"checkbox\"]').forEach(cb => cb.remove());\n}\n\nexport function insertUnorderedList() {\n const listEl = getSelectedList();\n if (listEl) {\n if (listEl.classList.contains('an-checklist')) {\n // Checklist → UL: strip checkboxes and class, swap tag if needed\n stripChecklist(listEl);\n if (listEl.tagName === 'OL') {\n changeTagName(listEl, 'ul');\n }\n } else if (listEl.tagName === 'OL') {\n // OL → UL: swap container tag\n changeTagName(listEl, 'ul');\n } else {\n // Already UL → toggle off via execCommand\n execCommand('insertUnorderedList');\n }\n } else {\n // Not in a list → create new UL via execCommand\n execCommand('insertUnorderedList');\n }\n}\n\n/**\n * Inserts an ordered (numbered) list, or converts the current list to `<ol>`.\n *\n * When the cursor is already inside a list, direct DOM manipulation is used to\n * transition between list types — `execCommand` alone cannot handle checklist →\n * UL/OL conversions because it has no awareness of the `an-checklist` class or\n * the checkbox `<input>` elements.\n *\n * Transition paths:\n * - **Checklist → OL**: strips `an-checklist` class and all checkbox inputs;\n * converts container to `<ol>` via `changeTagName()`.\n * - **UL → OL**: swaps the container tag via `changeTagName()`.\n * - **OL → paragraphs**: falls back to `execCommand('insertOrderedList')`\n * which toggles the list off (browser-native behaviour).\n * - **No list → OL**: falls back to `execCommand('insertOrderedList')`.\n */\nexport function insertOrderedList() {\n const listEl = getSelectedList();\n if (listEl) {\n if (listEl.classList.contains('an-checklist')) {\n // Checklist → OL: strip checkboxes and class, swap to <ol>\n stripChecklist(listEl);\n changeTagName(listEl, 'ol');\n } else if (listEl.tagName === 'UL') {\n // UL → OL: swap container tag\n changeTagName(listEl, 'ol');\n } else {\n // Already OL → toggle off via execCommand\n execCommand('insertOrderedList');\n }\n } else {\n // Not in a list → create new OL via execCommand\n execCommand('insertOrderedList');\n }\n}\n\n// ---------------------------------------------------------------------------\n// Line-height helper\n// ---------------------------------------------------------------------------\n\n/**\n * Set the line-height on every block-level element that intersects the current selection.\n *\n * If the selection is collapsed, the nearest enclosing block element receives the style.\n * For a non-collapsed selection, all unique block ancestors of text nodes that intersect the range are updated;\n * if none are found, the nearest block ancestor of the range's common ancestor is updated.\n * @param {string} value - Line-height value to apply; typically a unitless multiplier (for example, \"1.5\").\n */\nexport function lineHeight(value) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n\n const range = sel.getRangeAt(0);\n const BLOCK_TAGS = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI', 'BLOCKQUOTE', 'PRE', 'TD', 'TH']);\n\n const nearestBlock = (node) => {\n let el = node instanceof Element ? node : node.parentElement;\n while (el) {\n if (BLOCK_TAGS.has(el.tagName)) return el;\n el = el.parentElement;\n }\n return null;\n };\n\n if (range.collapsed) {\n const block = nearestBlock(range.startContainer);\n if (block) block.style.lineHeight = value;\n return;\n }\n\n // For a range selection, collect all unique block ancestors of text nodes\n const blocks = new Set();\n const iter = document.createTreeWalker(\n range.commonAncestorContainer,\n NodeFilter.SHOW_TEXT,\n { acceptNode: (node) => range.intersectsNode(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP },\n );\n let textNode;\n while ((textNode = iter.nextNode())) {\n const block = nearestBlock(textNode);\n if (block) blocks.add(block);\n }\n if (blocks.size === 0) {\n const block = nearestBlock(range.commonAncestorContainer);\n if (block) blocks.add(block);\n }\n blocks.forEach((block) => { block.style.lineHeight = value; });\n}\n\n// ---------------------------------------------------------------------------\n// Style query helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the computed styles relevant to the current cursor position.\n * @param {HTMLElement} editable\n * @returns {object} styleMap\n */\nexport function currentStyle(editable) {\n const range = currentRange(editable);\n if (!range) return {};\n\n const container = range.isCollapsed()\n ? range.sc\n : range.commonAncestor();\n\n const el = /** @type {Element|null} */ (isElement(container) ? container : container.parentElement);\n if (!el) return {};\n\n const computed = globalThis.getComputedStyle(el);\n\n return {\n bold: document.queryCommandState('bold'),\n italic: document.queryCommandState('italic'),\n underline: document.queryCommandState('underline'),\n strikethrough: document.queryCommandState('strikeThrough'),\n superscript: document.queryCommandState('superscript'),\n subscript: document.queryCommandState('subscript'),\n fontSize: computed.fontSize,\n fontFamily: computed.fontFamily,\n color: computed.color,\n backgroundColor: computed.backgroundColor,\n textAlign: computed.textAlign,\n lineHeight: computed.lineHeight,\n formatBlock: (closest(el, isPara, editable) || { nodeName: 'p' }).nodeName.toLowerCase(),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Inline code toggle\n// ---------------------------------------------------------------------------\n\n/**\n * Wraps the selection in an inline <code> element, or unwraps it if the\n * cursor is already inside a <code> that is not inside a <pre>.\n * @param {HTMLElement} [_editable]\n */\nexport function toggleInlineCode(_editable) {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n const range = sel.getRangeAt(0);\n let container = range.commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n const codeEl = /** @type {Element|null} */ (container)?.closest('code');\n if (codeEl && !codeEl.closest('pre')) {\n // Unwrap — save range endpoints relative to surrounding text so we can\n // restore the selection after normalize() merges adjacent text nodes.\n const parent = codeEl.parentNode;\n // Note the sibling before the code element so we can re-anchor later.\n const prevSibling = codeEl.previousSibling;\n const movedChildren = Array.from(codeEl.childNodes);\n while (codeEl.firstChild) parent.insertBefore(codeEl.firstChild, codeEl);\n codeEl.remove();\n // Normalize only the immediate parent to merge adjacent text nodes without\n // invalidating distant selection anchors (full editable.normalize() can\n // cause selection offsets to shift, making subsequent format toggles miss).\n parent?.normalize();\n // Restore selection to the text that was inside the unwrapped <code>.\n if (movedChildren.length > 0) {\n try {\n // After normalize, find the merged text node that contains the content.\n const firstMoved = movedChildren[0];\n const lastMoved = movedChildren.at(-1);\n const nr = document.createRange();\n // Use the (possibly merged) live node if still in the DOM.\n const anchorNode = firstMoved.parentNode === parent\n ? firstMoved\n : (prevSibling ? prevSibling.nextSibling : parent.firstChild);\n if (anchorNode) {\n nr.setStart(anchorNode, 0);\n const endAnchor = (lastMoved.parentNode === parent) ? lastMoved : anchorNode;\n nr.setEnd(endAnchor, endAnchor.nodeType === Node.TEXT_NODE ? endAnchor.textContent.length : endAnchor.childNodes.length);\n sel.removeAllRanges();\n sel.addRange(nr);\n }\n } catch (_) { void _; /* ignore */ }\n }\n } else {\n if (range.collapsed) return;\n try {\n const code = document.createElement('code');\n range.surroundContents(code);\n // Re-select wrapped content so subsequent format toggles work\n const newRange = document.createRange();\n newRange.selectNodeContents(code);\n sel.removeAllRanges();\n sel.addRange(newRange);\n } catch {\n // surroundContents fails across element boundaries — extract and rewrap\n const frag = range.extractContents();\n const code = document.createElement('code');\n code.appendChild(frag);\n range.insertNode(code);\n // Re-select wrapped content\n const newRange = document.createRange();\n newRange.selectNodeContents(code);\n sel.removeAllRanges();\n sel.addRange(newRange);\n }\n }\n}\n\n/**\n * Returns true when the cursor / selection is inside an inline <code>\n * (not nested in a <pre>).\n * Uses startContainer for reliable cross-browser detection regardless of\n * whether the selection is collapsed or a range (commonAncestorContainer\n * can behave inconsistently for range selections on some browsers).\n * @returns {boolean}\n */\nexport function isInlineCode() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return false;\n let sc = sel.getRangeAt(0).startContainer;\n if (sc.nodeType === 3) sc = sc.parentElement;\n const code = /** @type {Element|null} */ (sc)?.closest('code');\n return !!(code && !code.closest('pre'));\n}\n\n// ---------------------------------------------------------------------------\n// Checklist (task list)\n// ---------------------------------------------------------------------------\n\n/**\n * Changes the tag name of an element in the DOM while preserving attributes and children.\n * @param {Element} el\n * @param {string} newTagName\n * @returns {HTMLElement}\n */\nfunction changeTagName(el, newTagName) {\n const newEl = document.createElement(newTagName);\n for (const attr of el.attributes) {\n newEl.setAttribute(attr.name, attr.value);\n }\n while (el.firstChild) {\n newEl.appendChild(el.firstChild);\n }\n el.parentNode.replaceChild(newEl, el);\n return newEl;\n}\n\n/**\n * Ensures all list items under the list element have a checkbox.\n * @param {Element} listEl\n */\nfunction ensureCheckboxes(listEl) {\n listEl.querySelectorAll('li').forEach(li => {\n const existingCb = li.querySelector('input[type=\"checkbox\"]');\n if (!existingCb) {\n const cb = document.createElement('input');\n cb.type = 'checkbox';\n cb.contentEditable = 'false';\n li.insertBefore(cb, li.firstChild);\n }\n });\n}\n\n/**\n * Toggle a checklist at the current selection or caret.\n */\nexport function toggleChecklist() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n const range = sel.getRangeAt(0);\n let container = range.commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n\n const listEl = /** @type {Element|null} */ (container)?.closest('ul, ol');\n if (listEl) {\n if (listEl.classList.contains('an-checklist')) {\n // Transition from Checklist to Paragraphs (Toggle off checklist entirely)\n const parent = listEl.parentNode;\n if (parent) {\n const lis = Array.from(listEl.children);\n let /** @type {HTMLParagraphElement|null} */ firstP = null;\n lis.forEach(li => {\n const p = document.createElement('p');\n for (const child of li.childNodes) {\n if (child.nodeType === 1 && /** @type {Element} */ (child).tagName === 'INPUT') continue;\n p.appendChild(child.cloneNode(true));\n }\n p.innerHTML = p.innerHTML.replaceAll('\\u200b', '').replaceAll('\\u200B', '');\n if (!p.hasChildNodes() || !p.textContent.trim()) {\n p.innerHTML = '';\n p.appendChild(document.createTextNode('\\u00a0'));\n }\n listEl.before(p);\n if (!firstP) firstP = p;\n });\n listEl.remove();\n \n if (firstP) {\n const nr = document.createRange();\n nr.setStart(firstP.firstChild || firstP, 0);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n }\n }\n } else {\n // Transition from standard UL/OL to Checklist\n const targetUl = changeTagName(listEl, 'ul');\n targetUl.classList.add('an-checklist');\n ensureCheckboxes(targetUl);\n \n // Place caret inside the first LI\n const firstLi = targetUl.querySelector('li');\n if (firstLi) {\n const nr = document.createRange();\n nr.selectNodeContents(firstLi);\n nr.collapse(false);\n sel.removeAllRanges();\n sel.addRange(nr);\n }\n }\n } else {\n // Selection is not in a list: build the checklist directly via DOM\n // manipulation. execCommand('insertUnorderedList') is intentionally\n // avoided here — its behaviour on collapsed/empty selections and\n // non-standard blocks (e.g. <section>) is too inconsistent across\n // browsers (and a no-op in jsdom), which left toggleChecklist() as a\n // silent no-op in those cases.\n // The editable root itself is a <div> and must never be treated as a\n // \"block\" to convert/replace/remove — otherwise selections that include\n // raw text nodes sitting directly inside it (e.g. the first line typed\n // into an empty editor) would destroy the .an-editable element.\n const editableRoot = /** @type {Element|null} */ (container)?.closest('[contenteditable=\"true\"]');\n const isCollapsed = range.collapsed;\n if (isCollapsed) {\n // Find the nearest block-level ancestor (p, div, li, h1-h6, blockquote,\n // etc.) and convert it into a single checklist item.\n const BLOCK_TAGS = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE', 'LI']);\n let block = /** @type {Element|null} */ (container);\n while (block?.parentNode && block !== editableRoot && !BLOCK_TAGS.has(block.tagName)) {\n block = /** @type {Element|null} */ (block.parentNode);\n }\n if (block === editableRoot) block = null;\n // Fallback: if no block element found (e.g. cursor directly in editable\n // root), insert a fresh item with a zero-width-space so the cursor ends\n // up inside it.\n const itemText = (block && BLOCK_TAGS.has(block.tagName))\n ? Array.from(block.childNodes)\n .map((n) => n.textContent)\n .join('')\n .replaceAll('\\u00a0', ' ')\n : '';\n\n const newUl = document.createElement('ul');\n newUl.className = 'an-checklist';\n const li = document.createElement('li');\n const checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.contentEditable = 'false';\n li.appendChild(checkbox);\n li.appendChild(document.createTextNode(itemText || '\\u200B'));\n newUl.appendChild(li);\n\n if (block && BLOCK_TAGS.has(block.tagName)) {\n block.parentNode.replaceChild(newUl, block);\n } else {\n // Cursor directly in editable root — insert via Range API.\n const nativeRange = sel.getRangeAt(0);\n nativeRange.deleteContents();\n nativeRange.insertNode(newUl);\n }\n\n // Move caret to the text node inside the new <li>.\n const textNode = li.lastChild;\n const nr = document.createRange();\n const offset = textNode.nodeType === Node.TEXT_NODE ? textNode.textContent.length : 0;\n nr.setStart(textNode, offset);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n return;\n }\n\n // Non-collapsed selection — convert each intersected block element into\n // a checklist item using direct DOM manipulation.\n const rawSelText = sel.toString().replace(/[\\u00a0\\u200B]/g, ' ').trim();\n if (!rawSelText) return;\n\n const BLOCK_TAGS_MULTI = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE', 'PRE', 'LI']);\n\n // Collect block-level ancestors of every node in the selection, in order.\n const blocks = [];\n const seenBlocks = new Set();\n const commonAncestor = range.commonAncestorContainer;\n const iter = document.createNodeIterator(\n commonAncestor.nodeType === Node.TEXT_NODE ? commonAncestor.parentNode : commonAncestor,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT,\n null,\n );\n let node;\n while ((node = iter.nextNode())) {\n if (!range.intersectsNode(node)) continue;\n let blockEl = /** @type {Element|null} */ (node.nodeType === Node.TEXT_NODE ? node.parentElement : node);\n while (blockEl && blockEl !== editableRoot && !BLOCK_TAGS_MULTI.has(blockEl.tagName)) {\n blockEl = blockEl.parentElement;\n }\n if (blockEl === editableRoot) blockEl = null;\n if (blockEl && !seenBlocks.has(blockEl)) {\n seenBlocks.add(blockEl);\n blocks.push(blockEl);\n }\n }\n\n if (blocks.length === 0) return;\n\n // Build checklist and replace collected blocks.\n const newUl = document.createElement('ul');\n newUl.className = 'an-checklist';\n /** @type {Text|null} */ let lastTextNode = null;\n blocks.forEach((block) => {\n const li = document.createElement('li');\n const cb = document.createElement('input');\n cb.type = 'checkbox';\n cb.contentEditable = 'false';\n li.appendChild(cb);\n // Preserve plain text content; ZWS/NBSP are stripped for display.\n const blockText = Array.from(block.childNodes)\n .map((n) => n.textContent)\n .join('')\n .replace(/[\\u00a0\\u200B]/g, ' ')\n .trim();\n const tn = document.createTextNode(blockText || '\\u200B');\n li.appendChild(tn);\n newUl.appendChild(li);\n lastTextNode = tn;\n });\n\n // Insert the new list before the first block, then remove all source blocks.\n const firstBlock = blocks[0];\n firstBlock.parentNode.insertBefore(newUl, firstBlock);\n blocks.forEach((block) => block.remove());\n\n // Move caret to end of the last checklist item.\n if (lastTextNode) {\n const nr = document.createRange();\n nr.setStart(lastTextNode, lastTextNode.textContent.length);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n }\n }\n}\n\n/**\n * Returns true when the cursor is inside a checklist item.\n * @returns {boolean}\n */\nexport function isInChecklist() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return false;\n let container = sel.getRangeAt(0).commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n return !!(/** @type {Element|null} */ (container)?.closest('.an-checklist li'));\n}\n","/**\n * Buttons.js - Toolbar button definitions and factories\n * All buttons are plain objects describing their appearance and action.\n * They are rendered by the Toolbar module.\n */\n\nimport * as Style from '../editing/Style.js';\n\n// ---------------------------------------------------------------------------\n// Dropdown definition helper\n// ---------------------------------------------------------------------------\n\n/**\n * @typedef {object} DropdownDef\n * @property {string} name - unique identifier\n * @property {'select'} type - discriminator for Toolbar renderer\n * @property {string} tooltip\n * @property {Array<string|{value:string,label:string,disabled?:boolean}>} [items] - overridden at render time from options\n * @property {Function} action - called with (context, value)\n * @property {Function} [getValue] - called with (context) to get current value\n * @property {string} [selectClass] - extra CSS class(es) for the <select>\n * @property {string} [placeholder] - placeholder text for the empty option\n */\n\n// ---------------------------------------------------------------------------\n// Button factory helpers\n// ---------------------------------------------------------------------------\n\n/**\n * @typedef {object} ButtonDef\n * @property {string} name - unique identifier\n * @property {string} icon - SVG or HTML icon markup / text\n * @property {string} tooltip - tooltip string\n * @property {Function} action - called with (context) when clicked\n * @property {Function} [isActive] - called with (context) to determine active state\n * @property {Function} [isDisabled] - called with (context) to determine disabled state\n * @property {string} [className] - extra CSS class(es)\n */\n\n/**\n * Creates a simple button definition.\n * @param {string} name\n * @param {string} icon\n * @param {string} tooltip\n * @param {Function} action\n * @param {Function} [isActive]\n * @param {Function} [isDisabled]\n * @returns {ButtonDef}\n */\nfunction btn(name, icon, tooltip, action, isActive, isDisabled) {\n // `icon` is an identifier (e.g. 'bold', 'italic'). Rendering to\n // visual markup (FontAwesome or fallback) is done in Toolbar._createButton\n return { name, icon, tooltip, action, isActive, isDisabled };\n}\n\n// ---------------------------------------------------------------------------\n// Global button registry\n// ---------------------------------------------------------------------------\n\n/**\n * Global registry for custom buttons registered via AutumnNote.registerButton()\n * or via a plugin's `buttons` array. Toolbar resolves string names from here.\n * @type {Map<string, object>}\n */\nexport const _buttonRegistry = new Map();\n\n/**\n * Registers a button definition in the global registry so it can be referenced\n * by string name in toolbar configuration: `toolbar: [['myBtn', boldBtn]]`.\n * @param {object} btnDef - Any ToolbarItemDef-compatible object with a `name` string.\n */\nexport function registerButton(btnDef) {\n if (!btnDef || typeof btnDef.name !== 'string') {\n console.warn('[AutumnNote] registerButton: btnDef must have a string `name` property.');\n return;\n }\n if (_buttonRegistry.has(btnDef.name)) {\n console.warn(`[AutumnNote] registerButton: overwriting existing button \"${btnDef.name}\".`);\n }\n _buttonRegistry.set(btnDef.name, btnDef);\n}\n\n/**\n * Looks up a button definition by name from the global registry.\n * Returns undefined when not found.\n * @param {string} name\n * @returns {object|undefined}\n */\nexport function getButton(name) {\n return _buttonRegistry.get(name);\n}\n\n// ---------------------------------------------------------------------------\n// Style buttons\n// ---------------------------------------------------------------------------\n\nexport const boldBtn = btn('bold', 'bold', 'Bold (Ctrl+B)', () => Style.bold(), () => document.queryCommandState('bold'));\nexport const italicBtn = btn('italic', 'italic', 'Italic (Ctrl+I)', () => Style.italic(), () => document.queryCommandState('italic'));\nexport const underlineBtn = btn('underline', 'underline', 'Underline (Ctrl+U)', () => Style.underline(), () => {\n // queryCommandState('underline') is unreliable inside <code> elements;\n // also check for a <u> ancestor in the DOM using startContainer for\n // consistent behaviour across both collapsed and range selections.\n if (document.queryCommandState('underline')) return true;\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return false;\n let sc = sel.getRangeAt(0).startContainer;\n if (sc.nodeType === 3) sc = sc.parentElement;\n return !!(/** @type {Element} */ (sc)?.closest('u'));\n});\nexport const strikeBtn = btn('strikethrough', 'strikethrough', 'Strikethrough', () => Style.strikethrough(), () => document.queryCommandState('strikeThrough'));\nexport const superscriptBtn = btn('superscript', 'superscript', 'Superscript', () => Style.superscript(), () => document.queryCommandState('superscript'));\nexport const subscriptBtn = btn('subscript', 'subscript', 'Subscript', () => Style.subscript(), () => document.queryCommandState('subscript'));\n\n// ---------------------------------------------------------------------------\n// Alignment buttons\n// ---------------------------------------------------------------------------\n\nexport const alignLeftBtn = btn('alignLeft', 'align-left', 'Align Left', () => Style.justifyLeft());\nexport const alignCenterBtn = btn('alignCenter', 'align-center', 'Align Center', () => Style.justifyCenter());\nexport const alignRightBtn = btn('alignRight', 'align-right', 'Align Right', () => Style.justifyRight());\nexport const alignJustifyBtn = btn('alignJustify', 'align-justify', 'Justify', () => Style.justifyFull());\n\n// ---------------------------------------------------------------------------\n// List buttons\n// ---------------------------------------------------------------------------\n\nexport const ulBtn = btn('ul', 'list-ul', 'Unordered List', () => Style.insertUnorderedList());\nexport const olBtn = btn('ol', 'list-ol', 'Ordered List', () => Style.insertOrderedList());\n\n// ---------------------------------------------------------------------------\n// Indent buttons\n// ---------------------------------------------------------------------------\n\nexport const indentBtn = btn('indent', 'indent', 'Indent', () => Style.indent());\nexport const outdentBtn = btn('outdent', 'outdent', 'Outdent', () => Style.outdent());\n\n// ---------------------------------------------------------------------------\n// Undo / redo buttons\n// ---------------------------------------------------------------------------\n\nexport const undoBtn = btn('undo', 'undo', 'Undo (Ctrl+Z)', (_ctx) => _ctx.invoke('editor.undo'), undefined, (ctx) => !ctx.invoke('editor.canUndo'));\nexport const redoBtn = btn('redo', 'redo', 'Redo (Ctrl+Y)', (_ctx) => _ctx.invoke('editor.redo'), undefined, (ctx) => !ctx.invoke('editor.canRedo'));\n\n// ---------------------------------------------------------------------------\n// Insert media — HR, Link, Image\n// ---------------------------------------------------------------------------\n\nexport const hrBtn = btn('hr', 'minus', 'Horizontal Rule', () => Style.execCommand('insertHorizontalRule'));\nexport const linkBtn = btn('link', 'link', 'Insert Link', (ctx) => ctx.invoke('linkDialog.show'));\nexport const imageBtn = btn('image', 'image', 'Insert Image', (ctx) => ctx.invoke('imageDialog.show'));\nexport const videoBtn = btn('video', 'video', 'Insert Video', (ctx) => ctx.invoke('videoDialog.show'));\nexport const emojiBtn = btn('emoji', 'emoji', 'Insert Emoji', (ctx) => ctx.invoke('emojiDialog.show'));\nexport const iconBtn = btn('icon', 'icon', 'Insert FA Icon', (ctx) => ctx.invoke('iconDialog.show'));\n\n/** @type {ButtonDef & { type: 'grid' }} */\nexport const tableBtn = {\n name: 'table',\n type: 'grid',\n icon: 'table',\n tooltip: 'Insert Table',\n action: (ctx, rows, cols) => {\n ctx.invoke('editor.insertTable', cols, rows);\n ctx.invoke('editor.afterCommand');\n },\n};\n\n// ---------------------------------------------------------------------------\n// Font size dropdown\n// ---------------------------------------------------------------------------\n\n/** @type {DropdownDef} */\nexport const fontSizeBtn = {\n name: 'fontSize',\n type: 'select',\n tooltip: 'Font Size',\n placeholder: 'Size',\n selectClass: 'an-select-narrow',\n items: ['8px', '10px', '11px', '12px', '13px', '14px', '16px', '18px', '20px', '24px', '28px', '32px', '36px', '48px', '72px'],\n action: (ctx, value) => Style.fontSize(value, ctx.layoutInfo.editable),\n getValue: (ctx) => {\n try {\n const sel = globalThis.getSelection();\n if (sel?.rangeCount) {\n let el = /** @type {Element|null} */ (sel.getRangeAt(0).startContainer);\n if (el?.nodeType === 3) el = el.parentElement;\n while (el?.nodeType === 1 && !/** @type {HTMLElement} */ (el).style.fontSize) el = el.parentElement;\n const size = /** @type {HTMLElement} */ (el)?.style.fontSize || '';\n if (size) return size;\n }\n // Fallback: read the base font size from the editable element itself\n const editable = ctx?.layoutInfo?.editable;\n if (editable) return editable.style.fontSize || '';\n return '';\n } catch { return ''; }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Remove format button\n// ---------------------------------------------------------------------------\n\nexport const removeFormatBtn = btn('removeFormat', 'remove-format', 'Remove Format', () => Style.execCommand('removeFormat'));\n\n// ---------------------------------------------------------------------------\n// Direction (LTR / RTL) toggle button\n// ---------------------------------------------------------------------------\n\nexport const directionBtn = btn(\n 'direction',\n 'direction',\n 'Toggle Text Direction (LTR / RTL)',\n (ctx) => {\n const editable = ctx.layoutInfo.editable;\n const current = editable.getAttribute('dir') || 'ltr';\n const next = current === 'ltr' ? 'rtl' : 'ltr';\n editable.setAttribute('dir', next);\n editable.style.textAlign = next === 'rtl' ? 'right' : 'left';\n ctx.invoke('editor.afterCommand');\n },\n);\n\n// ---------------------------------------------------------------------------\n// Font family dropdown\n// ---------------------------------------------------------------------------\n\n/** @type {DropdownDef} */\nexport const fontFamilyBtn = {\n name: 'fontFamily',\n type: 'select',\n tooltip: 'Font Family',\n action: (ctx, value) => Style.fontName(value),\n getValue: () => {\n try { return document.queryCommandValue('fontName') || ''; } catch { return ''; }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Paragraph style dropdown (Normal / H1-H6 / Quote / Code)\n// ---------------------------------------------------------------------------\n\n/** @type {DropdownDef} */\nexport const paragraphStyleBtn = {\n name: 'paragraphStyle',\n type: 'select',\n tooltip: 'Paragraph Style',\n placeholder: 'Style',\n selectClass: 'an-select-style',\n items: [\n { value: 'p', label: 'Normal' },\n { value: 'h1', label: 'H1' },\n { value: 'h2', label: 'H2' },\n { value: 'h3', label: 'H3' },\n { value: 'h4', label: 'H4' },\n { value: 'h5', label: 'H5' },\n { value: 'h6', label: 'H6' },\n { value: 'blockquote', label: 'Quote' },\n { value: 'pre', label: 'Code' },\n ],\n action: (_ctx, value) => Style.formatBlock(value),\n getValue: () => {\n try {\n const raw = document.queryCommandValue('formatBlock').toLowerCase().replace(/[<>]/g, '');\n return raw === 'div' ? 'p' : (raw || 'p');\n } catch { return ''; }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Line-height dropdown\n// ---------------------------------------------------------------------------\n\n/** @type {DropdownDef} */\nexport const lineHeightBtn = {\n name: 'lineHeight',\n type: 'select',\n tooltip: 'Line Height',\n placeholder: '\\u2195 Line',\n selectClass: 'an-select-narrow',\n items: ['1.0', '1.15', '1.5', '1.75', '2.0', '2.5', '3.0'],\n action: (_ctx, value) => Style.lineHeight(value),\n getValue: () => {\n try {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return '';\n const BLOCKS = new Set(['P','DIV','H1','H2','H3','H4','H5','H6','LI','BLOCKQUOTE','PRE','TD','TH']);\n let el = /** @type {Element|null} */ (sel.getRangeAt(0).startContainer);\n if (el?.nodeType === 3) el = el.parentElement;\n while (el && !BLOCKS.has(/** @type {Element} */ (el).tagName)) el = el.parentElement;\n if (!el) return '';\n return /** @type {HTMLElement} */ (el).style.lineHeight || getComputedStyle(/** @type {Element} */ (el)).lineHeight || '';\n } catch { return ''; }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Code view / fullscreen\n// ---------------------------------------------------------------------------\n\nexport const codeviewBtn = btn('codeview', 'code', 'HTML Code View', (ctx) => ctx.invoke('codeview.toggle'), (ctx) => ctx.invoke('codeview.isActive'));\nexport const fullscreenBtn = btn('fullscreen', 'expand', 'Fullscreen', (ctx) => ctx.invoke('fullscreen.toggle'), (ctx) => ctx.invoke('fullscreen.isActive'));\nexport const shortcutsBtn = btn('shortcuts', 'keyboard', 'Keyboard Shortcuts (Ctrl+Shift+/)', (ctx) => ctx.invoke('shortcutsDialog.show'));\nexport const findBtn = btn('find', 'search', 'Find (Ctrl+F)', (ctx) => ctx.invoke('findReplace.show', 'find'));\nexport const findReplaceBtn = btn('findReplace', 'find-replace', 'Find & Replace (Ctrl+H)', (ctx) => ctx.invoke('findReplace.show', 'replace'));\nexport const inlineCodeBtn = btn('inlineCode', 'inline-code', 'Inline Code (Ctrl+`)', (ctx) => ctx.invoke('editor.inlineCode'), () => Style.isInlineCode());\nexport const checklistBtn = btn('checklist', 'checklist', 'Checklist', (ctx) => ctx.invoke('editor.toggleChecklist'), () => Style.isInChecklist());\nexport const printBtn = btn('print', 'print', 'Print', (ctx) => ctx.invoke('editor.print'));\n\n// ---------------------------------------------------------------------------\n// Text / background colour pickers\n// ---------------------------------------------------------------------------\n\n/** @type {{ name: string, type: 'colorpicker', icon: string, tooltip: string, defaultColor: string, action: Function }} */\nexport const foreColorBtn = {\n name: 'foreColor',\n type: 'colorpicker',\n icon: 'foreColor',\n tooltip: 'Text Color',\n defaultColor: '#e11d48',\n action: (ctx, color) => Style.foreColor(color),\n};\n\n/** @type {{ name: string, type: 'colorpicker', icon: string, tooltip: string, defaultColor: string, action: Function }} */\nexport const backColorBtn = {\n name: 'backColor',\n type: 'colorpicker',\n icon: 'backColor',\n tooltip: 'Highlight Color',\n defaultColor: '#fbbf24',\n action: (ctx, color) => Style.backColor(color),\n};\n\n// ---------------------------------------------------------------------------\n// Default toolbar layout\n// ---------------------------------------------------------------------------\n\n/**\n * The default toolbar button groups.\n * Each sub-array is a button group (separated by a divider).\n */\nexport const defaultToolbar = [\n [paragraphStyleBtn, fontFamilyBtn, fontSizeBtn, lineHeightBtn],\n [undoBtn, redoBtn],\n [boldBtn, italicBtn, underlineBtn, strikeBtn, inlineCodeBtn],\n [superscriptBtn, subscriptBtn],\n [foreColorBtn, backColorBtn],\n [alignLeftBtn, alignCenterBtn, alignRightBtn, alignJustifyBtn],\n [ulBtn, olBtn, checklistBtn, indentBtn, outdentBtn],\n [hrBtn, linkBtn, imageBtn, videoBtn, tableBtn, emojiBtn, iconBtn],\n [removeFormatBtn, codeviewBtn, fullscreenBtn, findBtn, printBtn, shortcutsBtn],\n];\n\n// ---------------------------------------------------------------------------\n// Buttons namespace — all pre-built button definitions in a single object.\n// Exposed as AutumnNote.buttons so UMD / CJS consumers can access them\n// without named imports: AutumnNote.buttons.boldBtn, etc.\n// ---------------------------------------------------------------------------\n\nexport const buttons = {\n boldBtn,\n italicBtn,\n underlineBtn,\n strikeBtn,\n superscriptBtn,\n subscriptBtn,\n alignLeftBtn,\n alignCenterBtn,\n alignRightBtn,\n alignJustifyBtn,\n ulBtn,\n olBtn,\n indentBtn,\n outdentBtn,\n undoBtn,\n redoBtn,\n hrBtn,\n linkBtn,\n imageBtn,\n videoBtn,\n emojiBtn,\n iconBtn,\n tableBtn,\n fontSizeBtn,\n removeFormatBtn,\n directionBtn,\n fontFamilyBtn,\n paragraphStyleBtn,\n lineHeightBtn,\n codeviewBtn,\n fullscreenBtn,\n shortcutsBtn,\n findBtn,\n findReplaceBtn,\n inlineCodeBtn,\n checklistBtn,\n printBtn,\n foreColorBtn,\n backColorBtn,\n defaultToolbar,\n};\n","/**\n * settings.js - Default editor options\n * Inspired by Summernote's settings.js\n */\n\nimport { defaultToolbar } from './module/Buttons.js';\n\n/**\n * @typedef {object} AsnOptions\n * @property {string} [placeholder] - Placeholder text when editor is empty\n * @property {number} [height] - Editor height in px (min)\n * @property {number} [minHeight] - Minimum height in px\n * @property {number} [maxHeight] - Maximum height in px (0 = unlimited)\n * @property {boolean} [focus] - Auto-focus on init\n * @property {boolean} [resizable] - Show resize handle\n * @property {Array} [toolbar] - Toolbar button group config\n * @property {boolean} [useBootstrap] - Use Bootstrap button classes on toolbar buttons\n * @property {string} [toolbarButtonClass] - CSS classes for Bootstrap toolbar buttons\n * @property {boolean} [useFontAwesome] - Use Font Awesome icons (default: true)\n * @property {string} [fontAwesomeClass] - Font Awesome prefix class, e.g. 'fas' or 'fa-solid'\n * @property {boolean} [fontAwesomeAutoInject] - Let the icon dialog inject Font Awesome CSS from a CDN when the host page has none (default: true)\n * @property {string} [fontAwesomeCDN] - Stylesheet URL used by that injection (defaults to cdnjs FA 6 Free)\n * @property {boolean} [pasteAsPlainText] - Force plain-text paste\n * @property {boolean} [pasteCleanHTML] - Sanitise HTML on paste\n * @property {boolean} [pasteStripAttributes] - Strip class/style/data-* from pasted HTML (default: false)\n * @property {boolean} [allowImageUpload] - Allow file upload in image dialog\n * @property {number} [maxImageSize] - Max upload size in MB\n * @property {number} [tabSize] - Spaces per tab in non-list context\n * @property {number} [historyLimit] - Maximum undo/redo history steps\n * @property {number} [historyMaxBytes] - Maximum combined size (chars) of all stacked undo/redo snapshots\n * @property {string} [defaultFontFamily] - Default font family applied to the editable area on init\n * @property {string} [defaultFontSize] - Default font size applied to the editable area on init (e.g. '14px')\n * @property {string[]} [fontFamilies] - Font families shown in the font-family toolbar dropdown\n * @property {Function} [onChange] - Callback on content change\n * @property {Function} [onFocus] - Callback on focus\n * @property {Function} [onBlur] - Callback on blur\n * @property {Function} [onInit] - Callback after the editor has initialised\n * @property {Function} [onImageUpload] - Upload handler: (files, { context, setProgress }) => void | string | string[] | Promise<string|string[]>.\n * Return (or resolve to) the uploaded URL(s) and the editor inserts a placeholder\n * immediately and swaps the real URL in when it arrives. Returning nothing keeps\n * the old behaviour: the handler is responsible for inserting the image itself.\n * @property {Function} [onImageError] - Callback when an image upload error occurs\n * @property {boolean} [stickyToolbar] - Stick the toolbar to the viewport top when scrolling\n * @property {number} [stickyToolbarOffset] - Top offset in px for sticky toolbar (e.g. fixed nav height)\n * @property {string} [theme] - 'light' (default) | 'dark'\n * @property {boolean} [codeHighlight] - Auto-load Prism.js for syntax highlighting of code blocks\n * @property {string} [codeHighlightCDN] - CDN base URL for Prism assets (defaults to cdnjs)\n * @property {boolean} [markdownPaste] - Convert pasted Markdown text to HTML (default: true)\n * @property {boolean} [readOnly] - Start editor in read-only / non-editable mode\n * @property {boolean} [spellcheck] - Enable browser spellcheck in the editable area (default: true)\n * @property {string} [direction] - Text direction: 'ltr' (default) | 'rtl'\n * @property {string} [toolbarOverflow] - Toolbar overflow strategy: 'wrap' (default) | 'scroll'\n * @property {boolean} [autoSave] - Auto-save content to localStorage on change\n * @property {string} [autoSaveKey] - localStorage key used for auto-save (default: 'autumnnote-autosave')\n * @property {number} [autoSaveDelay] - Debounce delay for auto-save writes in milliseconds\n * @property {object|null} [autoSaveAdapter] - Optional async persistence adapter with save/load/remove methods\n * @property {number} [maxChars] - Maximum character count (0 = unlimited). Shows warning in statusbar.\n * @property {number} [maxWords] - Maximum word count (0 = unlimited). Shows warning in statusbar.\n * @property {boolean} [tableHeaderRow] - Insert a header row (<thead><th>) when creating tables\n * @property {Function} [onPaste] - Callback fired on every paste: ({ text, html }) => void\n * @property {Function} [onPasteError] - Callback fired when pasted or dropped content cannot be processed\n * @property {Function} [onSelectionChange] - Callback fired on cursor/selection change: (context) => void\n * @property {string[]} [colorSwatches] - Custom brand colour swatches prepended to the colour-picker palette\n * @property {Function} [onDestroy] - Callback fired when the editor is destroyed: (context) => void\n * @property {Function} [onCharLimitReached] - Callback fired when the character limit is hit: (context) => void\n * @property {Function} [onWordLimitReached] - Callback fired when the word limit is hit: (context) => void\n * @property {string} [focusColor] - Custom focus ring colour, e.g. '#f97316'. Overrides the default blue.\n * @property {boolean} [autoSaveRestore] - Show a restore banner when a previously auto-saved draft exists\n * @property {number} [autoSaveRestoreTimeout] - Maximum age in days for a draft to be offered for restore (0 = no expiry)\n * @property {Function} [onAutoSaveRestore] - Callback fired after the user chooses to restore a draft\n * @property {boolean} [markdownShortcuts] - Convert markdown syntax typed inline to HTML\n * @property {boolean} [bubbleToolbar] - Show a mini floating toolbar above text selections\n * @property {string[]} [bubbleToolbarItems] - Button names for the bubble toolbar\n * @property {object|null} [mention] - @mention configuration (onSearch, minChars, ...)\n * @property {boolean} [slashMenu] - Show a \"/\" command palette for quick block insertion (default true)\n * @property {string} [lang] - Display language or partial locale object override\n */\n\nexport const defaultOptions = {\n placeholder: '',\n height: 200,\n minHeight: 100,\n maxHeight: 0,\n focus: false,\n resizable: true,\n toolbar: defaultToolbar,\n // UI integration options\n // If `useBootstrap` is true, toolbar buttons will use the Bootstrap button classes\n // (set `toolbarButtonClass` to customize). Works with Bootstrap 4 and 5.\n useBootstrap: false,\n toolbarButtonClass: 'btn btn-sm btn-light',\n // Icon options — uses Font Awesome by default. Consumers must include Font Awesome CSS.\n useFontAwesome: true,\n // Default FontAwesome prefix — 'fas' for FA5, 'fa-solid' for FA6. Change if needed.\n fontAwesomeClass: 'fas',\n // The icon dialog needs FA glyphs to render its grid. When the host page ships\n // no Font Awesome of its own, it pulls the stylesheet from a CDN. Set to false\n // on pages with a strict CSP, an offline deployment, or a no-third-party-request\n // policy — the dialog still works, it just renders without glyphs unless the\n // page provides FA itself.\n fontAwesomeAutoInject: true,\n fontAwesomeCDN: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css',\n pasteAsPlainText: false,\n pasteCleanHTML: true,\n pasteStripAttributes: false,\n allowImageUpload: true,\n maxImageSize: 5,\n tabSize: 4,\n onChange: null,\n onFocus: null,\n onBlur: null,\n onInit: null,\n onImageUpload: null,\n onImageError: null,\n stickyToolbar: false,\n stickyToolbarOffset: 0,\n theme: 'light',\n codeHighlight: true,\n codeHighlightCDN: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0',\n markdownPaste: true,\n historyLimit: 100,\n // Max combined size (chars) of all stacked undo/redo snapshots. Guards\n // against documents with many large embedded images holding dozens of\n // full-size copies in memory despite historyLimit.\n historyMaxBytes: 10 * 1024 * 1024,\n // Default font family applied to the editor and shown in the dropdown when no explicit font is set\n defaultFontFamily: 'Arial',\n // Default font size applied to the editor and shown in the size dropdown when no explicit size is set\n defaultFontSize: '14px',\n // Font families shown in the toolbar font-family dropdown\n fontFamilies: [\n 'Arial',\n 'Arial Black',\n 'Comic Sans MS',\n 'Courier New',\n 'Georgia',\n 'Impact',\n 'Tahoma',\n 'Times New Roman',\n 'Trebuchet MS',\n 'Verdana',\n ],\n // Read-only mode — disables all editing when true\n readOnly: false,\n // Enable/disable browser spell-check on the editable area\n spellcheck: true,\n // Text direction: 'ltr' (default) or 'rtl'\n direction: 'ltr',\n // How the toolbar handles overflow: 'wrap' (default, wraps to next line) or 'scroll' (single scrollable row)\n toolbarOverflow: 'wrap',\n // Auto-save content to localStorage on every change\n autoSave: false,\n // localStorage key used when autoSave is enabled\n autoSaveKey: 'autumnnote-autosave',\n autoSaveDelay: 400,\n autoSaveAdapter: null,\n // Maximum character count (0 = unlimited)\n maxChars: 0,\n // Maximum word count (0 = unlimited)\n maxWords: 0,\n // Insert a header row (<thead>) when creating new tables\n tableHeaderRow: false,\n // Callback fired on every cursor/selection change inside the editor\n onSelectionChange: null,\n // Custom brand colour swatches to prepend to the toolbar colour-picker palette\n colorSwatches: [],\n // Callback fired after a paste event: function({ text, html })\n onPaste: null,\n // Callback fired for rejected/failed paste and drop payloads: function({ message, size?, maxBytes? })\n onPasteError: null,\n // Callback fired just before the editor instance is destroyed\n onDestroy: null,\n // Callback fired when the character limit is reached: function(context)\n onCharLimitReached: null,\n // Callback fired when the word limit is reached: function(context)\n onWordLimitReached: null,\n // Custom focus ring colour — overrides the default blue when set.\n // Accepts any valid CSS colour string, e.g. '#f97316', 'hsl(25,90%,55%)'.\n focusColor: null,\n // Display language for the editor UI.\n // Built-in values: 'en' (default), 'vi', 'ja', 'zh', 'fr', 'de', 'es', 'ko'.\n // Pass a partial or full locale object to override individual strings.\n lang: 'en',\n\n // Auto-save restore: show a banner when a draft exists in localStorage.\n // Requires autoSave: true. Set autoSaveRestoreTimeout to the max age in days\n // (0 = no expiry). onAutoSaveRestore(html, context) fires after restore.\n autoSaveRestore: false,\n autoSaveRestoreTimeout: 7,\n onAutoSaveRestore: null,\n\n // Markdown input shortcuts: convert markdown syntax typed inline to HTML.\n // e.g. \"## \" at line start → <h2>, \"**bold**\" → <strong>\n markdownShortcuts: true,\n\n // \"/\" command palette for quick block insertion (headings, lists, table, image, ...).\n // Triggers only when \"/\" is the first character typed on an otherwise-empty line.\n slashMenu: true,\n // Additional slash-menu commands supplied by applications/plugins.\n slashCommands: [],\n\n // Optional import/export adapters keyed by format name.\n documentAdapters: {},\n // Optional collaboration bridge notified with local HTML changes.\n collaborationAdapter: null,\n\n // Optional image processor (for example a Web Worker bridge). Receives a\n // File and returns a data URL; Clipboard's canvas pipeline remains fallback.\n imageProcessor: null,\n // Add stable data-an-block-id attributes to top-level document blocks.\n blockIds: false,\n\n // Maximum paste size in bytes (default 5 MB). Pastes larger than this are silently dropped.\n maxPasteSize: 5 * 1024 * 1024,\n // Minimum image dimension in px during resize (width and height). Prevents images from being\n // resized below this value.\n minImageSize: 20,\n\n // Bubble toolbar: show a mini floating toolbar above text selections.\n bubbleToolbar: false,\n bubbleToolbarItems: ['bold', 'italic', 'underline', 'link', 'foreColor', 'hiliteColor', 'removeFormat'],\n\n // @mention support. mention.onSearch(query, callback) must be provided to activate.\n // mention.minChars defaults to 0 — dropdown opens immediately on trigger character.\n mention: null,\n};\n","/**\n * en.js - English locale (canonical reference)\n * All other locales deep-merge against this to fill missing keys.\n */\n\n/** @type {import('../../../types/index.js').AsnLocale} */\nexport const en = {\n toolbar: {\n bold: 'Bold (Ctrl+B)',\n italic: 'Italic (Ctrl+I)',\n underline: 'Underline (Ctrl+U)',\n strikethrough: 'Strikethrough',\n superscript: 'Superscript',\n subscript: 'Subscript',\n alignLeft: 'Align Left',\n alignCenter: 'Align Center',\n alignRight: 'Align Right',\n alignJustify: 'Justify',\n ul: 'Unordered List',\n ol: 'Ordered List',\n checklist: 'Checklist',\n indent: 'Indent',\n outdent: 'Outdent',\n undo: 'Undo (Ctrl+Z)',\n redo: 'Redo (Ctrl+Y)',\n hr: 'Horizontal Rule',\n link: 'Insert Link',\n image: 'Insert Image',\n video: 'Insert Video',\n emoji: 'Insert Emoji',\n icon: 'Insert FA Icon',\n table: 'Insert Table',\n fontSize: 'Font Size',\n fontSizePlaceholder: 'Size',\n removeFormat: 'Remove Format',\n direction: 'Toggle Text Direction (LTR / RTL)',\n fontFamily: 'Font Family',\n paragraphStyle: 'Paragraph Style',\n paragraphStylePlaceholder: 'Style',\n lineHeight: 'Line Height',\n lineHeightPlaceholder: '\\u2195 Line',\n codeview: 'HTML Code View',\n fullscreen: 'Fullscreen',\n shortcuts: 'Keyboard Shortcuts (Ctrl+Shift+/)',\n find: 'Find (Ctrl+F)',\n findReplace: 'Find & Replace (Ctrl+H)',\n inlineCode: 'Inline Code (Ctrl+`)',\n print: 'Print',\n foreColor: 'Text Color',\n backColor: 'Highlight Color',\n chooseTextColor: 'Choose text color',\n chooseHighlightColor: 'Choose highlight color',\n customColor: 'Custom color',\n insertTableLabel: 'Insert Table',\n /** Map of paragraph-style value → label (only values needing translation) */\n paragraphItems: {\n p: 'Normal',\n blockquote: 'Quote',\n pre: 'Code',\n },\n },\n\n linkDialog: {\n ariaLabel: 'Insert link',\n title: 'Insert Link',\n url: 'URL',\n urlPlaceholder: 'https://',\n displayText: 'Display Text',\n textPlaceholder: 'Link text',\n openInNewTab: 'Open in new tab',\n insertBtn: 'Insert',\n cancelBtn: 'Cancel',\n },\n\n imageDialog: {\n ariaLabel: 'Insert image',\n title: 'Insert Image',\n imageUrl: 'Image URL',\n urlPlaceholder: 'https://example.com/image.png',\n altText: 'Alt Text',\n altPlaceholder: 'Describe the image',\n alignment: 'Alignment',\n alignNone: 'None',\n alignLeft: 'Left',\n alignCenter: 'Center',\n alignRight: 'Right',\n uploadLabel: 'Or upload a file',\n insertBtn: 'Insert',\n cancelBtn: 'Cancel',\n },\n\n videoDialog: {\n ariaLabel: 'Insert video',\n title: 'Insert Video',\n videoUrl: 'Video URL',\n urlPlaceholder: 'YouTube, Vimeo, or direct .mp4 URL',\n widthLabel: 'Width (px)',\n widthPlaceholder: '560',\n insertBtn: 'Insert',\n cancelBtn: 'Cancel',\n /** @param {string} type */\n detected: (type) => `Detected: ${type}`,\n unknownFormat: 'Unknown format \\u2014 will try direct video embed',\n invalidUrl: 'Invalid URL \\u2014 please enter a valid video link.',\n },\n\n emojiDialog: {\n ariaLabel: 'Insert emoji',\n title: 'Insert Emoji',\n searchPlaceholder: 'Search emojis\\u2026',\n all: 'All',\n cancelBtn: 'Cancel',\n close: 'Close',\n categories: {\n smileys: 'Smileys',\n people: 'People',\n animals: 'Animals',\n food: 'Food',\n travel: 'Travel',\n objects: 'Objects',\n symbols: 'Symbols',\n },\n },\n\n iconDialog: {\n ariaLabel: 'Insert FA icon',\n title: 'Insert FA Icon',\n searchPlaceholder: 'Search icons\\u2026',\n all: 'All',\n style: 'Style',\n size: 'Size',\n color: 'Color',\n useColor: ' Use color',\n selectHint: 'Select an icon',\n insertBtn: 'Insert FA Icon',\n cancelBtn: 'Cancel',\n close: 'Close',\n categories: {\n popular: 'Popular',\n interface: 'Interface',\n navigation: 'Navigation',\n media: 'Media',\n communication: 'Communication',\n files: 'Files',\n people: 'People',\n objects: 'Objects',\n },\n },\n\n findReplace: {\n findTitle: 'Find',\n findReplaceTitle: 'Find & Replace',\n findPlaceholder: 'Find\\u2026',\n searchAriaLabel: 'Search text',\n caseSensitive: '\\u00a0Case sensitive',\n wholeWord: 'Whole Word',\n prevBtn: '\\u2190 Prev',\n nextBtn: 'Next \\u2192',\n replacePlaceholder: 'Replace with\\u2026',\n replaceAriaLabel: 'Replace with',\n replaceBtn: 'Replace',\n replaceAllBtn: 'Replace All',\n noResults: 'No results',\n useRegex: 'Use Regular Expression',\n close: '\\u00d7',\n },\n\n autoSaveRestore: {\n found: 'Draft found. Restore?',\n foundAt: 'Draft from {date}. Restore?',\n restore: 'Restore',\n discard: 'Discard',\n },\n\n shortcutsDialog: {\n title: 'Keyboard Shortcuts',\n ariaLabel: 'Keyboard Shortcuts',\n close: 'Close',\n shortcuts: [\n {\n category: 'Text Formatting',\n items: [\n { keys: 'Ctrl + B', action: 'Bold' },\n { keys: 'Ctrl + I', action: 'Italic' },\n { keys: 'Ctrl + U', action: 'Underline' },\n { keys: 'Ctrl + K', action: 'Insert / edit link' },\n ],\n },\n {\n category: 'History',\n items: [\n { keys: 'Ctrl + Z', action: 'Undo' },\n { keys: 'Ctrl + Y / Ctrl + Shift + Z', action: 'Redo' },\n ],\n },\n {\n category: 'Selection & Navigation',\n items: [\n { keys: 'Ctrl + A', action: 'Select all content' },\n { keys: 'Tab', action: 'Indent list item / insert spaces' },\n { keys: 'Shift + Tab', action: 'Outdent list item' },\n ],\n },\n {\n category: 'Clipboard',\n items: [\n { keys: 'Ctrl + Shift + V', action: 'Paste as plain text' },\n ],\n },\n {\n category: 'Find & Replace',\n items: [\n { keys: 'Ctrl + F', action: 'Find in document' },\n { keys: 'Ctrl + H', action: 'Find & Replace' },\n ],\n },\n {\n category: 'Editor',\n items: [\n { keys: 'Ctrl + Shift + /', action: 'Show this keyboard shortcuts dialog' },\n ],\n },\n ],\n },\n\n contextMenu: {\n cut: 'Cut',\n copy: 'Copy',\n paste: 'Paste',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n textColor: 'Text Color',\n highlightColor: 'Highlight Color',\n copyFormat: 'Copy Format',\n pasteFormat: 'Paste Format',\n removeFormat: 'Remove Format',\n link: 'Insert Link',\n image: 'Insert Image',\n video: 'Insert Video',\n table: 'Insert Table',\n back: 'Back',\n noHighlight: 'No highlight',\n customColor: 'Custom color',\n customColorLabel: 'Custom\\u2026',\n },\n\n statusbar: {\n resizeHandle: 'Resize editor',\n /** @param {number} n */\n words: (n) => `Words: ${n}`,\n /** @param {number} n @param {number} max */\n wordsLimit: (n, max) => `Words: ${n}/${max}`,\n /** @param {number} n */\n chars: (n) => `Chars: ${n}`,\n /** @param {number} n @param {number} max */\n charsLimit: (n, max) => `Chars: ${n}/${max}`,\n },\n\n tooltips: {\n link: {\n ariaLabel: 'Link actions',\n openLink: 'Open link',\n copyUrl: 'Copy URL',\n editLink: 'Edit link',\n removeLink: 'Remove link',\n },\n image: {\n ariaLabel: 'Image actions',\n label: 'Image',\n floatLeft: 'Float Left',\n noFloat: 'No Float',\n alignCenter: 'Align Center',\n floatRight: 'Float Right',\n originalSize: 'Original Size',\n rotateLeft: 'Rotate Left',\n rotateRight: 'Rotate Right',\n cropImage: 'Crop Image',\n addCaption: 'Add / Edit Caption',\n deleteImage: 'Delete Image',\n },\n code: {\n ariaLabel: 'Code block actions',\n label: 'Code',\n syntaxLanguage: 'Syntax Language',\n syntaxAriaLabel: 'Syntax language',\n copyCode: 'Copy Code',\n toggleWordWrap: 'Toggle Word Wrap',\n enableWordWrap: 'Enable Word Wrap',\n disableWordWrap: 'Disable Word Wrap',\n convertToParagraph: 'Convert to Paragraph',\n deleteCodeBlock: 'Delete Code Block',\n lineNumbers: 'Toggle Line Numbers',\n },\n table: {\n ariaLabel: 'Table actions',\n label: 'Table',\n selectCells: 'Select Cells',\n addRowAbove: 'Add Row Above',\n addRowBelow: 'Add Row Below',\n deleteRow: 'Delete Row',\n addColumnLeft: 'Add Column Left',\n addColumnRight: 'Add Column Right',\n deleteColumn: 'Delete Column',\n mergeCells: 'Merge Cells',\n unmergeCells: 'Unmerge Cells',\n columnWidth: 'Column Width',\n rowHeight: 'Row Height',\n tableBorderWidth: 'Table Border Width',\n tableBorderColor: 'Table Border Color',\n deleteTable: 'Delete Table',\n cellAlignLeft: 'Align Left',\n cellAlignCenter: 'Align Center',\n cellAlignRight: 'Align Right',\n cellAlignJustify: 'Align Justify',\n toggleHeaderRow: 'Toggle Header Row',\n cellBackground: 'Cell Background',\n noShading: 'No Shading',\n noBorderColor: 'No Border Color',\n columnWidthPx: 'Column Width (px)',\n rowHeightPx: 'Row Height (px)',\n tableBorderWidthPx: 'Table Border Width (px)',\n cancelBtn: 'Cancel',\n applyBtn: 'Apply',\n sortAsc: 'Sort Ascending',\n sortDesc: 'Sort Descending',\n exportCSV: 'Export as CSV',\n cellPadding: 'Cell Padding',\n cellPaddingPx: 'Cell Padding (px)',\n },\n video: {\n ariaLabel: 'Video actions',\n label: 'Video',\n floatLeft: 'Float Left',\n noFloat: 'No Float',\n alignCenter: 'Align Center',\n floatRight: 'Float Right',\n originalSize: 'Original Size',\n previewVideo: 'Preview Video',\n exitPreview: 'Exit Preview',\n deleteVideo: 'Delete Video',\n },\n },\n\n errors: {\n /** @param {string} type */\n imageFormat: (type) =>\n `Format \"${type}\" is not supported for display in web browsers. Please convert to JPEG, PNG, or WebP first.`,\n /** @param {number} maxSize */\n imageSize: (maxSize) =>\n `Image file is too large. Maximum allowed size is ${maxSize} MB.`,\n },\n\n slashMenu: {\n noResults: 'No matching commands',\n heading1: 'Heading 1',\n heading2: 'Heading 2',\n heading3: 'Heading 3',\n bulletList: 'Bullet List',\n numberedList: 'Numbered List',\n checklist: 'Checklist',\n blockquote: 'Blockquote',\n codeBlock: 'Code Block',\n horizontalRule: 'Horizontal Rule',\n table: 'Table',\n image: 'Image',\n },\n};\n","/**\n * i18n/index.js — Locale registry and resolver for autumn-note-ce.\n *\n * Only English ships in the ESM bundle. Bundling all eight locales cost every\n * consumer ~15 KB gzip even when they only ever rendered English, so the other\n * locales are opt-in via subpath imports:\n *\n * import AutumnNote from 'autumnnote';\n * import { vi } from 'autumnnote/i18n/vi';\n *\n * AutumnNote.registerLocale('vi', vi);\n * AutumnNote.create('#editor', { lang: 'vi' });\n *\n * The UMD/CDN build cannot tree-shake, so it pre-registers every locale and\n * `lang: 'vi'` keeps working there with no extra imports.\n *\n * Usage:\n * lang: 'en' → built-in English (always available)\n * lang: '<code>' → a locale previously passed to registerLocale()\n * lang: { ... } → custom locale object, deep-merged over English\n */\n\nimport { mergeDeep } from '../core/func.js';\nimport { en } from './en.js';\n\n/**\n * Locales available to `lang: '<code>'`. Starts with English only; other codes\n * are added through {@link registerLocale}.\n * @type {Record<string, Partial<AsnLocale>>}\n */\nexport const locales = { en };\n\n/**\n * Registers a locale so it can be selected by code.\n *\n * @param {string} code - Language code, e.g. 'vi'.\n * @param {Partial<AsnLocale>} locale - Locale object; missing keys fall back to English.\n * @returns {void}\n */\nexport function registerLocale(code, locale) {\n if (typeof code !== 'string' || !code) {\n throw new TypeError('[AutumnNote] registerLocale: code must be a non-empty string.');\n }\n if (!locale || typeof locale !== 'object') {\n throw new TypeError(`[AutumnNote] registerLocale: locale for \"${code}\" must be an object.`);\n }\n locales[code] = locale;\n}\n\n/**\n * Resolve a locale object from a lang option value.\n *\n * @param {string | Partial<AsnLocale> | null | undefined} lang\n * @returns {AsnLocale} A fully-populated locale (always contains every key from en.js).\n */\nexport function resolveLocale(lang) {\n // Default / English shortcut (no merge needed)\n if (!lang || lang === 'en') return en;\n\n if (typeof lang === 'string') {\n const partial = locales[lang];\n if (!partial) {\n // Unregistered code → English, but say why: silently rendering English\n // after asking for another language is confusing to debug.\n console.warn(\n `[AutumnNote] Locale \"${lang}\" is not registered, falling back to English. ` +\n `Import it first: import { ${lang} } from 'autumnnote/i18n/${lang}'; ` +\n `AutumnNote.registerLocale('${lang}', ${lang});`,\n );\n return en;\n }\n return mergeDeep(mergeDeep({}, en), partial);\n }\n\n if (typeof lang === 'object') {\n // Custom locale object supplied directly by the user\n return mergeDeep(mergeDeep({}, en), lang);\n }\n\n return en;\n}\n\n/**\n * @typedef {Object} AsnLocale (see types/index.d.ts for the full definition)\n */\n","/**\n * sanitise.js - Shared HTML and URL sanitisation utilities\n *\n * Single source of truth used by Editor, Clipboard, Codeview, and renderer.\n * DOM-parser based — no regex-based stripping of HTML (avoids bypass tricks).\n */\n\n/**\n * Tags that are unconditionally removed from editor content.\n *\n * Beyond the obvious script hosts this covers two SVG/MathML-specific classes:\n *\n * - SMIL animation (`animate`, `set`, `animateTransform`, `animateMotion`)\n * can rewrite an attribute *after* sanitisation finishes, so\n * `<svg><a><animate attributeName=\"href\" values=\"javascript:…\">` survives an\n * attribute-level filter untouched and still navigates on click. The editor\n * only ever emits static `<svg>` icons, so animation is pure attack surface.\n *\n * - `mglyph` / `malignmark` / `annotation-xml` are HTML integration points\n * inside the MathML namespace. They make the parser switch namespaces\n * mid-tree, which is what lets a crafted fragment re-parse into different\n * markup than it serialised from (mXSS). The rest of MathML is left alone so\n * pasted formulae survive.\n */\nconst PROHIBITED_TAGS = [\n 'script', 'style', 'iframe', 'object', 'embed', 'form', 'base', 'template',\n 'link', 'meta', 'noscript', 'portal', 'frame', 'frameset', 'applet',\n 'animate', 'set', 'animatetransform', 'animatemotion',\n 'mglyph', 'malignmark', 'annotation-xml',\n];\n\n/** Tags whose element wrapper is stripped but content (child nodes) is preserved. */\nconst UNWRAP_TAGS = new Set(['button']);\n\n/** Attributes whose values must be sanitised as URLs. */\nconst URL_ATTRS = ['href', 'src', 'action', 'formaction', 'xlink:href', 'poster', 'background', 'srcset'];\n\n/**\n * URL attributes that address media rather than navigation, so they are\n * validated against SAFE_MEDIA_PROTOCOLS regardless of which element carries\n * them (unlike `src`, whose meaning depends on the owning tag).\n */\nconst MEDIA_URL_ATTRS = new Set(['poster', 'background', 'srcset']);\n\n/**\n * Attributes removed outright: the editor never emits them and their only\n * effect is an outbound request the author did not ask for. `ping` fires a\n * POST beacon to arbitrary hosts when a link is clicked.\n */\nconst BEACON_ATTRS = new Set(['ping']);\n\n/** Inline style properties the editor's own toolbar/table features persist on saved content. */\nconst ALLOWED_STYLE_PROPS = new Set([\n 'color', 'background-color', 'font-size', 'line-height',\n 'text-align', 'vertical-align',\n 'width', 'min-width', 'height', 'min-height',\n 'border-width', 'border-style', 'border-color', 'padding',\n // The code block's word-wrap toggle persists as `white-space: pre-wrap` on\n // the <pre>. Dropping it meant the setting was lost through every path that\n // re-sanitises — setHTML, paste, and auto-save restore.\n 'white-space',\n]);\n\n/**\n * Value patterns that are never safe regardless of property.\n * `image-set()` and `src()` are covered alongside `url()` — all three fetch an\n * external resource, so allowing them would let pasted content phone home.\n */\nconst DANGEROUS_STYLE_VALUE_RE = /url\\s*\\(|image-set\\s*\\(|src\\s*\\(|expression\\s*\\(|@import|javascript:|vbscript:|behavior\\s*:|-moz-binding/i;\n\n/** Trusted hosts for iframe embeds when allowIframes is enabled. */\nconst TRUSTED_IFRAME_HOSTS = new Set([\n 'www.youtube.com',\n 'youtube.com',\n 'm.youtube.com',\n 'www.youtube-nocookie.com',\n 'youtube-nocookie.com',\n 'player.vimeo.com',\n]);\n\nconst SAFE_LINK_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);\nconst SAFE_MEDIA_PROTOCOLS = new Set(['http:', 'https:', 'blob:']);\nconst SAFE_RASTER_DATA_RE = /^data:image\\/(?:png|jpe?g|gif|webp|avif|bmp);base64,[a-z0-9+/=\\s]+$/i;\nconst URL_BASE = 'https://autumnnote.invalid/';\n\n/**\n * Produce a sanitized HTML string with dangerous elements and attributes removed.\n *\n * Removes disallowed tags and wrappers, strips event-handler attributes, rejects\n * `javascript:`/`vbscript:` URLs and most `data:` URIs, restricts iframe `src`\n * to trusted hosts when enabled, and permits only checklist checkboxes as inputs.\n *\n * @param {string} html - HTML fragment to sanitize.\n * @param {Object} [options]\n * @param {boolean} [options.allowIframes=false] - If true, `iframe` elements are not removed but their `src` is restricted to trusted hosts and `srcdoc` is removed.\n * @returns {string} The sanitized HTML fragment.\n */\nexport function sanitiseHTML(html, options) {\n return sanitiseToBody(html, options).innerHTML;\n}\n\n/**\n * The same sanitisation as {@link sanitiseHTML}, but handing back the parsed\n * `<body>` instead of its serialisation.\n *\n * A caller that is about to put the result into the DOM can adopt these nodes\n * directly and skip a serialise plus a re-parse — on a 217 KiB document that is\n * ~14 ms of the ~45 ms `setHTML` used to take. It is also the safer of the two\n * shapes: re-parsing a sanitised string is the step mXSS turns against you (see\n * the note on namespace-switching tags above), and adopting never re-parses.\n *\n * `sanitiseHTML` is unchanged and still the right entry point when a string is\n * what you need.\n *\n * @param {string} html - HTML fragment to sanitize.\n * @param {Object} [options]\n * @param {boolean} [options.allowIframes=false] - If true, `iframe` elements are not removed but their `src` is restricted to trusted hosts and `srcdoc` is removed.\n * @returns {HTMLElement} The sanitized `<body>` of a detached document.\n */\nexport function sanitiseToBody(html, { allowIframes = false } = {}) {\n const doc = new DOMParser().parseFromString(`<body>${html || ''}</body>`, 'text/html');\n\n // Single querySelectorAll pass — collect all elements once to avoid\n // repeated full-tree traversals for each category of check.\n const allElements = Array.from(doc.querySelectorAll('*'));\n\n // Build the prohibited tag set for fast O(1) lookup\n const prohibited = new Set(\n allowIframes ? PROHIBITED_TAGS.filter((t) => t !== 'iframe') : PROHIBITED_TAGS,\n );\n\n for (const el of allElements) {\n const tag = el.tagName.toLowerCase();\n\n // Unwrap elements whose wrapper is unsafe but whose content should be kept\n if (UNWRAP_TAGS.has(tag)) {\n el.replaceWith(...el.childNodes);\n continue;\n }\n\n // Remove outright dangerous elements\n if (prohibited.has(tag)) {\n el.remove();\n continue;\n }\n\n // Invalid embeds are removed rather than retained as empty iframes.\n if (tag === 'iframe') {\n const src = el.getAttribute('src');\n if (!src || !isTrustedIframeSrc(src)) {\n el.remove();\n continue;\n }\n }\n\n // Strip dangerous attributes\n for (const attr of Array.from(el.attributes)) {\n // Remove all event handlers (onclick, onload, onerror, …)\n if (attr.name.startsWith('on')) {\n el.removeAttribute(attr.name);\n continue;\n }\n // Filter the style attribute down to an allowlisted set of safe\n // properties (see ALLOWED_STYLE_PROPS) — not a blanket strip, since\n // the editor's own toolbar/table features persist inline styles\n // (text color/highlight, font size, line height, table alignment/\n // sizing/borders) that must survive sanitisation.\n if (attr.name === 'style') {\n const cleaned = sanitiseStyleValue(attr.value);\n if (cleaned) el.setAttribute('style', cleaned);\n else el.removeAttribute('style');\n continue;\n }\n // Drop tracking-beacon attributes outright\n if (BEACON_ATTRS.has(attr.name)) {\n el.removeAttribute(attr.name);\n continue;\n }\n // Sanitise URL attributes\n if (URL_ATTRS.includes(attr.name)) {\n const val = attr.value.trim();\n const isMediaSource = MEDIA_URL_ATTRS.has(attr.name) ||\n (attr.name === 'src' && ['IMG', 'VIDEO', 'AUDIO', 'SOURCE'].includes(el.tagName));\n const allowData = el.tagName === 'IMG';\n const safe = attr.name === 'srcset'\n ? isSafeSrcset(val, { allowData })\n : isSafeUrl(val, { media: isMediaSource, allowData });\n if (!safe) {\n el.removeAttribute(attr.name);\n continue;\n }\n }\n // Strip iframe HTML-injection vectors; limit src to trusted hosts\n if (el.tagName === 'IFRAME') {\n if (attr.name === 'srcdoc') {\n el.removeAttribute(attr.name);\n continue;\n }\n if (attr.name === 'src' && !isTrustedIframeSrc(attr.value)) {\n el.removeAttribute(attr.name);\n }\n }\n }\n\n if (tag === 'a' && el.getAttribute('target') === '_blank') {\n el.setAttribute('rel', 'noopener noreferrer');\n }\n\n // Allow only input[type=\"checkbox\"] inside ul.an-checklist li\n if (tag === 'input') {\n const inChecklist = el.closest('ul.an-checklist') !== null &&\n el.closest('li') !== null;\n if (!inChecklist || el.getAttribute('type') !== 'checkbox') {\n el.remove();\n } else {\n for (const attr of Array.from(el.attributes)) {\n if (!['type', 'checked', 'contenteditable'].includes(attr.name)) {\n el.removeAttribute(attr.name);\n }\n }\n }\n }\n }\n\n return doc.body;\n}\n\n/**\n * Filters a style attribute value down to an allowlisted set of CSS\n * properties (ALLOWED_STYLE_PROPS), dropping any declaration whose value\n * contains a dangerous construct — url(), expression(), an \"import\" rule,\n * javascript:/vbscript:, IE behavior/-moz-binding — regardless of property.\n * @param {string} value\n * @returns {string} The filtered declaration list, or '' if nothing survives.\n */\nfunction sanitiseStyleValue(value) {\n const kept = [];\n for (const decl of (value || '').split(';')) {\n const idx = decl.indexOf(':');\n if (idx === -1) continue;\n const prop = decl.slice(0, idx).trim().toLowerCase();\n const val = decl.slice(idx + 1).trim();\n if (!prop || !val) continue;\n if (!ALLOWED_STYLE_PROPS.has(prop)) continue;\n if (DANGEROUS_STYLE_VALUE_RE.test(val)) continue;\n kept.push(`${prop}: ${val}`);\n }\n return kept.join('; ');\n}\n\n/**\n * Validates every candidate URL in a `srcset` attribute.\n *\n * Per the HTML srcset grammar a candidate URL is a run of non-whitespace\n * characters — commas may appear *inside* it, which is why `data:` URLs work\n * there — optionally followed by a width (`300w`) or density (`2x`) descriptor.\n * Splitting on whitespace and skipping descriptor tokens therefore yields the\n * URL set. Anything unparseable makes the whole attribute fail, since a\n * partially-trusted candidate list is not something we can express.\n *\n * @param {string} value\n * @param {{ allowData?: boolean }} [options]\n * @returns {boolean}\n */\nfunction isSafeSrcset(value, { allowData = false } = {}) {\n const tokens = (value || '').trim().split(/\\s+/).filter(Boolean);\n for (const token of tokens) {\n if (/^[\\d.]+[xw],?$/i.test(token)) continue; // width/density descriptor\n const url = token.replace(/,+$/, ''); // trailing comma = candidate separator\n if (!url) continue;\n if (!isSafeUrl(url, { media: true, allowData })) return false;\n }\n return true;\n}\n\n/**\n * Returns true if iframe src points to an approved video host.\n * Relative, protocol-relative and invalid URLs are rejected.\n * @param {string} src\n * @returns {boolean}\n */\nfunction isTrustedIframeSrc(src) {\n const trimmed = (src || '').trim();\n if (!trimmed) return false;\n if (trimmed.startsWith('//') || trimmed.startsWith('/')) return false;\n try {\n const url = new URL(trimmed);\n if (url.protocol !== 'https:') return false;\n return TRUSTED_IFRAME_HOSTS.has(url.hostname.toLowerCase());\n } catch {\n return false;\n }\n}\n\n/**\n * Sanitises a URL string, rejecting dangerous protocols.\n *\n * Blocked protocols: javascript:, vbscript:\n * Optionally blocked: data: (safe to allow for img/src base64 embeds)\n *\n * @param {string} url\n * @param {{ allowData?: boolean, media?: boolean }} [opts]\n * @returns {string|null} The original URL if safe, null if rejected.\n */\nexport function sanitiseUrl(url, { allowData = false, media = allowData } = {}) {\n const trimmed = (url || '').trim();\n if (!trimmed && url == null) return null;\n return isSafeUrl(trimmed, { media, allowData }) ? url : null;\n}\n\n/**\n * Validate a URL using the browser URL parser so ASCII whitespace/control\n * characters cannot disguise a dangerous protocol (for example java\\nscript:).\n * @param {string} value\n * @param {{media?: boolean, allowData?: boolean}} [options]\n * @returns {boolean}\n */\nfunction isSafeUrl(value, { media = false, allowData = false } = {}) {\n const trimmed = (value || '').trim();\n if (!trimmed) return true;\n if (allowData && SAFE_RASTER_DATA_RE.test(trimmed)) return true;\n\n try {\n const parsed = new URL(trimmed, URL_BASE);\n const protocols = media ? SAFE_MEDIA_PROTOCOLS : SAFE_LINK_PROTOCOLS;\n return protocols.has(parsed.protocol);\n } catch {\n return false;\n }\n}\n","/**\n * renderer.js - Builds the editor DOM structure\n * Inspired by Summernote's renderer.js\n */\n\nimport { createElement } from './core/dom.js';\nimport { sanitiseHTML } from './core/sanitise.js';\n\n/**\n * Renders the editor layout around the original element.\n *\n * Structure:\n * <div class=\"an-container\">\n * <div class=\"an-toolbar\">...</div>\n * <div class=\"an-editable\" contenteditable=\"true\">...</div>\n * <div class=\"an-statusbar\">...</div>\n * </div>\n *\n * @param {HTMLElement} targetEl - the original element to replace/wrap\n * @param {import('./settings.js').AsnOptions} options\n * @returns {{ container: HTMLElement, editable: HTMLElement }}\n */\nexport function renderLayout(targetEl, options) {\n const container = createElement('div', { class: 'an-container' });\n\n // Editable area\n const editable = createElement('div', {\n class: 'an-editable',\n contenteditable: options.readOnly ? 'false' : 'true',\n spellcheck: String(options.spellcheck !== false),\n 'aria-multiline': 'true',\n 'aria-label': 'Rich text editor',\n role: 'textbox',\n });\n\n // Restore auto-saved content when available; fall back to element content\n let initialContent = '';\n if (options.autoSave && options.autoSaveKey) {\n try { initialContent = localStorage.getItem(options.autoSaveKey) || ''; } catch (_) { void _; }\n }\n if (!initialContent) {\n initialContent = targetEl.tagName === 'TEXTAREA'\n ? ((/** @type {HTMLTextAreaElement} */ (targetEl)).value || '').trim()\n : (targetEl.innerHTML || '').trim();\n }\n editable.innerHTML = sanitiseHTML(initialContent, { allowIframes: true });\n\n // Apply default font family so the editable renders in the configured font\n const defaultFont = options.defaultFontFamily || options.fontFamilies?.[0];\n if (defaultFont) {\n editable.style.fontFamily = defaultFont;\n }\n\n // Apply default font size so the size dropdown shows the correct value on startup\n if (options.defaultFontSize) {\n editable.style.fontSize = options.defaultFontSize;\n }\n\n // Apply height options.\n // `height` sets the initial visible height (takes priority).\n // `minHeight` is the drag-resize floor — only applied when no explicit `height` is given.\n if (options.height) {\n editable.style.minHeight = `${options.height}px`;\n } else if (options.minHeight) {\n editable.style.minHeight = `${options.minHeight}px`;\n }\n if (options.maxHeight) {\n editable.style.maxHeight = `${options.maxHeight}px`;\n }\n\n container.appendChild(editable);\n\n // Apply theme — also add to body so floating elements (dialogs, tooltips,\n // popovers) appended to document.body inherit the CSS rules.\n if (options.theme === 'dark') {\n container.classList.add('an-theme-dark');\n document.body.classList.add('an-theme-dark');\n } else if (options.theme === 'auto') {\n container.classList.add('an-theme-auto');\n document.body.classList.add('an-theme-auto');\n }\n\n // Read-only mode\n if (options.readOnly) {\n container.classList.add('an-disabled');\n editable.querySelectorAll('ul.an-checklist input[type=\"checkbox\"]').forEach((cb) => {\n cb.setAttribute('disabled', '');\n });\n }\n\n // Text direction\n if (options.direction === 'rtl') {\n editable.setAttribute('dir', 'rtl');\n container.classList.add('an-dir-rtl');\n }\n\n // Toolbar overflow\n if (options.toolbarOverflow === 'scroll') {\n container.classList.add('an-toolbar-overflow-scroll');\n }\n\n // Configure sticky toolbar\n if (options.stickyToolbar) {\n container.classList.add('an-sticky-toolbar');\n if (options.stickyToolbarOffset) {\n container.style.setProperty('--an-sticky-top', `${options.stickyToolbarOffset}px`);\n }\n }\n\n // Custom focus ring colour\n if (options.focusColor) {\n container.style.setProperty('--an-focus-color', options.focusColor);\n }\n\n // Hide the original element; keep it in DOM for form submission\n targetEl.style.display = 'none';\n targetEl.after(container);\n\n return { container, editable };\n}\n","/**\n * Context.js - Central hub for the editor instance\n * Holds references to all sub-modules and manages inter-module communication.\n * Inspired by Summernote's Context.js\n */\n\nimport { mergeDeep } from './core/func.js';\nimport { registerButton } from './module/Buttons.js';\nimport { defaultOptions } from './settings.js';\nimport { resolveLocale } from './i18n/index.js';\nimport { renderLayout } from './renderer.js';\nimport { on } from './core/dom.js';\n\n/** Module registry shared across all Context instances (populated via AutumnNote.registerModule). */\nexport const _customModules = new Map();\n\n/**\n * @typedef {object} ModuleDef\n * @property {string} name - Key the module is registered and invoked under.\n * @property {new (ctx: Context) => { initialize: () => any, destroy?: () => void }} Class\n * @property {(options: any) => boolean} [enabled] - Option gate. Omitted means always on.\n * Consulted at mount and again after updateOptions(), so a runtime toggle\n * starts or tears the module down instead of silently disagreeing with the\n * option value.\n */\n\n/**\n * Module table for every Context created from here on.\n *\n * Context deliberately imports no module of its own: whichever entry point the\n * consumer loaded installs the table. That is what lets `autumnnote/core` leave\n * the dialogs, tooltips and pickers out of the bundle entirely rather than\n * merely not registering them.\n * @type {ModuleDef[]}\n */\nlet _moduleDefs = [];\n\n/**\n * Installs the module table. Called by each entry point at import time.\n * @param {ModuleDef[]} defs\n */\nexport function setModuleDefs(defs) {\n _moduleDefs = Array.isArray(defs) ? defs : [];\n}\n\n/** The table currently installed. */\nexport function getModuleDefs() {\n return _moduleDefs;\n}\n\n/** Global plugin registry (populated via AutumnNote.use()). Applied to every new Context. */\nexport const _globalPlugins = new Map();\n\nexport class Context {\n /**\n * @param {HTMLElement} targetEl - The element to replace with the editor\n * @param {import('./settings.js').AsnOptions} [userOptions]\n */\n constructor(targetEl, userOptions = {}) {\n this.targetEl = targetEl;\n this.options = mergeDeep(defaultOptions, userOptions);\n\n /** @type {import('./i18n/index.js').AsnLocale} */\n this.locale = resolveLocale(this.options.lang);\n\n /** @type {{ container: HTMLElement, editable: HTMLElement, toolbar?: HTMLElement, statusbar?: HTMLElement }} */\n this.layoutInfo = /** @type {any} */ ({});\n\n /** @type {Map<string, Function[]>} */\n this._listeners = new Map();\n\n /** @type {Map<string, object>} */\n this._modules = new Map();\n\n /** @type {Map<string, { plugin: object, publicApi: * }>} */\n this._plugins = new Map();\n\n this._disposers = [];\n this._alive = false;\n this._autoSaveTimer = null;\n this._pendingAutoSave = null;\n this._suppressedRemoteHTML = null;\n /** @type {Promise<void>|null} Settles when destroy()'s closing auto-save finishes */\n this._destroyPromise = null;\n }\n\n // ---------------------------------------------------------------------------\n // Initialisation\n // ---------------------------------------------------------------------------\n\n initialize() {\n // 1. Render the DOM skeleton\n const { container, editable } = renderLayout(this.targetEl, this.options);\n this.layoutInfo.container = container;\n this.layoutInfo.editable = editable;\n\n // 2. Register core modules\n this._registerModules();\n\n // 3. Attach toolbar/statusbar to container\n const toolbar = this._modules.get('toolbar');\n if (toolbar?.el) {\n container.insertBefore(toolbar.el, editable);\n this.layoutInfo.toolbar = toolbar.el;\n }\n\n const statusbar = this._modules.get('statusbar');\n if (statusbar?.el) {\n container.appendChild(statusbar.el);\n this.layoutInfo.statusbar = statusbar.el;\n }\n\n // 4. Bind editor-level events\n this._bindEditorEvents(editable);\n\n // 5. Auto-focus if requested\n if (this.options.focus) {\n editable.focus();\n }\n\n this._alive = true;\n\n // Initial toolbar sync so dropdowns show the correct font on load\n this.invoke('toolbar.refresh');\n\n // Apply plugins registered globally via AutumnNote.use()\n this._applyGlobalPlugins();\n\n if (typeof this.options.onInit === 'function') {\n this.options.onInit(this);\n }\n\n return this;\n }\n\n _registerModules() {\n const register = (name, ModuleClass) => {\n const instance = new ModuleClass(this);\n this._modules.set(name, instance);\n instance.initialize();\n };\n\n for (const { name, Class, enabled } of _moduleDefs) {\n if (typeof enabled === 'function' && !enabled(this.options)) continue;\n register(name, Class);\n }\n\n // Custom modules registered via AutumnNote.registerModule()\n if (_customModules.size > 0) {\n for (const [name, ModuleClass] of _customModules) {\n register(name, ModuleClass);\n }\n }\n }\n\n /**\n * Registers or tears down option-gated modules so they match the current\n * option values. Called after `updateOptions()` so toggling e.g.\n * `bubbleToolbar` at runtime actually takes effect.\n */\n _syncOptionalModules() {\n for (const { name, Class, enabled } of _moduleDefs) {\n if (typeof enabled !== 'function') continue;\n const shouldRun = enabled(this.options);\n const isRunning = this._modules.has(name);\n if (shouldRun === isRunning) continue;\n\n if (shouldRun) {\n const instance = new Class(this);\n this._modules.set(name, instance);\n instance.initialize();\n } else {\n const instance = this._modules.get(name);\n if (typeof instance?.destroy === 'function') instance.destroy();\n this._modules.delete(name);\n }\n }\n }\n\n /**\n * Registers and initialises a custom module on this instance.\n * @param {string} name\n * @param {new (ctx: this) => any} ModuleClass\n * @returns {this}\n */\n registerModule(name, ModuleClass) {\n if (this._modules.has(name)) return this;\n const instance = new ModuleClass(this);\n instance.initialize();\n this._modules.set(name, instance);\n return this;\n }\n\n registerSlashCommand(command) {\n if (!command?.id || typeof command.run !== 'function') {\n throw new TypeError('[AutumnNote] Slash command requires an id and run(context) function.');\n }\n const commands = this.options.slashCommands || (this.options.slashCommands = []);\n const index = commands.findIndex((item) => item.id === command.id);\n if (index >= 0) commands[index] = command;\n else commands.push(command);\n this.invoke('slashMenu.refresh');\n return this;\n }\n\n /**\n * Installs a plugin on this editor instance.\n * If called after create(), buttons are registered immediately but the toolbar\n * must be rebuilt via ctx.invoke('toolbar.rebuild') to render new buttons.\n * @param {object} plugin - { name, version?, buttons?, install?, uninstall? }\n * @param {object} [options] - Forwarded to plugin.install(context, options)\n * @returns {this}\n */\n use(plugin, options = {}) {\n if (Array.isArray(plugin.buttons)) {\n plugin.buttons.forEach((b) => registerButton(b));\n }\n this._installPlugin(plugin, options);\n return this;\n }\n\n /**\n * Returns the public API returned by plugin.install(), or null.\n * @param {string} name\n * @returns {*}\n */\n getPlugin(name) {\n return this._plugins.get(name)?.publicApi ?? null;\n }\n\n _installPlugin(plugin, pluginOptions = {}) {\n const { name } = plugin;\n if (!name || typeof name !== 'string') {\n console.warn('[AutumnNote] Plugin must have a string `name` property.');\n return;\n }\n if (this._plugins.has(name)) {\n console.warn(`[AutumnNote] Plugin \"${name}\" already installed on this instance. Skipping.`);\n return;\n }\n const publicApi = (typeof plugin.install === 'function')\n ? plugin.install(this, pluginOptions) ?? null\n : null;\n this._plugins.set(name, { plugin, publicApi });\n }\n\n _applyGlobalPlugins() {\n if (_globalPlugins.size === 0) return;\n for (const { plugin, options } of _globalPlugins.values()) {\n this._installPlugin(plugin, options);\n }\n }\n\n _bindEditorEvents(editable) {\n // Keep the original textarea/input value in sync immediately on every input.\n // This guarantees form.submit() sees fresh data even before debounced change.\n const d0 = on(editable, 'input', () => this._syncToTarget());\n const d1 = on(editable, 'focus', () => {\n this.layoutInfo.container.classList.add('an-focused');\n if (typeof this.options.onFocus === 'function') {\n this.options.onFocus(this);\n }\n });\n const d2 = on(editable, 'blur', () => {\n this.layoutInfo.container.classList.remove('an-focused');\n this._syncToTarget();\n if (typeof this.options.onBlur === 'function') {\n this.options.onBlur(this);\n }\n });\n // Sync textarea/input value on every change so form.submit() always gets fresh content\n const d3 = this.on('change', (html) => this._syncToTarget(html));\n const dRemote = this.on('change', (html) => {\n if (this.options.blockIds) { this.ensureBlockIds(); html = this.getHTML(); }\n if (html === this._suppressedRemoteHTML) { this._suppressedRemoteHTML = null; return; }\n this.options.collaborationAdapter?.onLocalChange?.(html, this);\n });\n this._disposers.push(d0, d1, d2, d3, dRemote);\n\n // Auto-save to localStorage on every change (also writes :asrmeta for restore banner)\n if (this.options.autoSave && this.options.autoSaveKey) {\n const d4 = this.on('change', (html) => this._scheduleAutoSave(html));\n this._disposers.push(d4);\n }\n }\n\n _scheduleAutoSave(html) {\n this._pendingAutoSave = html;\n clearTimeout(this._autoSaveTimer);\n this._autoSaveTimer = setTimeout(() => this.flushAutoSave(), this.options.autoSaveDelay ?? 400);\n }\n\n async flushAutoSave() {\n clearTimeout(this._autoSaveTimer);\n this._autoSaveTimer = null;\n if (this._pendingAutoSave == null) return;\n const html = this._pendingAutoSave;\n this._pendingAutoSave = null;\n const key = this.options.autoSaveKey;\n const savedAt = Date.now();\n try {\n const adapter = this.options.autoSaveAdapter;\n if (typeof adapter?.save === 'function') {\n await adapter.save({ key, html, savedAt, context: this });\n } else {\n localStorage.setItem(key, html);\n localStorage.setItem(key + ':asrmeta', JSON.stringify({ savedAt }));\n }\n this.triggerEvent('autoSave', { key, html, savedAt });\n } catch (error) {\n this.triggerEvent('autoSaveError', { key, error });\n }\n }\n\n async loadAutoSave() {\n const adapter = this.options.autoSaveAdapter;\n if (typeof adapter?.load === 'function') {\n return adapter.load({ key: this.options.autoSaveKey, context: this });\n }\n try { return localStorage.getItem(this.options.autoSaveKey); } catch (_) { return null; }\n }\n\n // ---------------------------------------------------------------------------\n // Module invocation\n // ---------------------------------------------------------------------------\n\n /**\n * Invokes a method on a registered module.\n * Format: 'moduleName.methodName'\n * @param {string} path - e.g. 'editor.bold'\n * @param {...*} args\n * @returns {*}\n */\n invoke(path, ...args) {\n const [moduleName, methodName] = path.split('.');\n const module = this._modules.get(moduleName);\n if (!module) {\n console.warn(`[AutumnNote] invoke: module \"${moduleName}\" not found (path: \"${path}\")`);\n return undefined;\n }\n if (typeof module[methodName] !== 'function') {\n console.warn(`[AutumnNote] invoke: method \"${methodName}\" not found on module \"${moduleName}\" (path: \"${path}\")`);\n return undefined;\n }\n return module[methodName](...args);\n }\n\n // ---------------------------------------------------------------------------\n // Event system\n // ---------------------------------------------------------------------------\n\n /**\n * Subscribes to an editor event.\n * @param {string} eventName\n * @param {Function} handler\n * @returns {() => void} unsubscribe\n */\n on(eventName, handler) {\n if (!this._listeners.has(eventName)) {\n this._listeners.set(eventName, []);\n }\n this._listeners.get(eventName).push(handler);\n return () => this.off(eventName, handler);\n }\n\n /**\n * Unsubscribes from an editor event.\n * @param {string} eventName\n * @param {Function} handler\n */\n off(eventName, handler) {\n const handlers = this._listeners.get(eventName);\n if (!handlers) return;\n const idx = handlers.indexOf(handler);\n if (idx !== -1) handlers.splice(idx, 1);\n }\n\n /**\n * Triggers an editor event.\n * @param {string} eventName\n * @param {...*} args\n */\n triggerEvent(eventName, ...args) {\n const handlers = this._listeners.get(eventName) || [];\n handlers.forEach((h) => h(...args));\n\n // Also call options callback if present (e.g. onChange)\n const cbName = 'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);\n if (typeof this.options[cbName] === 'function') {\n this.options[cbName](...args);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Public editor API\n // ---------------------------------------------------------------------------\n\n /** Updates runtime-safe options without recreating the editor. */\n updateOptions(overrides = {}) {\n const next = mergeDeep(this.options, overrides);\n Object.keys(this.options).forEach((key) => delete this.options[key]);\n Object.assign(this.options, next);\n\n const { container, editable } = this.layoutInfo;\n if (Object.hasOwn(overrides, 'readOnly')) this.setDisabled(Boolean(this.options.readOnly));\n if (Object.hasOwn(overrides, 'spellcheck')) editable.spellcheck = this.options.spellcheck !== false;\n if (Object.hasOwn(overrides, 'placeholder')) editable.dataset.placeholder = this.options.placeholder || '';\n if (Object.hasOwn(overrides, 'direction')) {\n const rtl = this.options.direction === 'rtl';\n editable.setAttribute('dir', rtl ? 'rtl' : 'ltr');\n container.classList.toggle('an-dir-rtl', rtl);\n }\n if (Object.hasOwn(overrides, 'height') || Object.hasOwn(overrides, 'minHeight')) {\n const height = this.options.height || this.options.minHeight || 0;\n editable.style.minHeight = height ? `${height}px` : '';\n }\n if (Object.hasOwn(overrides, 'maxHeight')) {\n editable.style.maxHeight = this.options.maxHeight ? `${this.options.maxHeight}px` : '';\n }\n if (Object.hasOwn(overrides, 'toolbar')) this.invoke('toolbar.rebuild');\n // Start/stop option-gated modules (bubbleToolbar, mention, slashMenu, ...)\n // so toggling them here behaves the same as passing them to create().\n this._syncOptionalModules();\n this.invoke('statusbar.update');\n this.triggerEvent('optionsChange', { ...overrides });\n return this;\n }\n\n /**\n * Returns the current HTML content of the editor.\n * Zero-width spaces (U+200B) inserted by inline editing helpers are stripped\n * from the output so they don't leak into the consumer's HTML.\n * @returns {string}\n */\n getHTML() {\n const html = this.invoke('editor.getHTML');\n return typeof html === 'string' ? html.replace(//g, '') : html;\n }\n\n /**\n * Sets the HTML content of the editor.\n * @param {string} html\n */\n setHTML(html) {\n this.invoke('editor.setHTML', html);\n }\n\n /**\n * Returns the plain text content of the editor.\n * @returns {string}\n */\n getText() {\n return this.invoke('editor.getText');\n }\n\n /**\n * Sets the editor content as plain text (HTML-escaped).\n * @param {string} text\n */\n setText(text) {\n this.invoke('editor.setText', text);\n }\n\n /**\n * Clears the editor content.\n */\n clear() {\n this.invoke('editor.clear');\n }\n\n /**\n * Resets the undo/redo history stack.\n * Useful after programmatically loading a new document via setHTML() / setMarkdown()\n * so that Ctrl+Z cannot undo back to the previous document.\n */\n clearHistory() {\n this.invoke('editor.clearHistory');\n }\n\n /**\n * Returns the number of available undo steps.\n * @returns {number}\n */\n getUndoCount() {\n return this.invoke('editor.getUndoCount') ?? 0;\n }\n\n /**\n * Returns the number of available redo steps.\n * @returns {number}\n */\n getRedoCount() {\n return this.invoke('editor.getRedoCount') ?? 0;\n }\n\n /**\n * Returns true when the editor has no meaningful content.\n * @returns {boolean}\n */\n isEmpty() {\n return this.invoke('editor.isEmpty');\n }\n\n /**\n * Inserts HTML at the current cursor position.\n * @param {string} html\n */\n insertHTML(html) {\n this.invoke('editor.insertHTML', html);\n }\n\n /**\n * Inserts plain text at the current cursor position.\n * @param {string} text\n */\n insertText(text) {\n this.invoke('editor.insertText', text);\n }\n\n /**\n * Sets editor content from a Markdown string.\n * @param {string} md\n */\n setMarkdown(md) {\n this.invoke('editor.setMarkdown', md);\n }\n\n /**\n * Returns the editor content as Markdown.\n * @returns {string}\n */\n getMarkdown() {\n return this.invoke('editor.getMarkdown');\n }\n\n getSelectionBookmark() {\n return this.invoke('editor.getSelectionBookmark') ?? null;\n }\n\n restoreSelectionBookmark(bookmark) {\n return this.invoke('editor.restoreSelectionBookmark', bookmark);\n }\n\n async importDocument(format, data) {\n const adapter = this.options.documentAdapters?.[format];\n let html;\n if (typeof adapter?.import === 'function') html = await adapter.import(data, this);\n else if (format === 'html') html = String(data ?? '');\n else if (format === 'markdown') { this.setMarkdown(String(data ?? '')); return this; }\n else if (format === 'text') { this.setText(String(data ?? '')); return this; }\n else throw new Error(`[AutumnNote] No importer registered for \"${format}\".`);\n this.setHTML(html);\n return this;\n }\n\n async exportDocument(format) {\n const adapter = this.options.documentAdapters?.[format];\n if (typeof adapter?.export === 'function') return adapter.export(this, this.getHTML());\n if (format === 'html') return this.getHTML();\n if (format === 'markdown') return this.getMarkdown();\n if (format === 'text') return this.getText();\n throw new Error(`[AutumnNote] No exporter registered for \"${format}\".`);\n }\n\n ensureBlockIds() {\n const blocks = this.layoutInfo.editable.children;\n for (const block of blocks) {\n if (!block.hasAttribute('data-an-block-id')) {\n const id = globalThis.crypto?.randomUUID?.() || `an-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n block.setAttribute('data-an-block-id', id);\n }\n }\n return this;\n }\n\n getDocument() {\n if (this.options.blockIds) this.ensureBlockIds();\n return { version: 1, html: this.getHTML(), markdown: this.getMarkdown() };\n }\n\n loadDocument(documentData) {\n this.setHTML(documentData?.html || '');\n this.clearHistory();\n return this;\n }\n\n applyRemoteHTML(html) {\n this.setHTML(html);\n this._suppressedRemoteHTML = this.getHTML();\n this.clearHistory();\n return this;\n }\n\n /**\n * Returns the current word count of the editor content.\n * @returns {number}\n */\n getWordCount() {\n return this.invoke('statusbar.getWordCount') ?? 0;\n }\n\n /**\n * Returns the current character count of the editor content.\n * @returns {number}\n */\n getCharCount() {\n return this.invoke('statusbar.getCharCount') ?? 0;\n }\n\n /**\n * Downloads the editor content as an HTML file.\n * @param {string} [filename='document.html']\n */\n downloadHTML(filename = 'document.html') {\n this._download(this.getHTML(), filename, 'text/html');\n }\n\n /**\n * Downloads the editor content as a plain-text file.\n * @param {string} [filename='document.txt']\n */\n downloadText(filename = 'document.txt') {\n this._download(this.getText(), filename, 'text/plain');\n }\n\n /**\n * Downloads the editor content as a Markdown file.\n * @param {string} [filename='document.md']\n */\n downloadMarkdown(filename = 'document.md') {\n this._download(this.getMarkdown(), filename, 'text/markdown');\n }\n\n /**\n * Creates a temporary Blob URL and triggers a browser file download.\n * @param {string} content\n * @param {string} filename\n * @param {string} mimeType\n */\n _download(content, filename, mimeType) {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n a.style.display = 'none';\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n }\n\n /**\n * Opens the editor content in a new globalThis and triggers the browser print dialog.\n * @param {string} [title='']\n */\n print(title = '') {\n const content = this.getHTML();\n const safeTitle = (title || '').replace(/[<>&\"']/g, (c) => `&#${c.charCodeAt(0)};`);\n const markup = '<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\">' +\n `<title>${safeTitle}</title>` +\n '<style>' +\n 'body{font-family:system-ui,-apple-system,\"Segoe UI\",Roboto,Arial,sans-serif;font-size:14px;line-height:1.6;padding:20mm;color:#111827;}' +\n 'ul.an-checklist{list-style:none;padding-left:0;}' +\n 'ul.an-checklist li{padding-left:24px;position:relative;margin:2px 0;}' +\n 'ul.an-checklist li input[type=\"checkbox\"]{position:absolute;left:0;top:3px;}' +\n 'code{background:#f3f4f6;border-radius:3px;padding:.1em .35em;font-family:monospace;}' +\n 'pre{background:#f3f4f6;padding:.75em 1em;border-radius:4px;overflow-x:auto;}' +\n 'table{border-collapse:collapse;}td,th{border:1px solid #d1d5db;padding:4px 8px;}' +\n '</style>' +\n `</head><body>${content}</body></html>`;\n const blob = new Blob([markup], { type: 'text/html' });\n const url = URL.createObjectURL(blob);\n const w = globalThis.open(url, '_blank');\n if (!w) { URL.revokeObjectURL(url); return; } // popup blocked by browser\n w.addEventListener('load', () => {\n w.print();\n URL.revokeObjectURL(url);\n });\n }\n\n /**\n * Returns an array of heading objects representing the table of contents.\n * Each entry has: level (1-6), text (heading text), element (DOM element).\n * @returns {{ level: number, text: string, element: HTMLElement }[]}\n */\n getTableOfContents() {\n const headings = Array.from(\n this.layoutInfo.editable.querySelectorAll('h1,h2,h3,h4,h5,h6')\n );\n return headings.map((el) => ({\n level: parseInt(el.tagName[1], 10),\n text: el.textContent?.trim() ?? '',\n element: /** @type {HTMLElement} */ (el),\n }));\n }\n\n /**\n * Moves focus into the editable area.\n */\n focus() {\n this.layoutInfo.editable.focus();\n }\n\n /**\n * Removes focus from the editable area.\n */\n blur() {\n this.layoutInfo.editable.blur();\n }\n\n /**\n * Returns true when the editor is currently in fullscreen mode.\n * @returns {boolean}\n */\n isFullscreen() {\n return this.invoke('fullscreen.isActive') === true;\n }\n\n /**\n * Sets whether the editor is disabled (readonly).\n * @param {boolean} disabled\n */\n setDisabled(disabled) {\n const editable = this.layoutInfo.editable;\n if (disabled) {\n editable.setAttribute('contenteditable', 'false');\n this.layoutInfo.container.classList.add('an-disabled');\n editable.querySelectorAll('ul.an-checklist input[type=\"checkbox\"]').forEach((cb) => {\n cb.setAttribute('disabled', '');\n });\n } else {\n editable.setAttribute('contenteditable', 'true');\n this.layoutInfo.container.classList.remove('an-disabled');\n editable.querySelectorAll('ul.an-checklist input[type=\"checkbox\"]').forEach((cb) => {\n cb.removeAttribute('disabled');\n });\n }\n }\n\n // ---------------------------------------------------------------------------\n // Destroy\n // ---------------------------------------------------------------------------\n\n /**\n * Completely removes the editor and restores the original element.\n *\n * Teardown itself is synchronous; the returned promise only settles once the\n * closing auto-save has finished, so `await editor.destroy()` is worth doing\n * when using an async `autoSaveAdapter`. Ignoring the return value is safe.\n * @returns {Promise<void>}\n */\n destroy() {\n if (!this._alive) return this._destroyPromise ?? Promise.resolve();\n\n // Start the final auto-save before tearing anything down. `_listeners` is\n // deliberately kept alive until this settles, otherwise the closing\n // autoSave/autoSaveError event fires into an already-cleared listener map\n // and an async adapter's last write completes silently.\n const pendingFlush = this._pendingAutoSave != null\n ? this.flushAutoSave().catch(() => {})\n : null;\n\n this._modules.forEach((module) => {\n if (typeof module.destroy === 'function') module.destroy();\n });\n this._modules.clear();\n\n for (const { plugin } of this._plugins.values()) {\n if (typeof plugin.uninstall === 'function') {\n try { plugin.uninstall(this); } catch (_) { void _; }\n }\n }\n this._plugins.clear();\n\n this._disposers.forEach((d) => d());\n this._disposers = [];\n\n const container = this.layoutInfo.container;\n const wasDark = container?.classList.contains('an-theme-dark');\n const wasAuto = container?.classList.contains('an-theme-auto');\n if (container?.parentNode) {\n // Restore original element\n this.targetEl.style.display = '';\n container.remove();\n }\n // Clean up body theme classes if no other editors of that type remain\n if (wasDark && !document.querySelector('.an-container.an-theme-dark')) {\n document.body.classList.remove('an-theme-dark');\n }\n if (wasAuto && !document.querySelector('.an-container.an-theme-auto')) {\n document.body.classList.remove('an-theme-auto');\n }\n\n if (typeof this.options.onDestroy === 'function') {\n this.options.onDestroy(this);\n }\n\n this._alive = false;\n\n // Resolves once the closing auto-save (if any) has finished. Callers using\n // an async autoSaveAdapter can `await editor.destroy()` to be sure the last\n // write landed before unloading.\n this._destroyPromise = Promise.resolve(pendingFlush).then(() => {\n this._listeners.clear();\n });\n return this._destroyPromise;\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Syncs editor HTML back into the original textarea/input for form submission.\n */\n _syncToTarget(html) {\n if (this.targetEl.tagName === 'TEXTAREA' || this.targetEl.tagName === 'INPUT') {\n /** @type {HTMLInputElement} */ (this.targetEl).value = typeof html === 'string' ? html : this.getHTML();\n }\n }\n}\n","/**\n * History.js - Undo / redo stack for editor content\n * Inspired by Summernote's History module, rewritten without jQuery\n */\n\nexport class History {\n /**\n * @param {HTMLElement} editable - the contenteditable element\n * @param {number} [limit=100] - maximum number of undo/redo states\n * @param {number} [maxBytes=10485760] - maximum combined size (chars) of all\n * stacked snapshots (html + tokenized image data). Oldest states are\n * evicted first when exceeded, even if `limit` hasn't been reached —\n * documents with many large embedded images can otherwise hold dozens of\n * full-size copies in memory despite the step-count limit.\n */\n constructor(editable, limit = 100, maxBytes = 10 * 1024 * 1024) {\n this.editable = editable;\n this._limit = limit;\n this._maxBytes = maxBytes;\n this._bytes = 0;\n /** @type {Array<{html: string, images?: Record<string,string>, sel: {start: number, end: number}|null}>} */\n this.stack = [];\n this.stackOffset = -1;\n this._savePoint();\n }\n\n /**\n * Approximate in-memory size (chars) of one stacked snapshot: the tokenized\n * HTML string plus every image data URL it references.\n * @param {{html: string, images?: Record<string,string>}} entry\n * @returns {number}\n */\n _entrySize(entry) {\n let size = entry.html.length;\n if (entry.images) {\n for (const key in entry.images) size += entry.images[key].length;\n }\n return size;\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n _serialize() {\n return this.editable.innerHTML;\n }\n\n /**\n * Serializes the current selection as character offsets from the start of\n * the editable element, so it can be restored after innerHTML replacement.\n * @returns {{ start: number, end: number }|null}\n */\n _serializeSelection() {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const range = sel.getRangeAt(0);\n if (!this.editable.contains(range.startContainer)) return null;\n return {\n start: this._charOffset(range.startContainer, range.startOffset),\n end: this._charOffset(range.endContainer, range.endOffset),\n };\n }\n\n /**\n * Returns the character offset of (node, offset) from the beginning of\n * the editable's text content.\n * @param {Node} node\n * @param {number} offset\n * @returns {number}\n */\n _charOffset(node, offset) {\n let count = 0;\n const walker = document.createTreeWalker(this.editable, NodeFilter.SHOW_TEXT, null);\n let cur;\n while ((cur = walker.nextNode())) {\n if (cur === node) return count + offset;\n count += /** @type {Text} */ (cur).length;\n }\n return 0;\n }\n\n /**\n * Restores a previously serialized selection inside the editable.\n * @param {{ start: number, end: number }|null} saved\n */\n _restoreSelection(saved) {\n if (!saved) return;\n let startNode = null, startOff = 0;\n let endNode = null, endOff = 0;\n let count = 0;\n const walker = document.createTreeWalker(this.editable, NodeFilter.SHOW_TEXT, null);\n let cur;\n while ((cur = walker.nextNode())) {\n const len = /** @type {Text} */ (cur).length;\n if (!startNode && count + len >= saved.start) {\n startNode = cur;\n startOff = saved.start - count;\n }\n if (!endNode && count + len >= saved.end) {\n endNode = cur;\n endOff = saved.end - count;\n break;\n }\n count += len;\n }\n if (!startNode) {\n // Offset exceeds content (e.g. undo to a shorter state): place at end\n const lastWalker = document.createTreeWalker(this.editable, NodeFilter.SHOW_TEXT, null);\n let lastNode = null;\n while ((lastNode = lastWalker.nextNode())) { startNode = lastNode; }\n startOff = startNode ? /** @type {Text} */ (startNode).length : 0;\n endNode = startNode;\n endOff = startOff;\n }\n if (!endNode) { endNode = startNode; endOff = startOff; }\n try {\n const range = document.createRange();\n range.setStart(startNode, startOff);\n range.setEnd(endNode, endOff);\n const sel = globalThis.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n } catch (_) {\n void _; // detached node — fall back to placing cursor at start of editable\n try {\n const fb = document.createRange();\n fb.setStart(this.editable, 0);\n fb.collapse(true);\n const s = globalThis.getSelection();\n if (s) { s.removeAllRanges(); s.addRange(fb); }\n } catch (_2) { void _2; /* fully give up */ }\n }\n }\n\n _savePoint() {\n // Trim future history if we're mid-stack\n if (this.stackOffset < this.stack.length - 1) {\n for (const entry of this.stack.slice(this.stackOffset + 1)) {\n this._bytes -= this._entrySize(entry);\n }\n this.stack = this.stack.slice(0, this.stackOffset + 1);\n }\n const raw = this._serialize();\n const { html, images } = this._tokenizeImages(raw);\n const entry = { html, images, sel: this._serializeSelection() };\n this.stack.push(entry);\n this._bytes += this._entrySize(entry);\n\n // Evict oldest states first, whichever budget (step count or byte size)\n // is exceeded — always keep at least the just-pushed current state.\n while (this.stack.length > 1 && (this.stack.length > this._limit || this._bytes > this._maxBytes)) {\n this._bytes -= this._entrySize(this.stack.shift());\n }\n // The newly-pushed current state is always the final entry. Recompute the\n // offset from the resulting stack instead of incrementing conditionally:\n // a single oversized snapshot may evict several older entries at once.\n this.stackOffset = this.stack.length - 1;\n }\n\n _restore(point) {\n if (!point) return;\n this.editable.innerHTML = this._detokenizeImages(point);\n this._restoreSelection(point.sel);\n }\n\n // ---------------------------------------------------------------------------\n // Base64 tokenisation — keeps snapshot strings small so that the\n // per-keystroke `recordUndo` string comparison stays fast even when the\n // editor contains large embedded images.\n // ---------------------------------------------------------------------------\n\n /**\n * Replaces every `data:…;base64,…` occurrence in `html` with a compact\n * token `__asn_img_0__`, `__asn_img_1__`, … and returns the tokenized\n * string together with a map from token → original data URL.\n * @param {string} html\n * @returns {{ html: string, images: Object<string,string> }}\n */\n _tokenizeImages(html) {\n // Fast-path: skip regex entirely when there are no data URIs (common case)\n if (!html.includes('data:')) return { html, images: /** @type {Record<string,string>} */ ({}) };\n const images = /** @type {Record<string,string>} */ ({});\n let index = 0;\n const tokenized = html.replace(/data:[^;]+;base64,[^\"' >]*/g, (match) => {\n const token = `__asn_img_${index}__`;\n images[token] = match;\n index++;\n return token;\n });\n return { html: tokenized, images };\n }\n\n /**\n * Restores a snapshot by replacing tokens back with their data URLs.\n * @param {{ html: string, images: Object<string,string> }} point\n * @returns {string}\n */\n _detokenizeImages(point) {\n if (!point.images || Object.keys(point.images).length === 0) return point.html;\n return point.html.replace(/__asn_img_\\d+__/g, (token) => point.images[token] || token);\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n /**\n * Records the current editor state as a history checkpoint.\n */\n recordUndo() {\n const current = this._serialize();\n const { html: tokenized } = this._tokenizeImages(current);\n const prev = this.stack[this.stackOffset];\n if (prev?.html === tokenized) return; // No change\n this._savePoint();\n }\n\n /**\n * Undo to the previous state.\n */\n undo() {\n if (this.stackOffset <= 0) return;\n this.stackOffset--;\n this._restore(this.stack[this.stackOffset]);\n }\n\n /**\n * Redo to the next state.\n */\n redo() {\n if (this.stackOffset >= this.stack.length - 1) return;\n this.stackOffset++;\n this._restore(this.stack[this.stackOffset]);\n }\n\n /**\n * Resets the history stack (e.g. on editor destroy or full content replace).\n */\n reset() {\n this.stack = [];\n this.stackOffset = -1;\n this._bytes = 0;\n this._savePoint();\n }\n\n /** @returns {boolean} */\n canUndo() {\n return this.stackOffset > 0;\n }\n\n /** @returns {boolean} */\n canRedo() {\n return this.stackOffset < this.stack.length - 1;\n }\n\n /** @returns {number} */\n getUndoCount() {\n return Math.max(0, this.stackOffset);\n }\n\n /** @returns {number} */\n getRedoCount() {\n return Math.max(0, this.stack.length - 1 - this.stackOffset);\n }\n}\n","/**\n * Table.js - Table creation and manipulation utilities\n * Inspired by Summernote's table handling\n */\n\nimport { createElement } from '../core/dom.js';\n\n// ---------------------------------------------------------------------------\n// Table creation\n// ---------------------------------------------------------------------------\n\n/**\n * Build an HTML table with the given number of columns and rows, optionally including a header row.\n * @param {number} cols - Number of columns in each row.\n * @param {number} rows - Total number of rows to create (including header when `headerRow` is true).\n * @param {{ headerRow?: boolean }} [opts] - Options: `headerRow` creates a `<thead>` when true.\n * @returns {HTMLTableElement} The constructed `<table>` element with a `<tbody>` and optional `<thead>`; each cell contains a `<br>` placeholder.\n */\nexport function createTable(cols, rows, opts = {}) {\n const { headerRow = false } = opts;\n const table = createElement('table', { class: 'an-table' });\n\n if (headerRow && rows > 0) {\n const thead = createElement('thead');\n const tr = createElement('tr');\n for (let c = 0; c < cols; c++) {\n const th = createElement('th', {}, [document.createElement('br')]);\n tr.appendChild(th);\n }\n thead.appendChild(tr);\n table.appendChild(thead);\n }\n\n const bodyRows = headerRow ? Math.max(rows - 1, 1) : rows;\n const tbody = createElement('tbody');\n table.appendChild(tbody);\n\n for (let r = 0; r < bodyRows; r++) {\n const tr = createElement('tr');\n for (let c = 0; c < cols; c++) {\n const td = createElement('td', {}, [document.createElement('br')]);\n tr.appendChild(td);\n }\n tbody.appendChild(tr);\n }\n return /** @type {HTMLTableElement} */ (table);\n}\n\n/**\n * Insert a table at the current selection and place the caret into its first cell.\n * @param {number} cols - Number of columns for the new table.\n * @param {number} rows - Number of rows for the new table.\n * @param {{ headerRow?: boolean }} [opts] - Options for table creation.\n */\nexport function insertTable(cols, rows, opts = {}) {\n if (cols <= 0 || rows <= 0) return;\n const table = createTable(cols, rows, opts);\n\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n try {\n range.deleteContents();\n } catch (_) {\n return;\n }\n\n // Walk up to find the nearest block-level ancestor to insert after\n const BLOCK = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE', 'LI', 'PRE']);\n let anchor = /** @type {Element|null} */ (range.startContainer);\n if (anchor?.nodeType === 3) anchor = anchor.parentElement;\n while (anchor && !BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentElement) {\n anchor = anchor.parentElement;\n }\n\n if (anchor && BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentNode) {\n anchor.after(table);\n // Ensure there's a paragraph after the table for cursor landing\n if (!table.nextElementSibling) {\n const p = document.createElement('p');\n p.appendChild(document.createElement('br'));\n table.after(p);\n }\n // Remove the anchor block if it was empty (common case: cursor in blank paragraph)\n if (!anchor.textContent.trim() && !anchor.querySelector('img, video, table')) {\n anchor.remove();\n }\n } else {\n try {\n range.insertNode(table);\n } catch (_) {\n return;\n }\n }\n\n // Place cursor in the first cell\n const firstCell = table.querySelector('td, th');\n if (firstCell) {\n const nr = document.createRange();\n nr.setStart(firstCell, 0);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n }\n}\n","/**\n * key.js - Keyboard key code constants\n * Inspired by Summernote's key.js\n */\n\nexport const key = {\n BACKSPACE: 'Backspace',\n TAB: 'Tab',\n ENTER: 'Enter',\n ESCAPE: 'Escape',\n SPACE: ' ',\n PAGE_UP: 'PageUp',\n PAGE_DOWN: 'PageDown',\n END: 'End',\n HOME: 'Home',\n LEFT: 'ArrowLeft',\n UP: 'ArrowUp',\n RIGHT: 'ArrowRight',\n DOWN: 'ArrowDown',\n DELETE: 'Delete',\n // Numbers\n NUM0: '0',\n NUM1: '1',\n NUM2: '2',\n NUM3: '3',\n NUM4: '4',\n NUM5: '5',\n NUM6: '6',\n NUM7: '7',\n NUM8: '8',\n // Letters\n B: 'b',\n E: 'e',\n I: 'i',\n J: 'j',\n K: 'k',\n L: 'l',\n R: 'r',\n S: 's',\n U: 'u',\n V: 'v',\n Y: 'y',\n Z: 'z',\n SLASH: '/',\n PERIOD: '.',\n};\n\n/**\n * Returns true if the event matches the given key\n * @param {KeyboardEvent} event\n * @param {string} keyName - one of key.*\n * @returns {boolean}\n */\nexport function isKey(event, keyName) {\n return event.key === keyName || event.key === keyName.toUpperCase();\n}\n\n/**\n * Returns true if the event is a modifier key press (Ctrl/Cmd + key)\n * @param {KeyboardEvent} event\n * @param {string} keyName\n * @returns {boolean}\n */\nexport function isModifier(event, keyName) {\n return (event.ctrlKey || event.metaKey) && isKey(event, keyName);\n}\n","/**\n * Typing.js - Keyboard typing event handling (Enter, Tab, Backspace behaviour)\n * Inspired by Summernote's Typing module\n */\n\nimport { key, isKey } from '../core/key.js';\nimport { closestPara, isLi } from '../core/dom.js';\nimport { execCommand, outdent } from './Style.js';\nimport { currentRange } from '../core/range.js';\n\n// ---------------------------------------------------------------------------\n// Module-level predicates — defined once, not re-created on every keypress.\n// Previously these were arrow functions inside handleKeydown() which fires\n// at ~120+ events/sec during normal typing.\n// ---------------------------------------------------------------------------\nconst _FA_PATTERN = /\\bfa-/;\nconst isFAIcon = (n) => !!(n?.nodeName === 'I' && _FA_PATTERN.test(n.className || ''));\nconst isZwsAnchor = (n) => !!(n?.nodeType === Node.TEXT_NODE && (n.textContent === '\\u200B' || n.textContent === ''));\n\n/**\n * Extracts the content from `startContainer:startOffset` to the end of `li`.\n * Returns an empty fragment if the range is invalid (e.g. detached node).\n * @param {Range} nativeRange\n * @param {Element} li\n * @returns {DocumentFragment}\n */\nfunction extractAfterContent(nativeRange, li) {\n try {\n const r = document.createRange();\n r.setStart(nativeRange.startContainer, nativeRange.startOffset);\n r.setEnd(li, li.childNodes.length);\n return r.extractContents();\n } catch (_) {\n void _;\n return document.createDocumentFragment();\n }\n}\n\n/**\n * Handles special keydown behaviour inside the editor.\n * @param {KeyboardEvent} event\n * @param {HTMLElement} editable\n * @param {object} options - editor options\n * @returns {boolean} true if the event was consumed\n */\nexport function handleKeydown(event, editable, options = {}) {\n const moveCaret = (setFn) => {\n const sel = globalThis.getSelection();\n if (!sel) return false;\n const nr = document.createRange();\n setFn(nr);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n return true;\n };\n\n // -------------------------------------------------------------------------\n // Backspace key — one-press deletion of a preceding FA icon (<i> element)\n // -------------------------------------------------------------------------\n if (isKey(event, key.BACKSPACE)) {\n const sel = globalThis.getSelection();\n if (sel?.rangeCount > 0) {\n const r = sel.getRangeAt(0);\n if (r.collapsed && r.startContainer.nodeType === Node.TEXT_NODE) {\n const textNode = /** @type {ChildNode} */ (r.startContainer);\n // Case A: cursor at offset 0, preceding sibling is an FA icon\n if (r.startOffset === 0 && isFAIcon(textNode.previousSibling)) {\n event.preventDefault();\n /** @type {ChildNode} */ (textNode.previousSibling).remove();\n return true;\n }\n\n // Case B: cursor at offset 1 of a ZWS-only text node whose preceding\n // sibling is an FA icon. The ZWS is the invisible caret anchor inserted\n // by IconDialog; treat the whole Backspace as \"delete icon + its anchor\".\n if (r.startOffset === 1 && textNode.textContent === '\\u200B' &&\n isFAIcon(textNode.previousSibling)) {\n event.preventDefault();\n const parent = textNode.parentNode;\n const icon = /** @type {ChildNode} */ (textNode.previousSibling);\n const prevNode = icon.previousSibling; // node before the icon (e.g. ZWS of prior icon)\n icon.remove();\n textNode.remove();\n // Explicitly restore the cursor to the node preceding the deleted icon.\n // Without this, the browser collapses the selection to the parent element\n // (not a text node), causing the next Backspace to miss Cases A/B and\n // requiring an extra keypress when two icons are adjacent.\n const nr = document.createRange();\n if (prevNode?.nodeType === Node.TEXT_NODE) {\n nr.setStart(prevNode, prevNode.textContent.length);\n } else if (prevNode) {\n nr.setStartAfter(prevNode);\n } else if (parent) {\n nr.setStart(parent, 0);\n }\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n return true;\n }\n }\n }\n return false;\n }\n\n // -------------------------------------------------------------------------\n // ArrowLeft / ArrowRight — one-press navigation across FA icon nodes\n // -------------------------------------------------------------------------\n if (isKey(event, key.LEFT) || isKey(event, key.RIGHT)) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return false;\n\n const r = sel.getRangeAt(0);\n if (!r.collapsed) return false;\n\n const sc = r.startContainer;\n const movingLeft = isKey(event, key.LEFT);\n\n if (sc.nodeType === Node.TEXT_NODE) {\n const textNode = sc;\n\n if (movingLeft &&\n r.startOffset === 1 &&\n textNode.textContent === '\\u200B' &&\n isFAIcon(textNode.previousSibling)) {\n event.preventDefault();\n return moveCaret((nr) => nr.setStartBefore(textNode.previousSibling));\n }\n\n if (movingLeft && r.startOffset === 0 && isFAIcon(textNode.previousSibling)) {\n event.preventDefault();\n return moveCaret((nr) => nr.setStartBefore(textNode.previousSibling));\n }\n\n if (movingLeft &&\n r.startOffset === 0 &&\n isZwsAnchor(textNode.previousSibling) &&\n isFAIcon(textNode.previousSibling.previousSibling)) {\n event.preventDefault();\n return moveCaret((nr) => nr.setStartBefore(textNode.previousSibling.previousSibling));\n }\n\n if (!movingLeft &&\n r.startOffset === textNode.textContent.length &&\n isFAIcon(textNode.nextSibling)) {\n const icon = textNode.nextSibling;\n const after = icon.nextSibling;\n event.preventDefault();\n if (after?.nodeType === Node.TEXT_NODE) {\n const offset = ((after.textContent || '').startsWith('\\u200B')) ? 1 : 0;\n return moveCaret((nr) => nr.setStart(after, Math.min(offset, after.textContent.length)));\n }\n return moveCaret((nr) => nr.setStartAfter(icon));\n }\n\n if (!movingLeft &&\n r.startOffset === textNode.textContent.length &&\n isZwsAnchor(textNode.nextSibling) &&\n isFAIcon(textNode.nextSibling.nextSibling)) {\n const icon = textNode.nextSibling.nextSibling;\n const after = icon.nextSibling;\n event.preventDefault();\n if (after?.nodeType === Node.TEXT_NODE) {\n const offset = ((after.textContent || '').startsWith('\\u200B')) ? 1 : 0;\n return moveCaret((nr) => nr.setStart(after, Math.min(offset, after.textContent.length)));\n }\n return moveCaret((nr) => nr.setStartAfter(icon));\n }\n }\n\n if (sc.nodeType === Node.ELEMENT_NODE) {\n const el = sc;\n if (movingLeft && r.startOffset > 0) {\n const prev = el.childNodes[r.startOffset - 1];\n if (isFAIcon(prev)) {\n event.preventDefault();\n return moveCaret((nr) => nr.setStartBefore(prev));\n }\n if (isZwsAnchor(prev) && isFAIcon(prev.previousSibling)) {\n event.preventDefault();\n return moveCaret((nr) => nr.setStartBefore(prev.previousSibling));\n }\n }\n if (!movingLeft && r.startOffset < el.childNodes.length) {\n const next = el.childNodes[r.startOffset];\n if (isFAIcon(next)) {\n const after = next.nextSibling;\n event.preventDefault();\n if (after?.nodeType === Node.TEXT_NODE) {\n const offset = ((after.textContent || '').startsWith('\\u200B')) ? 1 : 0;\n return moveCaret((nr) => nr.setStart(after, Math.min(offset, after.textContent.length)));\n }\n return moveCaret((nr) => nr.setStartAfter(next));\n }\n if (isZwsAnchor(next) && isFAIcon(next.nextSibling)) {\n const icon = next.nextSibling;\n const after = icon.nextSibling;\n event.preventDefault();\n if (after?.nodeType === Node.TEXT_NODE) {\n const offset = ((after.textContent || '').startsWith('\\u200B')) ? 1 : 0;\n return moveCaret((nr) => nr.setStart(after, Math.min(offset, after.textContent.length)));\n }\n return moveCaret((nr) => nr.setStartAfter(icon));\n }\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Tab key — indent / outdent list items, or insert soft tab in code blocks\n // -------------------------------------------------------------------------\n if (isKey(event, key.TAB)) {\n const range = currentRange(editable);\n if (!range) return false;\n\n const para = closestPara(range.sc, editable);\n if (para && isLi(para)) {\n event.preventDefault();\n if (event.shiftKey) {\n outdent();\n } else {\n execCommand('indent');\n }\n return true;\n }\n\n // In a pre/code block, insert spaces using configured tabSize\n if (para?.nodeName.toUpperCase() === 'PRE') {\n if (event.shiftKey) return false;\n event.preventDefault();\n execCommand('insertText', ' '.repeat(options.tabSize || 4));\n return true;\n }\n\n // Default: insert * tabSize\n if (options.tabSize) {\n if (event.shiftKey) return false;\n event.preventDefault();\n execCommand('insertText', ' '.repeat(options.tabSize));\n return true;\n }\n }\n\n // -------------------------------------------------------------------------\n // Shift+Enter — insert <br> instead of opening a new block element\n // -------------------------------------------------------------------------\n if (isKey(event, key.ENTER) && event.shiftKey) {\n event.preventDefault();\n execCommand('insertLineBreak');\n return true;\n }\n\n // -------------------------------------------------------------------------\n // Enter key — keep consistent paragraph insertion\n // -------------------------------------------------------------------------\n if (isKey(event, key.ENTER) && !event.shiftKey) {\n const range = currentRange(editable);\n if (!range) return false;\n\n // Hoist sc/el once so all guards below can reuse them.\n const sc = range.sc;\n const el = /** @type {Element|null} */ (sc.nodeType === 3 ? sc.parentElement : sc);\n\n // Guard: if the cursor is inside a <i> FA icon element (zero text children,\n // rendered entirely by CSS ::before), pressing Enter would split the block\n // and leave an orphan <i> in the new paragraph — visually an \"auto-created\n // icon\". Push the cursor to just after the <i> first, then fall through so\n // the browser fires its default Enter at a safe text boundary.\n if (el?.nodeName === 'I' && /\\bfa-/.test(el.className || '')) {\n const nr = document.createRange();\n nr.setStartAfter(el);\n nr.collapse(true);\n const selI = globalThis.getSelection();\n if (selI) { selI.removeAllRanges(); selI.addRange(nr); }\n return false; // cursor is now outside <i> — let browser default handle Enter\n }\n\n // Video wrapper — Enter should create a new paragraph after the wrapper,\n // not split the wrapper's container and produce an empty video clone.\n const videoWrapper = el?.closest('.an-video-wrapper');\n if (videoWrapper) {\n event.preventDefault();\n const p = document.createElement('p');\n p.innerHTML = '\\u00a0';\n videoWrapper.parentNode.insertBefore(p, videoWrapper.nextSibling);\n const nr = document.createRange();\n nr.setStart(p, 0);\n nr.collapse(true);\n const sel = globalThis.getSelection();\n sel.removeAllRanges();\n sel.addRange(nr);\n return true;\n }\n\n // Checklist — Enter creates new item; empty item exits the list\n const checkLi = el?.closest('.an-checklist li');\n if (checkLi) {\n event.preventDefault();\n const ul = checkLi.closest('.an-checklist');\n const sel = globalThis.getSelection();\n let nativeRange = sel.getRangeAt(0);\n\n // Helper: get trimmed text content of a li, excluding the checkbox INPUT.\n // Strip both \\u00a0 (placeholder nbsp) and \\u200B (ZWS cursor anchors).\n const liText = (li) =>\n Array.from(li.childNodes)\n .filter((n) => !(n.nodeType === 1 && n.tagName === 'INPUT'))\n .map((n) => n.textContent).join('').replace(/[\\u00a0\\u200B]/g, ' ').trim();\n\n // 1. Check if the ENTIRE item is empty BEFORE any DOM mutation.\n // (Do NOT check only the \"before-cursor\" part — that check incorrectly\n // exits the list when cursor is at the start of a non-empty item.)\n if (!liText(checkLi)) {\n // Empty item — exit checklist, insert <p> after list\n const p = document.createElement('p');\n p.innerHTML = '\\u00a0';\n ul.parentNode.insertBefore(p, ul.nextSibling);\n checkLi.remove();\n if (ul.children.length === 0) ul.remove();\n const nr = document.createRange();\n nr.setStart(p.firstChild, 0);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n return true;\n }\n\n // 2. If selection is not collapsed, delete the selected content first —\n // mirrors browser-default Enter behaviour (delete selection, then split).\n if (!nativeRange.collapsed) {\n nativeRange.deleteContents();\n // nativeRange is now collapsed at the deletion point; re-read it\n if (sel.rangeCount === 0 || !checkLi.isConnected) return true;\n nativeRange = sel.getRangeAt(0);\n }\n\n // 3. Extract everything from cursor to end of li into afterFrag.\n // Use startContainer/startOffset (cursor position after potential delete),\n // NOT endContainer/endOffset which is wrong for non-collapsed ranges.\n const afterFrag = extractAfterContent(nativeRange, checkLi);\n\n // 4. Build the new checklist item with the extracted \"after\" content.\n const newLi = document.createElement('li');\n const cb = document.createElement('input');\n cb.type = 'checkbox';\n cb.setAttribute('contenteditable', 'false');\n newLi.appendChild(cb);\n\n // Append extracted \"after\" content (if any) then insert the new item.\n if (afterFrag.textContent.replace(/[\\u00a0\\u200B]/g, '').length > 0) {\n newLi.appendChild(afterFrag);\n }\n\n // Always ensure a text node exists so the cursor has a text-level\n // anchor. Use \\u200B (zero-width space) instead of an empty string:\n // Chrome does not reliably honour a Selection in an empty text node and\n // may normalise it to element-level, placing the caret before the\n // absolutely-positioned checkbox. \\u200B is stripped by getHTML().\n let cursorNode = newLi.childNodes[1]; // first child after checkbox\n if (cursorNode?.nodeType !== Node.TEXT_NODE) {\n cursorNode = document.createTextNode('\\u200B');\n newLi.appendChild(cursorNode);\n }\n checkLi.after(newLi);\n\n const nr = document.createRange();\n nr.setStart(cursorNode, 0);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n return true;\n }\n\n const para = closestPara(range.sc, editable);\n\n // Enter in a pre/code block: insert a literal newline instead of a new block\n if (para?.nodeName.toUpperCase() === 'PRE') {\n event.preventDefault();\n execCommand('insertText', '\\n');\n return true;\n }\n\n // Pressing Enter at the end of a blockquote should exit it\n if (para?.nodeName.toUpperCase() === 'BLOCKQUOTE') {\n const native = range.toNativeRange();\n native.setEnd(para, para.childNodes.length);\n if (native.toString() === '' && range.isCollapsed()) {\n event.preventDefault();\n execCommand('formatBlock', '<p>');\n return true;\n }\n }\n }\n\n return false;\n}\n","/**\n * markdown.js - Lightweight Markdown → HTML converter for paste handling.\n *\n * Handles: headings H1–H6, bold/italic/strikethrough/inline-code, fenced code\n * blocks (with language), blockquotes, unordered/ordered lists, horizontal\n * rules, links, images, and plain paragraphs.\n *\n * The HTML output MUST be passed through sanitiseHTML() before insertion.\n */\n\n/**\n * Converts an HTML string to Markdown.\n * Handles: headings, paragraphs, bold/italic/del/code, links, images,\n * unordered/ordered lists, blockquote, pre/code blocks, tables, hr.\n * @param {string} html\n * @returns {string}\n */\nexport function htmlToMarkdown(html) {\n const doc = new DOMParser().parseFromString(`<body>${html || ''}</body>`, 'text/html');\n return _domToMd(doc.body).replace(/\\n{3,}/g, '\\n\\n').trim();\n}\n\n/**\n * Convert a DOM node subtree into Markdown.\n *\n * Recursively produces a Markdown string representing the given DOM node and its descendants,\n * handling common HTML constructs such as paragraphs, headings, lists (with nested indentation),\n * blockquotes, fenced and inline code, links, images, tables, horizontal rules, and basic inline emphasis.\n *\n * @param {Node} node - The DOM node to convert.\n * @param {number} [depth=0] - Current nesting depth used to indent nested list items.\n * @returns {string} The Markdown representation of the node subtree.\n */\n/**\n * Direct child elements matching a tag name. Used instead of the CSS\n * `:scope > tag` combinator, which this project's jsdom version resolves\n * incorrectly (matches descendants at any depth, not just direct children).\n * @param {Element} el\n * @param {string} tagName\n * @returns {Element[]}\n */\nfunction _directChildren(el, tagName) {\n return Array.from(el.children).filter((c) => c.tagName === tagName.toUpperCase());\n}\n\n/**\n * Text of a code element with line breaks preserved.\n *\n * `textContent` drops `<br>` entirely, and contenteditable stores every line\n * break inside a `<pre>` as one — so a code block typed in the editor came out\n * of getMarkdown() as a single run-together line. Block-level children (some\n * browsers wrap lines in `<div>`) end a line too.\n * @param {Element} el\n * @returns {string}\n */\nfunction _codeText(el) {\n let out = '';\n for (const node of el.childNodes) {\n if (node.nodeType === 3) { out += node.textContent; continue; }\n if (node.nodeType !== 1) continue;\n const tag = node.nodeName.toLowerCase();\n if (tag === 'br') { out += '\\n'; continue; }\n if (tag === 'div' || tag === 'p') {\n if (out && !out.endsWith('\\n')) out += '\\n';\n out += _codeText(/** @type {Element} */ (node));\n out += '\\n';\n continue;\n }\n out += _codeText(/** @type {Element} */ (node));\n }\n return out;\n}\n\n/**\n * Backslash-escapes the inline Markdown syntax characters in a run of plain\n * text, so prose survives a round-trip instead of being re-read as formatting.\n *\n * Deliberately narrow: `_` is only escaped at a word boundary (intra-word\n * underscores are not emphasis, and escaping `snake_case_name` makes the\n * Markdown unreadable), and `~` only as part of a `~~` pair.\n * @param {string} text\n * @returns {string}\n */\nfunction _escapeInlineMd(text) {\n return text\n .replaceAll('\\\\', '\\\\\\\\')\n // An `&` that would read as a character reference has to become one itself,\n // otherwise the literal text \"©\" comes back as ©.\n .replace(/&(?=#\\d+;|#[xX][0-9a-fA-F]+;|[a-zA-Z][a-zA-Z0-9]*;)/g, '&')\n .replace(/!(?=\\[)/g, String.raw`\\!`)\n .replace(/([`*[\\]])/g, String.raw`\\$1`)\n .replace(/(?<!\\w)_|_(?!\\w)/g, String.raw`\\_`)\n .replace(/~(?=~)|(?<=~)~/g, String.raw`\\~`);\n}\n\n/**\n * Escapes a leading block marker so a line of prose is not re-read as a\n * heading, quote, list item, thematic break or setext underline.\n * @param {string} line\n * @returns {string}\n */\nfunction _escapeLineStart(line) {\n if (/^\\s*(?:-{2,}|={2,}|\\*{3,}|_{3,}|(?:[-*_] +){2,}[-*_])\\s*$/.test(line)) {\n return line.replace(/[-=*_]/, (c) => `\\\\${c}`);\n }\n return line\n .replace(/^(\\s*)(#{1,6})(?=\\s|$)/, (_, ws, h) => `${ws}\\\\${h}`)\n .replace(/^(\\s*)>/, (_, ws) => `${ws}\\\\>`)\n .replace(/^(\\s*)([-*+])(?=\\s)/, (_, ws, c) => `${ws}\\\\${c}`)\n .replace(/^(\\s*)(\\d+)([.)])(?=\\s)/, (_, ws, n, d) => `${ws}${n}\\\\${d}`);\n}\n\n/** Applies _escapeLineStart() to every line of a multi-line block body. */\nfunction _escapeBlockStarts(text) {\n return text.split('\\n').map(_escapeLineStart).join('\\n');\n}\n\n/**\n * Renders an `<a href>` / `<img src>` as a Markdown link destination, with the\n * element's `title` when it has one.\n *\n * A URL containing spaces or parentheses is wrapped in angle brackets, which is\n * the only form that survives re-parsing — `[x](http://e.com/a(b))` otherwise\n * closes at the inner `)`.\n * @param {Element} el\n * @param {'href'|'src'} attr\n * @returns {string}\n */\n/**\n * Renders one `<li>`'s content for a list at `depth`.\n *\n * A list item holding more than one paragraph produced a second paragraph at\n * column 0, which re-parsed as a sibling paragraph that ended the list. Any\n * continuation line is therefore indented to the child column — nested lists\n * already carry that indent from their own `depth`, so they are left as they\n * are rather than shifted twice.\n * @param {Element} li\n * @param {number} depth\n * @returns {string}\n */\nfunction _itemBody(li, depth) {\n const childIndent = ' '.repeat(depth + 1);\n return _domToMd(li, depth + 1).trim().split('\\n')\n .map((line, idx) => {\n if (idx === 0 || line.trim() === '') return line;\n return line.startsWith(childIndent) ? line : childIndent + line;\n })\n .join('\\n');\n}\n\nfunction _destination(el, attr) {\n const url = el.getAttribute(attr) || '';\n const wrapped = /[\\s()]/.test(url) ? `<${url}>` : url;\n const title = el.getAttribute('title');\n return title ? `${wrapped} \"${title.replaceAll('\"', String.raw`\\\"`)}\"` : wrapped;\n}\n\nfunction _domToMd(node, depth = 0) {\n if (node.nodeType === 3) {\n const text = node.textContent.replace(/\\s+/g, ' ');\n // Text inside <code>/<pre> is already literal in Markdown; everywhere else\n // it has to be escaped or the user's own prose turns into formatting on the\n // way back — \"2 * 3 * 4\" came back as \"2 <em> 3 </em> 4\".\n return node.parentElement?.closest('pre, code') ? text : _escapeInlineMd(text);\n }\n if (node.nodeType !== 1) return '';\n\n const el = /** @type {Element} */ (node);\n const tag = el.nodeName.toLowerCase();\n const inner = () => Array.from(el.childNodes).map(n => _domToMd(n, depth)).join('');\n\n switch (tag) {\n case 'p':\n case 'div': return `\\n\\n${_escapeBlockStarts(inner())}\\n\\n`;\n case 'br': return ' \\n';\n case 'h1': return `\\n\\n# ${inner()}\\n\\n`;\n case 'h2': return `\\n\\n## ${inner()}\\n\\n`;\n case 'h3': return `\\n\\n### ${inner()}\\n\\n`;\n case 'h4': return `\\n\\n#### ${inner()}\\n\\n`;\n case 'h5': return `\\n\\n##### ${inner()}\\n\\n`;\n case 'h6': return `\\n\\n###### ${inner()}\\n\\n`;\n case 'strong':\n case 'b': return `**${inner()}**`;\n case 'em':\n case 'i': return `*${inner()}*`;\n case 'del':\n case 's':\n case 'strike': return `~~${inner()}~~`;\n case 'sup': return `^${inner()}^`;\n case 'sub': return `~${inner()}~`;\n case 'u': return `<u>${inner()}</u>`;\n case 'span': {\n // Markdown has no native underline/color/size syntax; pass through as\n // raw inline HTML for the specific styles the editor's own toolbar\n // creates (foreColor/backColor/fontSize) — other noise spans (e.g. from\n // pasted content) are unwrapped to plain text as before.\n const style = el.getAttribute('style') || '';\n if (/\\b(color|background-color|font-size)\\s*:/.test(style)) {\n return `<span style=\"${_escAttr(style)}\">${inner()}</span>`;\n }\n return inner();\n }\n case 'code': {\n // Inside <pre> we emit raw text; outside we wrap in backticks\n if (el.closest('pre')) return inner();\n const content = inner();\n // A code span has to be fenced by more backticks than the longest run it\n // contains, and padded with spaces when it starts or ends with one —\n // otherwise `a ` b` closes at the wrong backtick and mangles the text.\n const longestRun = Math.max(0, ...Array.from(content.matchAll(/`+/g), (m) => m[0].length));\n const fence = '`'.repeat(longestRun + 1);\n const pad = /^`|`$/.test(content) ? ' ' : '';\n return `${fence}${pad}${content}${pad}${fence}`;\n }\n case 'pre': {\n const codeEl = el.querySelector('code');\n const langMatch = /language-(\\S+)/.exec(codeEl?.className || '');\n const lang = langMatch ? langMatch[1] : '';\n const content = _codeText(codeEl || el);\n // A block whose text already ends in a newline would otherwise gain a\n // blank line from the one added before the closing fence.\n return `\\n\\n\\`\\`\\`${lang}\\n${content.replace(/\\n$/, '')}\\n\\`\\`\\`\\n\\n`;\n }\n case 'blockquote': {\n const rawLines = inner().trim().split('\\n');\n // Collapse consecutive blank lines (from adjacent <p> blocks) into one.\n const lines = rawLines.filter((l, idx) => l.trim() !== '' || (rawLines[idx - 1] ?? '').trim() !== '');\n return `\\n\\n${lines.map((l) => (l.trim() === '' ? '>' : `> ${l}`)).join('\\n')}\\n\\n`;\n }\n case 'a': return `[${inner()}](${_destination(el, 'href')})`;\n case 'img': {\n const alt = _escapeInlineMd(el.getAttribute('alt') || '');\n return `})`;\n }\n case 'ul': {\n const items = _directChildren(el, 'li');\n if (!items.length) return inner();\n const indent = ' '.repeat(depth);\n const isChecklist = el.classList.contains('an-checklist');\n const lines = items.map((li) => {\n const cb = /** @type {HTMLInputElement | undefined} */ (\n _directChildren(li, 'input').find((c) => c.getAttribute('type') === 'checkbox')\n );\n let prefix = '- ';\n if (isChecklist || cb) {\n const checked = cb ? cb.checked : false;\n prefix = checked ? '- [x] ' : '- [ ] ';\n }\n return `${indent}${prefix}${_itemBody(li, depth)}`;\n }).join('\\n');\n return depth === 0 ? `\\n\\n${lines}\\n\\n` : `\\n${lines}`;\n }\n case 'ol': {\n const items = _directChildren(el, 'li');\n if (!items.length) return inner();\n const indent = ' '.repeat(depth);\n // Preserve an explicit start; markdownToHTML already emits `start` for a\n // list that does not begin at 1, so dropping it here broke the round-trip.\n const start = Number.parseInt(el.getAttribute('start') || '1', 10);\n const first = Number.isFinite(start) ? start : 1;\n const lines = items.map((li, i) => `${indent}${first + i}. ${_itemBody(li, depth)}`).join('\\n');\n return depth === 0 ? `\\n\\n${lines}\\n\\n` : `\\n${lines}`;\n }\n case 'li': return inner();\n case 'hr': return '\\n\\n---\\n\\n';\n case 'table': {\n const allRows = Array.from(el.querySelectorAll('tr'));\n if (!allRows.length) return inner();\n const theadEl = _directChildren(el, 'thead')[0];\n const firstRowIsHeader = !!theadEl || (\n allRows[0].children.length > 0 &&\n Array.from(allRows[0].children).every((c) => c.tagName === 'TH')\n );\n const cellTexts = allRows.map((tr) =>\n Array.from(tr.querySelectorAll('th, td')).map((c) =>\n _escapeInlineMd(c.textContent.trim()).replaceAll('|', String.raw`\\|`)),\n );\n const cols = Math.max(...cellTexts.map((r) => r.length));\n const padRow = (row) => { const r = [...row]; while (r.length < cols) r.push(''); return r; };\n const bodyStart = firstRowIsHeader ? 1 : 0;\n const headerCells = firstRowIsHeader ? padRow(cellTexts[0]) : new Array(cols).fill('');\n // Carry per-column alignment back into the delimiter row. markdownToHTML\n // writes it out as `text-align`, so without this a round-trip through\n // Markdown silently left every column default-aligned.\n const alignRow = Array.from({ length: cols }, (_unused, c) => {\n const cell = allRows[0]?.children[c];\n const align = /text-align:\\s*(left|center|right)/.exec(cell?.getAttribute('style') || '')?.[1];\n if (align === 'center') return ':---:';\n if (align === 'right') return '---:';\n if (align === 'left') return ':---';\n return '---';\n });\n let md = '\\n\\n';\n md += `| ${headerCells.join(' | ')} |\\n`;\n md += `| ${alignRow.join(' | ')} |\\n`;\n for (let r = bodyStart; r < cellTexts.length; r++) {\n md += `| ${padRow(cellTexts[r]).join(' | ')} |\\n`;\n }\n return md + '\\n';\n }\n default: return inner();\n }\n}\n\n/**\n * Removes a leading UTF-8 byte-order mark.\n *\n * `FileReader.readAsText` keeps the BOM, and editors on Windows write one by\n * default, so a dropped `.md` file arrived with U+FEFF glued to its first\n * character: the opening heading parsed as a paragraph and isMarkdown()\n * rejected the file outright.\n * @param {string} text\n * @returns {string}\n */\nfunction _stripBOM(text) {\n return String(text ?? '').replace(/^\\ufeff/, '');\n}\n\n/**\n * Detects whether a string likely contains Markdown syntax.\n *\n * Checks for common Markdown constructs such as ATX headings, unordered or\n * ordered list items, blockquotes, fenced code blocks, and bold emphasis.\n * @param {string} rawText - Input text to inspect for Markdown patterns.\n * @returns {boolean} `true` if any Markdown-like pattern is present, `false` otherwise.\n */\nexport function isMarkdown(rawText) {\n const text = _stripBOM(rawText);\n return /^#{1,6} [^\\s]|^[ \\t]*[-*+] [^\\s]|^[ \\t]*\\d+[.)] [^\\s]|^> ?[^\\s]|^ {0,3}(?:`{3,}|~{3,})|^\\*{2}[^*\\n]+\\*{2}/m.test(text)\n || /^.+\\n=+\\s*$/m.test(text)\n || /^.+\\n-{2,}\\s*$/m.test(text)\n || /^---[ \\t]*\\n(?:[\\s\\S]*?\\n)?(?:---|\\.\\.\\.)[ \\t]*(?:\\n|$)/.test(text)\n || /^\\|.+\\|[ \\t]*\\n\\|[ \\t:|-]+\\|/m.test(text)\n // Pipe table without outer pipes: `a | b` over `--- | ---`.\n || /^[^\\n|]*\\|[^\\n]*\\n[ \\t]*:?-+:?[ \\t]*(?:\\|[ \\t]*:?-+:?[ \\t]*)+$/m.test(text)\n // A link or image plus at least one other inline marker — either alone is\n // too weak a signal (bare URLs and \"(see note)\" are ordinary prose), but\n // together they reliably indicate Markdown rather than a plain-text body.\n || (/!?\\[[^\\]\\n]*\\]\\([^)\\n]*\\)/.test(text) && /`[^`\\n]+`|\\*\\*[^*\\n]+\\*\\*|^#{1,6} |^[-*+] /m.test(text));\n}\n\n// Blockquote line: optional up-to-3 leading spaces, '>', optional single space, rest of line.\nconst BQ_RE = /^ {0,3}>( ?)(.*)$/;\n// Indented code block: 4+ spaces or a leading tab, with actual content after it.\nconst INDENTED_CODE_RE = /^(?: {4}|\\t)\\s*\\S/;\n// Opening fence: up to 3 spaces, then 3+ backticks or 3+ tildes, then an info string.\nconst FENCE_RE = /^( {0,3})(`{3,}|~{3,})[ \\t]*([^\\s`~][^\\n]*)?$/;\n\n/**\n * Parses `line` as an opening code fence, or returns null.\n *\n * A backtick fence's info string may not contain a backtick (CommonMark) —\n * without that rule ```` ```` `` wrongly reads as a fence whose language is a\n * backtick, and a line like \"``a ` b``\" reads as a fence instead of a code span.\n * @param {string} line\n * @returns {{ marker: string, length: number, indent: number, lang: string }|null}\n */\nfunction _openingFence(line) {\n const m = FENCE_RE.exec(line);\n if (!m) return null;\n // The info-string group is optional, so it is undefined on a bare fence.\n const [, indent, fence, info = ''] = m;\n if (fence[0] === '`' && info.includes('`')) return null;\n return {\n marker: fence[0],\n length: fence.length,\n indent: indent.length,\n // Only the first word of the info string is the language.\n lang: info.trim().split(/\\s+/)[0] || '',\n };\n}\n\n/**\n * Removes up to `count` leading space-equivalents, expanding a leading tab to\n * the next 4-column stop the way CommonMark does.\n * @param {string} line\n * @param {number} count\n * @returns {string}\n */\nfunction _stripIndent(line, count) {\n let removed = 0;\n let idx = 0;\n while (idx < line.length && removed < count) {\n if (line[idx] === ' ') { removed += 1; idx += 1; continue; }\n if (line[idx] === '\\t') {\n const width = 4 - (removed % 4);\n if (removed + width > count) break;\n removed += width;\n idx += 1;\n continue;\n }\n break;\n }\n return line.slice(idx);\n}\n// Horizontal rule: 3+ of the same character (-, * or _), optionally space-separated.\nconst HR_RE = /^ {0,3}([-*_])( *\\1){2,}\\s*$/;\n// Hard-break marker — placed between paragraph lines that end in a\n// CommonMark hard-break (trailing 2+ spaces or a trailing backslash),\n// restored to <br> after _inline() runs. Distinct from _inline()'s own MARK.\nconst HARD_BREAK = String.fromCharCode(1);\n\n/**\n * Converts a Markdown string to an HTML string.\n * @param {string} text\n * @returns {string}\n */\nexport function markdownToHTML(text) {\n let lines = _stripBOM(text).replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n').split('\\n');\n lines = _stripFrontmatter(lines);\n const refs = _extractReferenceDefinitions(lines);\n lines = refs.clean;\n _linkDefs = refs.linkDefs;\n _footnoteIds = refs.footnoteIds;\n return _parseBlocks(lines);\n}\n\n/**\n * Parses a line array into block-level HTML. Called recursively for content\n * nested inside a blockquote so nested quotes and block content (lists,\n * headings, etc.) inside `>` are parsed the same as top-level content.\n * @param {string[]} lines\n * @returns {string}\n */\nfunction _parseBlocks(lines) {\n const out = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // ---- Fenced code block ```lang / ~~~lang ... ----------------------------\n const fence = _openingFence(line);\n if (fence) {\n const closeRe = new RegExp(`^ {0,3}\\\\${fence.marker}{${fence.length},}[ \\t]*$`);\n const codeLines = [];\n i++;\n while (i < lines.length && !closeRe.test(lines[i])) {\n // CommonMark strips up to as many leading spaces as the opening fence\n // was indented by, so an indented fence keeps its code left-aligned.\n codeLines.push(_escCode(_stripIndent(lines[i], fence.indent)));\n i++;\n }\n const langAttr = fence.lang ? ` class=\"language-${_escAttr(fence.lang)}\"` : '';\n out.push(`<pre><code${langAttr}>${codeLines.join('\\n')}</code></pre>`);\n i++; // skip closing fence (no-op at EOF — an unclosed fence runs to the end)\n continue;\n }\n\n // ---- Indented code block (4 spaces or a tab) -----------------------------\n // Only reachable at a block boundary: an indented line following a\n // paragraph is consumed as a lazy continuation before it gets here, which\n // matches CommonMark's rule that indented code cannot interrupt a paragraph.\n if (INDENTED_CODE_RE.test(line)) {\n const codeLines = [];\n while (i < lines.length && (INDENTED_CODE_RE.test(lines[i]) || lines[i].trim() === '')) {\n // A trailing run of blank lines belongs to whatever follows, not to the\n // code block, so only keep blanks that have more code after them.\n if (lines[i].trim() === '') {\n let j = i;\n while (j < lines.length && lines[j].trim() === '') j++;\n if (j >= lines.length || !INDENTED_CODE_RE.test(lines[j])) break;\n for (; i < j; i++) codeLines.push('');\n continue;\n }\n codeLines.push(_escCode(_stripIndent(lines[i], 4)));\n i++;\n }\n out.push(`<pre><code>${codeLines.join('\\n')}</code></pre>`);\n continue;\n }\n\n // ---- Setext headings (Title\\n=== or Title\\n---) -------------------------\n if (line.trim() && !HR_RE.test(line) && !/^#{1,6} /.test(line) && i + 1 < lines.length) {\n if (/^=+\\s*$/.test(lines[i + 1])) {\n out.push(`<h1>${_inline(line.trim())}</h1>`);\n i += 2;\n continue;\n }\n if (/^-{2,}\\s*$/.test(lines[i + 1])) {\n out.push(`<h2>${_inline(line.trim())}</h2>`);\n i += 2;\n continue;\n }\n }\n\n // ---- Horizontal rule --- / *** / ___ / - - - / * * * ----------------------\n if (HR_RE.test(line)) {\n out.push('<hr>');\n i++;\n continue;\n }\n\n // ---- ATX Headings # – ###### -------------------------------------------\n // The title may be empty: \"# \" on its own is a valid empty heading. It also\n // has to match here, because the paragraph collector below refuses any line\n // starting with a heading marker — a line this regex rejected but that one\n // also skipped consumed nothing, and the block loop spun forever.\n const hMatch = /^(#{1,6})[ \\t]+(.*)$/.exec(line);\n if (hMatch) {\n const level = hMatch[1].length;\n // Strip an optional closing sequence of #'s (e.g. \"## Heading ##\"),\n // only when preceded by whitespace — \"Heading#\" (no space) is untouched.\n const content = hMatch[2].replace(/(?:^|\\s)#+\\s*$/, '');\n out.push(`<h${level}>${_inline(content)}</h${level}>`);\n i++;\n continue;\n }\n\n // ---- Blockquote > text --------------------------------------------------\n if (BQ_RE.test(line)) {\n const bqLines = [];\n while (i < lines.length && BQ_RE.test(lines[i])) {\n bqLines.push(BQ_RE.exec(lines[i])[2]);\n i++;\n }\n out.push(`<blockquote>${_parseBlocks(bqLines)}</blockquote>`);\n continue;\n }\n\n // ---- Checklist or Unordered list - / * / + item ----------------------\n if (/^[-*+] /.test(line)) {\n const { html: listHtml, endIdx } = _parseListBlock(lines, i);\n out.push(listHtml); i = endIdx; continue;\n }\n\n // ---- Ordered list 1. item ----------------------------------------------\n if (/^\\d+[.)] /.test(line)) {\n const { html: listHtml, endIdx } = _parseListBlock(lines, i);\n out.push(listHtml); i = endIdx; continue;\n }\n\n // ---- Blank line ----------------------------------------------------------\n if (line.trim() === '') {\n i++;\n continue;\n }\n\n // ---- GFM Table | col | col | -------------------------------------------\n // A table starts with a pipe-prefixed or pipe-containing line followed by\n // a separator row (| --- | --- |). We detect and collect all rows.\n if (_isTableStart(lines, i)) {\n const headerCells = _parseTableRow(line);\n const alignments = _parseTableRow(lines[i + 1]).map((c) => {\n if (c.startsWith(':') && c.endsWith(':')) return 'center';\n if (c.endsWith(':')) return 'right';\n if (c.startsWith(':')) return 'left';\n return null;\n });\n i += 2; // skip header + separator\n const bodyRows = [];\n while (i < lines.length && lines[i].trim() !== '' && _countTableCells(lines[i]) > 1) {\n bodyRows.push(_parseTableRow(lines[i]));\n i++;\n }\n const _cell = (tag, content, align) => {\n const s = align ? ` style=\"text-align:${align}\"` : '';\n return `<${tag}${s}>${_inline(content)}</${tag}>`;\n };\n const thCells = headerCells.map((c, idx) => _cell('th', c, alignments[idx])).join('');\n const thead = `<thead><tr>${thCells}</tr></thead>`;\n const renderRow = (row) => `<tr>${row.map((c, idx) => _cell('td', c, alignments[idx])).join('')}</tr>`;\n const tbody = bodyRows.length ? `<tbody>${bodyRows.map(renderRow).join('')}</tbody>` : '';\n out.push(`<table>${thead}${tbody}</table>`);\n continue;\n }\n\n // ---- Paragraph: collect consecutive non-block lines ---------------------\n const paraLines = [];\n while (\n i < lines.length &&\n lines[i].trim() !== '' &&\n !/^(#{1,6} |[-*+] |\\d+[.)] )/.test(lines[i]) &&\n !_openingFence(lines[i]) &&\n !BQ_RE.test(lines[i]) &&\n !HR_RE.test(lines[i]) &&\n !_isTableStart(lines, i) &&\n !(i + 1 < lines.length && /^=+\\s*$/.test(lines[i + 1])) &&\n !(i + 1 < lines.length && /^-{2,}\\s*$/.test(lines[i + 1]))\n ) {\n paraLines.push(lines[i]);\n i++;\n }\n if (paraLines.length) {\n out.push(`<p>${_inline(_joinParagraphLines(paraLines)).replaceAll(HARD_BREAK, '<br>')}</p>`);\n } else {\n // Nothing above consumed this line and the paragraph collector rejected\n // it too. That combination is a bug in one of the branches, but the loop\n // must still move: spinning here froze the page on input as ordinary as a\n // heading marker with nothing after it. Emit the line and move on.\n out.push(`<p>${_inline(line)}</p>`);\n i++;\n }\n }\n\n return out.join('');\n}\n\n// ---------------------------------------------------------------------------\n// Inline formatting\n// ---------------------------------------------------------------------------\n\n/** Reference-link and footnote definitions collected per markdownToHTML() call. */\nlet _linkDefs = new Map();\nlet _footnoteIds = new Set();\n\n/**\n * Strips a leading YAML frontmatter block (--- ... --- or --- ... ...) from\n * the line array, only when it is the very first line and the enclosed body\n * looks like YAML (key: value / list items / indented continuations) — this\n * disambiguates real frontmatter from a horizontal rule followed by prose.\n * @param {string[]} lines\n * @returns {string[]}\n */\nfunction _stripFrontmatter(lines) {\n if ((lines[0] || '').trim() !== '---') return lines;\n let closeIdx = -1;\n for (let j = 1; j < lines.length; j++) {\n const t = lines[j].trim();\n if (t === '---' || t === '...') { closeIdx = j; break; }\n }\n if (closeIdx === -1) return lines;\n\n const body = lines.slice(1, closeIdx);\n const looksLikeYAML = body.every((l) =>\n l.trim() === '' ||\n /^[ \\t]*[\\w$.-]+\\s*:(\\s|$)/.test(l) ||\n /^[ \\t]*-\\s+\\S/.test(l) ||\n /^[ \\t]+\\S/.test(l));\n if (!looksLikeYAML) return lines;\n\n let start = closeIdx + 1;\n if (lines[start] !== undefined && lines[start].trim() === '') start++;\n return lines.slice(start);\n}\n\n/**\n * Extracts GFM reference-link definitions (`[ref]: url \"title\"`) and footnote\n * definitions (`[^id]: text`) from the line array, skipping fenced code\n * regions. Returns the definition-free line array plus lookup maps.\n * @param {string[]} lines\n * @returns {{ clean: string[], linkDefs: Map<string, {href: string, title?: string}>, footnoteIds: Set<string> }}\n */\nfunction _extractReferenceDefinitions(lines) {\n const linkDefs = new Map();\n const footnoteIds = new Set();\n const clean = [];\n let inFence = false;\n const linkDefRe = /^\\[([^\\]]+)\\]:\\s*(\\S+)(?:\\s+\"([^\"]*)\")?\\s*$/;\n const footnoteDefRe = /^\\[\\^([^\\]]+)\\]:[ \\t]*(\\S.*)$/;\n\n for (const line of lines) {\n // Definitions inside a fenced block are literal code, not definitions.\n if (inFence) {\n if (/^ {0,3}(?:`{3,}|~{3,})[ \\t]*$/.test(line)) inFence = false;\n clean.push(line);\n continue;\n }\n if (_openingFence(line)) { inFence = true; clean.push(line); continue; }\n {\n const fm = footnoteDefRe.exec(line);\n if (fm) { footnoteIds.add(fm[1]); continue; }\n const lm = linkDefRe.exec(line);\n if (lm) { linkDefs.set(lm[1].trim().toLowerCase(), { href: lm[2], title: lm[3] }); continue; }\n }\n clean.push(line);\n }\n return { clean, linkDefs, footnoteIds };\n}\n\n/**\n * Joins a paragraph's source lines into one string, converting CommonMark\n * hard-break markers (a trailing backslash, or 2+ trailing spaces) on all\n * but the last line into a HARD_BREAK placeholder instead of a plain space.\n * @param {string[]} paraLines\n * @returns {string}\n */\nfunction _joinParagraphLines(paraLines) {\n let joined = '';\n for (let idx = 0; idx < paraLines.length; idx++) {\n const isLast = idx === paraLines.length - 1;\n // Leading whitespace on a continuation line is not content — CommonMark\n // strips it before joining, so an indented lazy continuation does not carry\n // its indent into the paragraph text.\n const ln = paraLines[idx].replace(/^[ \\t]+/, '');\n if (!isLast && /\\\\$/.test(ln)) { joined += ln.replace(/\\\\$/, '') + HARD_BREAK; continue; }\n if (!isLast && / {2,}$/.test(ln)) { joined += ln.replace(/ {2,}$/, '') + HARD_BREAK; continue; }\n joined += ln + (isLast ? '' : ' ');\n }\n return joined;\n}\n\n/**\n * Splits a GFM table row string into trimmed cell strings, treating an\n * escaped pipe (`\\|`) as a literal character rather than a cell separator.\n * '| a | b | c |' → ['a', 'b', 'c']; '| a\\|b | c |' → ['a|b', 'c']\n * @param {string} row\n * @returns {string[]}\n */\n/** Number of cells a GFM table row would split into. */\nfunction _countTableCells(line) {\n return _parseTableRow(line).length;\n}\n\n/**\n * True when `lines[i]` is a GFM table header followed by a delimiter row.\n *\n * Leading and trailing pipes are optional in GFM (`a | b` / `--- | ---` is a\n * valid table), so the delimiter row is identified by shape instead.\n *\n * The pipe-delimited form stays deliberately lenient — a ragged table whose\n * delimiter row is short still renders, columns past it just unaligned. The\n * bare form has to be stricter, matching header and delimiter cell counts:\n * without that, prose containing a pipe followed by a `---` line would be read\n * as a one-column table instead of the setext heading it is.\n * @param {string[]} lines\n * @param {number} i\n * @returns {boolean}\n */\nfunction _isTableStart(lines, i) {\n const header = lines[i];\n const delim = lines[i + 1];\n if (delim === undefined || !header.includes('|')) return false;\n\n if (/^\\|.+\\|/.test(header)) return /^\\|[\\s|:-]+\\|/.test(delim);\n\n const delimCells = _parseTableRow(delim);\n if (delimCells.length < 2 || !delimCells.every((c) => /^:?-+:?$/.test(c))) return false;\n return _countTableCells(header) === delimCells.length;\n}\n\nfunction _parseTableRow(row) {\n const trimmed = row.replace(/^\\|/, '').replace(/\\|$/, '');\n const cells = [];\n let cur = '';\n for (let i = 0; i < trimmed.length; i++) {\n if (trimmed[i] === '\\\\' && trimmed[i + 1] === '|') { cur += '|'; i++; continue; }\n if (trimmed[i] === '|') { cells.push(cur); cur = ''; continue; }\n cur += trimmed[i];\n }\n cells.push(cur);\n return cells.map((c) => c.trim());\n}\n\nfunction _parseListBlock(lines, startIdx) {\n const baseIndent = (lines[startIdx].match(/^(\\s*)/)[1]).length;\n const isOL = /^\\s*\\d+[.)] /.test(lines[startIdx]);\n const items = [];\n let firstIsCB = null;\n let loose = false;\n let pendingBlank = false;\n let i = startIdx;\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (line.trim() === '') {\n // A blank line only ends the list if what follows isn't a continuation\n // of it (another item at the same marker/indent, or indented text\n // belonging to the current item) — otherwise it marks a \"loose\" list.\n const next = lines[i + 1];\n const nextIndent = next !== undefined ? (next.match(/^(\\s*)/)[1]).length : -1;\n const nextIsSameItem = next !== undefined &&\n /^\\s*(?:[-*+]|\\d+[.)]) /.test(next) &&\n (/^\\s*\\d+[.)] /.test(next) === isOL) &&\n nextIndent === baseIndent;\n const nextIsContinuation = next !== undefined && next.trim() !== '' && nextIndent > baseIndent;\n if (!items.length || (!nextIsSameItem && !nextIsContinuation)) break;\n loose = true;\n pendingBlank = true;\n i++;\n continue;\n }\n\n const indent = (line.match(/^(\\s*)/)[1]).length;\n if (indent < baseIndent) break;\n\n if (indent === baseIndent) {\n if (!/^\\s*(?:[-*+]|\\d+[.)]) /.test(line)) break;\n if (/^\\s*\\d+[.)] /.test(line) !== isOL) break;\n const raw = isOL ? line.replace(/^\\s*\\d+[.)] /, '') : line.replace(/^\\s*[-*+] /, '');\n // Checklists are intentionally UL-only: sanitise.js's checkbox guard,\n // the injected checklist CSS, and every checklist-toggle command are\n // all hardcoded to `ul.an-checklist` with no `ol` equivalent, so an\n // ordered-list checkbox would be stripped by the sanitiser and get no\n // styling even if parsed here — \"1. [ ] item\" intentionally stays plain.\n const isCB = !isOL && /^\\[[ xX]\\]\\s+/.test(raw);\n if (firstIsCB === null) firstIsCB = isCB;\n if (isCB !== firstIsCB) break;\n const checked = isCB && raw[1].toLowerCase() === 'x';\n const text = isCB ? raw.replace(/^\\[[ xX]\\]\\s+/, '') : raw;\n items.push({ paras: [text], isCB, checked, sub: '' });\n pendingBlank = false;\n i++;\n } else {\n if (!items.length) { i++; continue; }\n\n // A fenced block belonging to this item. Without this the fence lines\n // were folded into the item's paragraph text and the inline code-span\n // rule chewed them up — \"- a\\n\\n ```js\\n x\\n ```\" came out as\n // <li><p>a</p><p><code><code>js x </code></code></p></li>, with the\n // snippet's line breaks gone.\n const dedent = (l) => _stripIndent(l, indent);\n const fence = _openingFence(dedent(line));\n if (fence) {\n const closeRe = new RegExp(`^ {0,3}\\\\${fence.marker}{${fence.length},}[ \\t]*$`);\n const blockLines = [dedent(lines[i])];\n i++;\n while (i < lines.length && !closeRe.test(dedent(lines[i]))) {\n blockLines.push(dedent(lines[i]));\n i++;\n }\n if (i < lines.length) { blockLines.push(dedent(lines[i])); i++; }\n // Appended to `sub` so it keeps its position relative to a nested list.\n items[items.length - 1].sub += _parseBlocks(blockLines);\n pendingBlank = false;\n continue;\n }\n\n if (/^\\s*(?:[-*+]|\\d+[.)]) /.test(line)) {\n const nested = _parseListBlock(lines, i);\n items[items.length - 1].sub += nested.html;\n i = nested.endIdx;\n pendingBlank = false;\n } else if (pendingBlank) {\n items[items.length - 1].paras.push(line.trim());\n pendingBlank = false;\n i++;\n } else {\n const paras = items[items.length - 1].paras;\n paras[paras.length - 1] += ' ' + line.trim();\n i++;\n }\n }\n }\n\n const hasCB = !isOL && (firstIsCB === true);\n const startMatch = isOL ? /^\\s*(\\d+)[.)] /.exec(lines[startIdx]) : null;\n const startNum = startMatch ? Number.parseInt(startMatch[1], 10) : 1;\n const open = isOL\n ? (startNum !== 1 ? `<ol start=\"${startNum}\">` : '<ol>')\n : (hasCB ? '<ul class=\"an-checklist\">' : '<ul>');\n const close = isOL ? '</ol>' : '</ul>';\n const liHTML = items.map(({ paras, isCB, checked, sub }) => {\n const cbHTML = isCB\n ? `<input type=\"checkbox\" contenteditable=\"false\"${checked ? ' checked' : ''}>`\n : '';\n const body = loose\n ? paras.map((p, idx) => `<p>${idx === 0 ? cbHTML : ''}${_inline(p)}</p>`).join('')\n : `${cbHTML}${_inline(paras[0])}`;\n return `<li>${body}${sub}</li>`;\n }).join('');\n return { html: `${open}${liHTML}${close}`, endIdx: i };\n}\n\n// Backslash-escapable punctuation. This is CommonMark's full ASCII-punctuation\n// set rather than just the characters this converter emits syntax for: the\n// escaper on the htmlToMarkdown side has to be able to neutralise a leading\n// \"- \", \"1. \" or \"---\", and those only round-trip if the parser also unescapes\n// them.\nconst ESCAPABLE_RE = /\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g;\n// Placeholder marker for escaped literals — a NUL character can't appear in\n// real markdown text, so it's safe as a delimiter. Built at runtime (not\n// written as a literal escape) to avoid embedding a raw NUL byte in this file.\nconst MARK = String.fromCharCode(0);\n\n// Placeholder delimiter for extracted code spans. Distinct from MARK and\n// HARD_BREAK; like them it survives _esc() untouched and matches no syntax rule.\nconst CODE_MARK = String.fromCharCode(2);\n// A code span: a run of backticks, the shortest content that reaches a matching\n// run, and that run again.\nconst CODE_SPAN_RE = /(`+)([^]*?)\\1/g;\n\n/**\n * Pulls code spans out before anything else looks at the text.\n *\n * Their content is literal: no emphasis, no links, no backslash escapes, and no\n * character references — `&` inside backticks has to survive as those five\n * characters. Extracting first is the only way to tell an `<` the author\n * typed from one _esc() produced out of a raw `<`.\n * @param {string} text\n * @returns {{ text: string, codes: string[] }}\n */\nfunction _extractCodeSpans(text) {\n const codes = [];\n const replaced = text.replace(CODE_SPAN_RE, (whole, ticks, content) => {\n // An empty span (`` with nothing between) is literal text in CommonMark.\n if (content === '') return whole;\n codes.push(content);\n return `${CODE_MARK}${codes.length - 1}${CODE_MARK}`;\n });\n return { text: replaced, codes };\n}\n\n/**\n * Restores extracted code spans as `<code>` elements, escaping their content\n * as literal code.\n * @param {string} text\n * @param {string[]} codes\n * @param {string[]} literals - backslash-escaped characters, for spans containing them\n * @returns {string}\n */\nfunction _restoreCodeSpans(text, codes, literals) {\n return text.replace(new RegExp(`${CODE_MARK}(\\\\d+)${CODE_MARK}`, 'g'), (_, idx) => {\n let c = codes[Number(idx)];\n // A backslash escape is not an escape inside a code span — put the\n // backslash back so `a\\*b` shows as written.\n c = c.replace(new RegExp(`${MARK}(\\\\d+)${MARK}`, 'g'), (_m, i) => `\\\\${literals[Number(i)]}`);\n // CommonMark strips one leading and trailing space when both are present,\n // which is what lets a span hold a leading or trailing backtick.\n if (c.length > 2 && c.startsWith(' ') && c.endsWith(' ') && c.trim() !== '') c = c.slice(1, -1);\n return `<code>${_escCode(c)}</code>`;\n });\n}\n\n/**\n * Step 0 of _inline(): replaces backslash-escaped punctuation with inert\n * placeholders so later syntax regexes can't match them.\n * @param {string} text\n * @returns {{ text: string, literals: string[] }}\n */\nfunction _extractBackslashEscapes(text) {\n const literals = [];\n const replaced = text.replace(ESCAPABLE_RE, (_, ch) => {\n literals.push(ch);\n return `${MARK}${literals.length - 1}${MARK}`;\n });\n return { text: replaced, literals };\n}\n\n/**\n * Restores placeholders from _extractBackslashEscapes(), HTML-escaping each\n * literal since it's inserted directly into the output.\n * @param {string} text\n * @param {string[]} literals\n * @returns {string}\n */\nfunction _restoreBackslashEscapes(text, literals) {\n return text.replace(new RegExp(`${MARK}(\\\\d+)${MARK}`, 'g'), (_, idx) => _esc(literals[Number(idx)]));\n}\n\n// Inline link/image destination. The angle-bracket alternative comes first so a\n// URL containing `)` — `[x](<http://e.com/a(b)>)` — is taken whole instead of\n// being cut at the inner parenthesis. Matched against _esc()'d text, so the\n// brackets appear as entities.\nconst DEST = String.raw`(<.*?>(?:\\s+(?:\"[^\"]*\"|'[^']*'))?|[^)]*)`;\nconst IMAGE_RE = new RegExp(String.raw`!\\[([^\\]]*)\\]\\(${DEST}\\)`, 'g');\nconst LINK_RE = new RegExp(String.raw`\\[([^\\]]+)\\]\\(${DEST}\\)`, 'g');\n\n/**\n * Splits an inline link destination into its URL and optional title:\n * `url`, `url \"title\"`, `url 'title'`, `<url with spaces>`, `<url> \"title\"`.\n *\n * Without this the whole `url \"title\"` string landed in `href`, producing a\n * link that simply does not resolve — the title is extremely common in\n * generated Markdown, so this silently broke a lot of pasted content.\n *\n * Operates on _esc()'d text, hence the `<`/`>` comparisons.\n * @param {string} dest\n * @returns {{ href: string, title: string }}\n */\nfunction _splitDestAndTitle(dest) {\n const s = dest.trim();\n\n // Angle-bracket destination: everything up to the closing bracket is the URL,\n // so it may contain spaces and parentheses.\n const angle = /^<([\\s\\S]*?)>(?:[ \\t]*(?:\"([^\"]*)\"|'([^']*)'))?[ \\t]*$/.exec(s);\n if (angle) return { href: angle[1], title: angle[2] ?? angle[3] ?? '' };\n\n const withTitle = /^(\\S+)\\s+(?:\"([^\"]*)\"|'([^']*)')\\s*$/.exec(s);\n if (withTitle) return { href: withTitle[1], title: withTitle[2] ?? withTitle[3] ?? '' };\n\n return { href: s, title: '' };\n}\n\n/**\n * Resolves images, inline links, GFM reference-style links (explicit,\n * shortcut, and bare/implicit forms), and footnote markers. Must run on text\n * already passed through _esc() — see _inline()'s Step 1 comment.\n * @param {string} text\n * @returns {string}\n */\nfunction _resolveLinksAndFootnotes(text) {\n text = text.replace(IMAGE_RE, (_, alt, dest) => {\n const { href, title } = _splitDestAndTitle(dest);\n const titleAttr = title ? ` title=\"${_escAttrQuotes(title)}\"` : '';\n return `<img src=\"${_escAttrQuotes(href)}\" alt=\"${_escAttrQuotes(alt)}\"${titleAttr} class=\"an-image\">`;\n });\n text = text.replace(LINK_RE, (_, label, dest) => {\n const { href, title } = _splitDestAndTitle(dest);\n const titleAttr = title ? ` title=\"${_escAttrQuotes(title)}\"` : '';\n return `<a href=\"${_escAttrQuotes(href)}\"${titleAttr}>${label}</a>`;\n });\n text = text.replace(/\\[([^\\]]+)\\]\\[([^\\]]*)\\]/g, (m, label, ref) => {\n const def = _linkDefs.get(_unescAmpLtGt(ref || label).trim().toLowerCase());\n if (!def) return m;\n const titleAttr = def.title ? ` title=\"${_escAttr(def.title)}\"` : '';\n return `<a href=\"${_escAttr(def.href)}\"${titleAttr}>${label}</a>`;\n });\n text = text.replace(/\\[([^\\]]+)\\]/g, (m, label) => {\n const def = _linkDefs.get(_unescAmpLtGt(label).trim().toLowerCase());\n if (!def) return m;\n const titleAttr = def.title ? ` title=\"${_escAttr(def.title)}\"` : '';\n return `<a href=\"${_escAttr(def.href)}\"${titleAttr}>${label}</a>`;\n });\n text = text.replace(/\\[\\^([^\\]]+)\\]/g, (m, id) => (_footnoteIds.has(_unescAmpLtGt(id)) ? `<sup>[${id}]</sup>` : m));\n return text;\n}\n\n/**\n * Converts angle-bracket (`<https://...>`) and bare (`https://...`)\n * autolinks. Runs after _resolveLinksAndFootnotes() so an already-linked URL\n * isn't reprocessed, and on already-_esc()'d text (see _inline()).\n * @param {string} text\n * @returns {string}\n */\nfunction _applyAutolinks(text) {\n text = text.replace(/<(https?:\\/\\/[^\\s&]+?)>/g, (_, url) => `<a href=\"${_escAttrQuotes(url)}\">${url}</a>`);\n // Email autolink — CommonMark's `<user@host>` form gets a mailto: href.\n text = text.replace(\n /<([\\w.!#$%&'*+/=?^`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)>/g,\n (_, addr) => `<a href=\"mailto:${_escAttrQuotes(addr)}\">${addr}</a>`,\n );\n text = text.replace(/(^|[\\s(])(https?:\\/\\/[^\\s()]+)/g, (m, pre, rawUrl) => {\n const trail = /[.,;:!?)]+$/.exec(rawUrl);\n const url = trail ? rawUrl.slice(0, -trail[0].length) : rawUrl;\n if (!url) return m;\n const suffix = trail ? trail[0] : '';\n return `${pre}<a href=\"${_escAttrQuotes(url)}\">${url}</a>${suffix}`;\n });\n return text;\n}\n\n/**\n * Applies bold/italic/bold-italic (asterisk and underscore forms — underscore\n * requires a non-word-character boundary per CommonMark), strikethrough, and\n * inline code.\n * @param {string} text\n * @returns {string}\n */\nfunction _applyEmphasisAndCode(text) {\n text = text.replace(/\\*{3}([^*\\n]+?)\\*{3}/g, (_, c) => `<strong><em>${c}</em></strong>`);\n text = text.replace(/(?<!\\w)_{3}([^_\\n]+?)_{3}(?!\\w)/g, (_, c) => `<strong><em>${c}</em></strong>`);\n text = text.replace(/\\*{2}([^*\\n]+?)\\*{2}/g, (_, c) => `<strong>${c}</strong>`);\n text = text.replace(/(?<!\\w)_{2}([^_\\n]+?)_{2}(?!\\w)/g, (_, c) => `<strong>${c}</strong>`);\n text = text.replace(/\\*([^*\\n]+?)\\*/g, (_, c) => `<em>${c}</em>`);\n text = text.replace(/(?<!\\w)_([^_\\n]+?)_(?!\\w)/g, (_, c) => `<em>${c}</em>`);\n text = text.replace(/~~([^~\\n]+?)~~/g, (_, c) => `<del>${c}</del>`);\n return text;\n}\n\nfunction _inline(text) {\n // Step 0: backslash escapes (\\* \\_ \\` \\# \\[ \\] \\( \\) \\> \\\\ \\~ \\|) — replaced\n // with inert placeholders before any syntax regex below can match them, so\n // e.g. \\*not bold\\* never gets treated as emphasis. Restored at the end.\n // Backslash escapes first, so an escaped backtick cannot open a code span.\n // Code spans come out next: their content is literal, and must not be seen by\n // the entity, link or emphasis passes below.\n const { text: withoutEscapes, literals } = _extractBackslashEscapes(text);\n const { text: withoutCode, codes } = _extractCodeSpans(withoutEscapes);\n\n // Step 1: escape raw &/</> in the plain-text parts of the string exactly\n // once, up front — none of these are markdown-syntax characters used below,\n // so this doesn't interfere with matching. Capture-group content in the\n // steps below is therefore ALREADY escaped and must NOT be re-escaped;\n // attribute values captured from `text` only need quotes escaped\n // (_escAttrQuotes), since & < > are already entities. Values that come from\n // _linkDefs (sourced from the raw, unescaped line array) still need the\n // full _escAttr/_esc treatment.\n let result = _esc(withoutCode);\n\n result = _resolveLinksAndFootnotes(result);\n result = _applyAutolinks(result);\n result = _applyEmphasisAndCode(result);\n\n return _restoreCodeSpans(_restoreBackslashEscapes(result, literals), codes, literals);\n}\n\n// A complete named / decimal / hex character reference. An `&` that starts one\n// is left alone so `©` survives as a copyright sign instead of rendering\n// as the literal text \"©\". Everything the sanitiser cares about is decided\n// after this, on the parsed DOM, so preserving references does not widen what\n// can get through.\nconst ENTITY_RE = /&(?!#\\d+;|#[xX][0-9a-fA-F]+;|[a-zA-Z][a-zA-Z0-9]*;)/g;\n\nfunction _esc(v) {\n return String(v)\n .replace(ENTITY_RE, '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n}\n\n/**\n * Escaper for code content. Unlike _esc() it escapes every `&`, because a\n * character reference is not recognised inside a code span or code block —\n * `&` written in a fence has to survive as those five literal characters\n * rather than rendering as `&`.\n * @param {string} v\n * @returns {string}\n */\nfunction _escCode(v) {\n return String(v)\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n}\n\nfunction _escAttr(v) {\n return String(v)\n .replaceAll('&', '&')\n .replaceAll('\"', '"')\n .replaceAll(\"'\", ''')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n}\n\n/** Escapes only quote characters — for attribute values already run through _esc(). */\nfunction _escAttrQuotes(v) {\n return String(v).replaceAll('\"', '"').replaceAll(\"'\", ''');\n}\n\n/** Reverses _esc()'s &/</> substitutions, for matching against un-escaped _linkDefs/_footnoteIds keys. */\nfunction _unescAmpLtGt(v) {\n return String(v).replaceAll('<', '<').replaceAll('>', '>').replaceAll('&', '&');\n}\n","/**\n * detectLang.js — Heuristic programming-language detection for code snippets.\n *\n * Returns a Prism.js language identifier, or null when nothing scores clearly\n * enough to be worth guessing.\n *\n * ## Why scoring rather than an ordered if-chain\n *\n * The previous version returned on the first pattern that matched, so the\n * answer depended on the order the languages happened to be listed in. Every\n * new pattern risked stealing snippets from a language checked later, and a\n * snippet carrying signals for two languages was decided by position instead of\n * by strength of evidence — `export default { data() { … } }` came back as CSS\n * because the JavaScript rules did not cover `export default` and the CSS rule\n * happily read `a: 1` as a declaration.\n *\n * Instead every rule contributes weight to its language and the highest total\n * wins, so adding a signal makes one language more likely rather than\n * reshuffling the rest. Weights are roughly:\n *\n * 10 unmistakable — `<?php`, `#!/bin/bash`, `println!`, `fmt.Println`\n * 5 characteristic — `def f(...):`, `interface X {`, `val x: T`\n * 2 suggestive — shared with other languages, only useful to break a tie\n *\n * A language needs MIN_SCORE overall and a MIN_MARGIN lead over the runner-up;\n * otherwise the snippet is ambiguous and null is the honest answer.\n */\n\n/** Minimum winning score. Below this the evidence is one weak signal at most. */\nconst MIN_SCORE = 5;\n/** The winner must beat the runner-up by this much, or the snippet is ambiguous. */\nconst MIN_MARGIN = 2;\n\n/**\n * `[superset, base]` pairs. Valid base-language code is also valid in the\n * superset, so the superset inherits the base's score once it has shown a\n * marker of its own — `$var` + `&:hover` is SCSS even though everything around\n * it reads as ordinary CSS.\n * @type {Array<[string, string]>}\n */\nconst SUPERSETS = [\n ['typescript', 'javascript'],\n ['scss', 'css'],\n ['cpp', 'c'],\n];\n\n/**\n * @typedef {object} Rule\n * @property {string} lang - Prism language id this rule votes for.\n * @property {RegExp} re - Pattern to look for.\n * @property {number} w - Weight added when it matches.\n */\n\n/**\n * Every language this module can return. Exported so the code tooltip's picker\n * can be checked against it — a language the detector produces but the picker\n * cannot show leaves the select reading \"Plain text\" on a highlighted block.\n * @type {string[]}\n */\nexport const SUPPORTED_LANGS = [\n 'javascript', 'typescript', 'python', 'java', 'go', 'rust', 'csharp', 'kotlin',\n 'swift', 'cpp', 'c', 'ruby', 'php', 'html', 'xml', 'json', 'yaml', 'markdown',\n 'sql', 'scss', 'css', 'bash',\n];\n\n/** @type {Rule[]} */\nconst RULES = [\n // ── Unmistakable markers ───────────────────────────────────────────────────\n { lang: 'php', w: 10, re: /<\\?php\\b|<\\?=/ },\n { lang: 'bash', w: 10, re: /^#!.*\\/(?:ba|z|da|fi|k)?sh\\b/m },\n { lang: 'rust', w: 10, re: /\\b(?:println!|print!|format!|vec!|panic!)\\s*[([]/ },\n { lang: 'go', w: 10, re: /\\bfmt\\.(?:Print|Println|Printf|Sprintf|Errorf|Fprintf)\\s*\\(/ },\n { lang: 'java', w: 10, re: /\\bSystem\\.out\\.(?:print|println)\\s*\\(/ },\n { lang: 'csharp', w: 10, re: /\\bConsole\\.(?:Write|WriteLine)\\s*\\(/ },\n { lang: 'cpp', w: 10, re: /\\b(?:cout|cerr)\\s*<<|\\bcin\\s*>>|\\busing\\s+namespace\\s+std\\b|\\bstd::\\w/ },\n { lang: 'python', w: 10, re: /\\bdef[ \\t]+\\w+[ \\t]*\\([^)]*\\)[ \\t]*(?:->[^:\\n]*)?:|\\bif[ \\t]+__name__[ \\t]*==[ \\t]*['\"]__main__['\"]/ },\n { lang: 'html', w: 10, re: /^\\s*<!DOCTYPE\\s+html/i },\n { lang: 'xml', w: 10, re: /^\\s*<\\?xml\\s/i },\n\n // ── JavaScript ─────────────────────────────────────────────────────────────\n { lang: 'javascript', w: 6, re: /\\bconsole\\.(?:log|error|warn|info|debug)\\s*\\(/ },\n { lang: 'javascript', w: 6, re: /\\b(?:const|let)\\s+\\w+\\s*=|(?:^|\\n)\\s*var\\s+\\w+\\s*=/ },\n // No other language here spells a module boundary this way, so it carries\n // enough weight on its own — `export default { a: 1 }` used to tie with CSS,\n // which read the object body as a declaration block.\n { lang: 'javascript', w: 8, re: /\\bexport\\s+(?:default|const|function|class|async|\\{|\\*)|\\bmodule\\.exports\\b|\\brequire\\s*\\(\\s*['\"]/ },\n { lang: 'javascript', w: 5, re: /\\bfunction(?:[ \\t]+\\w+)?[ \\t]*\\([^)]*\\)[ \\t]*\\{|=>[ \\t]*[{([`\\w'\"]/ },\n { lang: 'javascript', w: 5, re: /\\bimport\\b[^'\"\\n]*[ \\t]from[ \\t]*['\"]/ },\n { lang: 'javascript', w: 4, re: /\\.(?:map|filter|forEach|reduce|then|catch|find|some|every)\\s*\\(/ },\n // Split rather than alternated: a one-line DOM call chain hits several of\n // these at once, and as a single rule it capped at one rule's weight and\n // scored too low to beat the ambiguity threshold.\n { lang: 'javascript', w: 4, re: /\\b(?:document|window|globalThis)\\.\\w/ },\n { lang: 'javascript', w: 4, re: /\\baddEventListener\\s*\\(|\\bquerySelector(?:All)?\\s*\\(|\\bgetElementById\\s*\\(/ },\n { lang: 'javascript', w: 3, re: /\\.(?:innerHTML|textContent|classList|dataset|style)\\b|\\bJSON\\.(?:parse|stringify)\\s*\\(/ },\n { lang: 'javascript', w: 4, re: /\\bawait\\s+\\w|\\basync\\s+(?:function|\\(|\\w+\\s*=>)|\\bnew\\s+Promise\\s*\\(/ },\n { lang: 'javascript', w: 3, re: /\\bReact\\.|\\buseState\\s*\\(|\\buseEffect\\s*\\(/ },\n\n // ── TypeScript — JS plus type syntax, so it also collects the JS points ────\n { lang: 'typescript', w: 8, re: /\\binterface\\s+\\w+(?:<[^>]*>)?\\s*(?:extends\\s[\\w<>, ]+)?\\{/ },\n { lang: 'typescript', w: 8, re: /\\btype\\s+\\w+(?:<[^>]*>)?\\s*=/ },\n { lang: 'typescript', w: 7, re: /:\\s*(?:string|number|boolean|void|never|any|unknown|object)\\b/ },\n { lang: 'typescript', w: 6, re: /\\benum\\s+\\w+\\s*\\{|\\breadonly\\s+\\w|\\bimplements\\s+\\w|\\bnamespace\\s+\\w+\\s*\\{/ },\n { lang: 'typescript', w: 6, re: /\\b(?:private|public|protected)\\s+(?:readonly\\s+)?\\w+\\s*[:?]/ },\n { lang: 'typescript', w: 5, re: /\\)\\s*:\\s*[A-Z]\\w*(?:<[^>]*>)?\\s*(?:\\{|=>)|\\)\\s*:\\s*(?:string|number|boolean|void)\\b/ },\n { lang: 'typescript', w: 4, re: /\\bfunction\\s+\\w+\\s*<[^>]+>\\s*\\(|\\bas\\s+(?:const\\b|[A-Z]\\w*)/ },\n { lang: 'typescript', w: 3, re: /\\w\\?\\s*:\\s*\\w|\\bimport\\s+type\\b|\\bsatisfies\\b/ },\n\n // ── Python ─────────────────────────────────────────────────────────────────\n { lang: 'python', w: 6, re: /(?:^|\\n)\\s*(?:from\\s+[\\w.]+\\s+import\\s|import\\s+\\w+(?:\\s*,\\s*\\w+)*\\s*$)/m },\n { lang: 'python', w: 6, re: /(?:^|\\n)\\s*class\\s+\\w+(?:\\([\\w., ]*\\))?\\s*:/ },\n { lang: 'python', w: 5, re: /(?:^|\\n)\\s*(?:with|elif|except|finally|async\\s+def)\\b[^\\n]*:/ },\n { lang: 'python', w: 5, re: /\\bself\\.\\w|\\b__init__\\b|\\bf[\"'][^\"']*\\{/ },\n { lang: 'python', w: 4, re: /(?:^|\\n)[ \\t]*for[ \\t]+\\w+[ \\t]+in[ \\t][^\\n:]*:|\\bfor[ \\t]+\\w+[ \\t]+in[ \\t]+range[ \\t]*\\(/ },\n { lang: 'python', w: 4, re: /\\bprint\\s*\\(|\\blen\\s*\\(|\\brange\\s*\\(/ },\n { lang: 'python', w: 3, re: /\\[[^\\]\\n]*\\bfor\\s+\\w+\\s+in\\s[^\\]\\n]*\\]|\\bNone\\b|\\bTrue\\b|\\bFalse\\b/ },\n { lang: 'python', w: 3, re: /\\*\\*\\w|\\bdict[ \\t]*\\(|\\blambda(?:[ \\t]+\\w+)?[ \\t]*:/ },\n\n // ── Go ─────────────────────────────────────────────────────────────────────\n { lang: 'go', w: 8, re: /(?:^|\\n)\\s*package\\s+\\w+\\s*$/m },\n { lang: 'go', w: 6, re: /\\btype\\s+\\w+\\s+struct\\s*\\{|\\btype\\s+\\w+\\s+interface\\s*\\{/ },\n { lang: 'go', w: 6, re: /\\bfunc(?:[ \\t]*\\([^)]*\\))?(?:[ \\t]+\\w+)?[ \\t]*\\([^)]*\\)[^\\n{]{0,40}\\{/ },\n { lang: 'go', w: 5, re: /\\bif\\s+err\\s*!=\\s*nil\\b|\\berr\\s*:=\\s|\\bdefer\\s+\\w/ },\n { lang: 'go', w: 4, re: /\\w+\\s*:=\\s*\\S|\\bchan\\s+\\w|\\bgo\\s+func\\b|\\bnil\\b/ },\n\n // ── Rust ───────────────────────────────────────────────────────────────────\n { lang: 'rust', w: 7, re: /\\bfn[ \\t]+\\w+(?:<[^>]*>)?[ \\t]*\\([^)]*\\)[^\\n{]{0,40}\\{/ },\n { lang: 'rust', w: 7, re: /\\blet\\s+mut\\s+\\w|\\bpub\\s+(?:fn|struct|enum|mod|use)\\b|\\bimpl\\s+\\w/ },\n { lang: 'rust', w: 5, re: /\\buse\\s+(?:std|crate|self|super)::|\\bmatch\\s+\\w+\\s*\\{[^}]*=>/ },\n { lang: 'rust', w: 4, re: /\\b(?:Option|Result|Vec|Box|Rc|Arc|HashMap)\\s*<|&(?:mut\\s+)?self\\b|\\b\\w+::<|->\\s*Result</ },\n { lang: 'rust', w: 3, re: /\\b(?:i8|i16|i32|i64|u8|u16|u32|u64|usize|isize|f32|f64)\\b|\\bunwrap\\s*\\(\\)|\\bderive\\s*\\(/ },\n\n // ── Java ───────────────────────────────────────────────────────────────────\n { lang: 'java', w: 7, re: /\\b(?:public|private|protected)\\s+(?:static\\s+)?(?:final\\s+)?(?:void|int|long|double|boolean|String|[A-Z]\\w*(?:<[^>]*>)?)\\s+\\w+\\s*[({]/ },\n { lang: 'java', w: 7, re: /\\bimport\\s+(?:java|javax|org\\.springframework)\\.[\\w.]+;/ },\n { lang: 'java', w: 6, re: /@(?:Override|Autowired|Component|Service|Controller|RestController|Entity|Test|SpringBootApplication)\\b/ },\n { lang: 'java', w: 5, re: /\\bnew\\s+(?:ArrayList|HashMap|HashSet|LinkedList|StringBuilder)\\s*<[^>]*>\\s*\\(|\\bthrows\\s+\\w*Exception/ },\n { lang: 'java', w: 4, re: /\\bpublic\\s+(?:class|interface|enum)\\s+\\w|\\bextends\\s+\\w+\\s*\\{|\\bList<\\w|\\bMap<\\w/ },\n\n // ── C# ─────────────────────────────────────────────────────────────────────\n { lang: 'csharp', w: 8, re: /\\busing\\s+System(?:\\.[\\w.]+)?\\s*;|\\bnamespace\\s+[\\w.]+\\s*[{;]/ },\n { lang: 'csharp', w: 8, re: /\\{\\s*get;\\s*(?:private\\s+)?set;\\s*\\}|\\b(?:public|private|protected|internal)\\s+(?:static\\s+)?async\\s+Task(?:<[^>]*>)?\\s+\\w/ },\n { lang: 'csharp', w: 6, re: /\\basync\\s+Task(?:<[^>]*>)?\\s+\\w|\\bawait\\s+\\w+\\.\\w+Async\\s*\\(/ },\n { lang: 'csharp', w: 5, re: /\\bIEnumerable<|\\bvar\\s+\\w+\\s*=\\s*new\\s+\\w|\\bpublic\\s+override\\b|\\[\\s*(?:HttpGet|HttpPost|Serializable|Required)\\s*\\]/ },\n { lang: 'csharp', w: 3, re: /\\.(?:Select|Where|FirstOrDefault|ToList|Any)\\s*\\(|\\bstring\\[\\]\\s+args\\b/ },\n\n // ── Kotlin ─────────────────────────────────────────────────────────────────\n { lang: 'kotlin', w: 8, re: /\\bfun\\s+\\w+\\s*\\([^)]*\\)\\s*(?::\\s*[\\w<>?.]+\\s*)?[={]|\\bdata\\s+class\\s+\\w/ },\n { lang: 'kotlin', w: 6, re: /\\bval[ \\t]+\\w+(?:[ \\t]*:[ \\t]*[\\w<>?.]+)?[ \\t]*=|\\bcompanion[ \\t]+object\\b|\\bsuspend[ \\t]+fun\\b/ },\n { lang: 'kotlin', w: 4, re: /\\bprintln\\s*\\(|\\bwhen\\s*\\([^)]*\\)\\s*\\{|\\bobject\\s+\\w+\\s*[:{]|\\?:\\s*\\w/ },\n\n // ── Swift ──────────────────────────────────────────────────────────────────\n { lang: 'swift', w: 8, re: /\\bguard\\s+(?:let|var)\\s[^\\n]*\\belse\\b|\\bfunc\\s+\\w+\\s*\\([^)]*\\)\\s*(?:async\\s+)?(?:throws\\s+)?->\\s*[\\w<>?[\\]]/ },\n { lang: 'swift', w: 6, re: /\\bprotocol[ \\t]+\\w+[^\\n{]{0,40}\\{|\\bextension[ \\t]+\\w+[^\\n{]{0,40}\\{|\\bimport[ \\t]+(?:SwiftUI|UIKit|Foundation)\\b/ },\n { lang: 'swift', w: 6, re: /\\b(?:let|var)\\s+\\w+\\s*:\\s*(?:Int|String|Double|Float|Bool|Character|Any|\\[[A-Z])|@(?:State|Binding|Published|IBOutlet|objc)\\b/ },\n { lang: 'swift', w: 4, re: /\\\\\\(\\w|\\bif[ \\t]+let[ \\t]+\\w|\\bstruct[ \\t]+\\w+[ \\t]*:[ \\t]*View\\b|\\bfunc[ \\t]+\\w+[ \\t]*\\([^)]*:[ \\t]*[A-Z]/ },\n { lang: 'swift', w: 3, re: /\\?\\?\\s*\\w|\\b\\w+\\?\\.\\w|\\bself\\.\\w+\\s*=/ },\n\n // ── C / C++ ────────────────────────────────────────────────────────────────\n { lang: 'cpp', w: 8, re: /#include\\s*<(?:iostream|vector|map|set|algorithm|string|memory|utility)>/ },\n { lang: 'cpp', w: 6, re: /\\btemplate\\s*<\\s*(?:typename|class)\\b|\\bnullptr\\b|\\bnamespace\\s+\\w+\\s*\\{/ },\n { lang: 'c', w: 8, re: /#include\\s*<(?:stdio|stdlib|string|math|time|ctype|unistd)\\.h>/ },\n { lang: 'c', w: 6, re: /\\b(?:printf|scanf|malloc|calloc|free|memcpy|strlen)\\s*\\(/ },\n { lang: 'c', w: 4, re: /\\bint\\s+main\\s*\\(\\s*(?:void|int\\s+argc|\\)\\s*\\{)/ },\n { lang: 'c', w: 3, re: /\\btypedef\\s+struct\\b|\\bsizeof\\s*\\(|\\bNULL\\b/ },\n\n // ── Ruby ───────────────────────────────────────────────────────────────────\n { lang: 'ruby', w: 8, re: /\\bdo[ \\t]*\\|[ \\t]*\\w[\\w, ]*\\|/ },\n { lang: 'ruby', w: 7, re: /\\battr_(?:accessor|reader|writer)\\s+:|\\brequire(?:_relative)?\\s+['\"]|\\bputs\\s+\\S/ },\n // Split from a single `def … end` span: two independent signals score the\n // same way here, and the span form put a lazy `[\\\\s\\\\S]*?` next to `\\\\s*`,\n // which backtracks super-linearly on input that never closes the block.\n { lang: 'ruby', w: 4, re: /(?:^|\\n)[ \\t]*def[ \\t]+\\w/ },\n { lang: 'ruby', w: 4, re: /(?:^|\\n)[ \\t]*end[ \\t]*$/m },\n { lang: 'ruby', w: 4, re: /\\bnil\\?\\b|\\b\\w+\\.new\\b|=>\\s*['\"\\w]|\\bmodule\\s+[A-Z]\\w*\\s*$/m },\n { lang: 'ruby', w: 3, re: /:\\w+[ \\t]*=>|\\bend[ \\t]*$/m },\n\n // ── PHP ────────────────────────────────────────────────────────────────────\n { lang: 'php', w: 7, re: /\\$this->\\w|\\bfunction\\s+\\w+\\s*\\([^)]*\\$\\w/ },\n { lang: 'php', w: 6, re: /\\$\\w+\\s*=\\s*\\S|\\bforeach\\s*\\(\\s*\\$\\w+\\s+as\\s+\\$/ },\n { lang: 'php', w: 5, re: /\\becho[ \\t][^;\\n]*[$'\"]|\\bnamespace[ \\t]+[\\w\\\\]+;|\\buse[ \\t]+[\\w\\\\]+\\\\\\w+;/ },\n // `public function` is PHP's spelling and nothing else's: Java and C# name a\n // return type in that position, and TypeScript class methods drop `function`\n // entirely. Weighted to clear JavaScript's generic `function name(…) {` rule,\n // which fires on the same line.\n { lang: 'php', w: 8, re: /\\b(?:public|private|protected)\\s+(?:static\\s+)?function\\s+\\w/ },\n { lang: 'php', w: 3, re: /->\\w+\\s*\\(|::\\w+\\s*\\(/ },\n\n // ── Markup and data ────────────────────────────────────────────────────────\n { lang: 'html', w: 7, re: /<(?:html|head|body|nav|section|article|header|footer|main|form)\\b[^>]*>/i },\n { lang: 'html', w: 5, re: /<(?:div|p|span|a|img|ul|ol|li|table|tr|td|input|button|h[1-6])\\b[^>]*>[\\s\\S]*<\\/(?:div|p|span|a|ul|ol|li|table|tr|td|button|h[1-6])>/i },\n { lang: 'html', w: 4, re: /<\\w+\\s+(?:class|id|href|src|type|style)\\s*=\\s*[\"']/i },\n { lang: 'xml', w: 6, re: /\\bxmlns(?::\\w+)?\\s*=\\s*[\"']|<\\/\\w+:\\w+>|<\\w+:\\w+[\\s>]/ },\n\n { lang: 'json', w: 8, re: /^\\s*[{[][\\s\\S]*\"[\\w-]+\"\\s*:\\s*(?:\"[^\"]*\"|-?\\d|\\{|\\[|true|false|null)/ },\n { lang: 'json', w: 3, re: /^\\s*\\{[\\s\\S]*\\}\\s*$|^\\s*\\[[\\s\\S]*\\]\\s*$/ },\n\n // ── YAML ───────────────────────────────────────────────────────────────────\n // Common enough in practice (CI configs, compose files, front matter) that\n // its absence made every such snippet fall through to null.\n { lang: 'yaml', w: 8, re: /^---\\s*$/m },\n { lang: 'yaml', w: 6, re: /^[ \\t]*-\\s+\\w+\\s*:\\s*\\S/m },\n { lang: 'yaml', w: 5, re: /^[a-z_][\\w-]*[ \\t]*:(?:[ \\t]*$|[ \\t]+(?:[|>][-+]?[ \\t]*$|['\"\\w[{]))/im },\n { lang: 'yaml', w: 4, re: /^[ \\t]+[a-z_][\\w-]*[ \\t]*:[ \\t]*\\S/im },\n { lang: 'yaml', w: 3, re: /^[ \\t]*-\\s+\\S/m },\n\n // ── Markdown ───────────────────────────────────────────────────────────────\n { lang: 'markdown', w: 7, re: /^#{1,6}\\s+\\S/m },\n { lang: 'markdown', w: 6, re: /^```|^\\|[^\\n|]+\\|[^\\n]*\\n\\s*\\|[\\s:|-]+\\|/m },\n { lang: 'markdown', w: 4, re: /\\[[^\\]\\n]+\\]\\([^)\\n]+\\)|!\\[[^\\]\\n]*\\]\\(/ },\n { lang: 'markdown', w: 3, re: /\\*\\*[^*\\n]+\\*\\*|^>\\s+\\S|^[-*+]\\s+\\S/m },\n\n // ── SQL ────────────────────────────────────────────────────────────────────\n { lang: 'sql', w: 9, re: /(?:^|\\n)\\s*(?:SELECT\\s+[\\w*]|INSERT\\s+INTO\\s|UPDATE\\s+\\w+\\s+SET\\s|DELETE\\s+FROM\\s)/i },\n { lang: 'sql', w: 8, re: /(?:^|\\n)\\s*(?:CREATE|ALTER|DROP)\\s+(?:TABLE|DATABASE|INDEX|VIEW|SCHEMA)\\b/i },\n { lang: 'sql', w: 4, re: /\\b(?:INNER|LEFT|RIGHT|FULL)\\s+(?:OUTER\\s+)?JOIN\\b|\\bGROUP\\s+BY\\b|\\bORDER\\s+BY\\b|\\bWITH\\s+\\w+\\s+AS\\s*\\(/i },\n\n // ── SCSS before CSS: every SCSS marker is invalid plain CSS ────────────────\n { lang: 'scss', w: 9, re: /^[ \\t]*\\$[\\w-]+[ \\t]*:[^;\\n]+;|@(?:mixin|include|extend|use|forward)[ \\t]+[\\w\"'-]/m },\n { lang: 'scss', w: 7, re: /^[ \\t]*&[\\s.:[&>+~]|#\\{[^}]*\\}/m },\n { lang: 'scss', w: 4, re: /^[ \\t]*\\/\\/[ \\t]*\\S/m },\n\n // The leading word must not be a statement keyword from another language:\n // an object or block literal reads exactly like a rule set otherwise.\n { lang: 'css', w: 6, re: /^[ \\t]*(?!(?:export|import|return|function|const|let|var|val|if|else|for|while|switch|case|class|new|public|private|protected|internal|def|func|fun|fn|pub|package|type|interface|enum|struct|impl|trait|mod|use|using|namespace|module|data|object|async|await|guard|extension|protocol|template|typedef)\\b)[.#]?[\\w-]+[^{}\\n]{0,60}\\{[^{}:]*:[^{};]+[;}]/m },\n { lang: 'css', w: 5, re: /@(?:media|supports|keyframes|font-face|import|charset)\\b/ },\n { lang: 'css', w: 4, re: /:\\s*(?:#[\\da-f]{3,8}|\\d+(?:px|rem|em|%|vh|vw)|flex|grid|block|none|absolute|relative)\\s*[;}]/i },\n { lang: 'css', w: 3, re: /::?(?:hover|focus|active|before|after|first-child|last-child|nth-child)\\b/ },\n\n // ── Bash ───────────────────────────────────────────────────────────────────\n { lang: 'bash', w: 7, re: /(?:^|\\n|&&|\\|\\|)\\s*(?:sudo\\s+)?(?:apt(?:-get)?|yum|brew|npm|pnpm|yarn|pip3?|docker|kubectl|git|systemctl|curl|wget|chmod|chown|mkdir|rm|cp|mv|tar|ssh|scp)\\s+[\\w./-]/ },\n { lang: 'bash', w: 6, re: /^\\s*(?:export|source|alias)\\s+\\w+|^\\s*\\w+=\\S+\\s*$/m },\n { lang: 'bash', w: 6, re: /\\bfi[ \\t]*$|(?:^|\\n)[ \\t]*(?:if|for|while)[ \\t][^\\n]*;[ \\t]*(?:then|do)\\b|(?:^|\\n)[ \\t]*done\\b/m },\n { lang: 'bash', w: 5, re: /\\$\\{?\\w+\\}?[/:]|\"\\$\\w|\\becho\\s+[\"'$]|\\$\\(\\w/ },\n { lang: 'bash', w: 4, re: /(?:^|\\n|\\|)\\s*(?:grep|awk|sed|cat|ls|cd|pwd|find|xargs|head|tail|sort|uniq|wc)\\s+[-\\w$'\"./]/ },\n { lang: 'bash', w: 3, re: /\\s\\|[ \\t]*\\w|\\s&&\\s|\\s2>&1|\\s-[\\w-]+\\s/ },\n];\n\n/**\n * How much of the input the rules actually run over.\n *\n * A language is identifiable from its opening lines, so scanning a whole file\n * buys nothing — and it costs a lot: several rules scan a line looking for a\n * trailing token, which is quadratic in line length. Pasting a minified bundle\n * (one 100 KB line) took over seven seconds before this cap, freezing the\n * editor. Bounding the input makes detection cost independent of file size.\n */\nconst SAMPLE_LIMIT = 4000;\n\n/**\n * First `SAMPLE_LIMIT` characters, cut back to a line boundary so the `^`/`$`\n * anchored rules do not see a line that the truncation invented.\n * @param {string} s\n * @returns {string}\n */\nfunction _sample(s) {\n if (s.length <= SAMPLE_LIMIT) return s;\n const head = s.slice(0, SAMPLE_LIMIT);\n const lastBreak = head.lastIndexOf('\\n');\n return lastBreak > 0 ? head.slice(0, lastBreak) : head;\n}\n\n/**\n * Detects the programming language of a code snippet.\n * @param {string} code\n * @returns {string|null} A Prism language id, or null when it is not clear.\n */\nexport function detectLang(code) {\n if (!code?.trim()) return null;\n const s = _sample(code.trim());\n\n /** @type {Map<string, number>} */\n const scores = new Map();\n for (const { lang, re, w } of RULES) {\n if (re.test(s)) scores.set(lang, (scores.get(lang) || 0) + w);\n }\n if (scores.size === 0) return null;\n\n // A superset language legitimately matches its base language's rules, so the\n // evidence would otherwise be split between the two and both fall under the\n // margin — or the base would win outright on shared signals alone. Fold the\n // base's score into the superset, but only once the superset has shown at\n // least one marker of its own.\n for (const [superset, base] of SUPERSETS) {\n const own = scores.get(superset);\n if (own) scores.set(superset, own + (scores.get(base) || 0));\n }\n\n const ranked = [...scores.entries()].sort((a, b) => b[1] - a[1]);\n const [winner, top] = ranked[0];\n const runnerUp = ranked[1]?.[1] ?? 0;\n\n if (top < MIN_SCORE || top - runnerUp < MIN_MARGIN) return null;\n return winner;\n}\n","/**\n * Editor.js - Core editing command module\n * Wraps all execCommand calls, undo/redo, and fires events via the context.\n * Inspired by Summernote's Editor module.\n */\n\nimport { History } from '../editing/History.js';\nimport * as Style from '../editing/Style.js';\nimport { insertTable } from '../editing/Table.js';\nimport { isModifier } from '../core/key.js';\nimport { handleKeydown } from '../editing/Typing.js';\nimport { on } from '../core/dom.js';\nimport { sanitiseHTML, sanitiseToBody, sanitiseUrl } from '../core/sanitise.js';\nimport { markdownToHTML, htmlToMarkdown } from '../core/markdown.js';\nimport { detectLang } from '../core/detectLang.js';\n\n/**\n * Blocks the caret cannot be placed after, so the editable always keeps a\n * trailing paragraph. Module-level because `_ensureTrailingParagraph` runs on\n * every keystroke and was rebuilding this set each time.\n */\nconst TRAPPING_TAGS = new Set(['PRE', 'BLOCKQUOTE', 'TABLE', 'FIGURE', 'UL', 'OL', 'HR']);\n\nexport class Editor {\n /**\n * @param {import('../Context.js').Context} context\n */\n constructor(context) {\n this.context = context;\n this.options = context.options;\n /** @type {History|null} */\n this._history = null;\n this._disposers = [];\n /** @type {number|null} Timer handle for debounced undo snapshot */\n this._snapshotTimer = null;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n initialize() {\n const editable = this.context.layoutInfo.editable;\n this._history = new History(\n editable,\n this.options.historyLimit || 100,\n this.options.historyMaxBytes || 10 * 1024 * 1024,\n );\n this._bindEvents(editable);\n return this;\n }\n\n destroy() {\n this._disposers.forEach((d) => d());\n this._disposers = [];\n this._history = null;\n clearTimeout(this._snapshotTimer);\n this._snapshotTimer = null;\n }\n\n // ---------------------------------------------------------------------------\n // Event binding\n // ---------------------------------------------------------------------------\n\n _bindEvents(editable) {\n // Keyboard shortcuts\n const onKeydown = (event) => this._onKeydown(event);\n // Catch ALL content mutations: typing, IME, spellcheck, voice, drag-drop text.\n const onInput = () => this.afterCommand();\n // Hard-enforce maxChars / maxWords before content is mutated\n const onBeforeInput = (event) => this._enforceLimit(event);\n // Refresh toolbar on selection change, scoped to this editor\n const onSelChange = () => {\n if (!this.context._alive) return;\n const sel = globalThis.getSelection();\n if (sel?.rangeCount > 0 && editable.contains(sel.anchorNode)) {\n this.context.invoke('toolbar.refresh');\n if (typeof this.options.onSelectionChange === 'function') {\n this.options.onSelectionChange(this.context);\n }\n }\n };\n\n // Checklist checkboxes are contenteditable=false so native clicks work;\n // hook afterCommand so the checked state is preserved in undo history.\n const onCheckboxClick = (e) => {\n if (e.target.type === 'checkbox' && e.target.closest('.an-checklist')) {\n this.afterCommand();\n }\n };\n\n // Guard: when cursor lands at the <li> element node of a checklist item\n // (before the checkbox), nudge it to the correct text position.\n //\n // mouseup: use caretRangeFromPoint / caretPositionFromPoint so the cursor\n // lands WHERE the user actually clicked (middle, end of text…).\n // keyup : arrow-key navigation may land at <li>[0]; move to start-of-text.\n const fixChecklistCursor = (event) => {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n const r = sel.getRangeAt(0);\n if (!r.collapsed) return;\n const sc = r.startContainer;\n\n // Only act when cursor is at the <li> element node itself (not inside\n // a text node — the browser already placed it correctly in that case).\n if (sc.nodeType !== Node.ELEMENT_NODE) return;\n const scEl = /** @type {Element} */ (sc);\n const li = scEl.matches('.an-checklist li') ? scEl : null;\n if (!li) return;\n const cb = li.querySelector('input[type=\"checkbox\"]');\n if (!cb) return;\n\n // For mouse events: ask the browser where the pointer landed so the\n // cursor respects the actual click position inside the text.\n if (event?.type === 'mouseup') {\n let caret = null;\n if (document.caretRangeFromPoint) {\n caret = document.caretRangeFromPoint(event.clientX, event.clientY);\n } else if (document.caretPositionFromPoint) {\n const cp = document.caretPositionFromPoint(event.clientX, event.clientY);\n if (cp) {\n caret = document.createRange();\n caret.setStart(cp.offsetNode, cp.offset);\n }\n }\n // If the caret from point landed inside a text node of this li, use it\n if (caret && editable.contains(caret.startContainer) &&\n caret.startContainer !== li) {\n caret.collapse(true);\n sel.removeAllRanges();\n sel.addRange(caret);\n return;\n }\n }\n\n // Fallback (keyboard nav, or caretRangeFromPoint not available / landed\n // at li again): prefer the first text node after the checkbox so the\n // cursor renders at the padding-left edge (after the visual checkbox)\n // rather than at element-level where the browser may place it at x=0.\n const nr = document.createRange();\n let anchorNode = null;\n for (const child of li.childNodes) {\n if (child !== cb && child.nodeType === Node.TEXT_NODE) {\n anchorNode = child;\n break;\n }\n }\n if (anchorNode) {\n nr.setStart(anchorNode, 0);\n } else {\n nr.setStartAfter(cb);\n }\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n };\n\n const isReadOnly = () => this.context.layoutInfo.container.classList.contains('an-disabled');\n\n this._disposers.push(\n on(editable, 'keydown', onKeydown),\n on(editable, 'beforeinput', onBeforeInput),\n on(editable, 'input', onInput),\n on(document, 'selectionchange', onSelChange),\n on(editable, 'click', onCheckboxClick),\n on(editable, 'mouseup', fixChecklistCursor),\n on(editable, 'keyup', fixChecklistCursor),\n // Block drag-out and external drops in read-only mode.\n // D-1: Also block dragging of iframes and .an-video-wrapper elements in\n // edit mode — a user can inadvertently drag the iframe out of its wrapper\n // (making it playable/removable from contenteditable protection) by holding\n // the mouse and moving outside the wrapper before releasing.\n on(editable, 'dragstart', (e) => {\n if (isReadOnly()) { e.preventDefault(); return; }\n const target = /** @type {Element} */ (e.target);\n if (target && (target.nodeName === 'IFRAME' ||\n target.closest('.an-video-wrapper'))) {\n e.preventDefault();\n }\n }),\n on(editable, 'drop', (e) => { if (isReadOnly()) e.preventDefault(); }),\n );\n\n // B-V: Re-apply superscript / subscript after IME composition ends.\n // Vietnamese and other IME-based inputs fire compositionstart/end around\n // the inserted characters. During composition the browser may place the\n // provisional text outside the current <sup>/<sub> element. When\n // compositionend fires we detect whether the cursor escaped the sup/sub\n // context and re-apply the command so the composed character stays inside.\n /** @type {string|null} 'superscript' | 'subscript' | null */\n let _compositionSupSub = null;\n const onCompositionStart = () => {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) { _compositionSupSub = null; return; }\n let node = sel.getRangeAt(0).startContainer;\n if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;\n if (node) {\n const el = /** @type {Element} */ (node);\n if (el.closest('sup')) _compositionSupSub = 'superscript';\n else if (el.closest('sub')) _compositionSupSub = 'subscript';\n else _compositionSupSub = null;\n }\n };\n const onCompositionEnd = () => {\n const tag = _compositionSupSub;\n _compositionSupSub = null;\n if (!tag) return;\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n let node = sel.getRangeAt(0).startContainer;\n if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;\n const el = /** @type {Element} */ (node);\n const inContext = tag === 'superscript' ? el?.closest('sup') : el?.closest('sub');\n if (!inContext) {\n // The composed character escaped the sup/sub — re-apply the format.\n document.execCommand(tag);\n }\n };\n this._disposers.push(\n on(editable, 'compositionstart', onCompositionStart),\n on(editable, 'compositionend', onCompositionEnd),\n );\n }\n\n _onKeydown(event) {\n const editable = this.context.layoutInfo.editable;\n\n // Let Typing module handle special keys (Tab, Enter etc.)\n if (handleKeydown(event, editable, this.options)) return;\n\n // Built-in shortcuts\n if (isModifier(event, 'z') && !event.shiftKey) {\n event.preventDefault();\n this.undo();\n return;\n }\n if ((isModifier(event, 'z') && event.shiftKey) || isModifier(event, 'y')) {\n event.preventDefault();\n this.redo();\n return;\n }\n if (isModifier(event, 'b')) { event.preventDefault(); this.bold(); return; }\n if (isModifier(event, 'i')) { event.preventDefault(); this.italic(); return; }\n if (isModifier(event, 'u')) { event.preventDefault(); this.underline(); return; }\n if (isModifier(event, 'k')) { event.preventDefault(); this.context.invoke('linkDialog.show'); return; }\n\n // Ctrl+Shift+V — paste as plain text (signals Clipboard module)\n if (isModifier(event, 'v') && event.shiftKey) {\n this.context.invoke('clipboard.setForcePlain', true);\n return; // let the native paste event fire\n }\n\n // Show keyboard shortcuts dialog: Ctrl+Shift+/\n if (event.key === '/' && event.shiftKey && event.ctrlKey && !event.metaKey) {\n event.preventDefault();\n this.context.invoke('shortcutsDialog.show');\n return;\n }\n // Find: Ctrl+F\n if (isModifier(event, 'f')) {\n event.preventDefault();\n this.context.invoke('findReplace.show', 'find');\n return;\n }\n // Ctrl+H — Find & Replace\n if (isModifier(event, 'h')) {\n event.preventDefault();\n this.context.invoke('findReplace.show', 'replace');\n }\n // Ctrl+` — Inline Code\n if (isModifier(event, '`')) {\n event.preventDefault();\n this.inlineCode();\n }\n }\n\n // ---------------------------------------------------------------------------\n // Limit enforcement\n // ---------------------------------------------------------------------------\n\n /**\n * Called from beforeinput to block typing when char/word limits are reached.\n * Deletions and non-typing input types are always allowed.\n * @param {InputEvent} event\n */\n _enforceLimit(event) {\n const maxChars = this.options.maxChars || 0;\n const maxWords = this.options.maxWords || 0;\n if (!maxChars && !maxWords) return;\n\n const type = event.inputType || '';\n // Allow deletions, undo, redo and non-insert operations\n if (type.startsWith('delete') || type === 'historyUndo' || type === 'historyRedo') return;\n // Allow paste/drop — handled after the fact by Clipboard\n if (type === 'insertFromPaste' || type === 'insertFromDrop') return;\n // Only enforce for keyboard/IME/composition insertions\n if (!type.startsWith('insert')) return;\n\n const text = this.context.layoutInfo.editable.innerText || '';\n const chars = text.replaceAll('\\n', '').length;\n\n if (maxChars && chars >= maxChars) {\n event.preventDefault();\n if (typeof this.options.onCharLimitReached === 'function') {\n this.options.onCharLimitReached(this.context);\n }\n return;\n }\n\n // Word limit: block space / newline insertion when already at the limit\n if (maxWords && (event.data === ' ' || type === 'insertParagraph' || type === 'insertLineBreak')) {\n const words = text.trim() ? text.trim().split(/\\s+/).length : 0;\n if (words >= maxWords) {\n event.preventDefault();\n if (typeof this.options.onWordLimitReached === 'function') {\n this.options.onWordLimitReached(this.context);\n }\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Post-command hook — records undo, fires change event\n // ---------------------------------------------------------------------------\n\n afterCommand() {\n // C4: Remove figure.an-figure elements whose <img> has been deleted so\n // orphaned figcaptions do not accumulate in the DOM.\n this._cleanOrphanedFigures();\n // Ensure the editable always ends with a paragraph so the user can click\n // and type after block elements that trap the cursor (pre, table, etc.).\n this._ensureTrailingParagraph();\n // Immediate: keep toolbar and statusbar in sync on every mutation.\n this.context.invoke('toolbar.refresh');\n this.context.invoke('statusbar.update');\n // Debounced: recording an undo snapshot and firing the change event require\n // a full innerHTML serialization. Batching rapid keystrokes prevents the\n // browser from re-serializing large content (e.g. embedded images) on every\n // single key press.\n this._scheduleSnapshot();\n }\n\n /**\n * Schedules a debounced undo snapshot + change event.\n * Resets the timer on each call so rapid typing produces one snapshot.\n */\n _scheduleSnapshot() {\n clearTimeout(this._snapshotTimer);\n this._snapshotTimer = setTimeout(() => {\n this._snapshotTimer = null;\n if (this._history) this._history.recordUndo();\n this.context.triggerEvent('change', this.getHTML());\n }, 400);\n }\n\n /**\n * C4: Removes figure.an-figure elements that no longer contain an <img>.\n * This happens when a user selects only the image (not the whole figure)\n * and deletes or replaces it, leaving a dangling figcaption.\n */\n _cleanOrphanedFigures() {\n const editable = this.context.layoutInfo.editable;\n editable.querySelectorAll('figure.an-figure').forEach((fig) => {\n if (!fig.querySelector('img')) {\n fig.remove();\n }\n });\n }\n\n /**\n * Ensures the editable always ends with a plain paragraph so the cursor can\n * be placed after block elements that do not naturally allow it\n * (pre, blockquote, table, figure, ul, ol, hr).\n * Without this, clicking below the last such element does nothing.\n */\n _ensureTrailingParagraph() {\n const editable = this.context.layoutInfo.editable;\n if (!editable) return;\n const last = editable.lastElementChild;\n if (!last) return;\n if (TRAPPING_TAGS.has(last.nodeName)) {\n const p = document.createElement('p');\n p.innerHTML = '<br>';\n editable.appendChild(p);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Focus management\n // ---------------------------------------------------------------------------\n\n focus() {\n const editable = this.context.layoutInfo.editable;\n editable.focus();\n }\n\n // ---------------------------------------------------------------------------\n // Content API\n // ---------------------------------------------------------------------------\n\n /**\n * Returns the editor HTML content.\n * @returns {string}\n */\n getHTML() {\n // Strip zero-width spaces inserted after icons to allow caret placement.\n const raw = this.context.layoutInfo.editable.innerHTML.replaceAll('\\u200B', '');\n // Replace any blob: URLs (lightweight DOM references to pasted/dropped images)\n // with their original data URLs so the returned HTML is fully self-contained.\n return this.context.invoke('clipboard.resolveImages', raw) ?? raw;\n }\n\n /**\n * Sets the editor HTML content.\n * @param {string} html - HTML string (will be sanitised)\n */\n setHTML(html) {\n // Adopt the sanitiser's nodes rather than its string: serialising them and\n // letting innerHTML parse them again was ~14 ms of a ~45 ms setHTML on a\n // 217 KiB document, and the re-parse is the step mXSS exploits.\n const body = sanitiseToBody(html, { allowIframes: true });\n this.context.layoutInfo.editable.replaceChildren(...body.childNodes);\n if (this._history) this._history.reset();\n this.afterCommand();\n }\n\n /**\n * Returns the editor plain text content.\n * @returns {string}\n */\n getText() {\n return this.context.layoutInfo.editable.innerText || '';\n }\n\n /**\n * Sets the editor content as plain text.\n * @param {string} text\n */\n setText(text) {\n this.context.layoutInfo.editable.textContent = text;\n if (this._history) this._history.reset();\n this.afterCommand();\n }\n\n /**\n * Clears the editor content.\n */\n clear() {\n this.setHTML('');\n }\n\n /**\n * Resets the undo/redo history stack.\n */\n clearHistory() {\n if (this._history) this._history.reset();\n }\n\n /**\n * Returns true when the editor has no meaningful content.\n * @returns {boolean}\n */\n isEmpty() {\n const text = (this.context.layoutInfo.editable.innerText || '')\n .trim()\n .replaceAll('\\u00a0', '');\n const hasMedia = !!this.context.layoutInfo.editable.querySelector('img, video, iframe, table');\n return !text && !hasMedia;\n }\n\n /**\n * Inserts HTML at the current cursor position.\n * @param {string} html\n */\n insertHTML(html) {\n if (!html) return;\n Style.execCommand('insertHTML', sanitiseHTML(html));\n this.afterCommand();\n }\n\n /**\n * Inserts plain text at the current cursor position.\n * @param {string} text\n */\n insertText(text) {\n if (!text) return;\n Style.execCommand('insertText', text);\n this.afterCommand();\n }\n\n /**\n * Sets editor content from a Markdown string.\n * @param {string} md\n */\n setMarkdown(md) {\n this.setHTML(markdownToHTML(md || ''));\n }\n\n /**\n * Returns the editor content as Markdown.\n * @returns {string}\n */\n getMarkdown() {\n return htmlToMarkdown(this.getHTML());\n }\n\n // ---------------------------------------------------------------------------\n // Undo / redo\n // ---------------------------------------------------------------------------\n\n undo() {\n if (this._history) {\n this._flushPendingSnapshot();\n this._history.undo();\n this.context.invoke('toolbar.refresh');\n this.context.invoke('statusbar.update');\n this.context.triggerEvent('change', this.getHTML());\n }\n }\n\n redo() {\n if (this._history) {\n this._flushPendingSnapshot();\n this._history.redo();\n this.context.invoke('toolbar.refresh');\n this.context.invoke('statusbar.update');\n this.context.triggerEvent('change', this.getHTML());\n }\n }\n\n /** Records a debounced change before an immediate undo/redo command. */\n _flushPendingSnapshot() {\n if (this._snapshotTimer === null) return;\n clearTimeout(this._snapshotTimer);\n this._snapshotTimer = null;\n this._history?.recordUndo();\n }\n\n canUndo() {\n return this._history ? this._history.canUndo() : false;\n }\n\n canRedo() {\n return this._history ? this._history.canRedo() : false;\n }\n\n getUndoCount() {\n return this._history ? this._history.getUndoCount() : 0;\n }\n\n getRedoCount() {\n return this._history ? this._history.getRedoCount() : 0;\n }\n\n getSelectionBookmark() {\n return this._history?._serializeSelection() ?? null;\n }\n\n restoreSelectionBookmark(bookmark) {\n if (!bookmark || !this._history) return false;\n this._history._restoreSelection(bookmark);\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Style commands (delegated to Style module)\n // ---------------------------------------------------------------------------\n\n bold() { Style.bold(); this.afterCommand(); }\n italic() { Style.italic(); this.afterCommand(); }\n underline() { Style.underline(); this.afterCommand(); }\n strikethrough() { Style.strikethrough(); this.afterCommand(); }\n superscript() { Style.superscript(); this.afterCommand(); }\n subscript() { Style.subscript(); this.afterCommand(); }\n justifyLeft() { Style.justifyLeft(); this.afterCommand(); }\n justifyCenter() { Style.justifyCenter(); this.afterCommand(); }\n justifyRight() { Style.justifyRight(); this.afterCommand(); }\n justifyFull() { Style.justifyFull(); this.afterCommand(); }\n indent() { Style.indent(); this.afterCommand(); }\n outdent() { Style.outdent(); this.afterCommand(); }\n insertUL() { Style.insertUnorderedList(); this.afterCommand(); }\n insertOL() { Style.insertOrderedList(); this.afterCommand(); }\n inlineCode() { Style.toggleInlineCode(this.context.layoutInfo.editable); this.afterCommand(); }\n toggleChecklist() { Style.toggleChecklist(); this.afterCommand(); }\n print() { this.context.print(); }\n\n /**\n * @param {string} tagName - e.g. 'h1', 'p', 'blockquote', 'pre'\n */\n formatBlock(tagName) {\n Style.formatBlock(tagName);\n\n // Auto-detect the programming language when the user formats a code block.\n // Only runs when converting TO <pre> and the block has no language yet.\n if (tagName === 'pre') {\n const sel = globalThis.getSelection();\n if (sel?.rangeCount > 0) {\n const container = sel.getRangeAt(0).commonAncestorContainer;\n const pre = /** @type {Element|null} */ (\n container.nodeType === 1\n ? /** @type {Element} */ (container).closest('pre')\n : (/** @type {Element|null} */ (container.parentElement))?.closest('pre')\n );\n if (pre && !/** @type {HTMLElement} */ (pre).dataset.language) {\n const code = pre.textContent || '';\n const lang = detectLang(code);\n if (lang) {\n this.context.invoke('codeTooltip.applyLanguage', pre, lang);\n return; // applyLanguage already calls afterCommand internally\n }\n }\n }\n }\n\n this.afterCommand();\n }\n\n /**\n * @param {string} color\n */\n foreColor(color) { Style.foreColor(color); this.afterCommand(); }\n\n /**\n * @param {string} color\n */\n backColor(color) { Style.backColor(color); this.afterCommand(); }\n\n /**\n * @param {string} name\n */\n fontName(name) { Style.fontName(name); this.afterCommand(); }\n\n /**\n * @param {string} size - e.g. '14px'\n */\n fontSize(size) { Style.fontSize(size, this.context.layoutInfo.editable); this.afterCommand(); }\n\n // ---------------------------------------------------------------------------\n // Insert helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Inserts a horizontal rule at the cursor.\n */\n insertHr() {\n Style.execCommand('insertHorizontalRule');\n this.afterCommand();\n }\n\n /**\n * Creates a link at the current selection.\n * @param {string} url\n * @param {string} text\n * @param {boolean} [openInNewTab=false]\n */\n insertLink(url, text, openInNewTab = false) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const safeUrl = sanitiseUrl(url);\n if (!safeUrl) return;\n\n const hasText = sel.toString().trim().length > 0;\n if (hasText) {\n Style.execCommand('createLink', safeUrl);\n if (openInNewTab) {\n const link = this._getClosestAnchor();\n if (link) {\n /** @type {Element} */ (link).setAttribute('target', '_blank');\n /** @type {Element} */ (link).setAttribute('rel', 'noopener noreferrer');\n }\n }\n } else {\n const displayText = this._escapeAttr(text || safeUrl);\n Style.execCommand('insertHTML', `<a href=\"${this._escapeAttr(safeUrl)}\"${openInNewTab ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : ''}>${displayText}</a>`);\n }\n this.afterCommand();\n }\n\n /**\n * Removes the link from the selected anchor.\n */\n unlink() {\n Style.execCommand('unlink');\n this.afterCommand();\n }\n\n /**\n * Inserts an image.\n * @param {string} src - URL or data-URI\n * @param {string} [alt]\n */\n insertImage(src, alt = '', align = '') {\n const safeSrc = sanitiseUrl(src, { allowData: true });\n if (!safeSrc) return;\n const styleMap = {\n left: 'float:left;margin:0 1em 1em 0',\n center: 'display:block;margin:0 auto',\n right: 'float:right;margin:0 0 1em 1em',\n };\n const style = styleMap[align] || '';\n const styleAttr = style ? ` style=\"${style}\"` : '';\n Style.execCommand('insertHTML', `<img src=\"${this._escapeAttr(safeSrc)}\" alt=\"${this._escapeAttr(alt)}\" class=\"an-image\"${styleAttr}>`);\n this.afterCommand();\n }\n\n /**\n * Inserts a video embed (iframe or <video> element).\n * The html string is already validated/built by VideoDialog.\n * @param {string} html\n */\n insertVideo(html) {\n if (!html) return;\n Style.execCommand('insertHTML', html);\n this.afterCommand();\n }\n\n /**\n * Inserts a table.\n * @param {number} cols\n * @param {number} rows\n */\n insertTable(cols, rows) {\n insertTable(cols, rows, { headerRow: this.context.options.tableHeaderRow });\n this.afterCommand();\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n _getClosestAnchor() {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n let node = sel.getRangeAt(0).startContainer;\n while (node) {\n if (node.nodeName === 'A') return node;\n node = node.parentNode;\n }\n return null;\n }\n\n /**\n * Escapes a string for safe use inside an HTML attribute value.\n * @param {string} str\n * @returns {string}\n */\n _escapeAttr(str) {\n return String(str ?? '')\n .replaceAll('&', '&')\n .replaceAll('\"', '"')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n }\n\n // --- delegated to shared sanitise.js ---\n}\n","/**\n * Toolbar.js - Builds and manages the editor toolbar UI\n * Inspired by Summernote's Toolbar module — rewritten without jQuery\n */\n\nimport { createElement, on } from '../core/dom.js';\nimport { getButton } from './Buttons.js';\n\n/** Resolve a toolbar item: string → registry lookup, object → pass-through. */\nconst _resolveBtn = (item) => (typeof item === 'string') ? getButton(item) : item;\n\n// Module-level cache for FontAwesome detection.\n// Evaluated once per page load so all Toolbar instances on the same page agree\n// on whether the HOST PAGE included FA — regardless of whether IconDialog later\n// auto-injects its own FA <link> for the icon-picker glyph rendering.\nlet _faPageLevelReady = null;\n\n// ---------------------------------------------------------------------------\n// Module-level icon lookup tables — built once, shared across all instances.\n// Previously these were re-created inside _createButton() on every button\n// render, producing O(buttons × map-size) allocations per toolbar init.\n// ---------------------------------------------------------------------------\nconst _S = 'stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';\nconst _svgWrap = (paths) =>\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" ${_S} style=\"display:block\">${paths}</svg>`;\n\nconst _SVG_MAP = new Map([\n // Format\n ['bold', _svgWrap('<path d=\"M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\"/><path d=\"M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\"/>')],\n ['italic', _svgWrap('<line x1=\"19\" y1=\"4\" x2=\"10\" y2=\"4\"/><line x1=\"14\" y1=\"20\" x2=\"5\" y2=\"20\"/><line x1=\"15\" y1=\"4\" x2=\"9\" y2=\"20\"/>')],\n ['underline', _svgWrap('<path d=\"M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3\"/><line x1=\"4\" y1=\"21\" x2=\"20\" y2=\"21\"/>')],\n ['strikethrough', _svgWrap('<path d=\"M17.3 12H6.7\"/><path d=\"M10 6.5C10 5.1 11.1 4 12.5 4c1.4 0 2.5 1.1 2.5 2.5 0 .8-.4 1.5-1 2\"/><path d=\"M14 17.5C14 19 12.9 20 11.5 20 10.1 20 9 18.9 9 17.5c0-.8.4-1.5 1-2\"/>')],\n ['superscript', _svgWrap('<path d=\"m4 19 8-8\"/><path d=\"m12 19-8-8\"/><path d=\"M20 12h-4c0-1.5.44-2 1.5-2.5S20 8.33 20 7.25C20 6 19 5 17.5 5S15 6 15 7\"/>')],\n ['subscript', _svgWrap('<path d=\"m4 5 8 8\"/><path d=\"m12 5-8 8\"/><path d=\"M20 21h-4c0-1.5.44-2 1.5-2.5S20 17.33 20 16.25C20 15 19 14 17.5 14S15 15 15 16\"/>')],\n // Alignment\n ['align-left', _svgWrap('<line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"/><line x1=\"15\" y1=\"12\" x2=\"3\" y2=\"12\"/><line x1=\"17\" y1=\"18\" x2=\"3\" y2=\"18\"/>')],\n ['align-center', _svgWrap('<line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"/><line x1=\"18\" y1=\"12\" x2=\"6\" y2=\"12\"/><line x1=\"21\" y1=\"18\" x2=\"3\" y2=\"18\"/>')],\n ['align-right', _svgWrap('<line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"/><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"/><line x1=\"21\" y1=\"18\" x2=\"7\" y2=\"18\"/>')],\n ['align-justify', _svgWrap('<line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"/><line x1=\"21\" y1=\"12\" x2=\"3\" y2=\"12\"/><line x1=\"21\" y1=\"18\" x2=\"3\" y2=\"18\"/>')],\n // Lists\n ['list-ul', _svgWrap('<line x1=\"9\" y1=\"6\" x2=\"20\" y2=\"6\"/><line x1=\"9\" y1=\"12\" x2=\"20\" y2=\"12\"/><line x1=\"9\" y1=\"18\" x2=\"20\" y2=\"18\"/><circle cx=\"4\" cy=\"6\" r=\"1\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"4\" cy=\"12\" r=\"1\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"4\" cy=\"18\" r=\"1\" fill=\"currentColor\" stroke=\"none\"/>')],\n ['list-ol', _svgWrap('<line x1=\"10\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"10\" y1=\"12\" x2=\"21\" y2=\"12\"/><line x1=\"10\" y1=\"18\" x2=\"21\" y2=\"18\"/><path d=\"M4 6h1V3\"/><path d=\"M4 10h2l-2 2h2\"/><path d=\"M4 16.5A1.5 1.5 0 0 1 5.5 15a1.5 1.5 0 0 1 0 3H4\"/>')],\n ['indent', _svgWrap('<polyline points=\"3 8 7 12 3 16\"/><line x1=\"21\" y1=\"12\" x2=\"11\" y2=\"12\"/><line x1=\"21\" y1=\"6\" x2=\"11\" y2=\"6\"/><line x1=\"21\" y1=\"18\" x2=\"11\" y2=\"18\"/>')],\n ['outdent', _svgWrap('<polyline points=\"7 8 3 12 7 16\"/><line x1=\"21\" y1=\"12\" x2=\"11\" y2=\"12\"/><line x1=\"21\" y1=\"6\" x2=\"11\" y2=\"6\"/><line x1=\"21\" y1=\"18\" x2=\"11\" y2=\"18\"/>')],\n // History\n ['undo', _svgWrap('<path d=\"M3 7v6h6\"/><path d=\"M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13\"/>')],\n ['redo', _svgWrap('<path d=\"M21 7v6h-6\"/><path d=\"M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13\"/>')],\n // Insert\n ['minus', _svgWrap('<line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>')],\n ['link', _svgWrap('<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/>')],\n ['image', _svgWrap('<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/>')],\n ['video', _svgWrap('<polygon points=\"23 7 16 12 23 17 23 7\"/><rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\"/>')],\n ['table', _svgWrap('<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/><line x1=\"3\" y1=\"15\" x2=\"21\" y2=\"15\"/><line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"21\"/><line x1=\"15\" y1=\"3\" x2=\"15\" y2=\"21\"/>')],\n ['emoji', _svgWrap('<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M8.5 14.5s1.5 2.5 3.5 2.5 3.5-2.5 3.5-2.5\"/><circle cx=\"9\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"15\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" stroke=\"none\"/>')],\n ['icon', _svgWrap('<circle cx=\"8\" cy=\"8\" r=\"3\"/><circle cx=\"16\" cy=\"8\" r=\"3\"/><rect x=\"5\" y=\"13\" width=\"6\" height=\"6\" rx=\"1\"/><rect x=\"13\" y=\"13\" width=\"6\" height=\"6\" rx=\"1\"/>')],\n // View\n ['code', _svgWrap('<polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/>')],\n ['expand', _svgWrap('<polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/>')],\n // Color pickers\n ['foreColor', _svgWrap('<path d=\"M4 20L12 4L20 20\"/><line x1=\"7.5\" y1=\"14\" x2=\"16.5\" y2=\"14\"/>')],\n ['backColor', _svgWrap('<path d=\"M3 21v-4l9-9 4 4-9 9z\"/><path d=\"M12 8l4 4\"/>')],\n ['keyboard', _svgWrap('<rect x=\"2\" y=\"6\" width=\"20\" height=\"12\" rx=\"2\"/><line x1=\"6\" y1=\"10\" x2=\"6\" y2=\"10\" stroke-width=\"2.5\"/><line x1=\"10\" y1=\"10\" x2=\"10\" y2=\"10\" stroke-width=\"2.5\"/><line x1=\"14\" y1=\"10\" x2=\"14\" y2=\"10\" stroke-width=\"2.5\"/><line x1=\"18\" y1=\"10\" x2=\"18\" y2=\"10\" stroke-width=\"2.5\"/><line x1=\"8\" y1=\"14\" x2=\"16\" y2=\"14\" stroke-width=\"2\"/>')],\n ['caption', _svgWrap('<rect x=\"3\" y=\"3\" width=\"18\" height=\"11\" rx=\"2\"/><line x1=\"6\" y1=\"18\" x2=\"18\" y2=\"18\"/><line x1=\"9\" y1=\"21\" x2=\"15\" y2=\"21\"/>')],\n ['remove-format', _svgWrap('<path d=\"m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21\"/><path d=\"M22 21H7\"/><path d=\"m5 11 9 9\"/>')],\n ['direction', _svgWrap('<path d=\"M12 20V4\"/><path d=\"m9 7-3 3 3 3\"/><path d=\"M4 10h8\"/><path d=\"m15 7 3 3-3 3\"/><path d=\"M20 10h-8\"/>')],\n ['search', _svgWrap('<circle cx=\"11\" cy=\"11\" r=\"7\"/><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"/>')],\n ['find-replace', _svgWrap('<circle cx=\"10\" cy=\"10\" r=\"6\"/><line x1=\"18\" y1=\"18\" x2=\"14.35\" y2=\"14.35\"/><path d=\"M16 19h6\"/><path d=\"M19 16v6\"/>')],\n ['inline-code', _svgWrap('<path d=\"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1\"/><path d=\"M16 3h1a2 2 0 0 1 2 2v5c0 1.1.9 2 2 2a2 2 0 0 1-2 2v5a2 2 0 0 1-2 2h-1\"/>')],\n ['checklist', _svgWrap('<rect x=\"3\" y=\"4\" width=\"5\" height=\"5\" rx=\"1\"/><path d=\"m4 6.5 1 1 2-2\"/><rect x=\"3\" y=\"13\" width=\"5\" height=\"5\" rx=\"1\"/><line x1=\"10\" y1=\"6.5\" x2=\"21\" y2=\"6.5\"/><line x1=\"10\" y1=\"15.5\" x2=\"21\" y2=\"15.5\"/>')],\n ['print', _svgWrap('<path d=\"M6 9V2h12v7\"/><path d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2\"/><rect x=\"6\" y=\"14\" width=\"12\" height=\"8\"/>')],\n]);\n\nconst _FA_MAP = new Map([\n ['bold', 'fa-bold'],\n ['italic', 'fa-italic'],\n ['underline', 'fa-underline'],\n ['strikethrough', 'fa-strikethrough'],\n ['superscript', 'fa-superscript'],\n ['subscript', 'fa-subscript'],\n ['align-left', 'fa-align-left'],\n ['align-center', 'fa-align-center'],\n ['align-right', 'fa-align-right'],\n ['align-justify', 'fa-align-justify'],\n ['list-ul', 'fa-list-ul'],\n ['list-ol', 'fa-list-ol'],\n ['indent', 'fa-indent'],\n ['outdent', 'fa-outdent'],\n ['undo', 'fa-rotate-left'],\n ['redo', 'fa-rotate-right'],\n ['minus', 'fa-minus'],\n ['link', 'fa-link'],\n ['image', 'fa-image'],\n ['code', 'fa-code'],\n ['expand', 'fa-expand'],\n ['emoji', 'fa-face-smile'],\n ['icon', 'fa-icons'],\n ['foreColor', 'fa-font'],\n ['backColor', 'fa-highlighter'],\n ['keyboard', 'fa-keyboard'],\n ['remove-format', 'fa-remove-format'],\n ['direction', 'fa-arrow-right-arrow-left'],\n ['search', 'fa-magnifying-glass'],\n ['find-replace', 'fa-magnifying-glass-plus'],\n ['inline-code', 'fa-code'],\n ['checklist', 'fa-list-check'],\n ['print', 'fa-print'],\n]);\n\nexport class Toolbar {\n /**\n * @param {import('../Context.js').Context} context\n */\n constructor(context) {\n this.context = context;\n this.options = context.options;\n /** @type {HTMLElement|null} */\n this.el = null;\n /** @type {Array<() => void>} disposers */\n this._disposers = [];\n /** @type {Array<() => void>} closers for all open color picker popups */\n this._colorPickerClosers = [];\n /** @type {number|null} rAF handle for debounced refresh */\n this._refreshRaf = null;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n initialize() {\n this.el = createElement('div', {\n class: 'an-toolbar',\n role: 'toolbar',\n 'aria-orientation': 'horizontal',\n // Matches the hardcoded English label renderer.js gives the editable.\n 'aria-label': 'Editor toolbar',\n });\n // Detect FontAwesome once at toolbar build time to avoid re-querying the DOM\n // for every button rendered.\n this._faReady = this._detectFontAwesome();\n this._buildButtons();\n this._initRovingFocus();\n this._btnMap = new Map(\n (this.options.toolbar || []).flat()\n .map(_resolveBtn).filter(Boolean).map((b) => [b.name, b]),\n );\n return this;\n }\n\n destroy() {\n if (this._refreshRaf) cancelAnimationFrame(this._refreshRaf);\n this._refreshRaf = null;\n this._disposers.forEach((d) => d());\n this._disposers = [];\n if (this.el?.parentNode) {\n this.el.remove();\n }\n this.el = null;\n }\n\n // ---------------------------------------------------------------------------\n // Build\n // ---------------------------------------------------------------------------\n\n _buildButtons() {\n const toolbar = this.options.toolbar || [];\n // Build into a DocumentFragment so all groups are appended in a single\n // DOM operation, avoiding one reflow per group.\n const fragment = document.createDocumentFragment();\n toolbar.forEach((group) => {\n const groupEl = createElement('div', { class: 'an-btn-group' });\n group.forEach((item) => {\n const btnDef = _resolveBtn(item);\n if (!btnDef) {\n console.warn(`[AutumnNote] Toolbar: button \"${item}\" not found in registry. Skipped.`);\n return;\n }\n let el;\n if (btnDef.type === 'select') el = this._createSelect(btnDef);\n else if (btnDef.type === 'grid') el = this._createGridPicker(btnDef);\n else if (btnDef.type === 'colorpicker') el = this._createColorPicker(btnDef);\n else el = this._createButton(btnDef);\n groupEl.appendChild(el);\n });\n fragment.appendChild(groupEl);\n });\n this.el.appendChild(fragment);\n }\n\n /**\n * Creates a table-grid picker button with a hoverable row/col selector popup.\n * @param {import('./Buttons.js').ButtonDef} def\n * @returns {HTMLDivElement}\n */\n _createGridPicker(def) {\n const ROWS = 10;\n const COLS = 10;\n\n const wrap = createElement('div', { class: 'an-table-picker-wrap' });\n\n const useBootstrap = !!this.options.useBootstrap;\n const baseClass = useBootstrap\n ? (this.options.toolbarButtonClass || 'btn btn-sm btn-light')\n : 'an-btn';\n const btn = createElement('button', {\n type: 'button',\n class: baseClass,\n title: this.context.locale.toolbar[def.name] || def.tooltip || '',\n 'data-btn': def.name,\n 'aria-label': this.context.locale.toolbar[def.name] || def.tooltip || def.name,\n 'aria-haspopup': 'true',\n 'aria-expanded': 'false',\n });\n\n // Set icon — inline SVG (table) with optional FontAwesome fallback\n if (this._faReady) {\n const faPrefix = this.options.fontAwesomeClass || 'fas';\n btn.innerHTML = `<i class=\"${faPrefix} fa-table\" aria-hidden=\"true\"></i>`;\n } else {\n const S = 'stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';\n btn.innerHTML = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" ${S} style=\"display:block\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/><line x1=\"3\" y1=\"15\" x2=\"21\" y2=\"15\"/><line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"21\"/><line x1=\"15\" y1=\"3\" x2=\"15\" y2=\"21\"/></svg>`;\n }\n\n // Popup\n const popup = createElement('div', {\n class: 'an-table-picker-popup',\n role: 'dialog',\n 'aria-label': 'Select table size',\n });\n const grid = createElement('div', { class: 'an-table-grid' });\n const label = createElement('div', { class: 'an-table-label' });\n label.textContent = this.context.locale.toolbar.insertTableLabel || 'Insert Table';\n\n const cells = [];\n for (let r = 1; r <= ROWS; r++) {\n for (let c = 1; c <= COLS; c++) {\n const cell = createElement('div', {\n class: 'an-table-cell',\n 'data-row': String(r),\n 'data-col': String(c),\n });\n cells.push(cell);\n grid.appendChild(cell);\n }\n }\n\n popup.appendChild(grid);\n popup.appendChild(label);\n\n let isOpen = false;\n\n const setHighlight = (rows, cols) => {\n cells.forEach((cell) => {\n const r = +cell.dataset.row;\n const c = +cell.dataset.col;\n cell.classList.toggle('active', r <= rows && c <= cols);\n });\n label.textContent = (rows && cols) ? `${rows} × ${cols}` : (this.context.locale.toolbar.insertTableLabel || 'Insert Table');\n };\n\n const openPopup = () => {\n isOpen = true;\n const rect = btn.getBoundingClientRect();\n\n // Measure popup dimensions while invisible so we can set the correct\n // position before the browser paints (matches the color-picker pattern).\n popup.style.visibility = 'hidden';\n popup.style.display = 'block';\n const pw = popup.offsetWidth;\n const ph = popup.offsetHeight;\n\n let left = rect.left;\n let top = rect.bottom + 4;\n if (left + pw > globalThis.innerWidth - 8) left = Math.max(8, globalThis.innerWidth - pw - 8);\n if (top + ph > globalThis.innerHeight - 8) top = rect.top - ph - 4;\n\n popup.style.left = `${left}px`;\n popup.style.top = `${top}px`;\n popup.style.visibility = '';\n btn.setAttribute('aria-expanded', 'true');\n };\n\n const closePopup = () => {\n isOpen = false;\n popup.style.display = 'none';\n btn.setAttribute('aria-expanded', 'false');\n setHighlight(0, 0);\n };\n\n const d1 = on(btn, 'click', (e) => {\n e.stopPropagation();\n if (isOpen) closePopup(); else openPopup();\n });\n\n const d2 = on(grid, 'mouseover', (e) => {\n const cell = /** @type {HTMLElement|null} */ (/** @type {Element} */ (e.target)?.closest('.an-table-cell'));\n if (!cell) return;\n setHighlight(+cell.dataset.row, +cell.dataset.col);\n });\n\n const d3 = on(grid, 'mouseleave', () => setHighlight(0, 0));\n\n const d4 = on(grid, 'click', (e) => {\n const cell = /** @type {HTMLElement|null} */ (/** @type {Element} */ (e.target)?.closest('.an-table-cell'));\n if (!cell) return;\n const rows = +cell.dataset.row;\n const cols = +cell.dataset.col;\n closePopup();\n this.context.invoke('editor.focus');\n def.action(this.context, rows, cols);\n });\n\n const d5 = on(document, 'click', () => { if (isOpen) closePopup(); });\n\n // Append popup to body so position:fixed is truly viewport-relative,\n // unaffected by any ancestor transform / filter (same pattern as color picker).\n this._disposers.push(d1, d2, d3, d4, d5, () => {\n if (popup.parentNode) popup.remove();\n });\n\n wrap.appendChild(btn);\n document.body.appendChild(popup);\n return /** @type {HTMLDivElement} */ (wrap);\n }\n\n /**\n * Creates a split color-picker widget:\n * [icon + strip | ▾] — left applies current color, right opens swatch popup.\n * @param {{ name: string, type: 'colorpicker', tooltip: string, defaultColor: string, action: Function }} def\n * @returns {HTMLDivElement}\n */\n _createColorPicker(def) {\n const PRESETS = [\n // Grayscale\n '#000000', '#434343', '#666666', '#999999', '#b7b7b7', '#cccccc', '#efefef', '#ffffff',\n // Saturated\n '#ff0000', '#ff9900', '#ffff00', '#00ff00', '#00ffff', '#4a86e8', '#9900ff', '#ff00ff',\n // Pastel\n '#f4cccc', '#fce5cd', '#fff2cc', '#d9ead3', '#d0e0e3', '#c9daf8', '#d9d2e9', '#ead1dc',\n ];\n\n let currentColor = def.defaultColor || '#000000';\n\n const wrap = createElement('div', { class: 'an-color-picker-wrap' });\n\n const useBootstrap = !!this.options.useBootstrap;\n const baseClass = useBootstrap ? (this.options.toolbarButtonClass || 'btn btn-sm btn-light') : 'an-btn';\n\n // ---- Apply button (icon + color strip) ----\n const applyBtn = createElement('button', {\n type: 'button',\n class: `${baseClass} an-color-btn`,\n title: this.context.locale.toolbar[def.name] || def.tooltip || '',\n 'data-btn': def.name,\n 'aria-label': this.context.locale.toolbar[def.name] || def.tooltip || def.name,\n });\n\n const S = 'stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';\n const iconSvg = def.name === 'foreColor'\n ? `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" ${S} style=\"display:block\"><path d=\"M4 20L12 4L20 20\"/><line x1=\"7.5\" y1=\"14\" x2=\"16.5\" y2=\"14\"/></svg>`\n : `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" ${S} style=\"display:block\"><path d=\"M3 21v-4l9-9 4 4-9 9z\"/><path d=\"M12 8l4 4\"/></svg>`;\n\n applyBtn.innerHTML = iconSvg;\n const strip = createElement('span', { class: 'an-color-strip' });\n strip.style.background = currentColor;\n applyBtn.appendChild(strip);\n\n // ---- Arrow button (open popup) ----\n const arrowBtn = createElement('button', {\n type: 'button',\n class: `${baseClass} an-color-arrow`,\n title: def.name === 'foreColor'\n ? (this.context.locale.toolbar.chooseTextColor || 'Choose text color')\n : (this.context.locale.toolbar.chooseHighlightColor || 'Choose highlight color'),\n 'aria-haspopup': 'true',\n 'aria-expanded': 'false',\n });\n arrowBtn.innerHTML = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"8\" height=\"8\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" style=\"display:block\"><path d=\"M7 10l5 5 5-5H7z\"/></svg>`;\n\n // ---- Popup ----\n const popup = createElement('div', { class: 'an-color-popup' });\n popup.style.display = 'none';\n\n const swatches = createElement('div', { class: 'an-color-swatches' });\n const userSwatches = Array.isArray(this.options.colorSwatches) ? this.options.colorSwatches : [];\n const allColors = [...new Set([...userSwatches, ...PRESETS])];\n allColors.forEach((color) => {\n const sw = createElement('div', { class: 'an-color-swatch', title: color, 'data-color': color });\n sw.style.background = color;\n swatches.appendChild(sw);\n });\n\n const customRow = createElement('div', { class: 'an-color-custom' });\n const colorInput = /** @type {HTMLInputElement} */ (createElement('input', { type: 'color', value: currentColor, title: this.context.locale.toolbar.customColor || 'Custom color' }));\n const customLabel = createElement('span', {}, [this.context.locale.toolbar.customColor || 'Custom color']);\n customRow.appendChild(colorInput);\n customRow.appendChild(customLabel);\n\n popup.appendChild(swatches);\n popup.appendChild(customRow);\n\n // ---- State ----\n let isOpen = false;\n /** @type {Range|null} saved selection range before popup opens */\n let savedRange = null;\n\n const saveSelection = () => {\n const sel = globalThis.getSelection();\n savedRange = sel?.rangeCount ? sel.getRangeAt(0).cloneRange() : null;\n };\n\n const restoreSelection = () => {\n if (!savedRange) return;\n try {\n const sel = globalThis.getSelection();\n if (!sel) return;\n sel.removeAllRanges();\n sel.addRange(savedRange);\n } catch (_) {\n void _; // range may be stale if DOM changed while popup was open\n }\n };\n\n const openPopup = () => {\n // Close any other open color picker before opening this one\n this._colorPickerClosers.forEach((fn) => { if (fn !== closePopup) fn(); });\n saveSelection();\n isOpen = true;\n // Use fixed positioning so the popup escapes any overflow-clipping ancestor\n // (notably toolbar scroll mode, where overflow-x:auto coerces overflow-y)\n const rect = arrowBtn.getBoundingClientRect();\n const popupMinW = 184;\n let left = rect.left;\n if (left + popupMinW > globalThis.innerWidth) left = rect.right - popupMinW;\n popup.style.top = `${rect.bottom + 4}px`;\n popup.style.left = `${Math.max(4, left)}px`;\n popup.style.display = 'block';\n arrowBtn.setAttribute('aria-expanded', 'true');\n };\n\n const closePopup = () => {\n isOpen = false;\n popup.style.display = 'none';\n popup.style.top = '';\n popup.style.left = '';\n arrowBtn.setAttribute('aria-expanded', 'false');\n };\n\n const applyColor = (color) => {\n currentColor = color;\n strip.style.background = color;\n colorInput.value = color;\n restoreSelection();\n def.action(this.context, color);\n this.context.invoke('editor.afterCommand');\n closePopup();\n };\n\n const d1 = on(applyBtn, 'click', (e) => {\n e.preventDefault();\n restoreSelection();\n def.action(this.context, currentColor);\n this.context.invoke('editor.afterCommand');\n });\n\n const d2 = on(arrowBtn, 'mousedown', (e) => {\n // Prevent editor blur so selection is preserved when the popup opens\n e.preventDefault();\n });\n\n const d2b = on(arrowBtn, 'click', (e) => {\n e.stopPropagation();\n if (isOpen) closePopup(); else openPopup();\n });\n\n const d3 = on(swatches, 'mousedown', (e) => {\n // Prevent blur before the click handler fires\n e.preventDefault();\n });\n\n const d3b = on(swatches, 'click', (e) => {\n const sw = /** @type {Element} */ (e.target)?.closest('.an-color-swatch');\n if (sw) applyColor(/** @type {HTMLElement} */ (sw).dataset.color);\n });\n\n const d4 = on(colorInput, 'change', (e) => {\n applyColor(/** @type {HTMLInputElement} */ (e.target).value);\n });\n\n const d5 = on(document, 'click', (e) => {\n // popup is in document.body, not inside wrap — check both\n if (isOpen && !wrap.contains(/** @type {Node} */ (e.target)) && !popup.contains(/** @type {Node} */ (e.target))) closePopup();\n });\n\n const d6 = on(popup, 'click', (e) => e.stopPropagation());\n\n // Close the popup when the viewport scrolls or resizes so the fixed-position\n // popup doesn't drift away from the button it belongs to.\n const onScrollResize = () => { if (isOpen) closePopup(); };\n document.addEventListener('scroll', onScrollResize, { passive: true, capture: true });\n globalThis.addEventListener('resize', onScrollResize, { passive: true });\n\n this._disposers.push(d1, d2, d2b, d3, d3b, d4, d5, d6,\n () => document.removeEventListener('scroll', onScrollResize, { capture: true }),\n () => globalThis.removeEventListener('resize', onScrollResize),\n // Remove popup from body on editor destroy\n () => { if (popup.parentNode) popup.remove(); },\n );\n\n // Register this popup's closer so other color pickers can close it\n this._colorPickerClosers.push(closePopup);\n this._disposers.push(() => {\n const idx = this._colorPickerClosers.indexOf(closePopup);\n if (idx !== -1) this._colorPickerClosers.splice(idx, 1);\n });\n\n // Append popup to document.body so it escapes all overflow-clipping and\n // contain:layout ancestors (contain:layout makes the container a fixed-pos\n // containing block per the CSS Contain spec, breaking viewport coordinates).\n wrap.appendChild(applyBtn);\n wrap.appendChild(arrowBtn);\n document.body.appendChild(popup);\n return /** @type {HTMLDivElement} */ (wrap);\n }\n\n /**\n * Creates a <select> dropdown for font-family (or similar) options.\n * @param {import('./Buttons.js').DropdownDef} def\n * @returns {HTMLSelectElement}\n */\n _createSelect(def) {\n const items = (def.name === 'fontFamily')\n ? (this.options.fontFamilies || [])\n : (def.items || []);\n\n const cls = def.selectClass ? `an-select ${def.selectClass}` : 'an-select';\n const select = createElement('select', {\n class: cls,\n title: this.context.locale.toolbar[def.name] || def.tooltip || '',\n 'data-btn': def.name,\n 'aria-label': this.context.locale.toolbar[def.name] || def.tooltip || def.name,\n });\n\n // Blank \"placeholder\" option (non-selectable header)\n const placeholderText = this.context.locale.toolbar[def.name + 'Placeholder'] || def.placeholder || 'Font';\n const placeholder = createElement('option', { value: '', disabled: '', hidden: '' }, [placeholderText]);\n select.appendChild(placeholder);\n\n items.forEach((item) => {\n const value = (typeof item === 'object') ? item.value : item;\n let label;\n if (typeof item !== 'object') {\n label = item;\n } else if (def.name === 'paragraphStyle') {\n label = this.context.locale.toolbar.paragraphItems?.[item.value] || item.label;\n } else {\n label = item.label;\n }\n const isHeader = (typeof item === 'object') && !!item.disabled;\n const attrs = { value };\n if (isHeader) attrs.disabled = '';\n const opt = createElement('option', attrs, [label]);\n // Only apply fontFamily face preview on real (non-header) entries\n if (def.name === 'fontFamily' && !isHeader) opt.style.fontFamily = value;\n select.appendChild(opt);\n });\n\n // Save the editor selection when the user starts interacting with the\n // dropdown (mousedown fires before the editor loses focus). When the\n // change handler runs, focus has moved to the <select>; we restore the\n // saved range so execCommand / fontSize() act on the intended text.\n /** @type {Range|null} */\n let _savedRange = null;\n const dMousedown = on(select, 'mousedown', () => {\n const sel = globalThis.getSelection();\n _savedRange = sel?.rangeCount ? sel.getRangeAt(0).cloneRange() : null;\n });\n\n const disposer = on(select, 'change', (e) => {\n const value = /** @type {HTMLSelectElement} */ (e.target).value;\n const selectedOpt = /** @type {HTMLSelectElement} */ (e.target).options[/** @type {HTMLSelectElement} */ (e.target).selectedIndex];\n if (!value || selectedOpt.disabled) return;\n this.context.invoke('editor.focus');\n // Restore selection saved on mousedown so the action targets the correct text.\n if (_savedRange) {\n try {\n const sel = globalThis.getSelection();\n if (sel) { sel.removeAllRanges(); sel.addRange(_savedRange); }\n } catch (_) { void _; /* range may be stale if DOM changed */ }\n }\n def.action(this.context, value);\n this.context.invoke('editor.afterCommand');\n });\n\n this._disposers.push(dMousedown, disposer);\n return /** @type {HTMLSelectElement} */ (select);\n }\n\n /**\n * @param {import('./Buttons.js').ButtonDef} btnDef\n * @returns {HTMLButtonElement}\n */\n _createButton(btnDef) {\n // Determine classes based on whether the consumer wants Bootstrap styling\n const useBootstrap = !!this.options.useBootstrap;\n const baseClass = useBootstrap ? (this.options.toolbarButtonClass || 'btn btn-sm btn-light') : `an-btn`;\n const extra = btnDef.className ? ` ${btnDef.className}` : '';\n const classAttr = `${baseClass}${extra}`;\n\n const btn = createElement('button', {\n type: 'button',\n class: classAttr,\n title: this.context.locale.toolbar[btnDef.name] || btnDef.tooltip || '',\n 'data-btn': btnDef.name,\n 'aria-label': this.context.locale.toolbar[btnDef.name] || btnDef.tooltip || btnDef.name,\n // A button that reports an active state is a toggle, so its state has to\n // be exposed to assistive tech and not only through the `.active` class.\n ...(typeof btnDef.isActive === 'function' ? { 'aria-pressed': 'false' } : {}),\n });\n\n // Render icon: prefer FontAwesome if enabled; otherwise fall back to SVG or text.\n const faPrefix = this.options.fontAwesomeClass || 'fas';\n const useFaNow = this._faReady;\n if (useFaNow) {\n const faName = _FA_MAP.get(btnDef.icon) || _FA_MAP.get(btnDef.name) || null;\n if (faName) {\n btn.innerHTML = `<i class=\"${faPrefix} ${faName}\" aria-hidden=\"true\"></i>`;\n } else if (_SVG_MAP.has(btnDef.icon)) {\n btn.innerHTML = _SVG_MAP.get(btnDef.icon);\n } else {\n btn.textContent = btnDef.icon || btnDef.name;\n }\n } else if (_SVG_MAP.has(btnDef.icon)) {\n // FontAwesome absent: use SVG fallback when available\n btn.innerHTML = _SVG_MAP.get(btnDef.icon);\n } else if (_SVG_MAP.has(btnDef.name)) {\n btn.innerHTML = _SVG_MAP.get(btnDef.name);\n } else {\n btn.textContent = btnDef.icon || btnDef.name;\n }\n\n const disposer = on(btn, 'click', (event) => {\n event.preventDefault();\n // Restore focus to the editor before executing the action\n this.context.invoke('editor.focus');\n btnDef.action(this.context);\n this.context.invoke('editor.afterCommand');\n this.refresh();\n });\n\n this._disposers.push(disposer);\n return /** @type {HTMLButtonElement} */ (btn);\n }\n\n // ---------------------------------------------------------------------------\n // Keyboard navigation — WAI-ARIA toolbar pattern\n // ---------------------------------------------------------------------------\n\n /**\n * Every control the toolbar contains, in visual order. Disabled ones are\n * included so their tabindex can be cleared; `_navigable()` filters them out.\n * @returns {HTMLElement[]}\n */\n _controls() {\n if (!this.el) return [];\n return /** @type {HTMLElement[]} */ (Array.from(this.el.querySelectorAll('button, select')));\n }\n\n /** @returns {HTMLElement[]} controls that can actually receive focus */\n _navigable() {\n return this._controls().filter(\n (el) => !(/** @type {HTMLButtonElement} */ (el).disabled),\n );\n }\n\n /**\n * Enforces the roving-tabindex invariant: exactly one control sits in the tab\n * order and the rest are reached with arrow keys. The default toolbar renders\n * 39 controls, so without this a keyboard user pressed Tab 39 times to get\n * past the toolbar and into the editable area.\n *\n * @param {HTMLElement} [focused] - control that should own the tab stop;\n * omitted on refresh, where the user's current position is preserved.\n */\n _syncRovingTabindex(focused) {\n const all = this._controls();\n const navigable = this._navigable();\n if (!navigable.length) return;\n const active = (focused && navigable.includes(focused))\n ? focused\n : navigable.find((el) => el.getAttribute('tabindex') === '0') || navigable[0];\n all.forEach((el) => el.setAttribute('tabindex', el === active ? '0' : '-1'));\n }\n\n /** Wires arrow-key navigation. Called on build and again after rebuild(). */\n _initRovingFocus() {\n if (!this.el) return;\n this._syncRovingTabindex();\n this._disposers.push(\n on(this.el, 'keydown', (e) => this._onToolbarKeydown(/** @type {KeyboardEvent} */ (e))),\n // Clicking or programmatically focusing a control moves the tab stop with\n // it, so Tab always leaves from wherever the user actually is.\n on(this.el, 'focusin', (e) => {\n const el = /** @type {Element} */ (e.target)?.closest?.('button, select');\n if (el) this._syncRovingTabindex(/** @type {HTMLElement} */ (el));\n }),\n );\n }\n\n /**\n * Home/End jump to the ends; Left/Right step between controls and wrap.\n * Up/Down are deliberately left alone so `<select>` controls keep their\n * native value-changing behaviour.\n * @param {KeyboardEvent} event\n */\n _onToolbarKeydown(event) {\n if (!['ArrowRight', 'ArrowLeft', 'Home', 'End'].includes(event.key)) return;\n const controls = this._navigable();\n const current = /** @type {HTMLElement|null} */ (\n /** @type {Element} */ (event.target)?.closest?.('button, select')\n );\n const idx = current ? controls.indexOf(current) : -1;\n if (idx === -1) return;\n\n let next;\n if (event.key === 'Home') {\n next = controls[0];\n } else if (event.key === 'End') {\n next = controls.at(-1);\n } else {\n // In RTL the arrow that points at the next control is the left one.\n const rtl = this.options.direction === 'rtl';\n const forward = (event.key === 'ArrowRight') !== rtl;\n next = controls[(idx + (forward ? 1 : -1) + controls.length) % controls.length];\n }\n if (!next) return;\n event.preventDefault();\n this._syncRovingTabindex(next);\n next.focus();\n }\n\n // ---------------------------------------------------------------------------\n // FontAwesome detection (run once at initialize time)\n // ---------------------------------------------------------------------------\n\n _detectFontAwesome() {\n if (!this.options.useFontAwesome) return false;\n // Return cached result when available. This ensures that a later-initialised\n // toolbar sees the same detection state as the first one — even if IconDialog\n // has since injected its own FA <link> into <head> for the icon-picker UI.\n if (_faPageLevelReady !== null) return _faPageLevelReady;\n if (document.querySelector('.fa, .fas, .far, .fal, .fab, .fa-solid')) {\n _faPageLevelReady = true;\n return true;\n }\n // Exclude the editor-self-injected link (id='an-fontawesome-css') so it doesn't\n // count as \"the host page loaded FA\" for toolbar icon rendering purposes.\n const links = Array.from(document.querySelectorAll('link[rel=\"stylesheet\"]'))\n .filter((l) => l.id !== 'an-fontawesome-css')\n .map((l) => /** @type {HTMLLinkElement} */ (l).href || '').join(' ');\n _faPageLevelReady = /fontawesome|font-awesome|use\\.fontawesome|all\\.css/.test(links);\n return _faPageLevelReady;\n }\n\n // ---------------------------------------------------------------------------\n // State refresh (active / disabled states)\n // ---------------------------------------------------------------------------\n\n refresh() {\n // Debounce via rAF — multiple rapid calls (e.g. afterCommand + button click)\n // collapse into a single update per animation frame.\n if (this._refreshRaf) cancelAnimationFrame(this._refreshRaf);\n this._refreshRaf = requestAnimationFrame(() => {\n this._refreshRaf = null;\n this._doRefresh();\n });\n }\n\n _doRefresh() {\n if (!this.el) return;\n const btnMap = this._btnMap || new Map();\n\n // Sync button active states\n this.el.querySelectorAll('button[data-btn]').forEach((btn) => {\n const def = btnMap.get(/** @type {HTMLElement} */ (btn).dataset.btn);\n if (def && typeof def.isActive === 'function') {\n const active = !!def.isActive(this.context);\n btn.classList.toggle('active', active);\n btn.setAttribute('aria-pressed', String(active));\n }\n if (def && typeof def.isDisabled === 'function') {\n /** @type {HTMLButtonElement} */ (btn).disabled = !!def.isDisabled(this.context);\n }\n });\n\n // A button disabled just now must not be the one holding the tab stop.\n this._syncRovingTabindex();\n\n // Sync select dropdowns (e.g. font family) with current cursor position\n this.el.querySelectorAll('select[data-btn]').forEach((select) => {\n const def = btnMap.get(/** @type {HTMLElement} */ (select).dataset.btn);\n if (!def || typeof def.getValue !== 'function') return;\n // queryCommandValue returns the font name, possibly quoted — strip quotes\n let raw = (def.getValue(this.context) || '').replace(/[\"']/g, '').trim();\n // Fallback: when no selection/font set, use the configured default font\n if (!raw) {\n raw = this.options.defaultFontFamily\n || this.options.fontFamilies?.[0]\n || '';\n }\n // Try to match against available options (case-insensitive)\n const sel = /** @type {HTMLSelectElement} */ (select);\n const matched = Array.from(sel.options).find(\n (opt) => opt.value?.toLowerCase() === raw.toLowerCase()\n );\n sel.value = matched ? matched.value : '';\n });\n }\n\n /**\n * Shows the toolbar.\n */\n show() {\n if (this.el) this.el.style.display = '';\n }\n\n /**\n * Hides the toolbar.\n */\n hide() {\n if (this.el) this.el.style.display = 'none';\n }\n\n /**\n * Tears down and re-renders the toolbar in-place.\n * Call after registering new buttons post-create via context.use(plugin)\n * or AutumnNote.registerButton() to make them appear in the toolbar.\n */\n rebuild() {\n if (this._refreshRaf) { cancelAnimationFrame(this._refreshRaf); this._refreshRaf = null; }\n this._disposers.forEach((d) => d());\n this._disposers = [];\n if (this.el) this.el.innerHTML = '';\n this._faReady = this._detectFontAwesome();\n this._buildButtons();\n // rebuild() cleared the disposers, taking the keydown/focusin listeners\n // with them — re-arm navigation over the new controls.\n this._initRovingFocus();\n this._btnMap = new Map(\n (this.options.toolbar || []).flat()\n .map(_resolveBtn).filter(Boolean).map((b) => [b.name, b]),\n );\n this.refresh();\n }\n}\n","/**\n * Statusbar.js - Displays word count, character count and resize handle\n * Inspired by Summernote's Statusbar module — rewritten without jQuery\n */\n\nimport { createElement, on } from '../core/dom.js';\n\n// Cache the segmenter instance at module level to avoid per-call allocation\nconst _segmenter =\n typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function'\n ? new Intl.Segmenter(undefined, { granularity: 'word' })\n : null;\n\n/**\n * Count words in a string, CJK-aware.\n * Uses Intl.Segmenter (Chromium 87+, Firefox 125+, Safari 17+) when available,\n * falling back to a simple whitespace split for older environments.\n * @param {string} text\n * @returns {number}\n */\nfunction _countWords(text) {\n const trimmed = text.trim();\n if (!trimmed) return 0;\n if (_segmenter) {\n let count = 0;\n for (const seg of _segmenter.segment(trimmed)) {\n if (seg.isWordLike) count++;\n }\n return count;\n }\n // Fallback: split on whitespace\n return trimmed.split(/\\s+/).length;\n}\n\n/**\n * Elements that start a new line of text. Used to join content the way the\n * reader sees it: `textContent` glues `<p>hello</p><p>world</p>` into\n * \"helloworld\", which any word counter then reports as one word.\n */\nconst BLOCK_TAGS = new Set([\n 'ADDRESS', 'ARTICLE', 'ASIDE', 'BLOCKQUOTE', 'BR', 'DD', 'DIV', 'DL', 'DT',\n 'FIELDSET', 'FIGCAPTION', 'FIGURE', 'FOOTER', 'FORM', 'H1', 'H2', 'H3', 'H4',\n 'H5', 'H6', 'HEADER', 'HR', 'LI', 'MAIN', 'NAV', 'OL', 'P', 'PRE', 'SECTION',\n 'TABLE', 'TBODY', 'TD', 'TFOOT', 'TH', 'THEAD', 'TR', 'UL',\n]);\n\n/**\n * Appends `node`'s text into `lines` with a newline at every block boundary,\n * and into `flat` without one.\n *\n * `lines` is what `innerText` gives, minus `innerText`'s forced layout pass —\n * the counters run on every keystroke, so a reflow per character is not on.\n * `flat` is exactly what `textContent` gives, produced by the same walk so the\n * cold path does not traverse the subtree twice to get both.\n * @param {Node} node\n * @param {string[]} lines\n * @param {string[]} flat\n */\nfunction _collectText(node, lines, flat) {\n for (let child = node.firstChild; child; child = child.nextSibling) {\n if (child.nodeType === 3) {\n const data = /** @type {Text} */ (child).data;\n lines.push(data);\n flat.push(data);\n } else if (child.nodeType === 1) {\n const block = BLOCK_TAGS.has(/** @type {Element} */ (child).tagName);\n if (block) lines.push('\\n');\n _collectText(child, lines, flat);\n if (block) lines.push('\\n');\n }\n }\n}\n\n/**\n * Both readings of a subtree's text: block-aware for counting words, flat for\n * matching `textContent`.\n * @param {Node} node\n * @returns {{ lines: string, flat: string }}\n */\nfunction readText(node) {\n if (node.nodeType === 3) {\n const data = /** @type {Text} */ (node).data;\n return { lines: data, flat: data };\n }\n /** @type {string[]} */ const lines = [];\n /** @type {string[]} */ const flat = [];\n _collectText(node, lines, flat);\n return { lines: lines.join(''), flat: flat.join('') };\n}\n\n/**\n * Toggles warning/exceeded CSS classes on a count element.\n * @param {HTMLElement} el\n * @param {number} current\n * @param {number} limit 0 = no limit\n */\nfunction _applyLimitClass(el, current, limit) {\n if (!limit) {\n el.classList.remove('an-count-warn', 'an-count-exceeded');\n return;\n }\n if (current > limit) {\n el.classList.add('an-count-exceeded');\n el.classList.remove('an-count-warn');\n } else if (current >= limit * 0.9) {\n el.classList.add('an-count-warn');\n el.classList.remove('an-count-exceeded');\n } else {\n el.classList.remove('an-count-warn', 'an-count-exceeded');\n }\n}\n\nexport class Statusbar {\n /**\n * @param {import('../Context.js').Context} context\n */\n constructor(context) {\n this.context = context;\n this.options = context.options;\n /** @type {HTMLElement|null} */\n this.el = null;\n this._disposers = [];\n /** @type {HTMLElement|null} */\n this._wordCountEl = null;\n /** @type {HTMLElement|null} */\n this._charCountEl = null;\n /**\n * Per-child word/char counts, keyed on the child node itself so removed\n * nodes fall out with no bookkeeping.\n * @type {WeakMap<Node, {key: string, words: number, chars: number}>}\n */\n this._countCache = new WeakMap();\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n initialize() {\n this.el = createElement('div', { class: 'an-statusbar' });\n\n // Resize handle\n if (this.options.resizable !== false) {\n const handle = createElement('div', {\n class: 'an-resize-handle',\n title: this.context.locale.statusbar.resizeHandle,\n 'aria-hidden': 'true',\n });\n this._bindResize(handle);\n this.el.appendChild(handle);\n }\n\n // Counters\n this._wordCountEl = createElement('span', { class: 'an-word-count', role: 'status', 'aria-live': 'polite', 'aria-atomic': 'true' });\n this._charCountEl = createElement('span', { class: 'an-char-count', 'aria-live': 'polite', 'aria-atomic': 'true' });\n const info = createElement('div', { class: 'an-status-info', 'aria-label': 'Editor statistics' });\n info.appendChild(this._wordCountEl);\n info.appendChild(this._charCountEl);\n this.el.appendChild(info);\n\n this.update();\n return this;\n }\n\n destroy() {\n this._disposers.forEach((d) => d());\n this._disposers = [];\n if (this._dragDisposers) {\n this._dragDisposers.forEach((d) => d());\n this._dragDisposers = null;\n }\n this.el?.remove();\n this.el = null;\n }\n\n // ---------------------------------------------------------------------------\n // Resize logic\n // ---------------------------------------------------------------------------\n\n _bindResize(handle) {\n let startY = 0;\n let startH = 0;\n // Resize the container (flex column parent) so that the editable — which\n // has flex:1 / flex-basis:0 — automatically fills the remaining space.\n // Setting height directly on a flex:1 item has no effect because the flex\n // algorithm ignores the height property when flex-basis is non-auto.\n const containerEl = this.context.layoutInfo.container;\n\n const applyDelta = (clientY) => {\n const delta = clientY - startY;\n // Compute the true minimum: fixed elements (toolbar + statusbar) must fit\n // inside the container. Sum the offsetHeight of every child that is NOT\n // the editable area, then add a small floor so the editable stays visible.\n const MIN_EDITABLE = 40;\n const fixedH = Array.from(containerEl.children)\n .filter(child => !child.classList.contains('an-editable'))\n .reduce((sum, child) => sum + /** @type {HTMLElement} */ (child).offsetHeight, 0);\n const trueMin = Math.max(this.options.minHeight || 100, fixedH + MIN_EDITABLE);\n containerEl.style.height = `${Math.max(trueMin, startH + delta)}px`;\n };\n\n // Mouse drag\n const onMouseMove = (event) => applyDelta(event.clientY);\n\n const onMouseUp = () => {\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n this._dragDisposers = null;\n };\n\n const onMouseDown = (event) => {\n startY = event.clientY;\n startH = containerEl.offsetHeight;\n // Clear the editable's inline min-height so the flex layout can compress\n // it freely once the container has a fixed height. Without this, the\n // editable's min-height (set from options.height) overflows the container\n // when the user drags the handle to a size smaller than that value.\n this.context.layoutInfo.editable.style.minHeight = '';\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n // Track drag-phase listeners so destroy() can remove them mid-drag\n this._dragDisposers = [\n () => document.removeEventListener('mousemove', onMouseMove),\n () => document.removeEventListener('mouseup', onMouseUp),\n ];\n event.preventDefault();\n };\n\n // Touch drag\n const onTouchMove = (event) => {\n const touch = event.touches[0];\n if (touch) { event.preventDefault(); applyDelta(touch.clientY); }\n };\n\n const onTouchEnd = () => {\n document.removeEventListener('touchmove', onTouchMove);\n document.removeEventListener('touchend', onTouchEnd);\n this._dragDisposers = null;\n };\n\n const onTouchStart = (event) => {\n const touch = event.touches[0];\n if (!touch) return;\n startY = touch.clientY;\n startH = containerEl.offsetHeight;\n // Same as onMouseDown: clear editable min-height so flex can compress it\n this.context.layoutInfo.editable.style.minHeight = '';\n document.addEventListener('touchmove', onTouchMove, { passive: false });\n document.addEventListener('touchend', onTouchEnd);\n this._dragDisposers = [\n () => document.removeEventListener('touchmove', onTouchMove),\n () => document.removeEventListener('touchend', onTouchEnd),\n ];\n };\n\n const d1 = on(handle, 'mousedown', onMouseDown);\n const d2 = on(handle, 'touchstart', onTouchStart);\n this._disposers.push(d1, d2);\n }\n\n // ---------------------------------------------------------------------------\n // Counter update\n // ---------------------------------------------------------------------------\n\n // Editor.afterCommand() already invokes 'statusbar.update' on every native\n // 'input' event and after every toolbar/formatting command, so a separate\n // content listener here would just re-run this on the same keystroke.\n /**\n * Word and character counts for the current content.\n *\n * Counts are cached per top-level child and reused while that child's text is\n * unchanged, because `Intl.Segmenter` over the whole document was the single\n * most expensive thing the editor did per keystroke — 6.4 ms of a 6.7 ms\n * `afterCommand` on a 217 KiB document. A keystroke changes one child, so\n * only that child is re-segmented; the rest costs a string comparison.\n *\n * Children that do miss are segmented together in one pass rather than one\n * call each. `Intl.Segmenter.segment()` carries enough per-call setup that\n * 1200 small calls cost roughly three times a single large one, so the cold\n * path — `setHTML`, paste, undo of a big edit — would otherwise pay for the\n * warm path's speed.\n * @returns {{ words: number, chars: number }}\n */\n _counts() {\n const editable = this.context.layoutInfo.editable;\n let words = 0;\n let chars = 0;\n /** @type {{node: Node, key: string, text: string, start: number}[]} */\n const cold = [];\n /** @type {string[]} */\n const parts = [];\n let offset = 0;\n\n for (let node = editable.firstChild; node; node = node.nextSibling) {\n const hit = this._countCache.get(node);\n // The flat text is the change key. Read it from the node only when there\n // is an entry that could still be valid; a node with no entry is being\n // walked anyway, and that walk yields the same string for free.\n if (hit && hit.key === (node.textContent || '')) {\n words += hit.words;\n chars += hit.chars;\n continue;\n }\n const { lines, flat } = readText(node);\n cold.push({ node, key: flat, text: lines, start: offset });\n parts.push(lines);\n offset += lines.length + 1; // +1 for the newline the join inserts\n }\n\n if (cold.length) {\n const counts = this._countBatch(cold, parts.join('\\n'));\n cold.forEach((child, i) => {\n const entry = {\n key: child.key,\n words: counts[i],\n // Newlines are separators, not characters the reader typed — and the\n // ones inside a <pre> were never counted either.\n chars: child.key.replaceAll('\\n', '').length,\n };\n this._countCache.set(child.node, entry);\n words += entry.words;\n chars += entry.chars;\n });\n }\n\n return { words, chars };\n }\n\n /**\n * Word counts for each cold child, from a single pass over their joined text.\n *\n * The children are joined with a newline, which is a word boundary in every\n * script, so no word can be counted across two of them. Segments arrive in\n * increasing offset order, so attributing each one is a walk, not a search.\n * @param {{start: number, text: string}[]} cold\n * @param {string} joined\n * @returns {number[]}\n */\n _countBatch(cold, joined) {\n if (!_segmenter) return cold.map((c) => _countWords(c.text));\n const counts = new Array(cold.length).fill(0);\n let i = 0;\n for (const seg of _segmenter.segment(joined)) {\n if (!seg.isWordLike) continue;\n while (i < cold.length - 1 && seg.index >= cold[i + 1].start) i++;\n counts[i]++;\n }\n return counts;\n }\n\n update() {\n if (!this._wordCountEl || !this._charCountEl) return;\n const { words, chars } = this._counts();\n const maxWords = this.options.maxWords || 0;\n const maxChars = this.options.maxChars || 0;\n\n const LS = this.context.locale.statusbar;\n this._wordCountEl.textContent = maxWords\n ? LS.wordsLimit(words, maxWords)\n : LS.words(words);\n this._charCountEl.textContent = maxChars\n ? LS.charsLimit(chars, maxChars)\n : LS.chars(chars);\n\n // Apply warning / exceeded styles\n _applyLimitClass(this._wordCountEl, words, maxWords);\n _applyLimitClass(this._charCountEl, chars, maxChars);\n }\n\n /**\n * Returns the current word count of the editor content.\n * @returns {number}\n */\n getWordCount() {\n return this._counts().words;\n }\n\n /**\n * Returns the current character count (excluding newlines) of the editor content.\n * @returns {number}\n */\n getCharCount() {\n return this._counts().chars;\n }\n}\n","/**\n * Clipboard.js - Handles paste events to strip unwanted formatting,\n * and paste/drop of image files.\n * Inspired by Summernote's Clipboard module\n */\n\nimport { on } from '../core/dom.js';\nimport { execCommand } from '../editing/Style.js';\nimport { sanitiseHTML, sanitiseUrl } from '../core/sanitise.js';\nimport { isMarkdown, markdownToHTML } from '../core/markdown.js';\n\nexport class Clipboard {\n /**\n * @param {import('../Context.js').Context} context\n */\n constructor(context) {\n this.context = context;\n this.options = context.options;\n this._disposers = [];\n }\n\n initialize() {\n /** @type {Map<string, string>} Maps blob: URL (in DOM) → data: URL (serialisable) */\n this._blobRegistry = new Map();\n /** @type {boolean} Set to true by Ctrl+Shift+V shortcut to force one-shot plain paste */\n this._forcePlain = false;\n const editable = this.context.layoutInfo.editable;\n this._disposers.push(\n on(editable, 'paste', (e) => this._onPaste(e)),\n on(editable, 'dragover', (e) => this._onDragover(e)),\n on(editable, 'drop', (e) => this._onDrop(e)),\n );\n\n // Watch for removed images so their blob: URLs are revoked immediately,\n // preventing memory leaks during long editing sessions.\n this._mutationObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of mutation.removedNodes) {\n this._revokeRemovedBlobs(node);\n }\n }\n });\n this._mutationObserver.observe(editable, { childList: true, subtree: true });\n\n return this;\n }\n\n destroy() {\n this._disposers.forEach((d) => d());\n this._disposers = [];\n if (this._mutationObserver) {\n this._mutationObserver.disconnect();\n this._mutationObserver = null;\n }\n // Release any remaining object URLs\n if (this._blobRegistry) {\n this._blobRegistry.forEach((_, blobUrl) => URL.revokeObjectURL(blobUrl));\n this._blobRegistry.clear();\n }\n // Previews for uploads still in flight when the editor went away.\n if (this._uploadPreviews) {\n this._uploadPreviews.forEach(({ previewUrl }) => URL.revokeObjectURL(previewUrl));\n this._uploadPreviews.clear();\n }\n }\n\n /**\n * Revokes blob URLs for any <img> elements removed from the DOM.\n * @param {Node} node\n */\n _revokeRemovedBlobs(node) {\n if (!this._blobRegistry?.size) return;\n const imgs = /** @type {Element[]} */ ([]);\n if (node.nodeName === 'IMG') {\n imgs.push(/** @type {Element} */ (node));\n } else if (/** @type {Element} */ (node).querySelectorAll) {\n imgs.push(.../** @type {Element} */ (node).querySelectorAll('img'));\n }\n imgs.forEach((img) => {\n const src = img.getAttribute('src') || '';\n if (src.startsWith('blob:') && this._blobRegistry.has(src)) {\n URL.revokeObjectURL(src);\n this._blobRegistry.delete(src);\n }\n });\n }\n\n // ---------------------------------------------------------------------------\n // Paste handler\n // ---------------------------------------------------------------------------\n\n /**\n * Strips Microsoft Word / Office HTML artefacts from a pasted HTML string.\n * Removes conditional comments, Office namespace elements, MsoXxx classes,\n * mso-* inline style rules, and empty paragraphs left behind by Word.\n * @param {string} html\n * @returns {string}\n */\n _cleanWordHtml(html) {\n return html\n // Conditional comments <!--[if ...]>...<![endif]-->\n .replace(/<!--\\[if[\\s\\S]*?\\[endif\\]-->/gi, '')\n // XML data blobs <xml>...</xml>\n .replace(/<xml[\\s\\S]*?<\\/xml>/gi, '')\n // XML processing instructions <?xml ... ?>\n .replace(/<\\?xml[\\s\\S]*?\\?>/gi, '')\n // Office namespace elements: <o:p>, <w:sDt>, <m:oMath>, <v:shape> …\n .replace(/<\\/?(o|w|m|v|st1):[a-z][^>]*>/gi, '')\n // MsoNormal, MsoBodyText, etc. class attributes\n .replace(/\\s+class=\"Mso[^\"]*\"/gi, '')\n // mso-* properties inside inline style attributes\n .replace(/\\s+style=\"([^\"]*)\"/gi, (_m, style) => {\n const cleaned = style.split(';')\n .map((s) => s.trim())\n .filter((s) => s && !/^mso-/i.test(s) && !/^(tab-stops|margin-[a-z]+-alt)/i.test(s))\n .join('; ');\n return cleaned ? ` style=\"${cleaned}\"` : '';\n })\n // Empty paragraphs Word sprinkles everywhere\n .replace(/<p[^>]*>\\s*( )?\\s*<\\/p>/gi, '');\n }\n\n /**\n * Detects and strips noise from social media sites (Facebook, X/Twitter, LinkedIn, etc.).\n * These React-based pages produce HTML with utility class names like `x1n2onr6` / `r-bcqeeo`,\n * `data-testid`, `data-lexical-*`, etc. We keep the semantic structure but remove all the noise.\n * @param {string} html\n * @returns {string}\n */\n _cleanSocialHtml(html) {\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, 'text/html');\n // Unwrap purely presentational wrapper spans/divs with no semantic meaning.\n // Single-pass reverse traversal: querySelectorAll returns elements in document\n // order, so iterating backwards processes innermost elements first — once a\n // child is unwrapped its parent may become unwrappable in the same pass.\n // This replaces the previous O(n²) while-loop that re-queried the whole tree\n // on every iteration.\n const candidates = Array.from(doc.querySelectorAll('span, div'));\n for (let i = candidates.length - 1; i >= 0; i--) {\n const el = candidates[i];\n if (!el.parentNode) continue; // already detached by an earlier iteration\n // Keep if it contains any semantic child element\n if (el.querySelector('a, strong, em, b, i, ul, ol, li, table, img, blockquote, pre, code, h1, h2, h3, h4, h5, h6')) continue;\n // Unwrap — replace el with its children\n const parent = el.parentNode;\n while (el.firstChild) parent.insertBefore(el.firstChild, el);\n el.remove();\n }\n // Strip class and all data-* attributes from every remaining element\n doc.querySelectorAll('*').forEach((el) => {\n el.removeAttribute('class');\n el.removeAttribute('id');\n Array.from(el.attributes)\n .filter((a) => a.name.startsWith('data-') || a.name.startsWith('aria-'))\n .forEach((a) => el.removeAttribute(a.name));\n });\n return doc.body.innerHTML;\n }\n\n /**\n * Strips presentational attributes (class, style, data-*, id) from all elements,\n * keeping only semantic structure and URL attributes.\n * Used when `pasteStripAttributes` option is true.\n * @param {string} html\n * @returns {string}\n */\n _stripAttributes(html) {\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, 'text/html');\n const KEEP_ATTRS = new Set(['href', 'src', 'alt', 'target', 'rel', 'colspan', 'rowspan', 'type']);\n doc.querySelectorAll('*').forEach((el) => {\n Array.from(el.attributes)\n .filter((a) => !KEEP_ATTRS.has(a.name))\n .forEach((a) => el.removeAttribute(a.name));\n });\n return doc.body.innerHTML;\n }\n\n /**\n * Normalizes task lists from external sources (GitHub, GitLab, etc.) so they\n * pass the sanitiser's `ul.an-checklist` guard. Runs before sanitiseHTML().\n * @param {string} html\n * @returns {string}\n */\n _normalizeExternalTaskLists(html) {\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, 'text/html');\n for (const cb of doc.querySelectorAll('input[type=\"checkbox\"]')) {\n const li = cb.closest('li');\n const ul = li?.closest('ul');\n if (!li || !ul || ul.classList.contains('an-checklist')) continue;\n ul.classList.add('an-checklist');\n cb.removeAttribute('disabled');\n cb.setAttribute('contenteditable', 'false');\n for (const attr of Array.from(cb.attributes)) {\n if (!['type', 'checked', 'contenteditable'].includes(attr.name)) {\n cb.removeAttribute(attr.name);\n }\n }\n }\n return doc.body.innerHTML;\n }\n\n /**\n * Checks whether an HTML payload has no semantic markup beyond plain\n * wrapper elements (e.g. a bare <div>/<p>). Used to decide whether a\n * markdown-shaped plain-text paste should win over an accompanying HTML\n * payload that isn't actually carrying any real rich-text formatting.\n * @param {string} html\n * @returns {boolean}\n */\n _isTriviallyPlainHtml(html) {\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, 'text/html');\n const SIGNIFICANT = 'a,img,table,ul,ol,li,blockquote,pre,code,h1,h2,h3,h4,h5,h6,strong,b,em,i,u,s,del,strike,hr,br';\n return !doc.body.querySelector(SIGNIFICANT);\n }\n\n /**\n * Forces the next paste operation to strip all HTML formatting.\n * Called by Editor when Ctrl+Shift+V is pressed.\n * @param {boolean} val\n */\n setForcePlain(val) {\n this._forcePlain = !!val;\n }\n\n _onPaste(event) {\n const clipboardData = event.clipboardData || /** @type {any} */ (globalThis).clipboardData;\n if (!clipboardData) return;\n\n // Consume and reset the one-shot plain-paste flag\n const forcePlain = this._forcePlain;\n this._forcePlain = false;\n\n // Enforce maxPasteSize limit (default 5 MB)\n const maxBytes = (this.options.maxPasteSize ?? 5) * 1024 * 1024;\n if (maxBytes > 0) {\n const text = clipboardData.getData('text/plain') || '';\n const html = clipboardData.getData('text/html') || '';\n const size = Math.max(text.length, html.length);\n if (size > maxBytes) {\n event.preventDefault();\n const message = `Pasted content (${size} bytes) exceeds the ${this.options.maxPasteSize ?? 5} MB paste size limit.`;\n this.context.triggerEvent('pasteError', { size, maxBytes, message });\n console.warn(`[AutumnNote] ${message}`);\n return;\n }\n }\n\n // 1. Image file in clipboard (screenshot, copy-image-from-browser, etc.)\n if (clipboardData.items) {\n const imageItems = Array.from(clipboardData.items).filter(\n (item) => item.kind === 'file' && item.type.startsWith('image/'),\n );\n if (imageItems.length > 0) {\n event.preventDefault();\n const files = imageItems.map((item) => item.getAsFile()).filter(Boolean);\n this._insertImageFiles(files);\n return;\n }\n }\n\n // Fire onPaste hook so consumers can observe / intercept\n if (typeof this.options.onPaste === 'function') {\n this.options.onPaste({\n text: clipboardData.getData('text/plain') || '',\n html: clipboardData.types.includes('text/html') ? clipboardData.getData('text/html') : null,\n });\n }\n\n // 2. Force plain-text only — strip all formatting\n if (forcePlain || this.options.pasteAsPlainText) {\n event.preventDefault();\n const text = clipboardData.getData('text/plain');\n const html = text\n .split(/\\r?\\n/)\n .map((line) => `<p>${this._escapeHTML(line) || '<br>'}</p>`)\n .join('');\n execCommand('insertHTML', html);\n this.context.invoke('editor.afterCommand');\n return;\n }\n\n // 3. Markdown paste — when there's no HTML on the clipboard, or the\n // accompanying HTML has no semantic markup (e.g. some terminal/clipboard\n // tools put both a markdown-shaped text/plain and a trivial <div>-wrapped\n // text/html on the clipboard). Real rich-text sources (Word, Docs, etc.)\n // always have semantic tags after cleaning, so this is unaffected.\n if (this.options.markdownPaste !== false) {\n const hasHtml = clipboardData.types.includes('text/html');\n const html = hasHtml ? clipboardData.getData('text/html') : '';\n const htmlTriviallyPlain = !hasHtml || this._isTriviallyPlainHtml(html);\n const text = clipboardData.getData('text/plain');\n if (text && htmlTriviallyPlain && isMarkdown(text)) {\n event.preventDefault();\n const converted = sanitiseHTML(markdownToHTML(text));\n execCommand('insertHTML', converted);\n this.context.invoke('editor.afterCommand');\n return;\n }\n }\n\n // 4. Sanitise HTML on paste when pasteCleanHTML is true (default)\n if (this.options.pasteCleanHTML !== false && clipboardData.types.includes('text/html')) {\n event.preventDefault();\n const raw = clipboardData.getData('text/html');\n // Detect source type and apply appropriate pre-cleaner\n const isWordContent = /<[a-z]+:[a-z]/i.test(raw) || /class=\"Mso/i.test(raw) || /\\bmso-/i.test(raw);\n const isSocialContent = /class=\"[^\"]*\\b(?:x[a-z0-9]{6,}|r-[a-z0-9]{3,})\\b/.test(raw);\n let html = raw;\n if (isWordContent) html = this._cleanWordHtml(html);\n else if (isSocialContent) html = this._cleanSocialHtml(html);\n html = this._normalizeExternalTaskLists(html);\n html = sanitiseHTML(html);\n if (this.options.pasteStripAttributes) html = this._stripAttributes(html);\n execCommand('insertHTML', html);\n this.context.invoke('editor.afterCommand');\n }\n\n // Otherwise let the browser handle paste natively\n }\n\n // ---------------------------------------------------------------------------\n // Drag & drop handlers\n // ---------------------------------------------------------------------------\n\n _onDragover(event) {\n if (!event.dataTransfer) return;\n const types = Array.from(event.dataTransfer.types || []);\n if (types.includes('Files')) {\n event.preventDefault();\n event.dataTransfer.dropEffect = 'copy';\n }\n }\n\n _onDrop(event) {\n const dt = event.dataTransfer;\n if (!dt?.files?.length) return;\n\n const imageFiles = Array.from(dt.files).filter((f) => f.type.startsWith('image/'));\n if (imageFiles.length > 0) {\n event.preventDefault();\n event.stopPropagation();\n // Place the caret at the drop coordinates before inserting\n this._placeCaretAtPoint(event.clientX, event.clientY);\n this._insertImageFiles(imageFiles);\n return;\n }\n\n if (this.options.markdownPaste !== false) {\n const mdFile = Array.from(dt.files).find((f) => /\\.md$/i.test(f.name) || f.type === 'text/markdown');\n if (mdFile) {\n event.preventDefault();\n event.stopPropagation();\n this._placeCaretAtPoint(event.clientX, event.clientY);\n this._insertMarkdownFile(mdFile);\n }\n }\n }\n\n /**\n * Reads a dropped `.md` File and inserts it converted to HTML at the\n * current caret. Skips the isMarkdown() heuristic — an explicit `.md`\n * extension/MIME type is an unambiguous signal, unlike pasted plain text.\n * @param {File} file\n */\n _insertMarkdownFile(file) {\n const maxBytes = (this.options.maxPasteSize ?? 5) * 1024 * 1024;\n if (maxBytes > 0 && file.size > maxBytes) {\n const message = `Dropped file \"${file.name}\" (${file.size} bytes) exceeds the ${this.options.maxPasteSize ?? 5} MB paste size limit.`;\n this.context.triggerEvent('pasteError', { size: file.size, maxBytes, message });\n console.warn(`[AutumnNote] ${message}`);\n return;\n }\n const reader = new FileReader();\n reader.onload = (e) => {\n const html = sanitiseHTML(markdownToHTML(/** @type {string} */ (e.target.result) || ''));\n execCommand('insertHTML', html);\n this.context.invoke('editor.afterCommand');\n };\n reader.onerror = () => {\n const message = `Failed to read dropped markdown file \"${file.name}\".`;\n console.warn(`[AutumnNote] ${message}`);\n this.context.triggerEvent('pasteError', { message });\n };\n reader.readAsText(file);\n }\n\n // ---------------------------------------------------------------------------\n // Image file processing — shared by paste and drop\n // ---------------------------------------------------------------------------\n\n /**\n * Inserts one or more image Files into the editor.\n * Delegates to `options.onImageUpload` when provided; otherwise compresses\n * and embeds as base64.\n * @param {File[]} files\n */\n _insertImageFiles(files) {\n if (!files || files.length === 0) return;\n\n if (typeof this.options.onImageUpload === 'function') {\n this._runUploadHandler(files);\n return;\n }\n\n // C2: Reject image formats that browsers cannot decode/display.\n const UNSUPPORTED = new Set(['image/tiff', 'image/x-tiff', 'image/bmp', 'image/x-bmp', 'image/x-ms-bmp']);\n const maxBytes = (this.options.maxImageSize || 5) * 1024 * 1024;\n files.forEach((file) => {\n if (!file?.type?.startsWith('image/')) return;\n if (UNSUPPORTED.has(file.type)) {\n const message = `Image format \"${file.type}\" is not supported for display in web browsers. Please convert to PNG, JPEG, or WebP first.`;\n this.context.triggerEvent('imageError', { file, message });\n console.warn('[AutumnNote]', message);\n return;\n }\n if (file.size > maxBytes) {\n const message = `Image \"${file.name}\" exceeds the ${this.options.maxImageSize || 5} MB size limit.`;\n this.context.triggerEvent('imageError', { file, message });\n console.warn(`[AutumnNote] ${message}`);\n return;\n }\n\n const alt = file.name.replace(/\\.[^.]+$/, '');\n this.compressAndRegister(file).then((blobUrl) => {\n this.context.invoke('editor.insertImage', blobUrl, alt);\n }).catch((err) => {\n const message = `Image \"${file.name}\" could not be processed.`;\n this.context.triggerEvent('imageError', { file, message, error: err });\n console.warn('[AutumnNote]', message, err);\n });\n });\n }\n\n /**\n * Escapes a value for use inside a double-quoted HTML attribute.\n * @param {string} v\n * @returns {string}\n */\n _escapeAttr(v) {\n return String(v)\n .replaceAll('&', '&')\n .replaceAll('\"', '"')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n }\n\n /**\n * Runs `options.onImageUpload` and, when it reports back, places the images\n * it uploaded.\n *\n * The handler has always been called with the dropped files; what it could\n * not do was hand the resulting URL back, so every integration that uploaded\n * to its own storage had to insert the image itself. Returning a URL — or a\n * promise of one — now inserts a placeholder immediately and swaps the real\n * URL in when it arrives.\n *\n * A handler that returns nothing keeps the old behaviour exactly: nothing is\n * inserted and no placeholder appears.\n * @param {File[]} files\n */\n async _runUploadHandler(files) {\n const helpers = {\n context: this.context,\n setProgress: (file, ratio) => this._setUploadProgress(file, ratio),\n };\n\n let result;\n try {\n result = this.options.onImageUpload(files, helpers);\n } catch (error) {\n this._reportUploadError(files, error);\n return;\n }\n\n // Legacy contract: the handler inserts the image itself.\n if (result === undefined) return;\n\n // Placeholders go in synchronously, before the promise is awaited, so the\n // image appears at the caret the moment it is dropped.\n const tokens = files.map((file) => this._insertUploadPlaceholder(file));\n\n let urls;\n try {\n urls = await result;\n } catch (error) {\n tokens.forEach((token, i) => this._failUpload(token, files[i], error));\n return;\n }\n\n const list = Array.isArray(urls) ? urls : [urls];\n tokens.forEach((token, i) => {\n const url = list[i];\n if (typeof url === 'string' && url) this._resolveUpload(token, url);\n // A handler that returned fewer URLs than files leaves the rest failed\n // rather than silently dropping a placeholder mid-document.\n else this._failUpload(token, files[i], new Error('No URL returned for this file.'));\n });\n }\n\n /**\n * Inserts a dimmed placeholder for a file being uploaded, previewing the\n * local file so the user sees what is on its way up.\n * @param {File} file\n * @returns {string} token identifying the placeholder\n */\n _insertUploadPlaceholder(file) {\n const token = `an-up-${Date.now().toString(36)}-${this._uploadSeq = (this._uploadSeq || 0) + 1}`;\n const previewUrl = URL.createObjectURL(file);\n this._uploadPreviews = this._uploadPreviews || new Map();\n this._uploadPreviews.set(token, { previewUrl, file });\n\n const alt = this._escapeAttr(file.name.replace(/\\.[^.]+$/, ''));\n execCommand('insertHTML',\n `<img src=\"${this._escapeAttr(previewUrl)}\" alt=\"${alt}\" class=\"an-image an-image-uploading\" data-an-upload=\"${token}\">`);\n this.context.invoke('editor.afterCommand');\n return token;\n }\n\n /** @param {string} token @returns {HTMLImageElement|null} */\n _findPlaceholder(token) {\n return /** @type {HTMLImageElement|null} */ (\n this.context.layoutInfo.editable?.querySelector(`img[data-an-upload=\"${token}\"]`) ?? null\n );\n }\n\n /**\n * Swaps a placeholder over to the uploaded URL.\n * @param {string} token\n * @param {string} url\n */\n _resolveUpload(token, url) {\n const img = this._findPlaceholder(token);\n const entry = this._uploadPreviews?.get(token);\n if (img) {\n const safe = sanitiseUrl(url, { allowData: true });\n if (safe) {\n img.setAttribute('src', safe);\n img.classList.remove('an-image-uploading');\n img.removeAttribute('data-an-upload');\n img.style.removeProperty('--an-upload-progress');\n } else {\n this._failUpload(token, entry?.file, new Error(`Rejected image URL: ${url}`));\n return;\n }\n }\n if (entry) {\n URL.revokeObjectURL(entry.previewUrl);\n this._uploadPreviews.delete(token);\n }\n this.context.invoke('editor.afterCommand');\n }\n\n /**\n * Marks a placeholder as failed and reports it. The preview is kept so the\n * user can still see which image did not make it; `retry` re-runs the\n * handler for that one file.\n * @param {string} token\n * @param {File|undefined} file\n * @param {unknown} error\n */\n _failUpload(token, file, error) {\n const img = this._findPlaceholder(token);\n if (img) {\n img.classList.remove('an-image-uploading');\n img.classList.add('an-image-failed');\n img.style.removeProperty('--an-upload-progress');\n }\n const message = `Image \"${file?.name ?? 'unknown'}\" could not be uploaded.`;\n console.warn('[AutumnNote]', message, error);\n this.context.triggerEvent('imageError', {\n file,\n message,\n error,\n retry: () => {\n img?.remove();\n this._uploadPreviews?.delete(token);\n if (file) this._runUploadHandler([file]);\n },\n });\n }\n\n /** Reports a handler that threw before any placeholder existed. */\n _reportUploadError(files, error) {\n const message = 'The image upload handler threw before any file was sent.';\n console.warn('[AutumnNote]', message, error);\n this.context.triggerEvent('imageError', { file: files[0], message, error });\n }\n\n /**\n * Records upload progress for a file, as a 0–1 ratio. Exposed to the handler\n * so a consumer with a progress-reporting transport can drive the indicator.\n * @param {File} file\n * @param {number} ratio\n */\n _setUploadProgress(file, ratio) {\n if (!this._uploadPreviews) return;\n const clamped = Math.max(0, Math.min(1, Number(ratio) || 0));\n for (const [token, entry] of this._uploadPreviews) {\n if (entry.file !== file) continue;\n const img = this._findPlaceholder(token);\n if (img) img.style.setProperty('--an-upload-progress', String(clamped));\n return;\n }\n }\n\n /**\n * Compresses an image File via canvas and registers the result behind a\n * lightweight blob: URL (see `resolveImages`), so callers never have to hold\n * the full base64 string in the DOM. Shared by paste/drop and ImageDialog's\n * file picker so every image-insertion path gets the same compression.\n * @param {File} file\n * @returns {Promise<string>} blob: URL usable as an <img src>\n */\n async compressAndRegister(file) {\n const processor = this.options.imageProcessor;\n const dataUrl = typeof processor === 'function'\n ? await processor(file, { context: this.context })\n : await this._compressImage(file);\n const blob = this._dataUrlToBlob(dataUrl);\n const blobUrl = URL.createObjectURL(blob);\n this._blobRegistry.set(blobUrl, dataUrl);\n return blobUrl;\n }\n\n /**\n * Replaces any blob: URLs created by this module with their original data URLs.\n * Called by Editor.getHTML() so the returned HTML is fully self-contained.\n * @param {string} html\n * @returns {string}\n */\n resolveImages(html) {\n if (!this._blobRegistry?.size) return html;\n return html.replace(/blob:[^\"'> \\t\\n\\r]*/g, (url) => this._blobRegistry.get(url) || url);\n }\n\n /**\n * Converts a data URL to a Blob (no FileReader — synchronous).\n * @param {string} dataUrl\n * @returns {Blob}\n */\n _dataUrlToBlob(dataUrl) {\n const [header, b64] = dataUrl.split(',');\n const mime = /:(.*?);/.exec(header)?.[1] ?? 'image/png';\n const binary = atob(b64);\n const arr = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) arr[i] = binary.charCodeAt(i);\n return new Blob([arr], { type: mime });\n }\n\n /**\n * Compresses an image File using a Canvas.\n * - Resizes so the longest edge is at most MAX_DIM pixels.\n * - Encodes as WebP (if supported) or JPEG at quality 0.85.\n * Falls back to plain FileReader if canvas is unavailable.\n * @param {File} file\n * @returns {Promise<string>} data URL\n */\n _compressImage(file) {\n const MAX_DIM = 1920;\n const QUALITY = 0.85;\n\n return new Promise((resolve, reject) => {\n const objectUrl = URL.createObjectURL(file);\n const img = new Image();\n\n img.onload = () => {\n URL.revokeObjectURL(objectUrl);\n\n let { width, height } = img;\n if (width > MAX_DIM || height > MAX_DIM) {\n if (width >= height) {\n height = Math.round((height * MAX_DIM) / width);\n width = MAX_DIM;\n } else {\n width = Math.round((width * MAX_DIM) / height);\n height = MAX_DIM;\n }\n }\n\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n // Canvas context unavailable (e.g. device memory limit) — fall back to\n // embedding the original file without compression.\n const reader = new FileReader();\n reader.onload = (e) => resolve(/** @type {string} */ (e.target.result));\n reader.onerror = () => reject(new Error('FileReader failed'));\n reader.readAsDataURL(file);\n return;\n }\n ctx.drawImage(img, 0, 0, width, height);\n\n // Prefer WebP for better compression; fall back to JPEG\n const webp = canvas.toDataURL('image/webp', QUALITY);\n resolve(webp.startsWith('data:image/webp') ? webp : canvas.toDataURL('image/jpeg', QUALITY));\n };\n\n img.onerror = () => {\n URL.revokeObjectURL(objectUrl);\n // Fallback: embed original without compression\n const reader = new FileReader();\n reader.onload = (e) => resolve(/** @type {string} */ (e.target.result));\n reader.onerror = () => reject(new Error('FileReader failed'));\n reader.readAsDataURL(file);\n };\n\n img.src = objectUrl;\n });\n }\n\n /**\n * Positions the caret at the given viewport coordinates.\n * Supports both Chrome (caretRangeFromPoint) and Firefox (caretPositionFromPoint).\n * @param {number} x\n * @param {number} y\n */\n _placeCaretAtPoint(x, y) {\n let range;\n if (document.caretRangeFromPoint) {\n range = document.caretRangeFromPoint(x, y);\n } else if (document.caretPositionFromPoint) {\n const pos = document.caretPositionFromPoint(x, y);\n if (pos) {\n range = document.createRange();\n range.setStart(pos.offsetNode, pos.offset);\n range.collapse(true);\n }\n }\n if (!range) return;\n const sel = globalThis.getSelection();\n if (sel) {\n sel.removeAllRanges();\n sel.addRange(range);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Escapes HTML special characters.\n * @param {string} str\n * @returns {string}\n */\n _escapeHTML(str) {\n return str\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\"', '"')\n .replaceAll(\"'\", ''');\n }\n}\n","/**\n * Placeholder.js - Shows placeholder text when the editor is empty\n * Inspired by Summernote's Placeholder module\n */\n\nimport { on } from '../core/dom.js';\n\n/**\n * Anything that is neither whitespace nor a zero-width space.\n *\n * `\\s` is exactly the set `String.prototype.trim` strips, so this matches the\n * old `textContent.replaceAll('\\u200B', '').trim().length > 0` test character\n * for character. ZWS is not whitespace and has to be listed: checklist and icon\n * insertion leave them behind as cursor anchors, and treating one as content\n * left the placeholder overlapping a visually empty editor (A-1).\n */\nconst MEANINGFUL_RE = /[^\\s\\u200B]/;\n\n/**\n * True when the subtree holds any character the reader would see.\n *\n * Stops at the first one instead of materialising the document's text and\n * copying it twice — this runs on every keystroke, where the old version cost\n * 0.2 ms on a 217 KiB document and this costs 0.0005 ms, because a non-empty\n * editor answers on its first text node.\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction _hasText(root) {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n if (MEANINGFUL_RE.test(/** @type {Text} */ (node).data)) return true;\n }\n return false;\n}\n\nexport class Placeholder {\n /**\n * @param {import('../Context.js').Context} context\n */\n constructor(context) {\n this.context = context;\n this.options = context.options;\n this._disposers = [];\n }\n\n initialize() {\n const editable = this.context.layoutInfo.editable;\n const placeholder = this.options.placeholder || '';\n if (placeholder) {\n editable.dataset.placeholder = placeholder;\n }\n\n const update = () => this._update();\n const d1 = on(editable, 'input', update);\n const d2 = on(editable, 'focus', update);\n const d3 = on(editable, 'blur', update);\n this._disposers.push(d1, d2, d3);\n this._update();\n return this;\n }\n\n destroy() {\n this._disposers.forEach((d) => d());\n this._disposers = [];\n }\n\n _update() {\n const editable = this.context.layoutInfo.editable;\n const isFocused = document.activeElement === editable;\n const isEmpty = !_hasText(editable) &&\n !editable.querySelector('img, table, hr, .an-video-wrapper');\n editable.classList.toggle('an-placeholder', isEmpty && !isFocused);\n }\n}\n","/**\n * presets/core.js — the smallest set that still makes a usable editor.\n *\n * Typing, the toolbar, the status bar, paste handling and the placeholder. No\n * dialogs, no floating tooltips, no emoji or icon pickers, no crop overlay.\n *\n * Nothing here imports a heavy module, which is the whole point: a build that\n * uses only this preset never reaches `presets/full.js` and the bundler drops\n * everything it lists.\n *\n * Toolbar buttons whose module is absent still render; invoking one logs a\n * warning from `Context.invoke` and does nothing. Pair this preset with a\n * toolbar that only names buttons the core modules can serve.\n */\n\nimport { Editor } from '../module/Editor.js';\nimport { Toolbar } from '../module/Toolbar.js';\nimport { Statusbar } from '../module/Statusbar.js';\nimport { Clipboard } from '../module/Clipboard.js';\nimport { Placeholder } from '../module/Placeholder.js';\n\n/**\n * @type {import('../Context.js').ModuleDef[]}\n */\nexport const CORE_MODULES = [\n { name: 'editor', Class: Editor },\n { name: 'toolbar', Class: Toolbar },\n { name: 'statusbar', Class: Statusbar },\n { name: 'clipboard', Class: Clipboard },\n { name: 'placeholder', Class: Placeholder },\n];\n\nexport { Editor, Toolbar, Statusbar, Clipboard, Placeholder };\n","/**\n * lists.js - Array/list utility helpers\n * Inspired by Summernote's lists.js\n */\n\n/**\n * Returns the last element of an array.\n * @template T\n * @param {T[]} arr\n * @returns {T|undefined}\n */\nexport function last(arr) {\n return arr[arr.length - 1];\n}\n\n/**\n * Returns the first element of an array.\n * @template T\n * @param {T[]} arr\n * @returns {T|undefined}\n */\nexport function first(arr) {\n return arr[0];\n}\n\n/**\n * Returns a new array without the last n items.\n * @template T\n * @param {T[]} arr\n * @param {number} [n=1]\n * @returns {T[]}\n */\nexport function initial(arr, n = 1) {\n return arr.slice(0, arr.length - n);\n}\n\n/**\n * Returns a new array without the first n items.\n * @template T\n * @param {T[]} arr\n * @param {number} [n=1]\n * @returns {T[]}\n */\nexport function tail(arr, n = 1) {\n return arr.slice(n);\n}\n\n/**\n * Returns a flattened (one level) array.\n * @template T\n * @param {T[][]} arr\n * @returns {T[]}\n */\nexport function flatten(arr) {\n return arr.flat();\n}\n\n/**\n * Returns unique elements of an array (using Set).\n * @template T\n * @param {T[]} arr\n * @returns {T[]}\n */\nexport function unique(arr) {\n return [...new Set(arr)];\n}\n\n/**\n * Splits an array into chunks of size n.\n * @template T\n * @param {T[]} arr\n * @param {number} n\n * @returns {T[][]}\n */\nexport function chunk(arr, n) {\n const result = [];\n for (let i = 0; i < arr.length; i += n) {\n result.push(arr.slice(i, i + n));\n }\n return result;\n}\n\n/**\n * Groups array elements by a key function.\n * @template T\n * @param {T[]} arr\n * @param {(item: T) => string} keyFn\n * @returns {Record<string, T[]>}\n */\nexport function groupBy(arr, keyFn) {\n return arr.reduce((groups, item) => {\n const key = keyFn(item);\n if (!groups[key]) {\n groups[key] = [];\n }\n groups[key].push(item);\n return groups;\n }, {});\n}\n\n/**\n * Returns true if all elements satisfy the predicate.\n * @template T\n * @param {T[]} arr\n * @param {(item: T) => boolean} predicate\n * @returns {boolean}\n */\nexport function all(arr, predicate) {\n return arr.every(predicate);\n}\n\n/**\n * Returns true if any element satisfies the predicate.\n * @template T\n * @param {T[]} arr\n * @param {(item: T) => boolean} predicate\n * @returns {boolean}\n */\nexport function any(arr, predicate) {\n return arr.some(predicate);\n}\n","/**\n * env.js - Environment / browser detection\n * Inspired by Summernote's env.js\n *\n * Every field is a lazy getter rather than a value computed at module load.\n * This module is re-exported from the package entry point, so reading\n * `navigator` eagerly meant that merely `import`ing autumnnote threw\n * `ReferenceError: navigator is not defined` under SSR on any runtime without\n * a global `navigator` — including Node 20, which package.json still supports.\n * Nothing inside the library reads these fields, so the crash happened before\n * an editor was ever created.\n */\n\n/** @returns {string} the current user agent, or '' when there is no navigator (SSR). */\nfunction ua() {\n return globalThis.navigator?.userAgent ?? '';\n}\n\nexport const env = {\n /** True if browser is Chrome (excludes Edge, whose UA also contains \"Chrome/\") */\n get isChrome() { return /Chrome\\//.test(ua()) && !/Edg\\//.test(ua()); },\n /** True if browser is Firefox */\n get isFF() { return /Firefox\\//.test(ua()); },\n /** True if browser is Safari (not Chrome) */\n get isSafari() { return /^((?!chrome|android).)*safari/i.test(ua()); },\n /** True if browser is Edge (Chromium) */\n get isEdge() { return /Edg\\//.test(ua()); },\n /** True if running on macOS */\n get isMac() { return /Macintosh/.test(ua()); },\n /** True if running on mobile */\n get isMobile() { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua()); },\n /** True if touch is supported */\n get isTouch() {\n return 'ontouchstart' in globalThis || (globalThis.navigator?.maxTouchPoints ?? 0) > 0;\n },\n /** Modifier key name depending on platform */\n get modifierKey() { return /Macintosh/.test(ua()) ? 'metaKey' : 'ctrlKey'; },\n};\n","/**\n * factory.js — the AutumnNote object and the public re-exports, shared by every\n * entry point.\n *\n * Deliberately imports no editor module and installs no module table. Each\n * entry point does that for itself: `index.js` installs the full preset,\n * `core.js` a minimal one. Keeping the choice out of here is what lets a\n * bundler drop the modules an entry never mentions.\n */\n\nimport { Context, _customModules, _globalPlugins } from './Context.js';\nimport { registerButton, buttons } from './module/Buttons.js';\nimport { defaultOptions } from './settings.js';\nimport { registerLocale } from './i18n/index.js';\n\n// Snapshot of factory defaults taken at module-load time (before any setDefaults() calls)\nconst _originalDefaults = { ...defaultOptions };\n\n// Re-export for tree-shaking / module consumers\nexport { Context } from './Context.js';\nexport { defaultOptions } from './settings.js';\nexport * from './core/dom.js';\nexport * from './core/range.js';\nexport * from './core/func.js';\nexport * from './core/key.js';\nexport * from './core/lists.js';\nexport * from './core/env.js';\nexport * from './core/sanitise.js';\n// Both were reachable only through an editor instance, which needs a DOM —\n// so converting or detecting on a server or in a build step meant reaching\n// into src/. They are already in the bundle; exporting them costs nothing.\nexport * from './core/markdown.js';\nexport * from './core/detectLang.js';\nexport * from './module/Buttons.js';\nexport { locales, resolveLocale, registerLocale } from './i18n/index.js';\n\n// ---------------------------------------------------------------------------\n// Main factory\n// ---------------------------------------------------------------------------\n\n/** @type {WeakMap<Element, Context>} */\nconst instances = new WeakMap();\n\nconst AutumnNote = {\n /**\n * Creates (or returns existing) editor instance on one or more elements.\n *\n * @param {string|Element|NodeList|Element[]} selector\n * @param {import('./settings.js').AsnOptions} [options]\n * @returns {Context|Context[]} single Context or array of Contexts\n */\n create(selector, options = {}) {\n const elements = resolveElements(selector);\n const ctxs = elements.map((el) => {\n if (instances.has(el)) return instances.get(el);\n const ctx = new Context(/** @type {HTMLElement} */ (el), options);\n ctx.initialize();\n instances.set(el, ctx);\n return ctx;\n });\n return ctxs.length === 1 ? ctxs[0] : ctxs;\n },\n\n /**\n * Destroys the editor(s) on the given selector.\n * @param {string|Element|NodeList|Element[]} selector\n */\n destroy(selector) {\n resolveElements(selector).forEach((el) => {\n const ctx = instances.get(el);\n if (ctx) {\n ctx.destroy();\n instances.delete(el);\n }\n });\n },\n\n /**\n * Returns the Context instance for a given element (or null).\n * @param {string|Element} selector\n * @returns {Context|null}\n */\n getInstance(selector) {\n const el = typeof selector === 'string' ? document.querySelector(selector) : selector;\n return el ? instances.get(el) || null : null;\n },\n\n /** Returns a shallow copy of the default options (read-only snapshot). */\n get defaults() { return { ...defaultOptions }; },\n\n /** Merges properties into the global defaults, applied to all future instances. */\n setDefaults(overrides) { Object.assign(defaultOptions, overrides); },\n\n /** Restores global defaults to their original factory values. */\n resetDefaults() {\n Object.keys(defaultOptions).forEach((k) => delete defaultOptions[k]);\n Object.assign(defaultOptions, _originalDefaults);\n },\n\n /**\n * Registers a custom module to be included in every new editor instance.\n * @param {string} name - unique module key used for ctx.invoke() calls\n * @param {Function} ModuleClass - class with initialize() and optional destroy()\n */\n registerModule(name, ModuleClass) { _customModules.set(name, ModuleClass); },\n\n /**\n * Installs a plugin globally — applied to every future editor instance.\n * Plugin `buttons` are registered to the global button registry immediately\n * so they are available when Toolbar initialises inside create().\n * Plugin `install()` is called after all built-in modules have initialised.\n * @param {object} plugin - { name, version?, buttons?, install?, uninstall? }\n * @param {object} [options] - Forwarded to plugin.install(context, options)\n * @returns {typeof AutumnNote}\n */\n use(plugin, options = {}) {\n if (!plugin || typeof plugin.name !== 'string') {\n throw new TypeError('[AutumnNote] AutumnNote.use: plugin must have a string `name` property.');\n }\n if (_globalPlugins.has(plugin.name)) {\n console.warn(`[AutumnNote] Plugin \"${plugin.name}\" already registered globally. Skipping.`);\n return this;\n }\n if (Array.isArray(plugin.buttons)) {\n plugin.buttons.forEach((b) => registerButton(b));\n }\n _globalPlugins.set(plugin.name, { plugin, options });\n return this;\n },\n\n /**\n * Returns true if a plugin with the given name has been registered globally.\n * @param {string} name\n * @returns {boolean}\n */\n hasPlugin(name) { return _globalPlugins.has(name); },\n\n /**\n * Registers a single button definition in the global button registry.\n * After create(), call ctx.invoke('toolbar.rebuild') to render new buttons.\n * @param {object} btnDef - ButtonDef-compatible object with a `name` string\n * @returns {typeof AutumnNote}\n */\n registerButton(btnDef) { registerButton(btnDef); return this; },\n\n /**\n * Registers a locale so `lang: '<code>'` can select it.\n * Only English ships in the ESM bundle — import others from\n * `autumnnote/i18n/<code>` and register them here.\n * @param {string} code\n * @param {object} locale\n */\n registerLocale(code, locale) { registerLocale(code, locale); return this; },\n\n /** Registers a slash-menu command for future editor instances. */\n registerSlashCommand(command) {\n if (!command?.id || typeof command.run !== 'function') {\n throw new TypeError('[AutumnNote] Slash command requires an id and run(context) function.');\n }\n const commands = defaultOptions.slashCommands;\n const index = commands.findIndex((item) => item.id === command.id);\n if (index >= 0) commands[index] = command;\n else commands.push(command);\n return this;\n },\n\n /** All pre-built button definitions — accessible in every module format including UMD/CJS. */\n buttons,\n\n /** Library version */\n version: '2.5.0',\n};\n\n// ---------------------------------------------------------------------------\n// Helper\n// ---------------------------------------------------------------------------\n\n/**\n * @param {string|Element|NodeList|Element[]} selector\n * @returns {Element[]}\n */\nfunction resolveElements(selector) {\n if (typeof selector === 'string') {\n return Array.from(document.querySelectorAll(selector));\n }\n if (selector instanceof Element) {\n return [selector];\n }\n if (selector instanceof NodeList || Array.isArray(selector)) {\n return /** @type {Element[]} */ (Array.from(selector));\n }\n return [];\n}\n\nexport default AutumnNote;\n","/**\n * core.js - Minimal entry point for AutumnNote (`autumnnote/core`).\n *\n * Same API as the default entry, but only the modules a usable editor needs:\n * typing, toolbar, status bar, paste handling and the placeholder. The dialogs,\n * floating tooltips, emoji and icon pickers and the crop overlay are not\n * imported at all, so a bundler leaves them out of the output rather than\n * shipping them switched off.\n *\n * import AutumnNote from 'autumnnote/core';\n * import 'autumnnote/dist/autumnnote.css'; // same stylesheet as the full build\n *\n * AutumnNote.create('#editor', {\n * toolbar: [['bold', 'italic', 'underline'], ['ul', 'ol']],\n * });\n *\n * Toolbar buttons whose module is absent still render, but invoking one logs a\n * warning and does nothing — give this preset a toolbar naming only buttons the\n * core modules serve, or use the default entry.\n */\n\n// The stylesheet is not imported here on purpose: it is identical to the full\n// build's and is already emitted as dist/autumnnote.css, which both entries\n// point consumers at. Importing it again would only duplicate ~8 KB gzip in the\n// package for no benefit.\nimport { setModuleDefs } from './Context.js';\nimport { CORE_MODULES } from './presets/core.js';\n\nsetModuleDefs(CORE_MODULES);\n\nexport * from './factory.js';\nexport { default } from './factory.js';\n"],"mappings":";AAYA,SAAgB,EAAM,GAAK,GAAK,GAAK;CACnC,OAAO,KAAK,IAAI,KAAK,IAAI,GAAK,CAAG,GAAG,CAAG;AACzC;AAQA,SAAgB,EAAS,GAAI,GAAO;CAClC,IAAI;CACJ,OAAO,SAAU,GAAG,GAAM;EAExB,AADA,aAAa,CAAK,GAClB,IAAQ,iBAAiB,EAAG,MAAM,MAAM,CAAI,GAAG,CAAK;CACtD;AACF;AAQA,SAAgB,EAAS,GAAI,GAAO;CAClC,IAAI,IAAW,WACX,IAAgB;CACpB,OAAO,SAAU,GAAG,GAAM;EACxB,IAAM,IAAM,YAAY,IAAI,GACtB,IAAU,IAAM;EACtB,IAAI,KAAW,GAIb,OAHA,IAAW,GACX,aAAa,CAAa,GAC1B,IAAgB,MACT,EAAG,MAAM,MAAM,CAAI;EAI5B,AADA,aAAa,CAAa,GAC1B,IAAgB,iBAAiB;GAG/B,AAFA,IAAW,YAAY,IAAI,GAC3B,IAAgB,MAChB,EAAG,MAAM,MAAM,CAAI;EACrB,GAAG,IAAQ,CAAO;CACpB;AACF;AAOA,SAAgB,EAAQ,GAAG,GAAK;CAC9B,QAAQ,MAAM,EAAI,aAAa,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC;AACjD;AAQA,SAAgB,EAAS,GAAG;CAC1B,OAAO;AACT;AAOA,SAAgB,EAAM,GAAK;CACzB,OAAO,KAAQ;AACjB;AAOA,SAAgB,EAAS,GAAK;CAC5B,OAAO,OAAO,KAAQ;AACxB;AAOA,SAAgB,EAAW,GAAK;CAC9B,OAAO,OAAO,KAAQ;AACxB;AAYA,SAAgB,EAAU,GAAQ,GAAQ;CAExC,IAAM,IAAS,CAAC;CAChB,KAAK,IAAM,KAAO,OAAO,KAAK,CAAM,GAClC,EAAO,KAAO,MAAM,QAAQ,EAAO,EAAI,IAAI,CAAC,GAAG,EAAO,EAAI,IAAI,EAAO;CAEvE,IAAI,EAAc,CAAM,KAAK,EAAc,CAAM,GAC/C,KAAK,IAAM,KAAO,OAAO,KAAK,CAAM,GAClC,AAAI,EAAc,EAAO,EAAI,IAK3B,EAAO,KAAO,EADD,EAAc,EAAO,EAAI,IAAI,EAAO,KAAO,CAAC,GAC3B,EAAO,EAAI,IAChC,MAAM,QAAQ,EAAO,EAAI,IAClC,EAAO,KAAO,CAAC,GAAG,EAAO,EAAI,IAE7B,EAAO,KAAO,EAAO;CAI3B,OAAO;AACT;AAOA,SAAgB,EAAc,GAAK;CACjC,OAAuB,OAAO,KAAQ,cAA/B,KAA2C,CAAC,MAAM,QAAQ,CAAG;AACtE;AAQA,SAAgB,EAAS,GAAM;CAE7B,OADK,IACE;EACL,KAAK,EAAK;EACV,MAAM,EAAK;EACX,OAAO,EAAK;EACZ,QAAQ,EAAK;EACb,QAAQ,EAAK;EACb,OAAO,EAAK;CACd,IARkB;AASpB;;;AC1JA,IAAa,IAAe,GACf,IAAY,GAGZ,KAAa,MAAS,GAAM,aAAA,GAE5B,KAAU,MAAS,GAAM,aAAA,GAEzB,KAAU,MAAS,EAAU,CAAI,KAAK,4EAA4E,KAAK,EAAK,QAAQ,GAEpI,KAAU,MAAS,EAAU,CAAI,KAAK,4CAA4C,KAAK,EAAK,QAAQ,GAEpG,MAAQ,MAAS,EAAU,CAAI,KAAK,UAAU,KAAK,EAAK,QAAQ,GAEhE,MAAU,MAAS,EAAU,CAAI,KAAK,aAAa,KAAK,EAAK,QAAQ,GAErE,MAAW,MAAS,EAAU,CAAI,KAAK,EAAK,SAAS,YAAY,MAAM,SAEvE,KAAY,MACvB,EAAU,CAAI,KACd,oKAAoK,KAAK,EAAK,QAAQ,GAE3K,KAAc,MAAS,EAAU,CAAI,KAAiC,EAAM,mBAE5E,MAAY,MAAS,EAAU,CAAI,KAAK,EAAK,SAAS,YAAY,MAAM,KAExE,MAAW,MAAS,EAAU,CAAI,KAAK,EAAK,SAAS,YAAY,MAAM;AAapF,SAAgB,EAAQ,GAAM,GAAW,GAAQ;CAC/C,IAAI,IAAM;CACV,OAAO,KAAO,MAAQ,IAAQ;EAC5B,IAAI,EAAU,CAAG,GAAG,OAAO;EAC3B,IAAM,EAAI;CACZ;CACA,OAAO;AACT;AAQA,SAAgB,EAAY,GAAM,GAAU;CAC1C,OAAO,EAAQ,GAAM,GAAQ,CAAQ;AACvC;AAQA,SAAgB,GAAU,GAAM,GAAQ;CACtC,IAAM,IAAS,CAAC,GACZ,IAAM,EAAK;CACf,OAAO,KAAO,MAAQ,IAEpB,AADA,EAAO,KAAK,CAAG,GACf,IAAM,EAAI;CAEZ,OAAO;AACT;AAOA,SAAgB,GAAS,GAAM;CAC7B,OAAO,MAAM,KAAK,EAAK,UAAU;AACnC;AAOA,SAAgB,GAAY,GAAM;CAChC,IAAI,IAAU,EAAK;CACnB,OAAO,KAAW,CAAC,EAAU,CAAO,IAClC,IAAU,EAAQ;CAEpB,OAAoC;AACtC;AAOA,SAAgB,GAAY,GAAM;CAChC,IAAI,IAAU,EAAK;CACnB,OAAO,KAAW,CAAC,EAAU,CAAO,IAClC,IAAU,EAAQ;CAEpB,OAAoC;AACtC;AAaA,SAAgB,EAAc,GAAK,IAAQ,CAAC,GAAG,IAAa,CAAC,GAAG;CAC9D,IAAM,IAAK,SAAS,cAAc,CAAG;CACrC,KAAK,IAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,CAAK,GACvC,EAAG,aAAa,GAAG,CAAC;CAEtB,KAAK,IAAM,KAAS,GAClB,AAAI,OAAO,KAAU,WACnB,EAAG,YAAY,SAAS,eAAe,CAAK,CAAC,IAE7C,EAAG,YAAY,CAAK;CAGxB,OAAO;AACT;AAMA,SAAgB,EAAO,GAAM;CAC3B,AAAI,GAAM,cACiB,EAAO,OAAO;AAE3C;AAMA,SAAgB,GAAO,GAAM;CAC3B,IAAM,IAAS,EAAK;CACf,OACL;SAAO,EAAK,aACV,EAAO,aAAa,EAAK,YAAY,CAAI;EAElB,EAAO,OAAO;CAFI;AAG7C;AAQA,SAAgB,GAAK,GAAM,GAAS;CAGlC,OAFA,EAAK,WAAW,aAAa,GAAS,CAAI,GAC1C,EAAQ,YAAY,CAAI,GACjB;AACT;AAOA,SAAgB,GAAY,GAAS,GAAS;CAC5C,AAAI,EAAQ,cACV,EAAQ,WAAW,aAAa,GAAS,EAAQ,WAAW,IAE5D,EAAQ,WAAW,YAAY,CAAO;AAE1C;AAWA,SAAgB,GAAU,GAAM;CAC9B,OAAO,EAAO,CAAI,IAAI,EAAK,YAAY,EAAK,eAAe;AAC7D;AASA,SAAgB,GAAQ,GAAM;CAI5B,OAHI,EAAO,CAAI,IAAU,CAAC,EAAK,YAC3B,EAAO,CAAI,IAAU,KACrB,EAAK,WAAW,WAAW,KAAK,EAAK,YAAY,aAAa,QAC3D,CAAC,EAAK,YAAY,KAAK,KAAK,CAAyB,EAAM,cAAc,uBAAuB;AACzG;AAOA,SAAgB,GAAU,GAAI;CAC5B,OAAO,EAAG;AACZ;AAUA,SAAgB,GAAW,GAAI;CAC7B,IAAM,IAAQ,SAAS,YAAY;CAEnC,AADA,EAAM,mBAAmB,CAAE,GAC3B,EAAM,SAAS,EAAK;CACpB,IAAM,IAAM,WAAW,aAAa;CACpC,AAAI,MACF,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAK;AAEtB;AAOA,SAAgB,GAAiB,GAAM;CACrC,OAAO,CAAC,CAAC,EAAQ,GAAM,CAAU;AACnC;AAcA,SAAgB,EAAG,GAAQ,GAAM,GAAS,GAAS;CAEjD,OADA,EAAO,iBAAiB,GAAM,GAAS,CAAO,SACjC,EAAO,oBAAoB,GAAM,GAAS,CAAO;AAChE;AAaA,SAAgB,GAAU,GAAW,GAAU;CAC7C,IAEM,UAAqB,MAAM,KAAK,EAAU,iBAAiB,6IAAS,CAAC,CAAC,CAAC,QAC1E,MAAO,CAAC,EAAG,QAAQ,4BAA0B,KAAK,CAAC,EAAG,QAAQ,2BAAyB,CAC1F,GAEM,KAAW,MAAM;EACrB,IAAI,EAAE,QAAQ,UAAU;GAEtB,AADA,EAAE,gBAAgB,GAClB,IAAW;GACX;EACF;EACA,IAAI,EAAE,QAAQ,OAAO;EACrB,IAAM,IAAM,EAAa;EACzB,IAAI,CAAC,EAAI,QAAQ;EACjB,IAAM,IAAQ,EAAI,IACZ,IAAO,EAAI,GAAG,EAAE;EACtB,AAAI,EAAE,WACA,SAAS,kBAAkB,MAC7B,EAAE,eAAe,GACU,EAAO,MAAM,KAEjC,SAAS,kBAAkB,MACpC,EAAE,eAAe,GACU,EAAQ,MAAM;CAE7C;CAGA,OADA,SAAS,iBAAiB,WAAW,CAAO,SAC/B,SAAS,oBAAoB,WAAW,CAAO;AAC9D;AAYA,SAAgB,GAAc,GAAQ,GAAK;CACzC,EAAO,MAAM,SAAS;CAEtB,IAAM,KAAe,MAAM;EAGzB,IAFI,EAAE,WAAW,KAEW,EAAE,OAAQ,QAAQ,oCAAoC,GAAG;EAKrF,IAHA,EAAE,eAAe,GAGb,CAAC,EAAI,QAAQ,cAAc;GAC7B,IAAM,IAAI,EAAI,sBAAsB;GAKpC,AAJA,EAAI,MAAM,WAAW,SACrB,EAAI,MAAM,SAAS,KACnB,EAAI,MAAM,OAAO,GAAG,EAAE,KAAK,KAC3B,EAAI,MAAM,MAAM,GAAG,EAAE,IAAI,KACzB,EAAI,QAAQ,eAAe;EAC7B;EAEA,IAAM,IAAS,EAAE,UAAU,OAAO,WAAW,EAAI,MAAM,IAAI,GACrD,IAAS,EAAE,UAAU,OAAO,WAAW,EAAI,MAAM,GAAG;EAE1D,EAAO,MAAM,SAAS;EAEtB,IAAM,KAAU,MAAO;GACrB,IAAM,IAAK,EAAI,aACT,IAAK,EAAI;GAEf,AADA,EAAI,MAAM,OAAO,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,EAAG,UAAU,GAAQ,WAAW,aAAc,CAAE,CAAC,EAAE,KAC5F,EAAI,MAAM,MAAO,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,EAAG,UAAU,GAAQ,WAAW,cAAc,CAAE,CAAC,EAAE;EAC9F,GAEM,UAAa;GAGjB,AAFA,EAAO,MAAM,SAAS,QACtB,SAAS,oBAAoB,aAAa,CAAM,GAChD,SAAS,oBAAoB,WAAa,CAAI;EAChD;EAGA,AADA,SAAS,iBAAiB,aAAa,CAAM,GAC7C,SAAS,iBAAiB,WAAa,CAAI;CAC7C;CAGA,OADA,EAAO,iBAAiB,aAAa,CAAW,SACnC,EAAO,oBAAoB,aAAa,CAAW;AAClE;;;ACxWA,IAAa,KAAb,MAA0B;CAOxB,YAAY,GAAI,GAAI,GAAI,GAAI;EAI1B,AAHA,KAAK,KAAK,GACV,KAAK,KAAK,GACV,KAAK,KAAK,GACV,KAAK,KAAK;CACZ;CAGA,cAAc;EACZ,OAAO,KAAK,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK;CACjD;CAGA,gBAAgB;EACd,IAAM,IAAQ,SAAS,YAAY;EACnC,IAAI;GAEF,AADA,EAAM,SAAS,KAAK,IAAI,KAAK,EAAE,GAC/B,EAAM,OAAO,KAAK,IAAI,KAAK,EAAE;EAC/B,QAAa,CAEb;EACA,OAAO;CACT;CAKA,SAAS;EACP,IAAM,IAAM,WAAW,aAAa;EAC/B,MACL,EAAI,gBAAgB,GACpB,EAAI,SAAS,KAAK,cAAc,CAAC;CACnC;CAMA,iBAAiB;EAEf,IAAM,IADS,KAAK,cACE,CAAC,CAAC;EACxB,OAAoC,EAAU,CAAQ,IAAI,IAAW,EAAS;CAChF;CAOA,UAAU,GAAU;EAClB,OAAoC,EAAQ,KAAK,KAAK,MAAM,EAAU,CAAC,KAAK,MAAM,GAAU,CAAQ;CACtG;CAMA,WAAW;EACT,OAAO,KAAK,cAAc,CAAC,CAAC,SAAS;CACvC;CAMA,iBAAiB;EACf,IAAM,IAAQ,KAAK,cAAc,CAAC,CAAC,eAAe;EAClD,OAAO,EAAM,SAAS,IAAI,EAAM,EAAM,SAAS,KAAK;CACtD;CAMA,WAAW,GAAM;EAEf,KADoB,cACf,CAAC,CAAC,WAAW,CAAI;CACxB;AAEF;AAWA,SAAgB,GAAgB,GAAO;CACrC,OAAO,IAAI,GACT,EAAM,gBACN,EAAM,aACN,EAAM,cACN,EAAM,SACR;AACF;AAQA,SAAgB,GAAa,GAAU;CACrC,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,KAAO,EAAI,eAAe,GAAG,OAAO;CACzC,IAAM,IAAS,EAAI,WAAW,CAAC;CAK/B,OAHI,KAAY,CAAC,EAAS,SAAS,EAAO,uBAAuB,IACxD,OAEF,GAAgB,CAAM;AAC/B;AAOA,SAAgB,GAAiB,GAAI;CACnC,OAAO,IAAI,GAAa,GAAI,GAAG,GAAI,EAAG,WAAW,MAAM;AACzD;AAQA,SAAgB,GAAe,GAAM,IAAS,GAAG;CAC/C,OAAO,IAAI,GAAa,GAAM,GAAQ,GAAM,CAAM;AACpD;AAWA,SAAgB,GAAkB,GAAI;CACpC,IAAM,IAAM,WAAW,aAAa;CAEpC,OADI,CAAC,KAAO,EAAI,eAAe,IAAU,KAClC,EAAG,SAAS,EAAI,WAAW,CAAC,CAAC,CAAC,uBAAuB;AAC9D;AAMA,SAAgB,GAAe,GAAI;CACjC,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,KAAO,EAAI,eAAe,GAAG;EAChC,EAAG,IAAI;EACP;CACF;CACA,IAAM,IAAQ,EAAI,WAAW,CAAC,CAAC,CAAC,WAAW;CAG3C,AAFA,EAAG,GAAgB,CAAK,CAAC,GACzB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAK;AACpB;AAQA,SAAgB,GAAU,GAAU,GAAQ;CAE1C,OAAO,CAAC,GADM,EAAS,UAAU,CACX,CAAC;AACzB;;;ACpKA,SAAS,GAAc,GAAM;CAC3B,IAAI,IAAM,KAAQ,EAAK,aAAa,IAA4B,IAAQ,GAAM;CAC9E,OAAO,IAAK;EACV,IAAM,IAAO,EAAI,eAAe,iBAAiB,KAAiC,EAAK;EACvF,IAAI,MAAS,SAAS,OAAO;EAE7B,IAAI,KAAQ,QAAQ,MAAS,WAAW,OAAO;EAC/C,IAAM,EAAI;CACZ;CACA,OAAO;AACT;AAeA,SAAS,GAAa,GAAU;CAC9B,IAAM,IAAM,WAAW,eAAe;CACtC,IAAI,CAAC,KAAO,EAAI,eAAe,GAAG,OAAO;CACzC,IAAM,IAAQ,EAAI,WAAW,CAAC;CAK9B,OAJI,KAAY,MAAa,WAEpBA,EAAK,SAAS,EAAM,uBAAuB,IAAI,IAAQ,OAEzD,GAAc,EAAM,uBAAuB,IAAI,IAAQ;AAChE;AAMA,SAAS,GAAY,GAAM;CACzB,IAAM,IAAM,WAAW,eAAe;CACtC,IAAI,CAAC,GAAK;CACV,IAAM,IAAQ,SAAS,YAAY;CAInC,AAHA,EAAM,cAAc,CAAI,GACxB,EAAM,SAAS,EAAI,GACnB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAK;AACpB;AAQA,SAAgB,GAAiB,GAAM,GAAU;CAC/C,IAAM,IAAQ,GAAa,CAAQ;CACnC,IAAI,CAAC,GAAO,OAAO;CAEnB,IAAM,IAAW,SAAS,cAAc,UAAU;CAClD,EAAS,YAAY;CACrB,IAAM,IAAW,EAAS,SAEpB,IAAW,EAAS;CAM1B,OAJA,EAAM,eAAe,GACrB,EAAM,WAAW,CAAQ,GAErB,KAAU,GAAY,CAAQ,GAC3B;AACT;AAWA,SAAgB,GAAiB,GAAM,GAAU;CAC/C,IAAM,IAAQ,GAAa,CAAQ;CACnC,IAAI,CAAC,GAAO,OAAO;CAEnB,EAAM,eAAe;CAErB,IAAM,IAAQ,OAAO,CAAI,GACnB,IAAW,SAAS,uBAAuB;CAIjD,AAAI,CAAC,EAAM,SAAS,IAAI,KAAK,GAAgB,EAAM,gBAAgB,CAAQ,IACzE,EAAS,YAAY,SAAS,eAAe,CAAK,CAAC,IAEnD,EAAM,MAAM,IAAI,CAAC,CAAC,SAAS,GAAM,MAAM;EAErC,AADI,IAAI,KAAG,EAAS,YAAY,SAAS,cAAc,IAAI,CAAC,GACxD,KAAM,EAAS,YAAY,SAAS,eAAe,CAAI,CAAC;CAC9D,CAAC;CAGH,IAAM,IAAW,EAAS;CAG1B,OAFA,EAAM,WAAW,CAAQ,GACrB,KAAU,GAAY,CAAQ,GAC3B;AACT;AAWA,SAAS,GAAgB,GAAM,GAAU;CACvC,IAAI,IAAM,EAAK,aAAa,IAA4B,IAAQ,EAAK;CACrE,OAAO,KAAO,MAAQ,IAAU;EAC9B,IAAI,EAAI,YAAY,SAAS,EAAI,YAAY,YAAY,OAAO;EAChE,IAAM,IAAK,WAAW,mBAAmB,CAAG,CAAC,EAAE;EAC/C,IAAI,KAAM,EAAG,WAAW,KAAK,GAAG,OAAO;EACvC,IAAM,EAAI;CACZ;CACA,OAAO;AACT;AAWA,SAAgB,GAA2B,GAAU;CACnD,IAAM,IAAQ,GAAa,CAAQ;CACnC,IAAI,CAAC,GAAO,OAAO;CAEnB,IAAM,IAAK,SAAS,cAAc,IAAI;CACtC,EAAM,eAAe;CAErB,IAAM,IAAQ,GAAc,EAAM,gBAAgB,CAAQ;CAC1D,AAAI,KAAS,EAAM,aACjB,EAAM,WAAW,aAAa,GAAI,EAAM,WAAW,IAEnD,EAAM,WAAW,CAAE;CAGrB,IAAI,IAAQ,EAAG;CACf,IAAI,CAAC,KAAS,EAAM,YAAY,MAAM;EACpC,IAAM,IAAI,SAAS,cAAc,GAAG;EAGpC,AAFA,EAAE,YAAY,SAAS,cAAc,IAAI,CAAC,GAC1C,EAAG,YAAY,aAAa,GAAG,EAAG,WAAW,GAC7C,IAAQ;CACV;CAEA,IAAM,IAAM,WAAW,eAAe;CACtC,IAAI,GAAK;EACP,IAAM,IAAQ,SAAS,YAAY;EAInC,AAHA,EAAM,SAAS,GAAO,CAAC,GACvB,EAAM,SAAS,EAAI,GACnB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAK;CACpB;CACA,OAAO;AACT;AAEA,IAAMC,qBAAa,IAAI,IAAI;CAAC;CAAK;CAAO;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAc;CAAO;AAAI,CAAC;AAQtG,SAAS,GAAc,GAAM,GAAU;CACrC,IAAI,IAAM,EAAK,aAAa,IAA4B,IAAQ,EAAK;CACrE,OAAO,KAAO,MAAQ,IAAU;EAC9B,IAAIA,GAAW,IAAI,EAAI,OAAO,GAAG,OAAO;EACxC,IAAM,EAAI;CACZ;CACA,OAAO;AACT;;;ACnMA,SAAgB,EAAY,GAAK,IAAQ,MAAM;CAS7C,OAHI,MAAQ,gBAAgB,GAAiB,OAAO,KAAS,EAAE,CAAC,KAC5D,MAAQ,gBAAgB,GAAiB,OAAO,KAAS,EAAE,CAAC,KAC5D,MAAQ,0BAA0B,GAA2B,IAAU,KACpE,SAAS,YAAY,GAAK,IAAO,CAAK;AAC/C;AASA,IAAa,WAAa,EAAY,MAAM,GAK/B,WAAe,EAAY,QAAQ;AAOhD,SAAgB,KAAY;CAC1B,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,GAAK,YAAY;CACtB,IAAI,IAAY,EAAI,WAAW,CAAC,CAAC,CAAC;CAClC,AAAI,EAAU,aAAa,MAAG,IAAY,EAAU;CAEpD,IAAM,IAAmC,GAAY,QAAQ,GAAG,GAC1D,IAAc,SAAS,kBAAkB,WAAW;CAC1D,IAAI,KAAO,CAAC,GAAa;EAGvB,IAAM,IAAS,EAAI;EACnB,OAAO,EAAI,aAAY,EAAO,aAAa,EAAI,YAAY,CAAG;EAC9D,EAAI,OAAO;EACX;CACF;CACA,EAAY,WAAW;AACzB;AAOA,SAAgB,KAAgB;CAC9B,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,GAAK,YAAY;CAItB,IAAI,IAAK,EAAI,WAAW,CAAC,CAAC,CAAC;CAC3B,AAAI,EAAG,aAAa,MAAG,IAAK,EAAG;CAC/B,IAAM,IAAmC,GAAK,QAAQ,GAAG,KAAkC,GAAK,QAAQ,QAAQ,GAC1G,IAAc,SAAS,kBAAkB,eAAe;CAC9D,IAAI,KAAO,CAAC,GAAa;EAGvB,IAAM,IAAS,EAAI;EACnB,OAAO,EAAI,aAAY,EAAO,aAAa,EAAI,YAAY,CAAG;EAC9D,EAAI,OAAO;EACX;CACF;CACA,EAAY,eAAe;AAC7B;AAKA,IAAa,WAAoB,EAAY,aAAa,GAK7C,WAAkB,EAAY,WAAW,GAMzC,MAAa,MAAU,EAAY,aAAa,CAAK,GAMrD,MAAa,MAAU,EAAY,eAAe,CAAK,GAMvD,MAAY,MAAS,EAAY,YAAY,CAAI;AAQ9D,SAAgB,GAAS,GAAM,IAAW,UAAU;CAClD,IAAM,IAAM,WAAW,aAAa,GAC9B,IAAe,CAAC,GAAK,cAAc,EAAI,WAAW,CAAC,CAAC,CAAC;CAU3D,IAAI,KAAgB,GAAK,aAAa,GAAG;EACvC,IAAI;GACF,IAAM,IAAQ,EAAI,WAAW,CAAC,GACxB,IAAO,SAAS,cAAc,MAAM;GAC1C,EAAK,MAAM,WAAW;GACtB,IAAM,IAAU,SAAS,eAAe,GAAQ;GAEhD,AADA,EAAK,YAAY,CAAO,GACxB,EAAM,WAAW,CAAI;GACrB,IAAM,IAAK,SAAS,YAAY;GAIhC,AAHA,EAAG,SAAS,GAAS,EAAQ,YAAY,MAAM,GAC/C,EAAG,SAAS,EAAI,GAChB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE;EACjB,QAAY,CAA8D;EAC1E;CACF;CAKA,EAAY,YAAY,GAAG;CAC3B,IAAM,IAAQ,aAAoB,cAAc,IAAW,UACrD,IAAW,CAAC;CAalB,IAZA,EAAM,iBAAiB,kBAAgB,CAAC,CAAC,SAAS,MAAO;EACvD,IAAM,IAAO,SAAS,cAAc,MAAM;EAG1C,KAFA,EAAK,MAAM,WAAW,GACtB,EAAG,WAAW,aAAa,GAAM,CAAE,GAC5B,EAAG,aAAY,EAAK,YAAY,EAAG,UAAU;EAEpD,AADA,EAAG,OAAO,GACV,EAAS,KAAK,CAAI;CACpB,CAAC,GAKG,CAAC,KAAgB,KAAO,EAAS,SAAS,GAAG;EAC/C,IAAM,IAAQ,EAAS,IACjB,IAAQ,EAAS,GAAG,EAAE;EAC5B,IAAI;GACF,IAAM,IAAK,SAAS,YAAY,GAC1B,IAAY,EAAM,cAAc,GAChC,IAAY,EAAK,aAAc;GAIrC,AAHA,EAAG,SAAS,GAAW,CAAC,GACxB,EAAG,OAAO,GAAS,EAAQ,aAAa,KAAK,YAAY,EAAQ,YAAY,SAAS,EAAQ,WAAW,MAAM,GAC/G,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE;EACjB,QAAY,CAA8D;CAC5E;AACF;AAUA,IAAa,MAAe,MAAY,EAAY,eAAe,IAAI,EAAQ,EAAE,GAKpE,WAAoB,EAAY,aAAa,GAK7C,WAAsB,EAAY,eAAe,GAKjD,WAAqB,EAAY,cAAc,GAK/C,WAAoB,EAAY,aAAa,GAK7C,WAAe,EAAY,QAAQ;AAQhD,SAAgB,KAAU;CACxB,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,GAAK,YAAY;EACnB,IAAI,IAAY,EAAI,WAAW,CAAC,CAAC,CAAC;EAClC,AAAI,EAAU,aAAa,MAAG,IAAY,EAAU;EACpD,IAAM,IAAuC,GAAY,QAAQ,kBAAkB;EACnF,IAAI,GAAS;GACX,GAA8C,CAAQ;GACtD;EACF;CACF;CACA,EAAY,SAAS;AACvB;AAaA,SAAS,GAAkB,GAAS;CAClC,IAAM,IAAU,EAAQ,QAAQ,eAAe;CAC/C,IAAI,CAAC,GAAS;CAEd,IAAM,IAAU,MAAM,KAAK,EAAQ,QAAQ,GACrC,IAAU,EAAO,QAAQ,CAAO,GAChC,IAAW,EAAO,MAAM,IAAU,CAAC,GAGnC,IAAI,SAAS,cAAc,GAAG;CACpC,KAAK,IAAM,KAAS,EAAQ,YACtB,EAAM,aAAa,KAA6B,EAAO,YAAY,WACvE,EAAE,YAAY,EAAM,UAAU,EAAI,CAAC;CAUrC,IAPA,EAAE,YAAY,EAAE,UAAU,WAAW,KAAU,EAAE,IAC7C,CAAC,EAAE,cAAc,KAAK,CAAC,EAAE,YAAY,KAAK,OAC5C,EAAE,YAAY,IACd,EAAE,YAAY,SAAS,eAAe,MAAQ,CAAC,IAI7C,EAAS,SAAS,GAAG;EACvB,IAAM,IAAQ,SAAS,cAAc,IAAI;EAGzC,AAFA,EAAM,YAAY,gBAClB,EAAS,SAAQ,MAAM,EAAM,YAAY,CAAE,CAAC,GAC5C,EAAQ,WAAW,aAAa,GAAO,EAAQ,WAAW;CAC5D;CAOA,AAJA,EAAQ,WAAW,aAAa,GAAG,EAAQ,WAAW,GAGtD,EAAQ,OAAO,GACX,EAAQ,SAAS,WAAW,KAAG,EAAQ,OAAO;CAGlD,IAAI;EACF,IAAM,IAAK,SAAS,YAAY,GAC1B,IAAa,EAAE;EAErB,AADA,EAAG,SAAS,GAAY,aAAa,IAAI,IAAa,GAAG,CAAC,GAC1D,EAAG,SAAS,EAAI;EAChB,IAAM,IAAI,WAAW,aAAa;EAClC,AAAI,MAAK,EAAE,gBAAgB,GAAG,EAAE,SAAS,CAAE;CAC7C,QAAQ,CAAC;AACX;AAsBA,SAAS,KAAkB;CACzB,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,GAAK,YAAY,OAAO;CAC7B,IAAI,IAAY,EAAI,WAAW,CAAC,CAAC,CAAC;CAElC,OADI,EAAU,aAAa,MAAG,IAAY,EAAU,gBAChB,GAAY,QAAQ,QAAQ,KAAK;AACvE;AAMA,SAAS,GAAe,GAAQ;CAE9B,AADA,EAAO,UAAU,OAAO,cAAc,GACtC,EAAO,iBAAiB,0BAAwB,CAAC,CAAC,SAAQ,MAAM,EAAG,OAAO,CAAC;AAC7E;AAEA,SAAgB,KAAsB;CACpC,IAAM,IAAS,GAAgB;CAC/B,AAAI,IACE,EAAO,UAAU,SAAS,cAAc,KAE1C,GAAe,CAAM,GACjB,EAAO,YAAY,QACrB,EAAc,GAAQ,IAAI,KAEnB,EAAO,YAAY,OAE5B,EAAc,GAAQ,IAAI,IAG1B,EAAY,qBAAqB,IAInC,EAAY,qBAAqB;AAErC;AAkBA,SAAgB,KAAoB;CAClC,IAAM,IAAS,GAAgB;CAC/B,AAAI,IACE,EAAO,UAAU,SAAS,cAAc,KAE1C,GAAe,CAAM,GACrB,EAAc,GAAQ,IAAI,KACjB,EAAO,YAAY,OAE5B,EAAc,GAAQ,IAAI,IAG1B,EAAY,mBAAmB,IAIjC,EAAY,mBAAmB;AAEnC;AAcA,SAAgB,GAAW,GAAO;CAChC,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,KAAO,EAAI,eAAe,GAAG;CAElC,IAAM,IAAQ,EAAI,WAAW,CAAC,GACxB,oBAAa,IAAI,IAAI;EAAC;EAAK;EAAO;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAc;EAAO;EAAM;CAAI,CAAC,GAE5G,KAAgB,MAAS;EAC7B,IAAI,IAAK,aAAgB,UAAU,IAAO,EAAK;EAC/C,OAAO,IAAI;GACT,IAAI,EAAW,IAAI,EAAG,OAAO,GAAG,OAAO;GACvC,IAAK,EAAG;EACV;EACA,OAAO;CACT;CAEA,IAAI,EAAM,WAAW;EACnB,IAAM,IAAQ,EAAa,EAAM,cAAc;EAC/C,AAAI,MAAO,EAAM,MAAM,aAAa;EACpC;CACF;CAGA,IAAM,oBAAS,IAAI,IAAI,GACjB,IAAO,SAAS,iBACpB,EAAM,yBACN,WAAW,WACX,EAAE,aAAa,MAAS,EAAM,eAAe,CAAI,IAAI,WAAW,gBAAgB,WAAW,YAAY,CACzG,GACI;CACJ,OAAQ,IAAW,EAAK,SAAS,IAAI;EACnC,IAAM,IAAQ,EAAa,CAAQ;EACnC,AAAI,KAAO,EAAO,IAAI,CAAK;CAC7B;CACA,IAAI,EAAO,SAAS,GAAG;EACrB,IAAM,IAAQ,EAAa,EAAM,uBAAuB;EACxD,AAAI,KAAO,EAAO,IAAI,CAAK;CAC7B;CACA,EAAO,SAAS,MAAU;EAAE,EAAM,MAAM,aAAa;CAAO,CAAC;AAC/D;AAkDA,SAAgB,GAAiB,GAAW;CAC1C,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,GAAK,YAAY;CACtB,IAAM,IAAQ,EAAI,WAAW,CAAC,GAC1B,IAAY,EAAM;CACtB,AAAI,EAAU,aAAa,MAAG,IAAY,EAAU;CACpD,IAAM,IAAsC,GAAY,QAAQ,MAAM;CACtE,IAAI,KAAU,CAAC,EAAO,QAAQ,KAAK,GAAG;EAGpC,IAAM,IAAS,EAAO,YAEhB,IAAc,EAAO,iBACrB,IAAgB,MAAM,KAAK,EAAO,UAAU;EAClD,OAAO,EAAO,aAAY,EAAO,aAAa,EAAO,YAAY,CAAM;EAOvE,IANA,EAAO,OAAO,GAId,GAAQ,UAAU,GAEd,EAAc,SAAS,GACzB,IAAI;GAEF,IAAM,IAAa,EAAc,IAC3B,IAAa,EAAc,GAAG,EAAE,GAChC,IAAK,SAAS,YAAY,GAE1B,IAAa,EAAW,eAAe,IACzC,IACC,IAAc,EAAY,cAAc,EAAO;GACpD,IAAI,GAAY;IACd,EAAG,SAAS,GAAY,CAAC;IACzB,IAAM,IAAa,EAAU,eAAe,IAAU,IAAY;IAGlE,AAFA,EAAG,OAAO,GAAW,EAAU,aAAa,KAAK,YAAY,EAAU,YAAY,SAAS,EAAU,WAAW,MAAM,GACvH,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE;GACjB;EACF,QAAY,CAAuB;CAEvC,OAAO;EACL,IAAI,EAAM,WAAW;EACrB,IAAI;GACF,IAAM,IAAO,SAAS,cAAc,MAAM;GAC1C,EAAM,iBAAiB,CAAI;GAE3B,IAAM,IAAW,SAAS,YAAY;GAGtC,AAFA,EAAS,mBAAmB,CAAI,GAChC,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAQ;EACvB,QAAQ;GAEN,IAAM,IAAO,EAAM,gBAAgB,GAC7B,IAAO,SAAS,cAAc,MAAM;GAE1C,AADA,EAAK,YAAY,CAAI,GACrB,EAAM,WAAW,CAAI;GAErB,IAAM,IAAW,SAAS,YAAY;GAGtC,AAFA,EAAS,mBAAmB,CAAI,GAChC,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAQ;EACvB;CACF;AACF;AAUA,SAAgB,KAAe;CAC7B,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,GAAK,YAAY,OAAO;CAC7B,IAAI,IAAK,EAAI,WAAW,CAAC,CAAC,CAAC;CAC3B,AAAI,EAAG,aAAa,MAAG,IAAK,EAAG;CAC/B,IAAM,IAAoC,GAAK,QAAQ,MAAM;CAC7D,OAAO,CAAC,EAAE,KAAQ,CAAC,EAAK,QAAQ,KAAK;AACvC;AAYA,SAAS,EAAc,GAAI,GAAY;CACrC,IAAM,IAAQ,SAAS,cAAc,CAAU;CAC/C,KAAK,IAAM,KAAQ,EAAG,YACpB,EAAM,aAAa,EAAK,MAAM,EAAK,KAAK;CAE1C,OAAO,EAAG,aACR,EAAM,YAAY,EAAG,UAAU;CAGjC,OADA,EAAG,WAAW,aAAa,GAAO,CAAE,GAC7B;AACT;AAMA,SAAS,GAAiB,GAAQ;CAChC,EAAO,iBAAiB,IAAI,CAAC,CAAC,SAAQ,MAAM;EAE1C,IAAI,CADe,EAAG,cAAc,0BACtB,GAAG;GACf,IAAM,IAAK,SAAS,cAAc,OAAO;GAGzC,AAFA,EAAG,OAAO,YACV,EAAG,kBAAkB,SACrB,EAAG,aAAa,GAAI,EAAG,UAAU;EACnC;CACF,CAAC;AACH;AAKA,SAAgB,KAAkB;CAChC,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,GAAK,YAAY;CACtB,IAAM,IAAQ,EAAI,WAAW,CAAC,GAC1B,IAAY,EAAM;CACtB,AAAI,EAAU,aAAa,MAAG,IAAY,EAAU;CAEpD,IAAM,IAAsC,GAAY,QAAQ,QAAQ;CACxE,IAAI,GACF,IAAI,EAAO,UAAU,SAAS,cAAc;MAE3B,EAAO,YACV;GACV,IAAM,IAAM,MAAM,KAAK,EAAO,QAAQ,GACO,IAAS;GAiBtD,IAhBA,EAAI,SAAQ,MAAM;IAChB,IAAM,IAAI,SAAS,cAAc,GAAG;IACpC,KAAK,IAAM,KAAS,EAAG,YACjB,EAAM,aAAa,KAA6B,EAAO,YAAY,WACvE,EAAE,YAAY,EAAM,UAAU,EAAI,CAAC;IAQrC,AANA,EAAE,YAAY,EAAE,UAAU,WAAW,KAAU,EAAE,CAAC,CAAC,WAAW,KAAU,EAAE,IACtE,CAAC,EAAE,cAAc,KAAK,CAAC,EAAE,YAAY,KAAK,OAC5C,EAAE,YAAY,IACd,EAAE,YAAY,SAAS,eAAe,MAAQ,CAAC,IAEjD,EAAO,OAAO,CAAC,GACf,AAAa,MAAS;GACxB,CAAC,GACD,EAAO,OAAO,GAEV,GAAQ;IACV,IAAM,IAAK,SAAS,YAAY;IAIhC,AAHA,EAAG,SAAS,EAAO,cAAc,GAAQ,CAAC,GAC1C,EAAG,SAAS,EAAI,GAChB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE;GACjB;EACF;QACK;EAEL,IAAM,IAAW,EAAc,GAAQ,IAAI;EAE3C,AADA,EAAS,UAAU,IAAI,cAAc,GACrC,GAAiB,CAAQ;EAGzB,IAAM,IAAU,EAAS,cAAc,IAAI;EAC3C,IAAI,GAAS;GACX,IAAM,IAAK,SAAS,YAAY;GAIhC,AAHA,EAAG,mBAAmB,CAAO,GAC7B,EAAG,SAAS,EAAK,GACjB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE;EACjB;CACF;MACK;EAWL,IAAM,IAA4C,GAAY,QAAQ,4BAA0B;EAEhG,IADoB,EAAM,WACT;GAGf,IAAM,oBAAa,IAAI,IAAI;IAAC;IAAK;IAAO;IAAM;IAAM;IAAM;IAAM;IAAM;IAAM;IAAc;GAAI,CAAC,GAC3F,IAAqC;GACzC,OAAO,GAAO,cAAc,MAAU,KAAgB,CAAC,EAAW,IAAI,EAAM,OAAO,IACjF,IAAqC,EAAM;GAE7C,AAAI,MAAU,MAAc,IAAQ;GAIpC,IAAM,IAAY,KAAS,EAAW,IAAI,EAAM,OAAO,IACnD,MAAM,KAAK,EAAM,UAAU,CAAC,CACzB,KAAK,MAAM,EAAE,WAAW,CAAC,CACzB,KAAK,EAAE,CAAC,CACR,WAAW,QAAU,GAAG,IAC3B,IAEE,IAAQ,SAAS,cAAc,IAAI;GACzC,EAAM,YAAY;GAClB,IAAM,IAAK,SAAS,cAAc,IAAI,GAChC,IAAW,SAAS,cAAc,OAAO;GAO/C,IANA,EAAS,OAAO,YAChB,EAAS,kBAAkB,SAC3B,EAAG,YAAY,CAAQ,GACvB,EAAG,YAAY,SAAS,eAAe,KAAY,GAAQ,CAAC,GAC5D,EAAM,YAAY,CAAE,GAEhB,KAAS,EAAW,IAAI,EAAM,OAAO,GACvC,EAAM,WAAW,aAAa,GAAO,CAAK;QACrC;IAEL,IAAM,IAAc,EAAI,WAAW,CAAC;IAEpC,AADA,EAAY,eAAe,GAC3B,EAAY,WAAW,CAAK;GAC9B;GAGA,IAAM,IAAW,EAAG,WACd,IAAK,SAAS,YAAY,GAC1B,IAAS,EAAS,aAAa,KAAK,YAAY,EAAS,YAAY,SAAS;GAIpF,AAHA,EAAG,SAAS,GAAU,CAAM,GAC5B,EAAG,SAAS,EAAI,GAChB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE;GACf;EACF;EAKA,IAAI,CADe,EAAI,SAAS,CAAC,CAAC,QAAQ,mBAAmB,GAAG,CAAC,CAAC,KACpD,GAAG;EAEjB,IAAM,oBAAmB,IAAI,IAAI;GAAC;GAAK;GAAO;GAAM;GAAM;GAAM;GAAM;GAAM;GAAM;GAAc;GAAO;EAAI,CAAC,GAGtG,IAAS,CAAC,GACV,oBAAa,IAAI,IAAI,GACrB,IAAiB,EAAM,yBACvB,IAAO,SAAS,mBACpB,EAAe,aAAa,KAAK,YAAY,EAAe,aAAa,GACzE,WAAW,YAAY,WAAW,cAClC,IACF,GACI;EACJ,OAAQ,IAAO,EAAK,SAAS,IAAI;GAC/B,IAAI,CAAC,EAAM,eAAe,CAAI,GAAG;GACjC,IAAI,IAAuC,EAAK,aAAa,KAAK,YAAY,EAAK,gBAAgB;GACnG,OAAO,KAAW,MAAY,KAAgB,CAAC,EAAiB,IAAI,EAAQ,OAAO,IACjF,IAAU,EAAQ;GAGpB,AADI,MAAY,MAAc,IAAU,OACpC,KAAW,CAAC,EAAW,IAAI,CAAO,MACpC,EAAW,IAAI,CAAO,GACtB,EAAO,KAAK,CAAO;EAEvB;EAEA,IAAI,EAAO,WAAW,GAAG;EAGzB,IAAM,IAAQ,SAAS,cAAc,IAAI;EACzC,EAAM,YAAY;EACO,IAAI,IAAe;EAC5C,EAAO,SAAS,MAAU;GACxB,IAAM,IAAK,SAAS,cAAc,IAAI,GAChC,IAAK,SAAS,cAAc,OAAO;GAGzC,AAFA,EAAG,OAAO,YACV,EAAG,kBAAkB,SACrB,EAAG,YAAY,CAAE;GAEjB,IAAM,IAAY,MAAM,KAAK,EAAM,UAAU,CAAC,CAC3C,KAAK,MAAM,EAAE,WAAW,CAAC,CACzB,KAAK,EAAE,CAAC,CACR,QAAQ,mBAAmB,GAAG,CAAC,CAC/B,KAAK,GACF,IAAK,SAAS,eAAe,KAAa,GAAQ;GAGxD,AAFA,EAAG,YAAY,CAAE,GACjB,EAAM,YAAY,CAAE,GACpB,IAAe;EACjB,CAAC;EAGD,IAAM,IAAa,EAAO;EAK1B,IAJA,EAAW,WAAW,aAAa,GAAO,CAAU,GACpD,EAAO,SAAS,MAAU,EAAM,OAAO,CAAC,GAGpC,GAAc;GAChB,IAAM,IAAK,SAAS,YAAY;GAIhC,AAHA,EAAG,SAAS,GAAc,EAAa,YAAY,MAAM,GACzD,EAAG,SAAS,EAAI,GAChB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE;EACjB;CACF;AACF;AAMA,SAAgB,KAAgB;CAC9B,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,GAAK,YAAY,OAAO;CAC7B,IAAI,IAAY,EAAI,WAAW,CAAC,CAAC,CAAC;CAElC,OADI,EAAU,aAAa,MAAG,IAAY,EAAU,gBAC7C,CAAC,CAA+B,GAAY,QAAQ,kBAAkB;AAC/E;;;ACnwBA,SAAS,EAAI,GAAM,GAAM,GAAS,GAAQ,GAAU,GAAY;CAG9D,OAAO;EAAE;EAAM;EAAM;EAAS;EAAQ;EAAU;CAAW;AAC7D;AAWA,IAAa,oBAAkB,IAAI,IAAI;AAOvC,SAAgB,EAAe,GAAQ;CACrC,IAAI,CAAC,KAAU,OAAO,EAAO,QAAS,UAAU;EAC9C,QAAQ,KAAK,yEAAyE;EACtF;CACF;CAIA,AAHI,EAAgB,IAAI,EAAO,IAAI,KACjC,QAAQ,KAAK,6DAA6D,EAAO,KAAK,GAAG,GAE3F,EAAgB,IAAI,EAAO,MAAM,CAAM;AACzC;AAQA,SAAgB,GAAU,GAAM;CAC9B,OAAO,EAAgB,IAAI,CAAI;AACjC;AAMA,IAAa,KAAU,EAAI,QAAQ,QAAQ,uBAAuBC,GAAW,SAAS,SAAS,kBAAkB,MAAM,CAAC,GAC3G,KAAY,EAAI,UAAU,UAAU,yBAAyBC,GAAa,SAAS,SAAS,kBAAkB,QAAQ,CAAC,GACvH,KAAe,EAAI,aAAa,aAAa,4BAA4BC,GAAgB,SAAS;CAI7G,IAAI,SAAS,kBAAkB,WAAW,GAAG,OAAO;CACpD,IAAM,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,GAAK,YAAY,OAAO;CAC7B,IAAI,IAAK,EAAI,WAAW,CAAC,CAAC,CAAC;CAE3B,OADI,EAAG,aAAa,MAAG,IAAK,EAAG,gBACxB,CAAC,CAA0B,GAAK,QAAQ,GAAG;AACpD,CAAC,GACY,KAAY,EAAI,iBAAiB,iBAAiB,uBAAuBC,GAAoB,SAAS,SAAS,kBAAkB,eAAe,CAAC,GACjJ,KAAiB,EAAI,eAAe,eAAe,qBAAqBC,GAAkB,SAAS,SAAS,kBAAkB,aAAa,CAAC,GAC5I,KAAe,EAAI,aAAa,aAAa,mBAAmBC,GAAgB,SAAS,SAAS,kBAAkB,WAAW,CAAC,GAMhI,KAAe,EAAI,aAAa,cAAc,oBAAoBC,GAAkB,CAAC,GACrF,KAAiB,EAAI,eAAe,gBAAgB,sBAAsBC,GAAoB,CAAC,GAC/F,KAAgB,EAAI,cAAc,eAAe,qBAAqBC,GAAmB,CAAC,GAC1F,KAAkB,EAAI,gBAAgB,iBAAiB,iBAAiBC,GAAkB,CAAC,GAM3F,KAAQ,EAAI,MAAM,WAAW,wBAAwBC,GAA0B,CAAC,GAChF,KAAQ,EAAI,MAAM,WAAW,sBAAsBC,GAAwB,CAAC,GAM5E,KAAY,EAAI,UAAU,UAAU,gBAAgBC,GAAa,CAAC,GAClE,KAAa,EAAI,WAAW,WAAW,iBAAiBC,GAAc,CAAC,GAMvE,KAAU,EAAI,QAAQ,QAAQ,kBAAkB,MAAS,EAAK,OAAO,aAAa,GAAG,KAAA,IAAY,MAAQ,CAAC,EAAI,OAAO,gBAAgB,CAAC,GACtI,KAAU,EAAI,QAAQ,QAAQ,kBAAkB,MAAS,EAAK,OAAO,aAAa,GAAG,KAAA,IAAY,MAAQ,CAAC,EAAI,OAAO,gBAAgB,CAAC,GAMtI,KAAQ,EAAI,MAAM,SAAS,yBAAyBC,EAAkB,sBAAsB,CAAC,GAC7F,KAAU,EAAI,QAAQ,QAAQ,gBAAgB,MAAQ,EAAI,OAAO,iBAAiB,CAAC,GACnF,KAAW,EAAI,SAAS,SAAS,iBAAiB,MAAQ,EAAI,OAAO,kBAAkB,CAAC,GACxF,KAAW,EAAI,SAAS,SAAS,iBAAiB,MAAQ,EAAI,OAAO,kBAAkB,CAAC,GACxF,KAAW,EAAI,SAAS,SAAS,iBAAiB,MAAQ,EAAI,OAAO,kBAAkB,CAAC,GACxF,KAAW,EAAI,QAAS,QAAS,mBAAmB,MAAQ,EAAI,OAAO,iBAAiB,CAAC,GAGzF,KAAW;CACtB,MAAM;CACN,MAAM;CACN,MAAM;CACN,SAAS;CACT,SAAS,GAAK,GAAM,MAAS;EAE3B,AADA,EAAI,OAAO,sBAAsB,GAAM,CAAI,GAC3C,EAAI,OAAO,qBAAqB;CAClC;AACF,GAOa,KAAc;CACzB,MAAM;CACN,MAAM;CACN,SAAS;CACT,aAAa;CACb,aAAa;CACb,OAAO;EAAC;EAAO;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;EAAQ;CAAM;CAC7H,SAAS,GAAK,MAAUC,GAAe,GAAO,EAAI,WAAW,QAAQ;CACrE,WAAW,MAAQ;EACjB,IAAI;GACF,IAAM,IAAM,WAAW,aAAa;GACpC,IAAI,GAAK,YAAY;IACnB,IAAI,IAAkC,EAAI,WAAW,CAAC,CAAC,CAAC;IAExD,KADI,GAAI,aAAa,MAAG,IAAK,EAAG,gBACzB,GAAI,aAAa,KAAK,CAA6B,EAAI,MAAM,WAAU,IAAK,EAAG;IACtF,IAAM,IAAmC,GAAK,MAAM,YAAY;IAChE,IAAI,GAAM,OAAO;GACnB;GAEA,IAAM,IAAW,GAAK,YAAY;GAElC,OADI,KAAiB,EAAS,MAAM,YAC7B;EACT,QAAQ;GAAE,OAAO;EAAI;CACvB;AACF,GAMa,KAAkB,EAAI,gBAAgB,iBAAiB,uBAAuBD,EAAkB,cAAc,CAAC,GAM/G,KAAe,EAC1B,aACA,aACA,sCACC,MAAQ;CACP,IAAM,IAAW,EAAI,WAAW,UAE1B,KADU,EAAS,aAAa,KAAK,KAAK,WACvB,QAAQ,QAAQ;CAGzC,AAFA,EAAS,aAAa,OAAO,CAAI,GACjC,EAAS,MAAM,YAAY,MAAS,QAAQ,UAAU,QACtD,EAAI,OAAO,qBAAqB;AAClC,CACF,GAOa,KAAgB;CAC3B,MAAM;CACN,MAAM;CACN,SAAS;CACT,SAAS,GAAK,MAAUE,GAAe,CAAK;CAC5C,gBAAgB;EACd,IAAI;GAAE,OAAO,SAAS,kBAAkB,UAAU,KAAK;EAAI,QAAQ;GAAE,OAAO;EAAI;CAClF;AACF,GAOa,KAAoB;CAC/B,MAAM;CACN,MAAM;CACN,SAAS;CACT,aAAa;CACb,aAAa;CACb,OAAO;EACL;GAAE,OAAO;GAAc,OAAO;EAAS;EACvC;GAAE,OAAO;GAAc,OAAO;EAAS;EACvC;GAAE,OAAO;GAAc,OAAO;EAAS;EACvC;GAAE,OAAO;GAAc,OAAO;EAAS;EACvC;GAAE,OAAO;GAAc,OAAO;EAAS;EACvC;GAAE,OAAO;GAAc,OAAO;EAAS;EACvC;GAAE,OAAO;GAAc,OAAO;EAAS;EACvC;GAAE,OAAO;GAAc,OAAO;EAAS;EACvC;GAAE,OAAO;GAAc,OAAO;EAAS;CACzC;CACA,SAAS,GAAM,MAAUC,GAAkB,CAAK;CAChD,gBAAgB;EACd,IAAI;GACF,IAAM,IAAM,SAAS,kBAAkB,aAAa,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,SAAS,EAAE;GACvF,OAAO,MAAQ,QAAQ,MAAO,KAAO;EACvC,QAAQ;GAAE,OAAO;EAAI;CACvB;AACF,GAOa,KAAgB;CAC3B,MAAM;CACN,MAAM;CACN,SAAS;CACT,aAAa;CACb,aAAa;CACb,OAAO;EAAC;EAAO;EAAQ;EAAO;EAAQ;EAAO;EAAO;CAAK;CACzD,SAAS,GAAM,MAAUC,GAAiB,CAAK;CAC/C,gBAAgB;EACd,IAAI;GACF,IAAM,IAAM,WAAW,aAAa;GACpC,IAAI,CAAC,GAAK,YAAY,OAAO;GAC7B,IAAM,oBAAS,IAAI,IAAI;IAAC;IAAI;IAAM;IAAK;IAAK;IAAK;IAAK;IAAK;IAAK;IAAK;IAAa;IAAM;IAAK;GAAI,CAAC,GAC9F,IAAkC,EAAI,WAAW,CAAC,CAAC,CAAC;GAExD,KADI,GAAI,aAAa,MAAG,IAAK,EAAG,gBACzB,KAAM,CAAC,EAAO,IAA4B,EAAI,OAAO,IAAG,IAAK,EAAG;GAEvE,OADK,MAC8B,EAAI,MAAM,cAAc,iBAAyC,CAAG,CAAC,CAAC,eADzF;EAElB,QAAQ;GAAE,OAAO;EAAI;CACvB;AACF,GAMa,KAAc,EAAI,YAAY,QAAQ,mBAAmB,MAAQ,EAAI,OAAO,iBAAiB,IAAI,MAAQ,EAAI,OAAO,mBAAmB,CAAC,GACxI,KAAgB,EAAI,cAAc,UAAU,eAAe,MAAQ,EAAI,OAAO,mBAAmB,IAAI,MAAQ,EAAI,OAAO,qBAAqB,CAAC,GAC9I,KAAe,EAAI,aAAa,YAAY,sCAAsC,MAAQ,EAAI,OAAO,sBAAsB,CAAC,GAC5H,KAAU,EAAI,QAAQ,UAAU,kBAAkB,MAAQ,EAAI,OAAO,oBAAoB,MAAM,CAAC,GAChG,KAAiB,EAAI,eAAe,gBAAgB,4BAA4B,MAAQ,EAAI,OAAO,oBAAoB,SAAS,CAAC,GACjI,KAAgB,EAAI,cAAc,eAAe,yBAAyB,MAAQ,EAAI,OAAO,mBAAmB,SAASC,GAAmB,CAAC,GAC7I,KAAgB,EAAI,aAAc,aAAe,cAAc,MAAQ,EAAI,OAAO,wBAAwB,SAASC,GAAoB,CAAC,GACxI,KAAgB,EAAI,SAAc,SAAe,UAAU,MAAQ,EAAI,OAAO,cAAc,CAAC,GAO7F,KAAe;CAC1B,MAAM;CACN,MAAM;CACN,MAAM;CACN,SAAS;CACT,cAAc;CACd,SAAS,GAAK,MAAUC,GAAgB,CAAK;AAC/C,GAGa,KAAe;CAC1B,MAAM;CACN,MAAM;CACN,MAAM;CACN,SAAS;CACT,cAAc;CACd,SAAS,GAAK,MAAUC,GAAgB,CAAK;AAC/C,GAUa,KAAiB;CAC5B;EAAC;EAAmB;EAAe;EAAa;CAAa;CAC7D,CAAC,IAAS,EAAO;CACjB;EAAC;EAAS;EAAW;EAAc;EAAW;CAAa;CAC3D,CAAC,IAAgB,EAAY;CAC7B,CAAC,IAAc,EAAY;CAC3B;EAAC;EAAc;EAAgB;EAAe;CAAe;CAC7D;EAAC;EAAO;EAAO;EAAc;EAAW;CAAU;CAClD;EAAC;EAAO;EAAS;EAAU;EAAU;EAAU;EAAU;CAAO;CAChE;EAAC;EAAiB;EAAa;EAAe;EAAS;EAAU;CAAY;AAC/E,GAQa,KAAU;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,GChUa,IAAiB;CAC5B,aAAa;CACb,QAAQ;CACR,WAAW;CACX,WAAW;CACX,OAAO;CACP,WAAW;CACX,SAAS;CAIT,cAAc;CACd,oBAAoB;CAEpB,gBAAgB;CAEhB,kBAAkB;CAMlB,uBAAuB;CACvB,gBAAgB;CAChB,kBAAkB;CAClB,gBAAgB;CAChB,sBAAsB;CACtB,kBAAkB;CAClB,cAAc;CACd,SAAS;CACT,UAAU;CACV,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,eAAe;CACf,cAAc;CACd,eAAe;CACf,qBAAqB;CACrB,OAAO;CACP,eAAe;CACf,kBAAkB;CAClB,eAAe;CACf,cAAc;CAId,iBAAiB,KAAK,OAAO;CAE7B,mBAAmB;CAEnB,iBAAiB;CAEjB,cAAc;EACZ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CAEA,UAAU;CAEV,YAAY;CAEZ,WAAW;CAEX,iBAAiB;CAEjB,UAAU;CAEV,aAAa;CACb,eAAe;CACf,iBAAiB;CAEjB,UAAU;CAEV,UAAU;CAEV,gBAAgB;CAEhB,mBAAmB;CAEnB,eAAe,CAAC;CAEhB,SAAS;CAET,cAAc;CAEd,WAAW;CAEX,oBAAoB;CAEpB,oBAAoB;CAGpB,YAAY;CAIZ,MAAM;CAKN,iBAAiB;CACjB,wBAAwB;CACxB,mBAAmB;CAInB,mBAAmB;CAInB,WAAW;CAEX,eAAe,CAAC;CAGhB,kBAAkB,CAAC;CAEnB,sBAAsB;CAItB,gBAAgB;CAEhB,UAAU;CAGV,cAAc,IAAI,OAAO;CAGzB,cAAc;CAGd,eAAe;CACf,oBAAoB;EAAC;EAAQ;EAAU;EAAa;EAAQ;EAAa;EAAe;CAAc;CAItG,SAAS;AACX,GC3Na,IAAK;CAChB,SAAS;EACP,MAAM;EACN,QAAQ;EACR,WAAW;EACX,eAAe;EACf,aAAa;EACb,WAAW;EACX,WAAW;EACX,aAAa;EACb,YAAY;EACZ,cAAc;EACd,IAAI;EACJ,IAAI;EACJ,WAAW;EACX,QAAQ;EACR,SAAS;EACT,MAAM;EACN,MAAM;EACN,IAAI;EACJ,MAAM;EACN,OAAO;EACP,OAAO;EACP,OAAO;EACP,MAAM;EACN,OAAO;EACP,UAAU;EACV,qBAAqB;EACrB,cAAc;EACd,WAAW;EACX,YAAY;EACZ,gBAAgB;EAChB,2BAA2B;EAC3B,YAAY;EACZ,uBAAuB;EACvB,UAAU;EACV,YAAY;EACZ,WAAW;EACX,MAAM;EACN,aAAa;EACb,YAAY;EACZ,OAAO;EACP,WAAW;EACX,WAAW;EACX,iBAAiB;EACjB,sBAAsB;EACtB,aAAa;EACb,kBAAkB;EAElB,gBAAgB;GACd,GAAY;GACZ,YAAY;GACZ,KAAY;EACd;CACF;CAEA,YAAY;EACV,WAAc;EACd,OAAc;EACd,KAAc;EACd,gBAAiB;EACjB,aAAc;EACd,iBAAiB;EACjB,cAAc;EACd,WAAc;EACd,WAAc;CAChB;CAEA,aAAa;EACX,WAAgB;EAChB,OAAgB;EAChB,UAAgB;EAChB,gBAAgB;EAChB,SAAgB;EAChB,gBAAgB;EAChB,WAAgB;EAChB,WAAgB;EAChB,WAAgB;EAChB,aAAgB;EAChB,YAAgB;EAChB,aAAgB;EAChB,WAAgB;EAChB,WAAgB;CAClB;CAEA,aAAa;EACX,WAAgB;EAChB,OAAgB;EAChB,UAAgB;EAChB,gBAAgB;EAChB,YAAgB;EAChB,kBAAkB;EAClB,WAAgB;EAChB,WAAgB;EAEhB,WAAiB,MAAS,aAAa;EACvC,eAAgB;EAChB,YAAgB;CAClB;CAEA,aAAa;EACX,WAAmB;EACnB,OAAmB;EACnB,mBAAmB;EACnB,KAAmB;EACnB,WAAmB;EACnB,OAAmB;EACnB,YAAY;GACV,SAAS;GACT,QAAS;GACT,SAAS;GACT,MAAS;GACT,QAAS;GACT,SAAS;GACT,SAAS;EACX;CACF;CAEA,YAAY;EACV,WAAmB;EACnB,OAAmB;EACnB,mBAAmB;EACnB,KAAmB;EACnB,OAAmB;EACnB,MAAmB;EACnB,OAAmB;EACnB,UAAmB;EACnB,YAAmB;EACnB,WAAmB;EACnB,WAAmB;EACnB,OAAmB;EACnB,YAAY;GACV,SAAe;GACf,WAAe;GACf,YAAe;GACf,OAAe;GACf,eAAe;GACf,OAAe;GACf,QAAe;GACf,SAAe;EACjB;CACF;CAEA,aAAa;EACX,WAAkB;EAClB,kBAAkB;EAClB,iBAAkB;EAClB,iBAAkB;EAClB,eAAkB;EAClB,WAAkB;EAClB,SAAkB;EAClB,SAAkB;EAClB,oBAAoB;EACpB,kBAAoB;EACpB,YAAoB;EACpB,eAAoB;EACpB,WAAoB;EACpB,UAAoB;EACpB,OAAoB;CACtB;CAEA,iBAAiB;EACf,OAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;CACX;CAEA,iBAAiB;EACf,OAAW;EACX,WAAW;EACX,OAAW;EACX,WAAW;GACT;IACE,UAAU;IACV,OAAO;KACL;MAAE,MAAM;MAAa,QAAQ;KAAO;KACpC;MAAE,MAAM;MAAa,QAAQ;KAAS;KACtC;MAAE,MAAM;MAAa,QAAQ;KAAY;KACzC;MAAE,MAAM;MAAa,QAAQ;KAAqB;IACpD;GACF;GACA;IACE,UAAU;IACV,OAAO,CACL;KAAE,MAAM;KAAiC,QAAQ;IAAO,GACxD;KAAE,MAAM;KAAiC,QAAQ;IAAO,CAC1D;GACF;GACA;IACE,UAAU;IACV,OAAO;KACL;MAAE,MAAM;MAAe,QAAQ;KAAqB;KACpD;MAAE,MAAM;MAAe,QAAQ;KAAmC;KAClE;MAAE,MAAM;MAAe,QAAQ;KAAoB;IACrD;GACF;GACA;IACE,UAAU;IACV,OAAO,CACL;KAAE,MAAM;KAAoB,QAAQ;IAAsB,CAC5D;GACF;GACA;IACE,UAAU;IACV,OAAO,CACL;KAAE,MAAM;KAAY,QAAQ;IAAmB,GAC/C;KAAE,MAAM;KAAY,QAAQ;IAAiB,CAC/C;GACF;GACA;IACE,UAAU;IACV,OAAO,CACL;KAAE,MAAM;KAAoB,QAAQ;IAAsC,CAC5E;GACF;EACF;CACF;CAEA,aAAa;EACX,KAAe;EACf,MAAe;EACf,OAAe;EACf,MAAe;EACf,QAAe;EACf,WAAe;EACf,WAAe;EACf,gBAAgB;EAChB,YAAe;EACf,aAAe;EACf,cAAe;EACf,MAAe;EACf,OAAe;EACf,OAAe;EACf,OAAe;EACf,MAAe;EACf,aAAe;EACf,aAAe;EACf,kBAAkB;CACpB;CAEA,WAAW;EACT,cAAc;EAEd,QAAa,MAAM,UAAU;EAE7B,aAAa,GAAG,MAAQ,UAAU,EAAE,GAAG;EAEvC,QAAa,MAAM,UAAU;EAE7B,aAAa,GAAG,MAAQ,UAAU,EAAE,GAAG;CACzC;CAEA,UAAU;EACR,MAAM;GACJ,WAAY;GACZ,UAAY;GACZ,SAAY;GACZ,UAAY;GACZ,YAAY;EACd;EACA,OAAO;GACL,WAAc;GACd,OAAc;GACd,WAAc;GACd,SAAc;GACd,aAAc;GACd,YAAc;GACd,cAAc;GACd,YAAc;GACd,aAAc;GACd,WAAc;GACd,YAAc;GACd,aAAc;EAChB;EACA,MAAM;GACJ,WAAoB;GACpB,OAAoB;GACpB,gBAAoB;GACpB,iBAAoB;GACpB,UAAoB;GACpB,gBAAoB;GACpB,gBAAoB;GACpB,iBAAoB;GACpB,oBAAoB;GACpB,iBAAoB;GACpB,aAAoB;EACtB;EACA,OAAO;GACL,WAAoB;GACpB,OAAoB;GACpB,aAAoB;GACpB,aAAoB;GACpB,aAAoB;GACpB,WAAoB;GACpB,eAAoB;GACpB,gBAAoB;GACpB,cAAoB;GACpB,YAAoB;GACpB,cAAoB;GACpB,aAAoB;GACpB,WAAoB;GACpB,kBAAoB;GACpB,kBAAoB;GACpB,aAAoB;GACpB,eAAoB;GACpB,iBAAoB;GACpB,gBAAoB;GACpB,kBAAoB;GACpB,iBAAoB;GACpB,gBAAoB;GACpB,WAAoB;GACpB,eAAoB;GACpB,eAAoB;GACpB,aAAoB;GACpB,oBAAoB;GACpB,WAAoB;GACpB,UAAoB;GACpB,SAAoB;GACpB,UAAoB;GACpB,WAAoB;GACpB,aAAoB;GACpB,eAAoB;EACtB;EACA,OAAO;GACL,WAAc;GACd,OAAc;GACd,WAAc;GACd,SAAc;GACd,aAAc;GACd,YAAc;GACd,cAAc;GACd,cAAc;GACd,aAAc;GACd,aAAc;EAChB;CACF;CAEA,QAAQ;EAEN,cAAc,MACZ,WAAW,EAAK;EAElB,YAAY,MACV,oDAAoD,EAAQ;CAChE;CAEA,WAAW;EACT,WAAgB;EAChB,UAAgB;EAChB,UAAgB;EAChB,UAAgB;EAChB,YAAgB;EAChB,cAAgB;EAChB,WAAgB;EAChB,YAAgB;EAChB,WAAgB;EAChB,gBAAgB;EAChB,OAAgB;EAChB,OAAgB;CAClB;AACF,GCjVa,KAAU,EAAE,MAAG;AAS5B,SAAgB,GAAe,GAAM,GAAQ;CAC3C,IAAI,OAAO,KAAS,YAAY,CAAC,GAC/B,MAAU,UAAU,+DAA+D;CAErF,IAAI,CAAC,KAAU,OAAO,KAAW,UAC/B,MAAU,UAAU,4CAA4C,EAAK,qBAAqB;CAE5F,GAAQ,KAAQ;AAClB;AAQA,SAAgB,GAAc,GAAM;CAElC,IAAI,CAAC,KAAQ,MAAS,MAAM,OAAO;CAEnC,IAAI,OAAO,KAAS,UAAU;EAC5B,IAAM,IAAU,GAAQ;EAWxB,OAVK,IAUE,EAAU,EAAU,CAAC,GAAG,CAAE,GAAG,CAAO,KAPzC,QAAQ,KACN,wBAAwB,EAAK,0EACA,EAAK,2BAA2B,EAAK,gCACpC,EAAK,KAAK,EAAK,GAC/C,GACO;CAGX;CAOA,OALI,OAAO,KAAS,WAEX,EAAU,EAAU,CAAC,GAAG,CAAE,GAAG,CAAI,IAGnC;AACT;;;ACxDA,IAAM,KAAkB;CACtB;CAAU;CAAS;CAAU;CAAU;CAAS;CAAQ;CAAQ;CAChE;CAAQ;CAAQ;CAAY;CAAU;CAAS;CAAY;CAC3D;CAAW;CAAO;CAAoB;CACtC;CAAU;CAAc;AAC1B,GAGM,qBAAc,IAAI,IAAI,CAAC,QAAQ,CAAC,GAGhC,KAAY;CAAC;CAAQ;CAAO;CAAU;CAAc;CAAc;CAAU;CAAc;AAAQ,GAOlG,qBAAkB,IAAI,IAAI;CAAC;CAAU;CAAc;AAAQ,CAAC,GAO5D,qBAAe,IAAI,IAAI,CAAC,MAAM,CAAC,GAG/B,qBAAsB,IAAI,IAAI;CAClC;CAAS;CAAoB;CAAa;CAC1C;CAAc;CACd;CAAS;CAAa;CAAU;CAChC;CAAgB;CAAgB;CAAgB;CAIhD;AACF,CAAC,GAOK,KAA2B,6GAG3B,qBAAuB,IAAI,IAAI;CACnC;CACA;CACA;CACA;CACA;CACA;AACF,CAAC,GAEK,qBAAsB,IAAI,IAAI;CAAC;CAAS;CAAU;CAAW;AAAM,CAAC,GACpE,qBAAuB,IAAI,IAAI;CAAC;CAAS;CAAU;AAAO,CAAC,GAC3D,KAAsB,wEACtB,KAAW;AAcjB,SAAgB,EAAa,GAAM,GAAS;CAC1C,OAAO,GAAe,GAAM,CAAO,CAAC,CAAC;AACvC;AAoBA,SAAgB,GAAe,GAAM,EAAE,kBAAe,OAAU,CAAC,GAAG;CAClE,IAAM,IAAM,IAAI,UAAU,CAAC,CAAC,gBAAgB,SAAS,KAAQ,GAAG,UAAU,WAAW,GAI/E,IAAc,MAAM,KAAK,EAAI,iBAAiB,GAAG,CAAC,GAGlD,IAAa,IAAI,IACrB,IAAe,GAAgB,QAAQ,MAAM,MAAM,QAAQ,IAAI,EACjE;CAEA,KAAK,IAAM,KAAM,GAAa;EAC5B,IAAM,IAAM,EAAG,QAAQ,YAAY;EAGnC,IAAI,GAAY,IAAI,CAAG,GAAG;GACxB,EAAG,YAAY,GAAG,EAAG,UAAU;GAC/B;EACF;EAGA,IAAI,EAAW,IAAI,CAAG,GAAG;GACvB,EAAG,OAAO;GACV;EACF;EAGA,IAAI,MAAQ,UAAU;GACpB,IAAM,IAAM,EAAG,aAAa,KAAK;GACjC,IAAI,CAAC,KAAO,CAAC,GAAmB,CAAG,GAAG;IACpC,EAAG,OAAO;IACV;GACF;EACF;EAGA,KAAK,IAAM,KAAQ,MAAM,KAAK,EAAG,UAAU,GAAG;GAE5C,IAAI,EAAK,KAAK,WAAW,IAAI,GAAG;IAC9B,EAAG,gBAAgB,EAAK,IAAI;IAC5B;GACF;GAMA,IAAI,EAAK,SAAS,SAAS;IACzB,IAAM,IAAU,GAAmB,EAAK,KAAK;IAC7C,AAAI,IAAS,EAAG,aAAa,SAAS,CAAO,IACxC,EAAG,gBAAgB,OAAO;IAC/B;GACF;GAEA,IAAI,GAAa,IAAI,EAAK,IAAI,GAAG;IAC/B,EAAG,gBAAgB,EAAK,IAAI;IAC5B;GACF;GAEA,IAAI,GAAU,SAAS,EAAK,IAAI,GAAG;IACjC,IAAM,IAAM,EAAK,MAAM,KAAK,GACtB,IAAgB,GAAgB,IAAI,EAAK,IAAI,KAChD,EAAK,SAAS,SAAS;KAAC;KAAO;KAAS;KAAS;IAAQ,CAAC,CAAC,SAAS,EAAG,OAAO,GAC3E,IAAY,EAAG,YAAY;IAIjC,IAAI,EAHS,EAAK,SAAS,WACvB,GAAa,GAAK,EAAE,aAAU,CAAC,IAC/B,GAAU,GAAK;KAAE,OAAO;KAAe;IAAU,CAAC,IAC3C;KACT,EAAG,gBAAgB,EAAK,IAAI;KAC5B;IACF;GACF;GAEA,IAAI,EAAG,YAAY,UAAU;IAC3B,IAAI,EAAK,SAAS,UAAU;KAC1B,EAAG,gBAAgB,EAAK,IAAI;KAC5B;IACF;IACA,AAAI,EAAK,SAAS,SAAS,CAAC,GAAmB,EAAK,KAAK,KACvD,EAAG,gBAAgB,EAAK,IAAI;GAEhC;EACF;EAOA,IALI,MAAQ,OAAO,EAAG,aAAa,QAAQ,MAAM,YAC/C,EAAG,aAAa,OAAO,qBAAqB,GAI1C,MAAQ,aAGN,EAFgB,EAAG,QAAQ,iBAAiB,MAAM,QAClC,EAAG,QAAQ,IAAI,MAAM,SACrB,EAAG,aAAa,MAAM,MAAM,YAC9C,EAAG,OAAO;OAEV,KAAK,IAAM,KAAQ,MAAM,KAAK,EAAG,UAAU,GACzC,AAAK;GAAC;GAAQ;GAAW;EAAiB,CAAC,CAAC,SAAS,EAAK,IAAI,KAC5D,EAAG,gBAAgB,EAAK,IAAI;CAKtC;CAEA,OAAO,EAAI;AACb;AAUA,SAAS,GAAmB,GAAO;CACjC,IAAM,IAAO,CAAC;CACd,KAAK,IAAM,MAAS,KAAS,GAAA,CAAI,MAAM,GAAG,GAAG;EAC3C,IAAM,IAAM,EAAK,QAAQ,GAAG;EAC5B,IAAI,MAAQ,IAAI;EAChB,IAAM,IAAO,EAAK,MAAM,GAAG,CAAG,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,GAC7C,IAAM,EAAK,MAAM,IAAM,CAAC,CAAC,CAAC,KAAK;EACjC,CAAC,KAAQ,CAAC,KACT,GAAoB,IAAI,CAAI,MAC7B,GAAyB,KAAK,CAAG,KACrC,EAAK,KAAK,GAAG,EAAK,IAAI,GAAK;CAC7B;CACA,OAAO,EAAK,KAAK,IAAI;AACvB;AAgBA,SAAS,GAAa,GAAO,EAAE,eAAY,OAAU,CAAC,GAAG;CACvD,IAAM,KAAU,KAAS,GAAA,CAAI,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO;CAC/D,KAAK,IAAM,KAAS,GAAQ;EAC1B,IAAI,kBAAkB,KAAK,CAAK,GAAG;EACnC,IAAM,IAAM,EAAM,QAAQ,OAAO,EAAE;EAC9B,SACD,CAAC,GAAU,GAAK;GAAE,OAAO;GAAM;EAAU,CAAC,GAAG,OAAO;CAC1D;CACA,OAAO;AACT;AAQA,SAAS,GAAmB,GAAK;CAC/B,IAAM,KAAW,KAAO,GAAA,CAAI,KAAK;CAEjC,IADI,CAAC,KACD,EAAQ,WAAW,IAAI,KAAK,EAAQ,WAAW,GAAG,GAAG,OAAO;CAChE,IAAI;EACF,IAAM,IAAM,IAAI,IAAI,CAAO;EAE3B,OADI,EAAI,aAAa,YACd,GAAqB,IAAI,EAAI,SAAS,YAAY,CAAC;CAC5D,QAAQ;EACN,OAAO;CACT;AACF;AAYA,SAAgB,EAAY,GAAK,EAAE,eAAY,IAAO,WAAQ,MAAc,CAAC,GAAG;CAC9E,IAAM,KAAW,KAAO,GAAA,CAAI,KAAK;CAEjC,OADI,CAAC,KAAW,KAAO,OAAa,OAC7B,GAAU,GAAS;EAAE;EAAO;CAAU,CAAC,IAAI,IAAM;AAC1D;AASA,SAAS,GAAU,GAAO,EAAE,WAAQ,IAAO,eAAY,OAAU,CAAC,GAAG;CACnE,IAAM,KAAW,KAAS,GAAA,CAAI,KAAK;CAEnC,IADI,CAAC,KACD,KAAa,GAAoB,KAAK,CAAO,GAAG,OAAO;CAE3D,IAAI;EACF,IAAM,IAAS,IAAI,IAAI,GAAS,EAAQ;EAExC,QADkB,IAAQ,KAAuB,GAAA,CAChC,IAAI,EAAO,QAAQ;CACtC,QAAQ;EACN,OAAO;CACT;AACF;;;ACnTA,SAAgB,GAAa,GAAU,GAAS;CAC9C,IAAM,IAAY,EAAc,OAAO,EAAE,OAAO,eAAe,CAAC,GAG1D,IAAW,EAAc,OAAO;EACpC,OAAO;EACP,iBAAiB,EAAQ,WAAW,UAAU;EAC9C,YAAY,OAAO,EAAQ,eAAe,EAAK;EAC/C,kBAAkB;EAClB,cAAc;EACd,MAAM;CACR,CAAC,GAGG,IAAiB;CACrB,IAAI,EAAQ,YAAY,EAAQ,aAC9B,IAAI;EAAE,IAAiB,aAAa,QAAQ,EAAQ,WAAW,KAAK;CAAI,QAAY,CAAU;CAOhG,AALA,AACE,MAAiB,EAAS,YAAY,cACI,EAAW,SAAS,GAAA,CAAI,KAAK,KAClE,EAAS,aAAa,GAAA,CAAI,KAAK,GAEtC,EAAS,YAAY,EAAa,GAAgB,EAAE,cAAc,GAAK,CAAC;CAGxE,IAAM,IAAc,EAAQ,qBAAqB,EAAQ,eAAe;CAsExE,OArEI,MACF,EAAS,MAAM,aAAa,IAI1B,EAAQ,oBACV,EAAS,MAAM,WAAW,EAAQ,kBAMhC,EAAQ,SACV,EAAS,MAAM,YAAY,GAAG,EAAQ,OAAO,MACpC,EAAQ,cACjB,EAAS,MAAM,YAAY,GAAG,EAAQ,UAAU,MAE9C,EAAQ,cACV,EAAS,MAAM,YAAY,GAAG,EAAQ,UAAU,MAGlD,EAAU,YAAY,CAAQ,GAI1B,EAAQ,UAAU,UACpB,EAAU,UAAU,IAAI,eAAe,GACvC,SAAS,KAAK,UAAU,IAAI,eAAe,KAClC,EAAQ,UAAU,WAC3B,EAAU,UAAU,IAAI,eAAe,GACvC,SAAS,KAAK,UAAU,IAAI,eAAe,IAIzC,EAAQ,aACV,EAAU,UAAU,IAAI,aAAa,GACrC,EAAS,iBAAiB,0CAAwC,CAAC,CAAC,SAAS,MAAO;EAClF,EAAG,aAAa,YAAY,EAAE;CAChC,CAAC,IAIC,EAAQ,cAAc,UACxB,EAAS,aAAa,OAAO,KAAK,GAClC,EAAU,UAAU,IAAI,YAAY,IAIlC,EAAQ,oBAAoB,YAC9B,EAAU,UAAU,IAAI,4BAA4B,GAIlD,EAAQ,kBACV,EAAU,UAAU,IAAI,mBAAmB,GACvC,EAAQ,uBACV,EAAU,MAAM,YAAY,mBAAmB,GAAG,EAAQ,oBAAoB,GAAG,IAKjF,EAAQ,cACV,EAAU,MAAM,YAAY,oBAAoB,EAAQ,UAAU,GAIpE,EAAS,MAAM,UAAU,QACzB,EAAS,MAAM,CAAS,GAEjB;EAAE;EAAW;CAAS;AAC/B;;;ACzGA,IAAa,qBAAiB,IAAI,IAAI,GAqBlC,KAAc,CAAC;AAMnB,SAAgB,GAAc,GAAM;CAClC,KAAc,MAAM,QAAQ,CAAI,IAAI,IAAO,CAAC;AAC9C;AAQA,IAAa,oBAAiB,IAAI,IAAI,GAEzB,KAAb,MAAqB;CAKnB,YAAY,GAAU,IAAc,CAAC,GAAG;EAyBtC,AAxBA,KAAK,WAAW,GAChB,KAAK,UAAU,EAAU,GAAgB,CAAW,GAGpD,KAAK,SAAS,GAAc,KAAK,QAAQ,IAAI,GAG7C,KAAK,aAAiC,CAAC,GAGvC,KAAK,6BAAa,IAAI,IAAI,GAG1B,KAAK,2BAAW,IAAI,IAAI,GAGxB,KAAK,2BAAW,IAAI,IAAI,GAExB,KAAK,aAAa,CAAC,GACnB,KAAK,SAAS,IACd,KAAK,iBAAiB,MACtB,KAAK,mBAAmB,MACxB,KAAK,wBAAwB,MAE7B,KAAK,kBAAkB;CACzB;CAMA,aAAa;EAEX,IAAM,EAAE,cAAW,gBAAa,GAAa,KAAK,UAAU,KAAK,OAAO;EAKxE,AAJA,KAAK,WAAW,YAAY,GAC5B,KAAK,WAAW,WAAW,GAG3B,KAAK,iBAAiB;EAGtB,IAAM,IAAU,KAAK,SAAS,IAAI,SAAS;EAC3C,AAAI,GAAS,OACX,EAAU,aAAa,EAAQ,IAAI,CAAQ,GAC3C,KAAK,WAAW,UAAU,EAAQ;EAGpC,IAAM,IAAY,KAAK,SAAS,IAAI,WAAW;EA0B/C,OAzBI,GAAW,OACb,EAAU,YAAY,EAAU,EAAE,GAClC,KAAK,WAAW,YAAY,EAAU,KAIxC,KAAK,kBAAkB,CAAQ,GAG3B,KAAK,QAAQ,SACf,EAAS,MAAM,GAGjB,KAAK,SAAS,IAGd,KAAK,OAAO,iBAAiB,GAG7B,KAAK,oBAAoB,GAErB,OAAO,KAAK,QAAQ,UAAW,cACjC,KAAK,QAAQ,OAAO,IAAI,GAGnB;CACT;CAEA,mBAAmB;EACjB,IAAM,KAAY,GAAM,MAAgB;GACtC,IAAM,IAAW,IAAI,EAAY,IAAI;GAErC,AADA,KAAK,SAAS,IAAI,GAAM,CAAQ,GAChC,EAAS,WAAW;EACtB;EAEA,KAAK,IAAM,EAAE,SAAM,UAAO,gBAAa,IACjC,OAAO,KAAY,cAAc,CAAC,EAAQ,KAAK,OAAO,KAC1D,EAAS,GAAM,CAAK;EAItB,IAAI,GAAe,OAAO,GACxB,KAAK,IAAM,CAAC,GAAM,MAAgB,IAChC,EAAS,GAAM,CAAW;CAGhC;CAOA,uBAAuB;EACrB,KAAK,IAAM,EAAE,SAAM,UAAO,gBAAa,IAAa;GAClD,IAAI,OAAO,KAAY,YAAY;GACnC,IAAM,IAAY,EAAQ,KAAK,OAAO;GAElC,UADc,KAAK,SAAS,IAAI,CACV,GAE1B,IAAI,GAAW;IACb,IAAM,IAAW,IAAI,EAAM,IAAI;IAE/B,AADA,KAAK,SAAS,IAAI,GAAM,CAAQ,GAChC,EAAS,WAAW;GACtB,OAAO;IACL,IAAM,IAAW,KAAK,SAAS,IAAI,CAAI;IAEvC,AADI,OAAO,GAAU,WAAY,cAAY,EAAS,QAAQ,GAC9D,KAAK,SAAS,OAAO,CAAI;GAC3B;EACF;CACF;CAQA,eAAe,GAAM,GAAa;EAChC,IAAI,KAAK,SAAS,IAAI,CAAI,GAAG,OAAO;EACpC,IAAM,IAAW,IAAI,EAAY,IAAI;EAGrC,OAFA,EAAS,WAAW,GACpB,KAAK,SAAS,IAAI,GAAM,CAAQ,GACzB;CACT;CAEA,qBAAqB,GAAS;EAC5B,IAAI,CAAC,GAAS,MAAM,OAAO,EAAQ,OAAQ,YACzC,MAAU,UAAU,sEAAsE;EAE5F,IAAM,IAAW,KAAK,QAAQ,kBAAkB,KAAK,QAAQ,gBAAgB,CAAC,IACxE,IAAQ,EAAS,WAAW,MAAS,EAAK,OAAO,EAAQ,EAAE;EAIjE,OAHI,KAAS,IAAG,EAAS,KAAS,IAC7B,EAAS,KAAK,CAAO,GAC1B,KAAK,OAAO,mBAAmB,GACxB;CACT;CAUA,IAAI,GAAQ,IAAU,CAAC,GAAG;EAKxB,OAJI,MAAM,QAAQ,EAAO,OAAO,KAC9B,EAAO,QAAQ,SAAS,MAAM,EAAe,CAAC,CAAC,GAEjD,KAAK,eAAe,GAAQ,CAAO,GAC5B;CACT;CAOA,UAAU,GAAM;EACd,OAAO,KAAK,SAAS,IAAI,CAAI,CAAC,EAAE,aAAa;CAC/C;CAEA,eAAe,GAAQ,IAAgB,CAAC,GAAG;EACzC,IAAM,EAAE,YAAS;EACjB,IAAI,CAAC,KAAQ,OAAO,KAAS,UAAU;GACrC,QAAQ,KAAK,yDAAyD;GACtE;EACF;EACA,IAAI,KAAK,SAAS,IAAI,CAAI,GAAG;GAC3B,QAAQ,KAAK,wBAAwB,EAAK,gDAAgD;GAC1F;EACF;EACA,IAAM,IAAa,OAAO,EAAO,WAAY,aACzC,EAAO,QAAQ,MAAM,CAAa,KAAK,OACvC;EACJ,KAAK,SAAS,IAAI,GAAM;GAAE;GAAQ;EAAU,CAAC;CAC/C;CAEA,sBAAsB;EAChB,MAAe,SAAS,GAC5B,KAAK,IAAM,EAAE,WAAQ,gBAAa,EAAe,OAAO,GACtD,KAAK,eAAe,GAAQ,CAAO;CAEvC;CAEA,kBAAkB,GAAU;EAG1B,IAAM,IAAK,EAAG,GAAU,eAAe,KAAK,cAAc,CAAC,GACrD,IAAK,EAAG,GAAU,eAAe;GAErC,AADA,KAAK,WAAW,UAAU,UAAU,IAAI,YAAY,GAChD,OAAO,KAAK,QAAQ,WAAY,cAClC,KAAK,QAAQ,QAAQ,IAAI;EAE7B,CAAC,GACK,IAAK,EAAG,GAAU,cAAc;GAGpC,AAFA,KAAK,WAAW,UAAU,UAAU,OAAO,YAAY,GACvD,KAAK,cAAc,GACf,OAAO,KAAK,QAAQ,UAAW,cACjC,KAAK,QAAQ,OAAO,IAAI;EAE5B,CAAC,GAEK,IAAK,KAAK,GAAG,WAAW,MAAS,KAAK,cAAc,CAAI,CAAC,GACzD,IAAU,KAAK,GAAG,WAAW,MAAS;GAE1C,IADI,KAAK,QAAQ,aAAY,KAAK,eAAe,GAAG,IAAO,KAAK,QAAQ,IACpE,MAAS,KAAK,uBAAuB;IAAE,KAAK,wBAAwB;IAAM;GAAQ;GACtF,KAAK,QAAQ,sBAAsB,gBAAgB,GAAM,IAAI;EAC/D,CAAC;EAID,IAHA,KAAK,WAAW,KAAK,GAAI,GAAI,GAAI,GAAI,CAAO,GAGxC,KAAK,QAAQ,YAAY,KAAK,QAAQ,aAAa;GACrD,IAAM,IAAK,KAAK,GAAG,WAAW,MAAS,KAAK,kBAAkB,CAAI,CAAC;GACnE,KAAK,WAAW,KAAK,CAAE;EACzB;CACF;CAEA,kBAAkB,GAAM;EAGtB,AAFA,KAAK,mBAAmB,GACxB,aAAa,KAAK,cAAc,GAChC,KAAK,iBAAiB,iBAAiB,KAAK,cAAc,GAAG,KAAK,QAAQ,iBAAiB,GAAG;CAChG;CAEA,MAAM,gBAAgB;EAGpB,IAFA,aAAa,KAAK,cAAc,GAChC,KAAK,iBAAiB,MAClB,KAAK,oBAAoB,MAAM;EACnC,IAAM,IAAO,KAAK;EAClB,KAAK,mBAAmB;EACxB,IAAM,IAAM,KAAK,QAAQ,aACnB,IAAU,KAAK,IAAI;EACzB,IAAI;GACF,IAAM,IAAU,KAAK,QAAQ;GAO7B,AANI,OAAO,GAAS,QAAS,aAC3B,MAAM,EAAQ,KAAK;IAAE;IAAK;IAAM;IAAS,SAAS;GAAK,CAAC,KAExD,aAAa,QAAQ,GAAK,CAAI,GAC9B,aAAa,QAAQ,IAAM,YAAY,KAAK,UAAU,EAAE,WAAQ,CAAC,CAAC,IAEpE,KAAK,aAAa,YAAY;IAAE;IAAK;IAAM;GAAQ,CAAC;EACtD,SAAS,GAAO;GACd,KAAK,aAAa,iBAAiB;IAAE;IAAK;GAAM,CAAC;EACnD;CACF;CAEA,MAAM,eAAe;EACnB,IAAM,IAAU,KAAK,QAAQ;EAC7B,IAAI,OAAO,GAAS,QAAS,YAC3B,OAAO,EAAQ,KAAK;GAAE,KAAK,KAAK,QAAQ;GAAa,SAAS;EAAK,CAAC;EAEtE,IAAI;GAAE,OAAO,aAAa,QAAQ,KAAK,QAAQ,WAAW;EAAG,QAAY;GAAE,OAAO;EAAM;CAC1F;CAaA,OAAO,GAAM,GAAG,GAAM;EACpB,IAAM,CAAC,GAAY,KAAc,EAAK,MAAM,GAAG,GACzC,IAAS,KAAK,SAAS,IAAI,CAAU;EAC3C,IAAI,CAAC,GAAQ;GACX,QAAQ,KAAK,gCAAgC,EAAW,sBAAsB,EAAK,GAAG;GACtF;EACF;EACA,IAAI,OAAO,EAAO,MAAgB,YAAY;GAC5C,QAAQ,KAAK,gCAAgC,EAAW,yBAAyB,EAAW,YAAY,EAAK,GAAG;GAChH;EACF;EACA,OAAO,EAAO,EAAW,CAAC,GAAG,CAAI;CACnC;CAYA,GAAG,GAAW,GAAS;EAKrB,OAJK,KAAK,WAAW,IAAI,CAAS,KAChC,KAAK,WAAW,IAAI,GAAW,CAAC,CAAC,GAEnC,KAAK,WAAW,IAAI,CAAS,CAAC,CAAC,KAAK,CAAO,SAC9B,KAAK,IAAI,GAAW,CAAO;CAC1C;CAOA,IAAI,GAAW,GAAS;EACtB,IAAM,IAAW,KAAK,WAAW,IAAI,CAAS;EAC9C,IAAI,CAAC,GAAU;EACf,IAAM,IAAM,EAAS,QAAQ,CAAO;EACpC,AAAI,MAAQ,MAAI,EAAS,OAAO,GAAK,CAAC;CACxC;CAOA,aAAa,GAAW,GAAG,GAAM;EAE/B,CADiB,KAAK,WAAW,IAAI,CAAS,KAAK,CAAC,EAAA,CAC3C,SAAS,MAAM,EAAE,GAAG,CAAI,CAAC;EAGlC,IAAM,IAAS,OAAO,EAAU,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,EAAU,MAAM,CAAC;EAC3E,AAAI,OAAO,KAAK,QAAQ,MAAY,cAClC,KAAK,QAAQ,EAAO,CAAC,GAAG,CAAI;CAEhC;CAOA,cAAc,IAAY,CAAC,GAAG;EAC5B,IAAM,IAAO,EAAU,KAAK,SAAS,CAAS;EAE9C,AADA,OAAO,KAAK,KAAK,OAAO,CAAC,CAAC,SAAS,MAAQ,OAAO,KAAK,QAAQ,EAAI,GACnE,OAAO,OAAO,KAAK,SAAS,CAAI;EAEhC,IAAM,EAAE,cAAW,gBAAa,KAAK;EAIrC,IAHI,OAAO,OAAO,GAAW,UAAU,KAAG,KAAK,YAAY,EAAQ,KAAK,QAAQ,QAAS,GACrF,OAAO,OAAO,GAAW,YAAY,MAAG,EAAS,aAAa,KAAK,QAAQ,eAAe,KAC1F,OAAO,OAAO,GAAW,aAAa,MAAG,EAAS,QAAQ,cAAc,KAAK,QAAQ,eAAe,KACpG,OAAO,OAAO,GAAW,WAAW,GAAG;GACzC,IAAM,IAAM,KAAK,QAAQ,cAAc;GAEvC,AADA,EAAS,aAAa,OAAO,IAAM,QAAQ,KAAK,GAChD,EAAU,UAAU,OAAO,cAAc,CAAG;EAC9C;EACA,IAAI,OAAO,OAAO,GAAW,QAAQ,KAAK,OAAO,OAAO,GAAW,WAAW,GAAG;GAC/E,IAAM,IAAS,KAAK,QAAQ,UAAU,KAAK,QAAQ,aAAa;GAChE,EAAS,MAAM,YAAY,IAAS,GAAG,EAAO,MAAM;EACtD;EAUA,OATI,OAAO,OAAO,GAAW,WAAW,MACtC,EAAS,MAAM,YAAY,KAAK,QAAQ,YAAY,GAAG,KAAK,QAAQ,UAAU,MAAM,KAElF,OAAO,OAAO,GAAW,SAAS,KAAG,KAAK,OAAO,iBAAiB,GAGtE,KAAK,qBAAqB,GAC1B,KAAK,OAAO,kBAAkB,GAC9B,KAAK,aAAa,iBAAiB,EAAE,GAAG,EAAU,CAAC,GAC5C;CACT;CAQA,UAAU;EACR,IAAM,IAAO,KAAK,OAAO,gBAAgB;EACzC,OAAO,OAAO,KAAS,WAAW,EAAK,QAAQ,MAAM,EAAE,IAAI;CAC7D;CAMA,QAAQ,GAAM;EACZ,KAAK,OAAO,kBAAkB,CAAI;CACpC;CAMA,UAAU;EACR,OAAO,KAAK,OAAO,gBAAgB;CACrC;CAMA,QAAQ,GAAM;EACZ,KAAK,OAAO,kBAAkB,CAAI;CACpC;CAKA,QAAQ;EACN,KAAK,OAAO,cAAc;CAC5B;CAOA,eAAe;EACb,KAAK,OAAO,qBAAqB;CACnC;CAMA,eAAe;EACb,OAAO,KAAK,OAAO,qBAAqB,KAAK;CAC/C;CAMA,eAAe;EACb,OAAO,KAAK,OAAO,qBAAqB,KAAK;CAC/C;CAMA,UAAU;EACR,OAAO,KAAK,OAAO,gBAAgB;CACrC;CAMA,WAAW,GAAM;EACf,KAAK,OAAO,qBAAqB,CAAI;CACvC;CAMA,WAAW,GAAM;EACf,KAAK,OAAO,qBAAqB,CAAI;CACvC;CAMA,YAAY,GAAI;EACd,KAAK,OAAO,sBAAsB,CAAE;CACtC;CAMA,cAAc;EACZ,OAAO,KAAK,OAAO,oBAAoB;CACzC;CAEA,uBAAuB;EACrB,OAAO,KAAK,OAAO,6BAA6B,KAAK;CACvD;CAEA,yBAAyB,GAAU;EACjC,OAAO,KAAK,OAAO,mCAAmC,CAAQ;CAChE;CAEA,MAAM,eAAe,GAAQ,GAAM;EACjC,IAAM,IAAU,KAAK,QAAQ,mBAAmB,IAC5C;EACJ,IAAI,OAAO,GAAS,UAAW,YAAY,IAAO,MAAM,EAAQ,OAAO,GAAM,IAAI;OAC5E,IAAI,MAAW,QAAQ,IAAO,OAAO,KAAQ,EAAE;OAC/C,IAAI,MAAW,YAAoD,OAAtC,KAAK,YAAY,OAAO,KAAQ,EAAE,CAAC,GAAU;OAC1E,IAAI,MAAW,QAA4C,OAAlC,KAAK,QAAQ,OAAO,KAAQ,EAAE,CAAC,GAAU;OAClE,MAAU,MAAM,4CAA4C,EAAO,GAAG;EAE3E,OADA,KAAK,QAAQ,CAAI,GACV;CACT;CAEA,MAAM,eAAe,GAAQ;EAC3B,IAAM,IAAU,KAAK,QAAQ,mBAAmB;EAChD,IAAI,OAAO,GAAS,UAAW,YAAY,OAAO,EAAQ,OAAO,MAAM,KAAK,QAAQ,CAAC;EACrF,IAAI,MAAW,QAAQ,OAAO,KAAK,QAAQ;EAC3C,IAAI,MAAW,YAAY,OAAO,KAAK,YAAY;EACnD,IAAI,MAAW,QAAQ,OAAO,KAAK,QAAQ;EAC3C,MAAU,MAAM,4CAA4C,EAAO,GAAG;CACxE;CAEA,iBAAiB;EACf,IAAM,IAAS,KAAK,WAAW,SAAS;EACxC,KAAK,IAAM,KAAS,GAClB,IAAI,CAAC,EAAM,aAAa,kBAAkB,GAAG;GAC3C,IAAM,IAAK,WAAW,QAAQ,aAAa,KAAK,MAAM,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC;GACtG,EAAM,aAAa,oBAAoB,CAAE;EAC3C;EAEF,OAAO;CACT;CAEA,cAAc;EAEZ,OADI,KAAK,QAAQ,YAAU,KAAK,eAAe,GACxC;GAAE,SAAS;GAAG,MAAM,KAAK,QAAQ;GAAG,UAAU,KAAK,YAAY;EAAE;CAC1E;CAEA,aAAa,GAAc;EAGzB,OAFA,KAAK,QAAQ,GAAc,QAAQ,EAAE,GACrC,KAAK,aAAa,GACX;CACT;CAEA,gBAAgB,GAAM;EAIpB,OAHA,KAAK,QAAQ,CAAI,GACjB,KAAK,wBAAwB,KAAK,QAAQ,GAC1C,KAAK,aAAa,GACX;CACT;CAMA,eAAe;EACb,OAAO,KAAK,OAAO,wBAAwB,KAAK;CAClD;CAMA,eAAe;EACb,OAAO,KAAK,OAAO,wBAAwB,KAAK;CAClD;CAMA,aAAa,IAAW,iBAAiB;EACvC,KAAK,UAAU,KAAK,QAAQ,GAAG,GAAU,WAAW;CACtD;CAMA,aAAa,IAAW,gBAAgB;EACtC,KAAK,UAAU,KAAK,QAAQ,GAAG,GAAU,YAAY;CACvD;CAMA,iBAAiB,IAAW,eAAe;EACzC,KAAK,UAAU,KAAK,YAAY,GAAG,GAAU,eAAe;CAC9D;CAQA,UAAU,GAAS,GAAU,GAAU;EACrC,IAAM,IAAO,IAAI,KAAK,CAAC,CAAO,GAAG,EAAE,MAAM,EAAS,CAAC,GAC7C,IAAM,IAAI,gBAAgB,CAAI,GAC9B,IAAI,SAAS,cAAc,GAAG;EAOpC,AANA,EAAE,OAAO,GACT,EAAE,WAAW,GACb,EAAE,MAAM,UAAU,QAClB,SAAS,KAAK,YAAY,CAAC,GAC3B,EAAE,MAAM,GACR,EAAE,OAAO,GACT,IAAI,gBAAgB,CAAG;CACzB;CAMA,MAAM,IAAQ,IAAI;EAChB,IAAM,IAAU,KAAK,QAAQ,GAEvB,IAAS,sEADI,KAAS,GAAA,CAAI,QAAQ,aAAa,MAAM,KAAK,EAAE,WAAW,CAAC,EAAE,EAE5D,EAAE,8lBAUJ,EAAQ,iBACpB,IAAO,IAAI,KAAK,CAAC,CAAM,GAAG,EAAE,MAAM,YAAY,CAAC,GAC/C,IAAM,IAAI,gBAAgB,CAAI,GAC9B,IAAI,WAAW,KAAK,GAAK,QAAQ;EACvC,IAAI,CAAC,GAAG;GAAE,IAAI,gBAAgB,CAAG;GAAG;EAAQ;EAC5C,EAAE,iBAAiB,cAAc;GAE/B,AADA,EAAE,MAAM,GACR,IAAI,gBAAgB,CAAG;EACzB,CAAC;CACH;CAOA,qBAAqB;EAInB,OAHiB,MAAM,KACrB,KAAK,WAAW,SAAS,iBAAiB,mBAAmB,CAEjD,CAAC,CAAC,KAAK,OAAQ;GAC3B,OAAO,SAAS,EAAG,QAAQ,IAAI,EAAE;GACjC,MAAM,EAAG,aAAa,KAAK,KAAK;GAChC,SAAqC;EACvC,EAAE;CACJ;CAKA,QAAQ;EACN,KAAK,WAAW,SAAS,MAAM;CACjC;CAKA,OAAO;EACL,KAAK,WAAW,SAAS,KAAK;CAChC;CAMA,eAAe;EACb,OAAO,KAAK,OAAO,qBAAqB,MAAM;CAChD;CAMA,YAAY,GAAU;EACpB,IAAM,IAAW,KAAK,WAAW;EACjC,AAAI,KACF,EAAS,aAAa,mBAAmB,OAAO,GAChD,KAAK,WAAW,UAAU,UAAU,IAAI,aAAa,GACrD,EAAS,iBAAiB,0CAAwC,CAAC,CAAC,SAAS,MAAO;GAClF,EAAG,aAAa,YAAY,EAAE;EAChC,CAAC,MAED,EAAS,aAAa,mBAAmB,MAAM,GAC/C,KAAK,WAAW,UAAU,UAAU,OAAO,aAAa,GACxD,EAAS,iBAAiB,0CAAwC,CAAC,CAAC,SAAS,MAAO;GAClF,EAAG,gBAAgB,UAAU;EAC/B,CAAC;CAEL;CAcA,UAAU;EACR,IAAI,CAAC,KAAK,QAAQ,OAAO,KAAK,mBAAmB,QAAQ,QAAQ;EAMjE,IAAM,IAAe,KAAK,oBAAoB,OAE1C,OADA,KAAK,cAAc,CAAC,CAAC,YAAY,CAAC,CAAC;EAMvC,AAHA,KAAK,SAAS,SAAS,MAAW;GAChC,AAAI,OAAO,EAAO,WAAY,cAAY,EAAO,QAAQ;EAC3D,CAAC,GACD,KAAK,SAAS,MAAM;EAEpB,KAAK,IAAM,EAAE,eAAY,KAAK,SAAS,OAAO,GAC5C,IAAI,OAAO,EAAO,aAAc,YAC9B,IAAI;GAAE,EAAO,UAAU,IAAI;EAAG,QAAY,CAAU;EAMxD,AAHA,KAAK,SAAS,MAAM,GAEpB,KAAK,WAAW,SAAS,MAAM,EAAE,CAAC,GAClC,KAAK,aAAa,CAAC;EAEnB,IAAM,IAAY,KAAK,WAAW,WAC5B,IAAU,GAAW,UAAU,SAAS,eAAe,GACvD,IAAU,GAAW,UAAU,SAAS,eAAe;EA0B7D,OAzBI,GAAW,eAEb,KAAK,SAAS,MAAM,UAAU,IAC9B,EAAU,OAAO,IAGf,KAAW,CAAC,SAAS,cAAc,6BAA6B,KAClE,SAAS,KAAK,UAAU,OAAO,eAAe,GAE5C,KAAW,CAAC,SAAS,cAAc,6BAA6B,KAClE,SAAS,KAAK,UAAU,OAAO,eAAe,GAG5C,OAAO,KAAK,QAAQ,aAAc,cACpC,KAAK,QAAQ,UAAU,IAAI,GAG7B,KAAK,SAAS,IAKd,KAAK,kBAAkB,QAAQ,QAAQ,CAAY,CAAC,CAAC,WAAW;GAC9D,KAAK,WAAW,MAAM;EACxB,CAAC,GACM,KAAK;CACd;CASA,cAAc,GAAM;EAClB,CAAI,KAAK,SAAS,YAAY,cAAc,KAAK,SAAS,YAAY,aACpC,KAAM,SAAU,QAAQ,OAAO,KAAS,WAAW,IAAO,KAAK,QAAQ;CAE3G;AACF,GChzBa,KAAb,MAAqB;CAUnB,YAAY,GAAU,IAAQ,KAAK,IAAW,KAAK,OAAO,MAAM;EAQ9D,AAPA,KAAK,WAAW,GAChB,KAAK,SAAS,GACd,KAAK,YAAY,GACjB,KAAK,SAAS,GAEd,KAAK,QAAQ,CAAC,GACd,KAAK,cAAc,IACnB,KAAK,WAAW;CAClB;CAQA,WAAW,GAAO;EAChB,IAAI,IAAO,EAAM,KAAK;EACtB,IAAI,EAAM,QACR,KAAK,IAAM,KAAO,EAAM,QAAQ,KAAQ,EAAM,OAAO,EAAI,CAAC;EAE5D,OAAO;CACT;CAMA,aAAa;EACX,OAAO,KAAK,SAAS;CACvB;CAOA,sBAAsB;EACpB,IAAM,IAAM,WAAW,aAAa;EACpC,IAAI,CAAC,KAAO,EAAI,eAAe,GAAG,OAAO;EACzC,IAAM,IAAQ,EAAI,WAAW,CAAC;EAE9B,OADK,KAAK,SAAS,SAAS,EAAM,cAAc,IACzC;GACL,OAAO,KAAK,YAAY,EAAM,gBAAgB,EAAM,WAAW;GAC/D,KAAK,KAAK,YAAY,EAAM,cAAc,EAAM,SAAS;EAC3D,IAJ0D;CAK5D;CASA,YAAY,GAAM,GAAQ;EACxB,IAAI,IAAQ,GACN,IAAS,SAAS,iBAAiB,KAAK,UAAU,WAAW,WAAW,IAAI,GAC9E;EACJ,OAAQ,IAAM,EAAO,SAAS,IAAI;GAChC,IAAI,MAAQ,GAAM,OAAO,IAAQ;GACjC,KAA8B,EAAK;EACrC;EACA,OAAO;CACT;CAMA,kBAAkB,GAAO;EACvB,IAAI,CAAC,GAAO;EACZ,IAAI,IAAY,MAAM,IAAW,GAC7B,IAAU,MAAM,IAAS,GACzB,IAAQ,GACN,IAAS,SAAS,iBAAiB,KAAK,UAAU,WAAW,WAAW,IAAI,GAC9E;EACJ,OAAQ,IAAM,EAAO,SAAS,IAAI;GAChC,IAAM,IAA2B,EAAK;GAKtC,IAJI,CAAC,KAAa,IAAQ,KAAO,EAAM,UACrC,IAAY,GACZ,IAAW,EAAM,QAAQ,IAEvB,CAAC,KAAW,IAAQ,KAAO,EAAM,KAAK;IAExC,AADA,IAAU,GACV,IAAS,EAAM,MAAM;IACrB;GACF;GACA,KAAS;EACX;EACA,IAAI,CAAC,GAAW;GAEd,IAAM,IAAa,SAAS,iBAAiB,KAAK,UAAU,WAAW,WAAW,IAAI,GAClF,IAAW;GACf,OAAQ,IAAW,EAAW,SAAS,IAAM,IAAY;GAGzD,AAFA,IAAW,IAAiC,EAAW,SAAS,GAChE,IAAU,GACV,IAAS;EACX;EACA,AAAK,MAAW,IAAU,GAAW,IAAS;EAC9C,IAAI;GACF,IAAM,IAAQ,SAAS,YAAY;GAEnC,AADA,EAAM,SAAS,GAAW,CAAQ,GAClC,EAAM,OAAO,GAAS,CAAM;GAC5B,IAAM,IAAM,WAAW,aAAa;GAEpC,AADA,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAK;EACpB,QAAY;GAEV,IAAI;IACF,IAAM,IAAK,SAAS,YAAY;IAEhC,AADA,EAAG,SAAS,KAAK,UAAU,CAAC,GAC5B,EAAG,SAAS,EAAI;IAChB,IAAM,IAAI,WAAW,aAAa;IAClC,AAAI,MAAK,EAAE,gBAAgB,GAAG,EAAE,SAAS,CAAE;GAC7C,QAAa,CAA+B;EAC9C;CACF;CAEA,aAAa;EAEX,IAAI,KAAK,cAAc,KAAK,MAAM,SAAS,GAAG;GAC5C,KAAK,IAAM,KAAS,KAAK,MAAM,MAAM,KAAK,cAAc,CAAC,GACvD,KAAK,UAAU,KAAK,WAAW,CAAK;GAEtC,KAAK,QAAQ,KAAK,MAAM,MAAM,GAAG,KAAK,cAAc,CAAC;EACvD;EACA,IAAM,IAAM,KAAK,WAAW,GACtB,EAAE,SAAM,cAAW,KAAK,gBAAgB,CAAG,GAC3C,IAAQ;GAAE;GAAM;GAAQ,KAAK,KAAK,oBAAoB;EAAE;EAM9D,KALA,KAAK,MAAM,KAAK,CAAK,GACrB,KAAK,UAAU,KAAK,WAAW,CAAK,GAI7B,KAAK,MAAM,SAAS,MAAM,KAAK,MAAM,SAAS,KAAK,UAAU,KAAK,SAAS,KAAK,aACrF,KAAK,UAAU,KAAK,WAAW,KAAK,MAAM,MAAM,CAAC;EAKnD,KAAK,cAAc,KAAK,MAAM,SAAS;CACzC;CAEA,SAAS,GAAO;EACT,MACL,KAAK,SAAS,YAAY,KAAK,kBAAkB,CAAK,GACtD,KAAK,kBAAkB,EAAM,GAAG;CAClC;CAeA,gBAAgB,GAAM;EAEpB,IAAI,CAAC,EAAK,SAAS,OAAO,GAAG,OAAO;GAAE;GAAM,QAA8C,CAAC;EAAG;EAC9F,IAAM,IAA+C,CAAC,GAClD,IAAQ;EAOZ,OAAO;GAAE,MANS,EAAK,QAAQ,gCAAgC,MAAU;IACvE,IAAM,IAAQ,aAAa,EAAM;IAGjC,OAFA,EAAO,KAAS,GAChB,KACO;GACT,CACuB;GAAG;EAAO;CACnC;CAOA,kBAAkB,GAAO;EAEvB,OADI,CAAC,EAAM,UAAU,OAAO,KAAK,EAAM,MAAM,CAAC,CAAC,WAAW,IAAU,EAAM,OACnE,EAAM,KAAK,QAAQ,qBAAqB,MAAU,EAAM,OAAO,MAAU,CAAK;CACvF;CASA,aAAa;EACX,IAAM,IAAU,KAAK,WAAW,GAC1B,EAAE,MAAM,MAAc,KAAK,gBAAgB,CAAO;EAC3C,KAAK,MAAM,KAAK,YACrB,EAAE,SAAS,KACnB,KAAK,WAAW;CAClB;CAKA,OAAO;EACD,KAAK,eAAe,MACxB,KAAK,eACL,KAAK,SAAS,KAAK,MAAM,KAAK,YAAY;CAC5C;CAKA,OAAO;EACD,KAAK,eAAe,KAAK,MAAM,SAAS,MAC5C,KAAK,eACL,KAAK,SAAS,KAAK,MAAM,KAAK,YAAY;CAC5C;CAKA,QAAQ;EAIN,AAHA,KAAK,QAAQ,CAAC,GACd,KAAK,cAAc,IACnB,KAAK,SAAS,GACd,KAAK,WAAW;CAClB;CAGA,UAAU;EACR,OAAO,KAAK,cAAc;CAC5B;CAGA,UAAU;EACR,OAAO,KAAK,cAAc,KAAK,MAAM,SAAS;CAChD;CAGA,eAAe;EACb,OAAO,KAAK,IAAI,GAAG,KAAK,WAAW;CACrC;CAGA,eAAe;EACb,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,IAAI,KAAK,WAAW;CAC7D;AACF;;;ACvPA,SAAgB,GAAY,GAAM,GAAM,IAAO,CAAC,GAAG;CACjD,IAAM,EAAE,eAAY,OAAU,GACxB,IAAQ,EAAc,SAAS,EAAE,OAAO,WAAW,CAAC;CAE1D,IAAI,KAAa,IAAO,GAAG;EACzB,IAAM,IAAQ,EAAc,OAAO,GAC7B,IAAK,EAAc,IAAI;EAC7B,KAAK,IAAI,IAAI,GAAG,IAAI,GAAM,KAAK;GAC7B,IAAM,IAAK,EAAc,MAAM,CAAC,GAAG,CAAC,SAAS,cAAc,IAAI,CAAC,CAAC;GACjE,EAAG,YAAY,CAAE;EACnB;EAEA,AADA,EAAM,YAAY,CAAE,GACpB,EAAM,YAAY,CAAK;CACzB;CAEA,IAAM,IAAW,IAAY,KAAK,IAAI,IAAO,GAAG,CAAC,IAAI,GAC/C,IAAQ,EAAc,OAAO;CACnC,EAAM,YAAY,CAAK;CAEvB,KAAK,IAAI,IAAI,GAAG,IAAI,GAAU,KAAK;EACjC,IAAM,IAAK,EAAc,IAAI;EAC7B,KAAK,IAAI,IAAI,GAAG,IAAI,GAAM,KAAK;GAC7B,IAAM,IAAK,EAAc,MAAM,CAAC,GAAG,CAAC,SAAS,cAAc,IAAI,CAAC,CAAC;GACjE,EAAG,YAAY,CAAE;EACnB;EACA,EAAM,YAAY,CAAE;CACtB;CACA,OAAwC;AAC1C;AAQA,SAAgB,GAAY,GAAM,GAAM,IAAO,CAAC,GAAG;CACjD,IAAI,KAAQ,KAAK,KAAQ,GAAG;CAC5B,IAAM,IAAQ,GAAY,GAAM,GAAM,CAAI,GAEpC,IAAM,WAAW,aAAa;CACpC,IAAI,CAAC,KAAO,EAAI,eAAe,GAAG;CAClC,IAAM,IAAQ,EAAI,WAAW,CAAC;CAC9B,IAAI;EACF,EAAM,eAAe;CACvB,QAAY;EACV;CACF;CAGA,IAAM,oBAAQ,IAAI,IAAI;EAAC;EAAK;EAAO;EAAM;EAAM;EAAM;EAAM;EAAM;EAAM;EAAc;EAAM;CAAK,CAAC,GAC7F,IAAsC,EAAM;CAEhD,KADI,GAAQ,aAAa,MAAG,IAAS,EAAO,gBACrC,KAAU,CAAC,EAAM,IAAI,EAAO,SAAS,YAAY,CAAC,KAAK,EAAO,gBACnE,IAAS,EAAO;CAGlB,IAAI,KAAU,EAAM,IAAI,EAAO,SAAS,YAAY,CAAC,KAAK,EAAO,YAAY;EAG3E,IAFA,EAAO,MAAM,CAAK,GAEd,CAAC,EAAM,oBAAoB;GAC7B,IAAM,IAAI,SAAS,cAAc,GAAG;GAEpC,AADA,EAAE,YAAY,SAAS,cAAc,IAAI,CAAC,GAC1C,EAAM,MAAM,CAAC;EACf;EAEA,AAAI,CAAC,EAAO,YAAY,KAAK,KAAK,CAAC,EAAO,cAAc,mBAAmB,KACzE,EAAO,OAAO;CAElB,OACE,IAAI;EACF,EAAM,WAAW,CAAK;CACxB,QAAY;EACV;CACF;CAIF,IAAM,IAAY,EAAM,cAAc,QAAQ;CAC9C,IAAI,GAAW;EACb,IAAM,IAAK,SAAS,YAAY;EAIhC,AAHA,EAAG,SAAS,GAAW,CAAC,GACxB,EAAG,SAAS,EAAI,GAChB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE;CACjB;AACF;;;ACnGA,IAAa,IAAM;CACjB,WAAW;CACX,KAAK;CACL,OAAO;CACP,QAAQ;CACR,OAAO;CACP,SAAS;CACT,WAAW;CACX,KAAK;CACL,MAAM;CACN,MAAM;CACN,IAAI;CACJ,OAAO;CACP,MAAM;CACN,QAAQ;CAER,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CACN,MAAM;CAEN,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,OAAO;CACP,QAAQ;AACV;AAQA,SAAgB,EAAM,GAAO,GAAS;CACpC,OAAO,EAAM,QAAQ,KAAW,EAAM,QAAQ,EAAQ,YAAY;AACpE;AAQA,SAAgB,EAAW,GAAO,GAAS;CACzC,QAAQ,EAAM,WAAW,EAAM,YAAY,EAAM,GAAO,CAAO;AACjE;;;AClDA,IAAM,KAAc,SACd,KAAY,MAAM,CAAC,EAAE,GAAG,aAAa,OAAO,GAAY,KAAK,EAAE,aAAa,EAAE,IAC9E,KAAe,MAAS,GAAG,aAAa,KAAK,cAAc,EAAE,gBAAgB,OAAY,EAAE,gBAAgB;AASjH,SAAS,GAAoB,GAAa,GAAI;CAC5C,IAAI;EACF,IAAM,IAAI,SAAS,YAAY;EAG/B,OAFA,EAAE,SAAS,EAAY,gBAAgB,EAAY,WAAW,GAC9D,EAAE,OAAO,GAAI,EAAG,WAAW,MAAM,GAC1B,EAAE,gBAAgB;CAC3B,QAAY;EAEV,OAAO,SAAS,uBAAuB;CACzC;AACF;AASA,SAAgB,GAAc,GAAO,GAAU,IAAU,CAAC,GAAG;CAC3D,IAAM,KAAa,MAAU;EAC3B,IAAM,IAAM,WAAW,aAAa;EACpC,IAAI,CAAC,GAAK,OAAO;EACjB,IAAM,IAAK,SAAS,YAAY;EAKhC,OAJA,EAAM,CAAE,GACR,EAAG,SAAS,EAAI,GAChB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE,GACR;CACT;CAKA,IAAI,EAAM,GAAO,EAAI,SAAS,GAAG;EAC/B,IAAM,IAAM,WAAW,aAAa;EACpC,IAAI,GAAK,aAAa,GAAG;GACvB,IAAM,IAAI,EAAI,WAAW,CAAC;GAC1B,IAAI,EAAE,aAAa,EAAE,eAAe,aAAa,KAAK,WAAW;IAC/D,IAAM,IAAqC,EAAE;IAE7C,IAAI,EAAE,gBAAgB,KAAK,EAAS,EAAS,eAAe,GAG1D,OAFA,EAAM,eAAe,GACI,EAAU,gBAAiB,OAAO,GACpD;IAMT,IAAI,EAAE,gBAAgB,KAAK,EAAS,gBAAgB,OAChD,EAAS,EAAS,eAAe,GAAG;KACtC,EAAM,eAAe;KACrB,IAAM,IAAW,EAAS,YACpB,IAAqC,EAAS,iBAC9C,IAAW,EAAK;KAEtB,AADA,EAAK,OAAO,GACZ,EAAS,OAAO;KAKhB,IAAM,IAAK,SAAS,YAAY;KAWhC,OAVI,GAAU,aAAa,KAAK,YAC9B,EAAG,SAAS,GAAU,EAAS,YAAY,MAAM,IACxC,IACT,EAAG,cAAc,CAAQ,IAChB,KACT,EAAG,SAAS,GAAQ,CAAC,GAEvB,EAAG,SAAS,EAAI,GAChB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE,GACR;IACT;GACF;EACF;EACA,OAAO;CACT;CAKA,IAAI,EAAM,GAAO,EAAI,IAAI,KAAK,EAAM,GAAO,EAAI,KAAK,GAAG;EACrD,IAAM,IAAM,WAAW,aAAa;EACpC,IAAI,CAAC,KAAO,EAAI,eAAe,GAAG,OAAO;EAEzC,IAAM,IAAI,EAAI,WAAW,CAAC;EAC1B,IAAI,CAAC,EAAE,WAAW,OAAO;EAEzB,IAAM,IAAK,EAAE,gBACP,IAAa,EAAM,GAAO,EAAI,IAAI;EAExC,IAAI,EAAG,aAAa,KAAK,WAAW;GAClC,IAAM,IAAW;GAUjB,IARI,KACA,EAAE,gBAAgB,KAClB,EAAS,gBAAgB,OACzB,EAAS,EAAS,eAAe,KAKjC,KAAc,EAAE,gBAAgB,KAAK,EAAS,EAAS,eAAe,GAExE,OADA,EAAM,eAAe,GACd,GAAW,MAAO,EAAG,eAAe,EAAS,eAAe,CAAC;GAGtE,IAAI,KACA,EAAE,gBAAgB,KAClB,EAAY,EAAS,eAAe,KACpC,EAAS,EAAS,gBAAgB,eAAe,GAEnD,OADA,EAAM,eAAe,GACd,GAAW,MAAO,EAAG,eAAe,EAAS,gBAAgB,eAAe,CAAC;GAGtF,IAAI,CAAC,KACD,EAAE,gBAAgB,EAAS,YAAY,UACvC,EAAS,EAAS,WAAW,GAAG;IAClC,IAAM,IAAO,EAAS,aAChB,IAAQ,EAAK;IAEnB,IADA,EAAM,eAAe,GACjB,GAAO,aAAa,KAAK,WAAW;KACtC,IAAM,IAAA,IAAW,EAAM,eAAe,GAAA,CAAI,WAAW,GAAQ;KAC7D,OAAO,GAAW,MAAO,EAAG,SAAS,GAAO,KAAK,IAAI,GAAQ,EAAM,YAAY,MAAM,CAAC,CAAC;IACzF;IACA,OAAO,GAAW,MAAO,EAAG,cAAc,CAAI,CAAC;GACjD;GAEA,IAAI,CAAC,KACD,EAAE,gBAAgB,EAAS,YAAY,UACvC,EAAY,EAAS,WAAW,KAChC,EAAS,EAAS,YAAY,WAAW,GAAG;IAC9C,IAAM,IAAO,EAAS,YAAY,aAC5B,IAAQ,EAAK;IAEnB,IADA,EAAM,eAAe,GACjB,GAAO,aAAa,KAAK,WAAW;KACtC,IAAM,IAAA,IAAW,EAAM,eAAe,GAAA,CAAI,WAAW,GAAQ;KAC7D,OAAO,GAAW,MAAO,EAAG,SAAS,GAAO,KAAK,IAAI,GAAQ,EAAM,YAAY,MAAM,CAAC,CAAC;IACzF;IACA,OAAO,GAAW,MAAO,EAAG,cAAc,CAAI,CAAC;GACjD;EACF;EAEA,IAAI,EAAG,aAAa,KAAK,cAAc;GACrC,IAAM,IAAK;GACX,IAAI,KAAc,EAAE,cAAc,GAAG;IACnC,IAAM,IAAO,EAAG,WAAW,EAAE,cAAc;IAC3C,IAAI,EAAS,CAAI,GAEf,OADA,EAAM,eAAe,GACd,GAAW,MAAO,EAAG,eAAe,CAAI,CAAC;IAElD,IAAI,EAAY,CAAI,KAAK,EAAS,EAAK,eAAe,GAEpD,OADA,EAAM,eAAe,GACd,GAAW,MAAO,EAAG,eAAe,EAAK,eAAe,CAAC;GAEpE;GACA,IAAI,CAAC,KAAc,EAAE,cAAc,EAAG,WAAW,QAAQ;IACvD,IAAM,IAAO,EAAG,WAAW,EAAE;IAC7B,IAAI,EAAS,CAAI,GAAG;KAClB,IAAM,IAAQ,EAAK;KAEnB,IADA,EAAM,eAAe,GACjB,GAAO,aAAa,KAAK,WAAW;MACtC,IAAM,IAAA,IAAW,EAAM,eAAe,GAAA,CAAI,WAAW,GAAQ;MAC7D,OAAO,GAAW,MAAO,EAAG,SAAS,GAAO,KAAK,IAAI,GAAQ,EAAM,YAAY,MAAM,CAAC,CAAC;KACzF;KACA,OAAO,GAAW,MAAO,EAAG,cAAc,CAAI,CAAC;IACjD;IACA,IAAI,EAAY,CAAI,KAAK,EAAS,EAAK,WAAW,GAAG;KACnD,IAAM,IAAO,EAAK,aACZ,IAAQ,EAAK;KAEnB,IADA,EAAM,eAAe,GACjB,GAAO,aAAa,KAAK,WAAW;MACtC,IAAM,IAAA,IAAW,EAAM,eAAe,GAAA,CAAI,WAAW,GAAQ;MAC7D,OAAO,GAAW,MAAO,EAAG,SAAS,GAAO,KAAK,IAAI,GAAQ,EAAM,YAAY,MAAM,CAAC,CAAC;KACzF;KACA,OAAO,GAAW,MAAO,EAAG,cAAc,CAAI,CAAC;IACjD;GACF;EACF;CACF;CAKA,IAAI,EAAM,GAAO,EAAI,GAAG,GAAG;EACzB,IAAM,IAAQ,GAAa,CAAQ;EACnC,IAAI,CAAC,GAAO,OAAO;EAEnB,IAAM,IAAO,EAAY,EAAM,IAAI,CAAQ;EAC3C,IAAI,KAAQ,GAAK,CAAI,GAOnB,OANA,EAAM,eAAe,GACjB,EAAM,WACR,GAAQ,IAER,EAAY,QAAQ,GAEf;EAIT,IAAI,GAAM,SAAS,YAAY,MAAM,OAInC,OAHI,EAAM,WAAiB,MAC3B,EAAM,eAAe,GACrB,EAAY,cAAc,IAAI,OAAO,EAAQ,WAAW,CAAC,CAAC,GACnD;EAIT,IAAI,EAAQ,SAIV,OAHI,EAAM,WAAiB,MAC3B,EAAM,eAAe,GACrB,EAAY,cAAc,IAAI,OAAO,EAAQ,OAAO,CAAC,GAC9C;CAEX;CAKA,IAAI,EAAM,GAAO,EAAI,KAAK,KAAK,EAAM,UAGnC,OAFA,EAAM,eAAe,GACrB,EAAY,iBAAiB,GACtB;CAMT,IAAI,EAAM,GAAO,EAAI,KAAK,KAAK,CAAC,EAAM,UAAU;EAC9C,IAAM,IAAQ,GAAa,CAAQ;EACnC,IAAI,CAAC,GAAO,OAAO;EAGnB,IAAM,IAAK,EAAM,IACX,IAAkC,EAAG,aAAa,IAAI,EAAG,gBAAgB;EAO/E,IAAI,GAAI,aAAa,OAAO,QAAQ,KAAK,EAAG,aAAa,EAAE,GAAG;GAC5D,IAAM,IAAK,SAAS,YAAY;GAEhC,AADA,EAAG,cAAc,CAAE,GACnB,EAAG,SAAS,EAAI;GAChB,IAAM,IAAO,WAAW,aAAa;GAErC,OADI,MAAQ,EAAK,gBAAgB,GAAG,EAAK,SAAS,CAAE,IAC7C;EACT;EAIA,IAAM,IAAe,GAAI,QAAQ,mBAAmB;EACpD,IAAI,GAAc;GAChB,EAAM,eAAe;GACrB,IAAM,IAAI,SAAS,cAAc,GAAG;GAEpC,AADA,EAAE,YAAY,QACd,EAAa,WAAW,aAAa,GAAG,EAAa,WAAW;GAChE,IAAM,IAAK,SAAS,YAAY;GAEhC,AADA,EAAG,SAAS,GAAG,CAAC,GAChB,EAAG,SAAS,EAAI;GAChB,IAAM,IAAM,WAAW,aAAa;GAGpC,OAFA,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE,GACR;EACT;EAGA,IAAM,IAAU,GAAI,QAAQ,kBAAkB;EAC9C,IAAI,GAAS;GACX,EAAM,eAAe;GACrB,IAAM,IAAK,EAAQ,QAAQ,eAAe,GACpC,IAAM,WAAW,aAAa,GAChC,IAAc,EAAI,WAAW,CAAC;GAYlC,IAAI,GARY,MACd,MAAM,KAAK,EAAG,UAAU,CAAC,CACtB,QAAQ,MAAM,EAAE,EAAE,aAAa,KAAK,EAAE,YAAY,QAAQ,CAAC,CAC3D,KAAK,MAAM,EAAE,WAAW,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,mBAAmB,GAAG,CAAC,CAAC,KAAK,EAKxE,CAAO,CAAO,GAAG;IAEpB,IAAM,IAAI,SAAS,cAAc,GAAG;IAIpC,AAHA,EAAE,YAAY,QACd,EAAG,WAAW,aAAa,GAAG,EAAG,WAAW,GAC5C,EAAQ,OAAO,GACX,EAAG,SAAS,WAAW,KAAG,EAAG,OAAO;IACxC,IAAM,IAAK,SAAS,YAAY;IAKhC,OAJA,EAAG,SAAS,EAAE,YAAY,CAAC,GAC3B,EAAG,SAAS,EAAI,GAChB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE,GACR;GACT;GAIA,IAAI,CAAC,EAAY,WAAW;IAG1B,IAFA,EAAY,eAAe,GAEvB,EAAI,eAAe,KAAK,CAAC,EAAQ,aAAa,OAAO;IACzD,IAAc,EAAI,WAAW,CAAC;GAChC;GAKA,IAAM,IAAY,GAAoB,GAAa,CAAO,GAGpD,IAAQ,SAAS,cAAc,IAAI,GACnC,IAAK,SAAS,cAAc,OAAO;GAMzC,AALA,EAAG,OAAO,YACV,EAAG,aAAa,mBAAmB,OAAO,GAC1C,EAAM,YAAY,CAAE,GAGhB,EAAU,YAAY,QAAQ,mBAAmB,EAAE,CAAC,CAAC,SAAS,KAChE,EAAM,YAAY,CAAS;GAQ7B,IAAI,IAAa,EAAM,WAAW;GAKlC,AAJI,GAAY,aAAa,KAAK,cAChC,IAAa,SAAS,eAAe,GAAQ,GAC7C,EAAM,YAAY,CAAU,IAE9B,EAAQ,MAAM,CAAK;GAEnB,IAAM,IAAK,SAAS,YAAY;GAKhC,OAJA,EAAG,SAAS,GAAY,CAAC,GACzB,EAAG,SAAS,EAAI,GAChB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE,GACR;EACT;EAEA,IAAM,IAAO,EAAY,EAAM,IAAI,CAAQ;EAG3C,IAAI,GAAM,SAAS,YAAY,MAAM,OAGnC,OAFA,EAAM,eAAe,GACrB,EAAY,cAAc,IAAI,GACvB;EAIT,IAAI,GAAM,SAAS,YAAY,MAAM,cAAc;GACjD,IAAM,IAAS,EAAM,cAAc;GAEnC,IADA,EAAO,OAAO,GAAM,EAAK,WAAW,MAAM,GACtC,EAAO,SAAS,MAAM,MAAM,EAAM,YAAY,GAGhD,OAFA,EAAM,eAAe,GACrB,EAAY,eAAe,KAAK,GACzB;EAEX;CACF;CAEA,OAAO;AACT;;;AC3XA,SAAgB,GAAe,GAAM;CAEnC,OAAO,GADK,IAAI,UAAU,CAAC,CAAC,gBAAgB,SAAS,KAAQ,GAAG,UAAU,WACxD,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,WAAW,MAAM,CAAC,CAAC,KAAK;AAC5D;AAqBA,SAAS,EAAgB,GAAI,GAAS;CACpC,OAAO,MAAM,KAAK,EAAG,QAAQ,CAAC,CAAC,QAAQ,MAAM,EAAE,YAAY,EAAQ,YAAY,CAAC;AAClF;AAYA,SAAS,GAAU,GAAI;CACrB,IAAI,IAAM;CACV,KAAK,IAAM,KAAQ,EAAG,YAAY;EAChC,IAAI,EAAK,aAAa,GAAG;GAAE,KAAO,EAAK;GAAa;EAAU;EAC9D,IAAI,EAAK,aAAa,GAAG;EACzB,IAAM,IAAM,EAAK,SAAS,YAAY;EACtC,IAAI,MAAQ,MAAM;GAAE,KAAO;GAAM;EAAU;EAC3C,IAAI,MAAQ,SAAS,MAAQ,KAAK;GAGhC,AAFI,KAAO,CAAC,EAAI,SAAS,IAAI,MAAG,KAAO,OACvC,KAAO,GAAkC,CAAK,GAC9C,KAAO;GACP;EACF;EACA,KAAO,GAAkC,CAAK;CAChD;CACA,OAAO;AACT;AAYA,SAAS,GAAgB,GAAM;CAC7B,OAAO,EACJ,WAAW,MAAM,MAAM,CAAC,CAGxB,QAAQ,wDAAwD,OAAO,CAAC,CACxE,QAAQ,YAAY,OAAO,GAAG,IAAI,CAAC,CACnC,QAAQ,cAAc,OAAO,GAAG,KAAK,CAAC,CACtC,QAAQ,qBAAqB,OAAO,GAAG,IAAI,CAAC,CAC5C,QAAQ,mBAAmB,OAAO,GAAG,IAAI;AAC9C;AAQA,SAAS,GAAiB,GAAM;CAI9B,OAHI,4DAA4D,KAAK,CAAI,IAChE,EAAK,QAAQ,WAAW,MAAM,KAAK,GAAG,IAExC,EACJ,QAAQ,2BAA2B,GAAG,GAAI,MAAM,GAAG,EAAG,IAAI,GAAG,CAAC,CAC9D,QAAQ,YAAY,GAAG,MAAO,GAAG,EAAG,IAAI,CAAC,CACzC,QAAQ,wBAAwB,GAAG,GAAI,MAAM,GAAG,EAAG,IAAI,GAAG,CAAC,CAC3D,QAAQ,4BAA4B,GAAG,GAAI,GAAG,MAAM,GAAG,IAAK,EAAE,IAAI,GAAG;AAC1E;AAGA,SAAS,GAAmB,GAAM;CAChC,OAAO,EAAK,MAAM,IAAI,CAAC,CAAC,IAAI,EAAgB,CAAC,CAAC,KAAK,IAAI;AACzD;AAyBA,SAAS,GAAU,GAAI,GAAO;CAC5B,IAAM,IAAc,KAAK,OAAO,IAAQ,CAAC;CACzC,OAAO,GAAS,GAAI,IAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAC9C,KAAK,GAAM,MACN,MAAQ,KAAK,EAAK,KAAK,MAAM,MAC1B,EAAK,WAAW,CAAW,IADU,IACC,IAAc,CAC5D,CAAC,CACD,KAAK,IAAI;AACd;AAEA,SAAS,GAAa,GAAI,GAAM;CAC9B,IAAM,IAAM,EAAG,aAAa,CAAI,KAAK,IAC/B,IAAU,SAAS,KAAK,CAAG,IAAI,IAAI,EAAI,KAAK,GAC5C,IAAQ,EAAG,aAAa,OAAO;CACrC,OAAO,IAAQ,GAAG,EAAQ,IAAI,EAAM,WAAW,MAAK,OAAO,GAAG,IAAI,EAAE,KAAK;AAC3E;AAEA,SAAS,GAAS,GAAM,IAAQ,GAAG;CACjC,IAAI,EAAK,aAAa,GAAG;EACvB,IAAM,IAAO,EAAK,YAAY,QAAQ,QAAQ,GAAG;EAIjD,OAAO,EAAK,eAAe,QAAQ,WAAW,IAAI,IAAO,GAAgB,CAAI;CAC/E;CACA,IAAI,EAAK,aAAa,GAAG,OAAO;CAEhC,IAAM,IAA6B,GAC7B,IAAM,EAAG,SAAS,YAAY,GAC9B,UAAc,MAAM,KAAK,EAAG,UAAU,CAAC,CAAC,KAAI,MAAK,GAAS,GAAG,CAAK,CAAC,CAAC,CAAC,KAAK,EAAE;CAElF,QAAQ,GAAR;EACE,KAAK;EACL,KAAK,OAAY,OAAO,OAAO,GAAmB,EAAM,CAAC,EAAE;EAC3D,KAAK,MAAY,OAAO;EACxB,KAAK,MAAY,OAAO,SAAS,EAAM,EAAE;EACzC,KAAK,MAAY,OAAO,UAAU,EAAM,EAAE;EAC1C,KAAK,MAAY,OAAO,WAAW,EAAM,EAAE;EAC3C,KAAK,MAAY,OAAO,YAAY,EAAM,EAAE;EAC5C,KAAK,MAAY,OAAO,aAAa,EAAM,EAAE;EAC7C,KAAK,MAAY,OAAO,cAAc,EAAM,EAAE;EAC9C,KAAK;EACL,KAAK,KAAY,OAAO,KAAK,EAAM,EAAE;EACrC,KAAK;EACL,KAAK,KAAY,OAAO,IAAI,EAAM,EAAE;EACpC,KAAK;EACL,KAAK;EACL,KAAK,UAAY,OAAO,KAAK,EAAM,EAAE;EACrC,KAAK,OAAY,OAAO,IAAI,EAAM,EAAE;EACpC,KAAK,OAAY,OAAO,IAAI,EAAM,EAAE;EACpC,KAAK,KAAY,OAAO,MAAM,EAAM,EAAE;EACtC,KAAK,QAAQ;GAKX,IAAM,IAAQ,EAAG,aAAa,OAAO,KAAK;GAI1C,OAHI,2CAA2C,KAAK,CAAK,IAChD,gBAAgB,EAAS,CAAK,EAAE,IAAI,EAAM,EAAE,WAE9C,EAAM;EACf;EACA,KAAK,QAAQ;GAEX,IAAI,EAAG,QAAQ,KAAK,GAAG,OAAO,EAAM;GACpC,IAAM,IAAU,EAAM,GAIhB,IAAa,KAAK,IAAI,GAAG,GAAG,MAAM,KAAK,EAAQ,SAAS,KAAK,IAAI,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GACnF,IAAQ,IAAI,OAAO,IAAa,CAAC,GACjC,IAAM,QAAQ,KAAK,CAAO,IAAI,MAAM;GAC1C,OAAO,GAAG,IAAQ,IAAM,IAAU,IAAM;EAC1C;EACA,KAAK,OAAO;GACV,IAAM,IAAS,EAAG,cAAc,MAAM,GAChC,IAAY,iBAAiB,KAAK,GAAQ,aAAa,EAAE;GAK/D,OAAO,aAJM,IAAY,EAAU,KAAK,GAIf,IAHT,GAAU,KAAU,CAGD,CAAC,CAAC,QAAQ,OAAO,EAAE,EAAE;EAC1D;EACA,KAAK,cAAc;GACjB,IAAM,IAAW,EAAM,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI;GAG1C,OAAO,OADO,EAAS,QAAQ,GAAG,MAAQ,EAAE,KAAK,MAAM,OAAO,EAAS,IAAM,MAAM,GAAA,CAAI,KAAK,MAAM,EAChF,CAAC,CAAC,KAAK,MAAO,EAAE,KAAK,MAAM,KAAK,MAAM,KAAK,GAAI,CAAC,CAAC,KAAK,IAAI,EAAE;EAChF;EACA,KAAK,KAAM,OAAO,IAAI,EAAM,EAAE,IAAI,GAAa,GAAI,MAAM,EAAE;EAC3D,KAAK,OAEH,OAAO,KADK,GAAgB,EAAG,aAAa,KAAK,KAAK,EACxC,EAAE,IAAI,GAAa,GAAI,KAAK,EAAE;EAE9C,KAAK,MAAM;GACT,IAAM,IAAQ,EAAgB,GAAI,IAAI;GACtC,IAAI,CAAC,EAAM,QAAQ,OAAO,EAAM;GAChC,IAAM,IAAS,KAAK,OAAO,CAAK,GAC1B,IAAc,EAAG,UAAU,SAAS,cAAc,GAClD,IAAQ,EAAM,KAAK,MAAO;IAC9B,IAAM,IACJ,EAAgB,GAAI,OAAO,CAAC,CAAC,MAAM,MAAM,EAAE,aAAa,MAAM,MAAM,UAAU,GAE5E,IAAS;IAKb,QAJI,KAAe,OAEjB,IADgB,KAAK,EAAG,UACL,WAAW,WAEzB,GAAG,IAAS,IAAS,GAAU,GAAI,CAAK;GACjD,CAAC,CAAC,CAAC,KAAK,IAAI;GACZ,OAAO,MAAU,IAAI,OAAO,EAAM,QAAQ,KAAK;EACjD;EACA,KAAK,MAAM;GACT,IAAM,IAAQ,EAAgB,GAAI,IAAI;GACtC,IAAI,CAAC,EAAM,QAAQ,OAAO,EAAM;GAChC,IAAM,IAAS,KAAK,OAAO,CAAK,GAG1B,IAAQ,OAAO,SAAS,EAAG,aAAa,OAAO,KAAK,KAAK,EAAE,GAC3D,IAAQ,OAAO,SAAS,CAAK,IAAI,IAAQ,GACzC,IAAQ,EAAM,KAAK,GAAI,MAAM,GAAG,IAAS,IAAQ,EAAE,IAAI,GAAU,GAAI,CAAK,GAAG,CAAC,CAAC,KAAK,IAAI;GAC9F,OAAO,MAAU,IAAI,OAAO,EAAM,QAAQ,KAAK;EACjD;EACA,KAAK,MAAO,OAAO,EAAM;EACzB,KAAK,MAAO,OAAO;EACnB,KAAK,SAAS;GACZ,IAAM,IAAU,MAAM,KAAK,EAAG,iBAAiB,IAAI,CAAC;GACpD,IAAI,CAAC,EAAQ,QAAQ,OAAO,EAAM;GAElC,IAAM,IAAmB,CAAC,CADV,EAAgB,GAAI,OAAO,CAAC,CAAC,MAE3C,EAAQ,EAAE,CAAC,SAAS,SAAS,KAC7B,MAAM,KAAK,EAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,OAAO,MAAM,EAAE,YAAY,IAAI,GAE3D,IAAY,EAAQ,KAAK,MAC7B,MAAM,KAAK,EAAG,iBAAiB,QAAQ,CAAC,CAAC,CAAC,KAAK,MAC7C,GAAgB,EAAE,YAAY,KAAK,CAAC,CAAC,CAAC,WAAW,KAAK,OAAO,GAAG,IAAI,CAAC,CACzE,GACM,IAAO,KAAK,IAAI,GAAG,EAAU,KAAK,MAAM,EAAE,MAAM,CAAC,GACjD,KAAU,MAAQ;IAAE,IAAM,IAAI,CAAC,GAAG,CAAG;IAAG,OAAO,EAAE,SAAS,IAAM,EAAE,KAAK,EAAE;IAAG,OAAO;GAAG,GACtF,IAAY,MACZ,IAAc,IAAmB,EAAO,EAAU,EAAE,IAAQ,MAAM,CAAI,CAAC,CAAC,KAAK,EAAE,GAI/E,IAAW,MAAM,KAAK,EAAE,QAAQ,EAAK,IAAI,GAAS,MAAM;IAC5D,IAAM,IAAO,EAAQ,EAAE,EAAE,SAAS,IAC5B,IAAQ,oCAAoC,KAAK,GAAM,aAAa,OAAO,KAAK,EAAE,CAAC,GAAG;IAI5F,OAHI,MAAU,WAAiB,UAC3B,MAAU,UAAgB,SAC1B,MAAU,SAAe,SACtB;GACT,CAAC,GACG,IAAK;GAET,AADA,KAAM,KAAK,EAAY,KAAK,KAAK,EAAE,OACnC,KAAM,KAAK,EAAS,KAAK,KAAK,EAAE;GAChC,KAAK,IAAI,IAAI,GAAW,IAAI,EAAU,QAAQ,KAC5C,KAAM,KAAK,EAAO,EAAU,EAAE,CAAC,CAAC,KAAK,KAAK,EAAE;GAE9C,OAAO,IAAK;EACd;EACA,SAAS,OAAO,EAAM;CACxB;AACF;AAYA,SAAS,GAAU,GAAM;CACvB,OAAO,OAAO,KAAQ,EAAE,CAAC,CAAC,QAAQ,WAAW,EAAE;AACjD;AAUA,SAAgB,GAAW,GAAS;CAClC,IAAM,IAAO,GAAU,CAAO;CAC9B,OAAO,6GAA6G,KAAK,CAAI,KACxH,eAAe,KAAK,CAAI,KACxB,kBAAkB,KAAK,CAAI,KAC3B,0DAA0D,KAAK,CAAI,KACnE,gCAAgC,KAAK,CAAI,KAEzC,kEAAkE,KAAK,CAAI,KAI1E,4BAA4B,KAAK,CAAI,KAAK,8CAA8C,KAAK,CAAI;AACzG;AAGA,IAAM,IAAQ,qBAER,KAAmB,qBAEnB,KAAW;AAWjB,SAAS,EAAc,GAAM;CAC3B,IAAM,IAAI,GAAS,KAAK,CAAI;CAC5B,IAAI,CAAC,GAAG,OAAO;CAEf,IAAM,GAAG,GAAQ,GAAO,IAAO,MAAM;CAErC,OADI,EAAM,OAAO,OAAO,EAAK,SAAS,GAAG,IAAU,OAC5C;EACL,QAAQ,EAAM;EACd,QAAQ,EAAM;EACd,QAAQ,EAAO;EAEf,MAAM,EAAK,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;CACvC;AACF;AASA,SAAS,GAAa,GAAM,GAAO;CACjC,IAAI,IAAU,GACV,IAAM;CACV,OAAO,IAAM,EAAK,UAAU,IAAU,IAAO;EAC3C,IAAI,EAAK,OAAS,KAAK;GAAgB,AAAd,KAAW,GAAG,KAAO;GAAG;EAAU;EAC3D,IAAI,EAAK,OAAS,KAAM;GACtB,IAAM,IAAQ,IAAK,IAAU;GAC7B,IAAI,IAAU,IAAQ,GAAO;GAE7B,AADA,KAAW,GACX,KAAO;GACP;EACF;EACA;CACF;CACA,OAAO,EAAK,MAAM,CAAG;AACvB;AAEA,IAAM,KAAQ,gCAIR,KAAa;AAOnB,SAAgB,EAAe,GAAM;CACnC,IAAI,IAAQ,GAAU,CAAI,CAAC,CAAC,WAAW,QAAQ,IAAI,CAAC,CAAC,WAAW,MAAM,IAAI,CAAC,CAAC,MAAM,IAAI;CACtF,IAAQ,GAAkB,CAAK;CAC/B,IAAM,IAAO,GAA6B,CAAK;CAI/C,OAHA,IAAQ,EAAK,OACb,KAAY,EAAK,UACjB,KAAe,EAAK,aACb,GAAa,CAAK;AAC3B;AASA,SAAS,GAAa,GAAO;CAC3B,IAAM,IAAM,CAAC,GACT,IAAI;CAER,OAAO,IAAI,EAAM,SAAQ;EACvB,IAAM,IAAO,EAAM,IAGb,IAAQ,EAAc,CAAI;EAChC,IAAI,GAAO;GACT,IAAM,IAAc,OAAO,YAAY,EAAM,OAAO,GAAG,EAAM,OAAO,UAAU,GACxE,IAAY,CAAC;GAEnB,KADA,KACO,IAAI,EAAM,UAAU,CAAC,EAAQ,KAAK,EAAM,EAAE,IAI/C,AADA,EAAU,KAAK,GAAS,GAAa,EAAM,IAAI,EAAM,MAAM,CAAC,CAAC,GAC7D;GAEF,IAAM,IAAW,EAAM,OAAO,oBAAoB,EAAS,EAAM,IAAI,EAAE,KAAK;GAE5E,AADA,EAAI,KAAK,aAAa,EAAS,GAAG,EAAU,KAAK,IAAI,EAAE,cAAc,GACrE;GACA;EACF;EAMA,IAAI,GAAiB,KAAK,CAAI,GAAG;GAC/B,IAAM,IAAY,CAAC;GACnB,OAAO,IAAI,EAAM,WAAW,GAAiB,KAAK,EAAM,EAAE,KAAK,EAAM,EAAE,CAAC,KAAK,MAAM,MAAK;IAGtF,IAAI,EAAM,EAAE,CAAC,KAAK,MAAM,IAAI;KAC1B,IAAI,IAAI;KACR,OAAO,IAAI,EAAM,UAAU,EAAM,EAAE,CAAC,KAAK,MAAM,KAAI;KACnD,IAAI,KAAK,EAAM,UAAU,CAAC,GAAiB,KAAK,EAAM,EAAE,GAAG;KAC3D,OAAO,IAAI,GAAG,KAAK,EAAU,KAAK,EAAE;KACpC;IACF;IAEA,AADA,EAAU,KAAK,GAAS,GAAa,EAAM,IAAI,CAAC,CAAC,CAAC,GAClD;GACF;GACA,EAAI,KAAK,cAAc,EAAU,KAAK,IAAI,EAAE,cAAc;GAC1D;EACF;EAGA,IAAI,EAAK,KAAK,KAAK,CAAC,GAAM,KAAK,CAAI,KAAK,CAAC,WAAW,KAAK,CAAI,KAAK,IAAI,IAAI,EAAM,QAAQ;GACtF,IAAI,UAAU,KAAK,EAAM,IAAI,EAAE,GAAG;IAEhC,AADA,EAAI,KAAK,OAAO,EAAQ,EAAK,KAAK,CAAC,EAAE,MAAM,GAC3C,KAAK;IACL;GACF;GACA,IAAI,aAAa,KAAK,EAAM,IAAI,EAAE,GAAG;IAEnC,AADA,EAAI,KAAK,OAAO,EAAQ,EAAK,KAAK,CAAC,EAAE,MAAM,GAC3C,KAAK;IACL;GACF;EACF;EAGA,IAAI,GAAM,KAAK,CAAI,GAAG;GAEpB,AADA,EAAI,KAAK,MAAM,GACf;GACA;EACF;EAOA,IAAM,IAAS,uBAAuB,KAAK,CAAI;EAC/C,IAAI,GAAQ;GACV,IAAM,IAAQ,EAAO,EAAE,CAAC,QAGlB,IAAU,EAAO,EAAE,CAAC,QAAQ,kBAAkB,EAAE;GAEtD,AADA,EAAI,KAAK,KAAK,EAAM,GAAG,EAAQ,CAAO,EAAE,KAAK,EAAM,EAAE,GACrD;GACA;EACF;EAGA,IAAI,EAAM,KAAK,CAAI,GAAG;GACpB,IAAM,IAAU,CAAC;GACjB,OAAO,IAAI,EAAM,UAAU,EAAM,KAAK,EAAM,EAAE,IAE5C,AADA,EAAQ,KAAK,EAAM,KAAK,EAAM,EAAE,CAAC,CAAC,EAAE,GACpC;GAEF,EAAI,KAAK,eAAe,GAAa,CAAO,EAAE,cAAc;GAC5D;EACF;EAGA,IAAI,UAAU,KAAK,CAAI,GAAG;GACxB,IAAM,EAAE,MAAM,GAAU,cAAW,GAAgB,GAAO,CAAC;GACvC,AAApB,EAAI,KAAK,CAAQ,GAAG,IAAI;GAAQ;EAClC;EAGA,IAAI,YAAY,KAAK,CAAI,GAAG;GAC1B,IAAM,EAAE,MAAM,GAAU,cAAW,GAAgB,GAAO,CAAC;GACvC,AAApB,EAAI,KAAK,CAAQ,GAAG,IAAI;GAAQ;EAClC;EAGA,IAAI,EAAK,KAAK,MAAM,IAAI;GACtB;GACA;EACF;EAKA,IAAI,GAAc,GAAO,CAAC,GAAG;GAC3B,IAAM,IAAc,EAAe,CAAI,GACjC,IAAa,EAAe,EAAM,IAAI,EAAE,CAAC,CAAC,KAAK,MAC/C,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,IAAU,WAC7C,EAAE,SAAS,GAAG,IAAU,UACxB,EAAE,WAAW,GAAG,IAAU,SACvB,IACR;GACD,KAAK;GACL,IAAM,IAAW,CAAC;GAClB,OAAO,IAAI,EAAM,UAAU,EAAM,EAAE,CAAC,KAAK,MAAM,MAAM,GAAiB,EAAM,EAAE,IAAI,IAEhF,AADA,EAAS,KAAK,EAAe,EAAM,EAAE,CAAC,GACtC;GAEF,IAAM,KAAS,GAAK,GAAS,MAEpB,IAAI,IADD,IAAQ,sBAAsB,EAAM,KAAK,GAChC,GAAG,EAAQ,CAAO,EAAE,IAAI,EAAI,IAG3C,IAAQ,cADE,EAAY,KAAK,GAAG,MAAQ,EAAM,MAAM,GAAG,EAAW,EAAI,CAAC,CAAC,CAAC,KAAK,EAChD,EAAE,gBAE9B,IAAQ,EAAS,SAAS,UAAU,EAAS,KADhC,MAAQ,OAAO,EAAI,KAAK,GAAG,MAAQ,EAAM,MAAM,GAAG,EAAW,EAAI,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,MAChC,CAAC,CAAC,KAAK,EAAE,EAAE,YAAY;GACvF,EAAI,KAAK,UAAU,IAAQ,EAAM,SAAS;GAC1C;EACF;EAGA,IAAM,IAAY,CAAC;EACnB,OACE,IAAI,EAAM,UACV,EAAM,EAAE,CAAC,KAAK,MAAM,MACpB,CAAC,6BAA6B,KAAK,EAAM,EAAE,KAC3C,CAAC,EAAc,EAAM,EAAE,KACvB,CAAC,EAAM,KAAK,EAAM,EAAE,KACpB,CAAC,GAAM,KAAK,EAAM,EAAE,KACpB,CAAC,GAAc,GAAO,CAAC,KACvB,EAAE,IAAI,IAAI,EAAM,UAAU,UAAU,KAAK,EAAM,IAAI,EAAE,MACrD,EAAE,IAAI,IAAI,EAAM,UAAU,aAAa,KAAK,EAAM,IAAI,EAAE,KAGxD,AADA,EAAU,KAAK,EAAM,EAAE,GACvB;EAEF,AAAI,EAAU,SACZ,EAAI,KAAK,MAAM,EAAQ,GAAoB,CAAS,CAAC,CAAC,CAAC,WAAW,IAAY,MAAM,EAAE,KAAK,KAM3F,EAAI,KAAK,MAAM,EAAQ,CAAI,EAAE,KAAK,GAClC;CAEJ;CAEA,OAAO,EAAI,KAAK,EAAE;AACpB;AAOA,IAAI,qBAAY,IAAI,IAAI,GACpB,qBAAe,IAAI,IAAI;AAU3B,SAAS,GAAkB,GAAO;CAChC,KAAK,EAAM,MAAM,GAAA,CAAI,KAAK,MAAM,OAAO,OAAO;CAC9C,IAAI,IAAW;CACf,KAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,KAAK;EACrC,IAAM,IAAI,EAAM,EAAE,CAAC,KAAK;EACxB,IAAI,MAAM,SAAS,MAAM,OAAO;GAAE,IAAW;GAAG;EAAO;CACzD;CASA,IARI,MAAa,MAQb,CANS,EAAM,MAAM,GAAG,CACH,CAAC,CAAC,OAAO,MAChC,EAAE,KAAK,MAAM,MACb,4BAA4B,KAAK,CAAC,KAClC,gBAAgB,KAAK,CAAC,KACtB,YAAY,KAAK,CAAC,CACH,GAAG,OAAO;CAE3B,IAAI,IAAQ,IAAW;CAEvB,OADI,EAAM,OAAW,KAAA,KAAa,EAAM,EAAM,CAAC,KAAK,MAAM,MAAI,KACvD,EAAM,MAAM,CAAK;AAC1B;AASA,SAAS,GAA6B,GAAO;CAC3C,IAAM,oBAAW,IAAI,IAAI,GACnB,oBAAc,IAAI,IAAI,GACtB,IAAQ,CAAC,GACX,IAAU,IACR,IAAY,+CACZ,IAAgB;CAEtB,KAAK,IAAM,KAAQ,GAAO;EAExB,IAAI,GAAS;GAEX,AADI,gCAAgC,KAAK,CAAI,MAAG,IAAU,KAC1D,EAAM,KAAK,CAAI;GACf;EACF;EACA,IAAI,EAAc,CAAI,GAAG;GAAkB,AAAhB,IAAU,IAAM,EAAM,KAAK,CAAI;GAAG;EAAU;EACvE;GACE,IAAM,IAAK,EAAc,KAAK,CAAI;GAClC,IAAI,GAAI;IAAE,EAAY,IAAI,EAAG,EAAE;IAAG;GAAU;GAC5C,IAAM,IAAK,EAAU,KAAK,CAAI;GAC9B,IAAI,GAAI;IAAE,EAAS,IAAI,EAAG,EAAE,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG;KAAE,MAAM,EAAG;KAAI,OAAO,EAAG;IAAG,CAAC;IAAG;GAAU;EAC/F;EACA,EAAM,KAAK,CAAI;CACjB;CACA,OAAO;EAAE;EAAO;EAAU;CAAY;AACxC;AASA,SAAS,GAAoB,GAAW;CACtC,IAAI,IAAS;CACb,KAAK,IAAI,IAAM,GAAG,IAAM,EAAU,QAAQ,KAAO;EAC/C,IAAM,IAAS,MAAQ,EAAU,SAAS,GAIpC,IAAK,EAAU,EAAI,CAAC,QAAQ,WAAW,EAAE;EAC/C,IAAI,CAAC,KAAU,MAAM,KAAK,CAAE,GAAG;GAAE,KAAU,EAAG,QAAQ,OAAO,EAAE,IAAI;GAAY;EAAU;EACzF,IAAI,CAAC,KAAU,SAAS,KAAK,CAAE,GAAG;GAAE,KAAU,EAAG,QAAQ,UAAU,EAAE,IAAI;GAAY;EAAU;EAC/F,KAAU,KAAM,IAAS,KAAK;CAChC;CACA,OAAO;AACT;AAUA,SAAS,GAAiB,GAAM;CAC9B,OAAO,EAAe,CAAI,CAAC,CAAC;AAC9B;AAiBA,SAAS,GAAc,GAAO,GAAG;CAC/B,IAAM,IAAS,EAAM,IACf,IAAQ,EAAM,IAAI;CACxB,IAAI,MAAU,KAAA,KAAa,CAAC,EAAO,SAAS,GAAG,GAAG,OAAO;CAEzD,IAAI,UAAU,KAAK,CAAM,GAAG,OAAO,gBAAgB,KAAK,CAAK;CAE7D,IAAM,IAAa,EAAe,CAAK;CAEvC,OADI,EAAW,SAAS,KAAK,CAAC,EAAW,OAAO,MAAM,WAAW,KAAK,CAAC,CAAC,IAAU,KAC3E,GAAiB,CAAM,MAAM,EAAW;AACjD;AAEA,SAAS,EAAe,GAAK;CAC3B,IAAM,IAAU,EAAI,QAAQ,OAAO,EAAE,CAAC,CAAC,QAAQ,OAAO,EAAE,GAClD,IAAQ,CAAC,GACX,IAAM;CACV,KAAK,IAAI,IAAI,GAAG,IAAI,EAAQ,QAAQ,KAAK;EACvC,IAAI,EAAQ,OAAO,QAAQ,EAAQ,IAAI,OAAO,KAAK;GAAc,AAAZ,KAAO,KAAK;GAAK;EAAU;EAChF,IAAI,EAAQ,OAAO,KAAK;GAAmB,AAAjB,EAAM,KAAK,CAAG,GAAG,IAAM;GAAI;EAAU;EAC/D,KAAO,EAAQ;CACjB;CAEA,OADA,EAAM,KAAK,CAAG,GACP,EAAM,KAAK,MAAM,EAAE,KAAK,CAAC;AAClC;AAEA,SAAS,GAAgB,GAAO,GAAU;CACxC,IAAM,IAAc,EAAM,EAAS,CAAC,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAE,QAClD,IAAO,eAAe,KAAK,EAAM,EAAS,GAC1C,IAAQ,CAAC,GACX,IAAY,MACZ,IAAQ,IACR,IAAe,IACf,IAAI;CAER,OAAO,IAAI,EAAM,SAAQ;EACvB,IAAM,IAAO,EAAM;EAEnB,IAAI,EAAK,KAAK,MAAM,IAAI;GAItB,IAAM,IAAO,EAAM,IAAI,IACjB,IAAa,MAAS,KAAA,IAA+C,KAAlC,EAAK,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAE,QAC5D,IAAiB,MAAS,KAAA,KAC9B,yBAAyB,KAAK,CAAI,KACjC,eAAe,KAAK,CAAI,MAAM,KAC/B,MAAe,GACX,IAAqB,MAAS,KAAA,KAAa,EAAK,KAAK,MAAM,MAAM,IAAa;GACpF,IAAI,CAAC,EAAM,UAAW,CAAC,KAAkB,CAAC,GAAqB;GAG/D,AAFA,IAAQ,IACR,IAAe,IACf;GACA;EACF;EAEA,IAAM,IAAU,EAAK,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAE;EACzC,IAAI,IAAS,GAAY;EAEzB,IAAI,MAAW,GAAY;GAEzB,IADI,CAAC,yBAAyB,KAAK,CAAI,KACnC,eAAe,KAAK,CAAI,MAAM,GAAM;GACxC,IAAM,IAAM,IAAO,EAAK,QAAQ,gBAAgB,EAAE,IAAI,EAAK,QAAQ,cAAc,EAAE,GAM7E,IAAO,CAAC,KAAQ,gBAAgB,KAAK,CAAG;GAE9C,IADI,MAAc,SAAM,IAAY,IAChC,MAAS,GAAW;GACxB,IAAM,IAAU,KAAQ,EAAI,EAAE,CAAC,YAAY,MAAM,KAC3C,IAAO,IAAO,EAAI,QAAQ,iBAAiB,EAAE,IAAI;GAGvD,AAFA,EAAM,KAAK;IAAE,OAAO,CAAC,CAAI;IAAG;IAAM;IAAS,KAAK;GAAG,CAAC,GACpD,IAAe,IACf;EACF,OAAO;GACL,IAAI,CAAC,EAAM,QAAQ;IAAE;IAAK;GAAU;GAOpC,IAAM,KAAU,MAAM,GAAa,GAAG,CAAM,GACtC,IAAQ,EAAc,EAAO,CAAI,CAAC;GACxC,IAAI,GAAO;IACT,IAAM,IAAc,OAAO,YAAY,EAAM,OAAO,GAAG,EAAM,OAAO,UAAU,GACxE,IAAa,CAAC,EAAO,EAAM,EAAE,CAAC;IAEpC,KADA,KACO,IAAI,EAAM,UAAU,CAAC,EAAQ,KAAK,EAAO,EAAM,EAAE,CAAC,IAEvD,AADA,EAAW,KAAK,EAAO,EAAM,EAAE,CAAC,GAChC;IAKF,AAHI,IAAI,EAAM,WAAU,EAAW,KAAK,EAAO,EAAM,EAAE,CAAC,GAAG,MAE3D,EAAM,EAAM,SAAS,EAAE,CAAC,OAAO,GAAa,CAAU,GACtD,IAAe;IACf;GACF;GAEA,IAAI,yBAAyB,KAAK,CAAI,GAAG;IACvC,IAAM,IAAS,GAAgB,GAAO,CAAC;IAGvC,AAFA,EAAM,EAAM,SAAS,EAAE,CAAC,OAAO,EAAO,MACtC,IAAI,EAAO,QACX,IAAe;GACjB,OAAO,IAAI,GAGT,AAFA,EAAM,EAAM,SAAS,EAAE,CAAC,MAAM,KAAK,EAAK,KAAK,CAAC,GAC9C,IAAe,IACf;QACK;IACL,IAAM,IAAQ,EAAM,EAAM,SAAS,EAAE,CAAC;IAEtC,AADA,EAAM,EAAM,SAAS,MAAM,MAAM,EAAK,KAAK,GAC3C;GACF;EACF;CACF;CAEA,IAAM,IAAQ,CAAC,KAAS,MAAc,IAChC,IAAa,IAAO,iBAAiB,KAAK,EAAM,EAAS,IAAI,MAC7D,IAAW,IAAa,OAAO,SAAS,EAAW,IAAI,EAAE,IAAI,GAC7D,IAAO,IACR,MAAa,IAAiC,SAA7B,cAAc,EAAS,MACxC,IAAQ,gCAA8B,QACrC,IAAQ,IAAO,UAAU;CAU/B,OAAO;EAAE,MAAM,GAAG,IATH,EAAM,KAAK,EAAE,UAAO,SAAM,YAAS,aAAU;GAC1D,IAAM,IAAS,IACX,iDAAiD,IAAU,aAAa,GAAG,KAC3E;GAIJ,OAAO,OAHM,IACT,EAAM,KAAK,GAAG,MAAQ,MAAM,MAAQ,IAAI,IAAS,KAAK,EAAQ,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,IAC/E,GAAG,IAAS,EAAQ,EAAM,EAAE,MACX,EAAI;EAC3B,CAAC,CAAC,CAAC,KAAK,EACsB,IAAI;EAAS,QAAQ;CAAE;AACvD;AAOA,IAAM,KAAe,8CAIf,IAAO,MAIP,IAAY,KAGZ,KAAe;AAYrB,SAAS,GAAkB,GAAM;CAC/B,IAAM,IAAQ,CAAC;CAOf,OAAO;EAAE,MANQ,EAAK,QAAQ,KAAe,GAAO,GAAO,MAErD,MAAY,KAAW,KAC3B,EAAM,KAAK,CAAO,GACX,GAAG,IAAY,EAAM,SAAS,IAAI,IAErB;EAAG;CAAM;AACjC;AAUA,SAAS,GAAkB,GAAM,GAAO,GAAU;CAChD,OAAO,EAAK,QAAY,OAAO,GAAG,EAAU,QAAQ,KAAa,GAAG,IAAI,GAAG,MAAQ;EACjF,IAAI,IAAI,EAAM,OAAO,CAAG;EAOxB,OAJA,IAAI,EAAE,QAAY,OAAO,GAAG,EAAK,QAAQ,KAAQ,GAAG,IAAI,GAAI,MAAM,KAAK,EAAS,OAAO,CAAC,IAAI,GAGxF,EAAE,SAAS,KAAK,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,KAAK,EAAE,KAAK,MAAM,OAAI,IAAI,EAAE,MAAM,GAAG,EAAE,IACvF,SAAS,GAAS,CAAC,EAAE;CAC9B,CAAC;AACH;AAQA,SAAS,GAAyB,GAAM;CACtC,IAAM,IAAW,CAAC;CAKlB,OAAO;EAAE,MAJQ,EAAK,QAAQ,KAAe,GAAG,OAC9C,EAAS,KAAK,CAAE,GACT,GAAG,IAAO,EAAS,SAAS,IAAI,IAEnB;EAAG;CAAS;AACpC;AASA,SAAS,GAAyB,GAAM,GAAU;CAChD,OAAO,EAAK,QAAY,OAAO,GAAG,EAAK,QAAQ,KAAQ,GAAG,IAAI,GAAG,MAAQ,GAAK,EAAS,OAAO,CAAG,EAAE,CAAC;AACtG;AAMA,IAAM,KAAO,OAAO,GAAG,kDACjB,KAAW,IAAI,OAAO,OAAO,GAAG,kBAAkB,GAAK,KAAK,GAAG,GAC/D,KAAU,IAAI,OAAO,OAAO,GAAG,iBAAiB,GAAK,KAAK,GAAG;AAcnE,SAAS,GAAmB,GAAM;CAChC,IAAM,IAAI,EAAK,KAAK,GAId,IAAQ,+DAA+D,KAAK,CAAC;CACnF,IAAI,GAAO,OAAO;EAAE,MAAM,EAAM;EAAI,OAAO,EAAM,MAAM,EAAM,MAAM;CAAG;CAEtE,IAAM,IAAY,uCAAuC,KAAK,CAAC;CAG/D,OAFI,IAAkB;EAAE,MAAM,EAAU;EAAI,OAAO,EAAU,MAAM,EAAU,MAAM;CAAG,IAE/E;EAAE,MAAM;EAAG,OAAO;CAAG;AAC9B;AASA,SAAS,GAA0B,GAAM;CAwBvC,OAvBA,IAAO,EAAK,QAAQ,KAAW,GAAG,GAAK,MAAS;EAC9C,IAAM,EAAE,SAAM,aAAU,GAAmB,CAAI,GACzC,IAAY,IAAQ,WAAW,EAAe,CAAK,EAAE,KAAK;EAChE,OAAO,aAAa,EAAe,CAAI,EAAE,SAAS,EAAe,CAAG,EAAE,GAAG,EAAU;CACrF,CAAC,GACD,IAAO,EAAK,QAAQ,KAAU,GAAG,GAAO,MAAS;EAC/C,IAAM,EAAE,SAAM,aAAU,GAAmB,CAAI,GACzC,IAAY,IAAQ,WAAW,EAAe,CAAK,EAAE,KAAK;EAChE,OAAO,YAAY,EAAe,CAAI,EAAE,GAAG,EAAU,GAAG,EAAM;CAChE,CAAC,GACD,IAAO,EAAK,QAAQ,8BAA8B,GAAG,GAAO,MAAQ;EAClE,IAAM,IAAM,GAAU,IAAI,GAAc,KAAO,CAAK,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC;EAC1E,IAAI,CAAC,GAAK,OAAO;EACjB,IAAM,IAAY,EAAI,QAAQ,WAAW,EAAS,EAAI,KAAK,EAAE,KAAK;EAClE,OAAO,YAAY,EAAS,EAAI,IAAI,EAAE,GAAG,EAAU,GAAG,EAAM;CAC9D,CAAC,GACD,IAAO,EAAK,QAAQ,kBAAkB,GAAG,MAAU;EACjD,IAAM,IAAM,GAAU,IAAI,GAAc,CAAK,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC;EACnE,IAAI,CAAC,GAAK,OAAO;EACjB,IAAM,IAAY,EAAI,QAAQ,WAAW,EAAS,EAAI,KAAK,EAAE,KAAK;EAClE,OAAO,YAAY,EAAS,EAAI,IAAI,EAAE,GAAG,EAAU,GAAG,EAAM;CAC9D,CAAC,GACD,IAAO,EAAK,QAAQ,oBAAoB,GAAG,MAAQ,GAAa,IAAI,GAAc,CAAE,CAAC,IAAI,SAAS,EAAG,WAAW,CAAE,GAC3G;AACT;AASA,SAAS,GAAgB,GAAM;CAc7B,OAbA,IAAO,EAAK,QAAQ,mCAAmC,GAAG,MAAQ,YAAY,EAAe,CAAG,EAAE,IAAI,EAAI,KAAK,GAE/G,IAAO,EAAK,QACV,0IACC,GAAG,MAAS,mBAAmB,EAAe,CAAI,EAAE,IAAI,EAAK,KAChE,GACA,IAAO,EAAK,QAAQ,oCAAoC,GAAG,GAAK,MAAW;EACzE,IAAM,IAAQ,cAAc,KAAK,CAAM,GACjC,IAAM,IAAQ,EAAO,MAAM,GAAG,CAAC,EAAM,EAAE,CAAC,MAAM,IAAI;EACxD,IAAI,CAAC,GAAK,OAAO;EACjB,IAAM,IAAS,IAAQ,EAAM,KAAK;EAClC,OAAO,GAAG,EAAI,WAAW,EAAe,CAAG,EAAE,IAAI,EAAI,MAAM;CAC7D,CAAC,GACM;AACT;AASA,SAAS,GAAsB,GAAM;CAQnC,OAPA,IAAO,EAAK,QAAQ,0BAA0B,GAAG,MAAM,eAAe,EAAE,eAAe,GACvF,IAAO,EAAK,QAAQ,qCAAqC,GAAG,MAAM,eAAe,EAAE,eAAe,GAClG,IAAO,EAAK,QAAQ,0BAA0B,GAAG,MAAM,WAAW,EAAE,UAAU,GAC9E,IAAO,EAAK,QAAQ,qCAAqC,GAAG,MAAM,WAAW,EAAE,UAAU,GACzF,IAAO,EAAK,QAAQ,oBAAoB,GAAG,MAAM,OAAO,EAAE,MAAM,GAChE,IAAO,EAAK,QAAQ,+BAA+B,GAAG,MAAM,OAAO,EAAE,MAAM,GAC3E,IAAO,EAAK,QAAQ,oBAAoB,GAAG,MAAM,QAAQ,EAAE,OAAO,GAC3D;AACT;AAEA,SAAS,EAAQ,GAAM;CAOrB,IAAM,EAAE,MAAM,GAAgB,gBAAa,GAAyB,CAAI,GAClE,EAAE,MAAM,GAAa,aAAU,GAAkB,CAAc,GAUjE,IAAS,GAAK,CAAW;CAM7B,OAJA,IAAS,GAA0B,CAAM,GACzC,IAAS,GAAgB,CAAM,GAC/B,IAAS,GAAsB,CAAM,GAE9B,GAAkB,GAAyB,GAAQ,CAAQ,GAAG,GAAO,CAAQ;AACtF;AAOA,IAAM,KAAY;AAElB,SAAS,GAAK,GAAG;CACf,OAAO,OAAO,CAAC,CAAC,CACb,QAAQ,IAAW,OAAO,CAAC,CAC3B,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,KAAK,MAAM;AAC3B;AAUA,SAAS,GAAS,GAAG;CACnB,OAAO,OAAO,CAAC,CAAC,CACb,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,KAAK,MAAM;AAC3B;AAEA,SAAS,EAAS,GAAG;CACnB,OAAO,OAAO,CAAC,CAAC,CACb,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,MAAK,QAAQ,CAAC,CACzB,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,KAAK,MAAM;AAC3B;AAGA,SAAS,EAAe,GAAG;CACzB,OAAO,OAAO,CAAC,CAAC,CAAC,WAAW,MAAK,QAAQ,CAAC,CAAC,WAAW,KAAK,OAAO;AACpE;AAGA,SAAS,GAAc,GAAG;CACxB,OAAO,OAAO,CAAC,CAAC,CAAC,WAAW,QAAQ,GAAG,CAAC,CAAC,WAAW,QAAQ,GAAG,CAAC,CAAC,WAAW,SAAS,GAAG;AAC1F;;;ACvkCA,IAAM,KAAY,GAEZ,KAAa,GASb,KAAY;CAChB,CAAC,cAAc,YAAY;CAC3B,CAAC,QAAQ,KAAK;CACd,CAAC,OAAO,GAAG;AACb,GAea,KAAkB;CAC7B;CAAc;CAAc;CAAU;CAAQ;CAAM;CAAQ;CAAU;CACtE;CAAS;CAAO;CAAK;CAAQ;CAAO;CAAQ;CAAO;CAAQ;CAAQ;CACnE;CAAO;CAAQ;CAAO;AACxB,GAGM,KAAQ;CAEZ;EAAE,MAAM;EAAc,GAAG;EAAI,IAAI;CAAgB;CACjD;EAAE,MAAM;EAAc,GAAG;EAAI,IAAI;CAAgC;CACjE;EAAE,MAAM;EAAc,GAAG;EAAI,IAAI;CAAmD;CACpF;EAAE,MAAM;EAAc,GAAG;EAAI,IAAI;CAA8D;CAC/F;EAAE,MAAM;EAAc,GAAG;EAAI,IAAI;CAAwC;CACzE;EAAE,MAAM;EAAc,GAAG;EAAI,IAAI;CAAsC;CACvE;EAAE,MAAM;EAAc,GAAG;EAAI,IAAI;CAAwE;CACzG;EAAE,MAAM;EAAc,GAAG;EAAI,IAAI;CAAsG;CACvI;EAAE,MAAM;EAAc,GAAG;EAAI,IAAI;CAAwB;CACzD;EAAE,MAAM;EAAc,GAAG;EAAI,IAAI;CAAgB;CAGjD;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAgD;CAChF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAqD;CAIrF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAoG;CACpI;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAqE;CACrG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAwC;CACxE;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAkE;CAIlG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAuC;CACvE;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA6E;CAC7G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAyF;CACzH;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAuE;CACvG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA6C;CAG7E;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA4D;CAC5F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA+B;CAC/D;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAgE;CAChG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA6E;CAC7G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA8D;CAC9F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAsF;CACtH;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA8D;CAC9F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAgD;CAGhF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA2E;CAC3G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA8C;CAC9E;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA+D;CAC/F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA0C;CAC1E;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA4F;CAC5H;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAuC;CACvE;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAqE;CACrG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAsD;CAGtF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAgC;CAChE;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA2D;CAC3F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAwE;CACxG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAoD;CACpF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAkD;CAGlF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAyD;CACzF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAoE;CACpG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA+D;CAC/F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA0F;CAC1H;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA0F;CAG1H;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAwI;CACxK;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA0D;CAC1F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA0G;CAC1I;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAwG;CACxI;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAmF;CAGnH;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAgE;CAChG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA6H;CAC7J;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA+D;CAC/F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAuH;CACvJ;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA0E;CAG1G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA0E;CAC1G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAkG;CAClI;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAwE;CAGxG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA8G;CAC9I;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAoH;CACpJ;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAgI;CAChK;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA6G;CAC7I;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAwC;CAGxE;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA2E;CAC3G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA2E;CAC3G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAiE;CACjG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA2D;CAC3F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAkD;CAClF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA8C;CAG9E;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAgC;CAChE;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAmF;CAInH;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA4B;CAC5D;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA4B;CAC5D;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA8D;CAC9F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA6B;CAG7D;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA4C;CAC5E;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAkD;CAClF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA6E;CAK7G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA+D;CAC/F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAwB;CAGxD;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA2E;CAC3G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAwI;CACxK;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAsD;CACtF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAwD;CAExF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAuE;CACvG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA0C;CAK1E;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAY;CAC5C;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA2B;CAC3D;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAwE;CACxG;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAuC;CACvE;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAiB;CAGjD;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAgB;CAChD;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA4C;CAC5E;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA0C;CAC1E;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAuC;CAGvE;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAsF;CACtH;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA6E;CAC7G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA0G;CAG1I;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAqF;CACrH;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAkC;CAClE;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAuB;CAIvD;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA8V;CAC9X;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA2D;CAC3F;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAgG;CAChI;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA4E;CAG5G;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAuK;CACvM;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAqD;CACrF;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAkG;CAClI;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA8C;CAC9E;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAA8F;CAC9H;EAAE,MAAM;EAAc,GAAG;EAAG,IAAI;CAAyC;AAC3E,GAWM,KAAe;AAQrB,SAAS,GAAQ,GAAG;CAClB,IAAI,EAAE,UAAU,IAAc,OAAO;CACrC,IAAM,IAAO,EAAE,MAAM,GAAG,EAAY,GAC9B,IAAY,EAAK,YAAY,IAAI;CACvC,OAAO,IAAY,IAAI,EAAK,MAAM,GAAG,CAAS,IAAI;AACpD;AAOA,SAAgB,GAAW,GAAM;CAC/B,IAAI,CAAC,GAAM,KAAK,GAAG,OAAO;CAC1B,IAAM,IAAI,GAAQ,EAAK,KAAK,CAAC,GAGvB,oBAAS,IAAI,IAAI;CACvB,KAAK,IAAM,EAAE,SAAM,OAAI,UAAO,IAC5B,AAAI,EAAG,KAAK,CAAC,KAAG,EAAO,IAAI,IAAO,EAAO,IAAI,CAAI,KAAK,KAAK,CAAC;CAE9D,IAAI,EAAO,SAAS,GAAG,OAAO;CAO9B,KAAK,IAAM,CAAC,GAAU,MAAS,IAAW;EACxC,IAAM,IAAM,EAAO,IAAI,CAAQ;EAC/B,AAAI,KAAK,EAAO,IAAI,GAAU,KAAO,EAAO,IAAI,CAAI,KAAK,EAAE;CAC7D;CAEA,IAAM,IAAS,CAAC,GAAG,EAAO,QAAQ,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE,GACzD,CAAC,GAAQ,KAAO,EAAO,IACvB,IAAW,EAAO,EAAE,GAAG,MAAM;CAGnC,OADI,IAAM,MAAa,IAAM,IAAW,KAAmB,OACpD;AACT;;;ACjRA,IAAM,qBAAgB,IAAI,IAAI;CAAC;CAAO;CAAc;CAAS;CAAU;CAAM;CAAM;AAAI,CAAC,GAE3E,KAAb,MAAoB;CAIlB,YAAY,GAAS;EAOnB,AANA,KAAK,UAAU,GACf,KAAK,UAAU,EAAQ,SAEvB,KAAK,WAAW,MAChB,KAAK,aAAa,CAAC,GAEnB,KAAK,iBAAiB;CACxB;CAMA,aAAa;EACX,IAAM,IAAW,KAAK,QAAQ,WAAW;EAOzC,OANA,KAAK,WAAW,IAAI,GAClB,GACA,KAAK,QAAQ,gBAAgB,KAC7B,KAAK,QAAQ,mBAAmB,KAAK,OAAO,IAC9C,GACA,KAAK,YAAY,CAAQ,GAClB;CACT;CAEA,UAAU;EAKR,AAJA,KAAK,WAAW,SAAS,MAAM,EAAE,CAAC,GAClC,KAAK,aAAa,CAAC,GACnB,KAAK,WAAW,MAChB,aAAa,KAAK,cAAc,GAChC,KAAK,iBAAiB;CACxB;CAMA,YAAY,GAAU;EAEpB,IAAM,KAAa,MAAU,KAAK,WAAW,CAAK,GAE5C,UAAgB,KAAK,aAAa,GAElC,KAAiB,MAAU,KAAK,cAAc,CAAK,GAEnD,UAAoB;GACxB,IAAI,CAAC,KAAK,QAAQ,QAAQ;GAC1B,IAAM,IAAM,WAAW,aAAa;GACpC,AAAI,GAAK,aAAa,KAAK,EAAS,SAAS,EAAI,UAAU,MACzD,KAAK,QAAQ,OAAO,iBAAiB,GACjC,OAAO,KAAK,QAAQ,qBAAsB,cAC5C,KAAK,QAAQ,kBAAkB,KAAK,OAAO;EAGjD,GAIM,KAAmB,MAAM;GAC7B,AAAI,EAAE,OAAO,SAAS,cAAc,EAAE,OAAO,QAAQ,eAAe,KAClE,KAAK,aAAa;EAEtB,GAQM,KAAsB,MAAU;GACpC,IAAM,IAAM,WAAW,aAAa;GACpC,IAAI,CAAC,GAAK,YAAY;GACtB,IAAM,IAAI,EAAI,WAAW,CAAC;GAC1B,IAAI,CAAC,EAAE,WAAW;GAClB,IAAM,IAAK,EAAE;GAIb,IAAI,EAAG,aAAa,KAAK,cAAc;GACvC,IAAM,IAA+B,GAC/B,IAAK,EAAK,QAAQ,kBAAkB,IAAI,IAAO;GACrD,IAAI,CAAC,GAAI;GACT,IAAM,IAAK,EAAG,cAAc,0BAAwB;GACpD,IAAI,CAAC,GAAI;GAIT,IAAI,GAAO,SAAS,WAAW;IAC7B,IAAI,IAAQ;IACZ,IAAI,SAAS,qBACX,IAAQ,SAAS,oBAAoB,EAAM,SAAS,EAAM,OAAO;SAC5D,IAAI,SAAS,wBAAwB;KAC1C,IAAM,IAAK,SAAS,uBAAuB,EAAM,SAAS,EAAM,OAAO;KACvE,AAAI,MACF,IAAQ,SAAS,YAAY,GAC7B,EAAM,SAAS,EAAG,YAAY,EAAG,MAAM;IAE3C;IAEA,IAAI,KAAS,EAAS,SAAS,EAAM,cAAc,KAC/C,EAAM,mBAAmB,GAAI;KAG/B,AAFA,EAAM,SAAS,EAAI,GACnB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAK;KAClB;IACF;GACF;GAMA,IAAM,IAAK,SAAS,YAAY,GAC5B,IAAa;GACjB,KAAK,IAAM,KAAS,EAAG,YACrB,IAAI,MAAU,KAAM,EAAM,aAAa,KAAK,WAAW;IACrD,IAAa;IACb;GACF;GASF,AAPI,IACF,EAAG,SAAS,GAAY,CAAC,IAEzB,EAAG,cAAc,CAAE,GAErB,EAAG,SAAS,EAAI,GAChB,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAE;EACjB,GAEM,UAAmB,KAAK,QAAQ,WAAW,UAAU,UAAU,SAAS,aAAa;EAE3F,KAAK,WAAW,KACd,EAAG,GAAU,WAAW,CAAS,GACjC,EAAG,GAAU,eAAe,CAAa,GACzC,EAAG,GAAU,SAAS,CAAO,GAC7B,EAAG,UAAU,mBAAmB,CAAW,GAC3C,EAAG,GAAU,SAAS,CAAe,GACrC,EAAG,GAAU,WAAW,CAAkB,GAC1C,EAAG,GAAU,SAAW,CAAkB,GAM1C,EAAG,GAAU,cAAc,MAAM;GAC/B,IAAI,EAAW,GAAG;IAAE,EAAE,eAAe;IAAG;GAAQ;GAChD,IAAM,IAAiC,EAAE;GACzC,AAAI,MAAW,EAAO,aAAa,YAC/B,EAAO,QAAQ,mBAAmB,MACpC,EAAE,eAAe;EAErB,CAAC,GACD,EAAG,GAAU,SAAc,MAAM;GAAE,AAAI,EAAW,KAAG,EAAE,eAAe;EAAG,CAAC,CAC5E;EASA,IAAI,IAAqB;EA4BzB,KAAK,WAAW,KACd,EAAG,GAAU,0BA5BkB;GAC/B,IAAM,IAAM,WAAW,aAAa;GACpC,IAAI,CAAC,GAAK,YAAY;IAAE,IAAqB;IAAM;GAAQ;GAC3D,IAAI,IAAO,EAAI,WAAW,CAAC,CAAC,CAAC;GAE7B,IADI,EAAK,aAAa,KAAK,cAAW,IAAO,EAAK,gBAC9C,GAAM;IACR,IAAM,IAA6B;IACnC,AAEK,IAFD,EAAG,QAAQ,KAAK,IAAwB,gBACnC,EAAG,QAAQ,KAAK,IAAwB,cACvB;GAC5B;EACF,CAiBqD,GACnD,EAAG,GAAU,wBAjBgB;GAC7B,IAAM,IAAM;GAEZ,IADA,IAAqB,MACjB,CAAC,GAAK;GACV,IAAM,IAAM,WAAW,aAAa;GACpC,IAAI,CAAC,GAAK,YAAY;GACtB,IAAI,IAAO,EAAI,WAAW,CAAC,CAAC,CAAC;GAC7B,AAAI,EAAK,aAAa,KAAK,cAAW,IAAO,EAAK;GAClD,IAAM,IAA6B;GAEnC,CADkB,MAAQ,gBAAgB,GAAI,QAAQ,KAAK,IAAI,GAAI,QAAQ,KAAK,MAG9E,SAAS,YAAY,CAAG;EAE5B,CAGmD,CACnD;CACF;CAEA,WAAW,GAAO;EAChB,IAAM,IAAW,KAAK,QAAQ,WAAW;EAGrC,QAAc,GAAO,GAAU,KAAK,OAAO,GAG/C;OAAI,EAAW,GAAO,GAAG,KAAK,CAAC,EAAM,UAAU;IAE7C,AADA,EAAM,eAAe,GACrB,KAAK,KAAK;IACV;GACF;GACA,IAAK,EAAW,GAAO,GAAG,KAAK,EAAM,YAAa,EAAW,GAAO,GAAG,GAAG;IAExE,AADA,EAAM,eAAe,GACrB,KAAK,KAAK;IACV;GACF;GACA,IAAI,EAAW,GAAO,GAAG,GAAG;IAA0B,AAAxB,EAAM,eAAe,GAAG,KAAK,KAAK;IAAG;GAAQ;GAC3E,IAAI,EAAW,GAAO,GAAG,GAAG;IAA0B,AAAxB,EAAM,eAAe,GAAG,KAAK,OAAO;IAAG;GAAQ;GAC7E,IAAI,EAAW,GAAO,GAAG,GAAG;IAA0B,AAAxB,EAAM,eAAe,GAAG,KAAK,UAAU;IAAG;GAAQ;GAChF,IAAI,EAAW,GAAO,GAAG,GAAG;IAA0B,AAAxB,EAAM,eAAe,GAAG,KAAK,QAAQ,OAAO,iBAAiB;IAAG;GAAQ;GAGtG,IAAI,EAAW,GAAO,GAAG,KAAK,EAAM,UAAU;IAC5C,KAAK,QAAQ,OAAO,2BAA2B,EAAI;IACnD;GACF;GAGA,IAAI,EAAM,QAAQ,OAAO,EAAM,YAAY,EAAM,WAAW,CAAC,EAAM,SAAS;IAE1E,AADA,EAAM,eAAe,GACrB,KAAK,QAAQ,OAAO,sBAAsB;IAC1C;GACF;GAEA,IAAI,EAAW,GAAO,GAAG,GAAG;IAE1B,AADA,EAAM,eAAe,GACrB,KAAK,QAAQ,OAAO,oBAAoB,MAAM;IAC9C;GACF;GAOA,AALI,EAAW,GAAO,GAAG,MACvB,EAAM,eAAe,GACrB,KAAK,QAAQ,OAAO,oBAAoB,SAAS,IAG/C,EAAW,GAAO,GAAG,MACvB,EAAM,eAAe,GACrB,KAAK,WAAW;EArClB;CAuCF;CAWA,cAAc,GAAO;EACnB,IAAM,IAAW,KAAK,QAAQ,YAAY,GACpC,IAAW,KAAK,QAAQ,YAAY;EAC1C,IAAI,CAAC,KAAY,CAAC,GAAU;EAE5B,IAAM,IAAO,EAAM,aAAa;EAMhC,IAJI,EAAK,WAAW,QAAQ,KAAK,MAAS,iBAAiB,MAAS,iBAEhE,MAAS,qBAAqB,MAAS,oBAEvC,CAAC,EAAK,WAAW,QAAQ,GAAG;EAEhC,IAAM,IAAO,KAAK,QAAQ,WAAW,SAAS,aAAa,IACrD,IAAQ,EAAK,WAAW,MAAM,EAAE,CAAC,CAAC;EAExC,IAAI,KAAY,KAAS,GAAU;GAEjC,AADA,EAAM,eAAe,GACjB,OAAO,KAAK,QAAQ,sBAAuB,cAC7C,KAAK,QAAQ,mBAAmB,KAAK,OAAO;GAE9C;EACF;EAGA,AAAI,MAAa,EAAM,SAAS,OAAO,MAAS,qBAAqB,MAAS,uBAC9D,EAAK,KAAK,IAAI,EAAK,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,SAAS,MACjD,MACX,EAAM,eAAe,GACjB,OAAO,KAAK,QAAQ,sBAAuB,cAC7C,KAAK,QAAQ,mBAAmB,KAAK,OAAO;CAIpD;CAMA,eAAe;EAcb,AAXA,KAAK,sBAAsB,GAG3B,KAAK,yBAAyB,GAE9B,KAAK,QAAQ,OAAO,iBAAiB,GACrC,KAAK,QAAQ,OAAO,kBAAkB,GAKtC,KAAK,kBAAkB;CACzB;CAMA,oBAAoB;EAElB,AADA,aAAa,KAAK,cAAc,GAChC,KAAK,iBAAiB,iBAAiB;GAGrC,AAFA,KAAK,iBAAiB,MAClB,KAAK,YAAU,KAAK,SAAS,WAAW,GAC5C,KAAK,QAAQ,aAAa,UAAU,KAAK,QAAQ,CAAC;EACpD,GAAG,GAAG;CACR;CAOA,wBAAwB;EAEtB,KADsB,QAAQ,WAAW,SAChC,iBAAiB,kBAAkB,CAAC,CAAC,SAAS,MAAQ;GAC7D,AAAK,EAAI,cAAc,KAAK,KAC1B,EAAI,OAAO;EAEf,CAAC;CACH;CAQA,2BAA2B;EACzB,IAAM,IAAW,KAAK,QAAQ,WAAW;EACzC,IAAI,CAAC,GAAU;EACf,IAAM,IAAO,EAAS;EACjB,SACD,GAAc,IAAI,EAAK,QAAQ,GAAG;GACpC,IAAM,IAAI,SAAS,cAAc,GAAG;GAEpC,AADA,EAAE,YAAY,QACd,EAAS,YAAY,CAAC;EACxB;CACF;CAMA,QAAQ;EAEN,KADsB,QAAQ,WAAW,SAChC,MAAM;CACjB;CAUA,UAAU;EAER,IAAM,IAAM,KAAK,QAAQ,WAAW,SAAS,UAAU,WAAW,KAAU,EAAE;EAG9E,OAAO,KAAK,QAAQ,OAAO,2BAA2B,CAAG,KAAK;CAChE;CAMA,QAAQ,GAAM;EAIZ,IAAM,IAAO,GAAe,GAAM,EAAE,cAAc,GAAK,CAAC;EAGxD,AAFA,KAAK,QAAQ,WAAW,SAAS,gBAAgB,GAAG,EAAK,UAAU,GAC/D,KAAK,YAAU,KAAK,SAAS,MAAM,GACvC,KAAK,aAAa;CACpB;CAMA,UAAU;EACR,OAAO,KAAK,QAAQ,WAAW,SAAS,aAAa;CACvD;CAMA,QAAQ,GAAM;EAGZ,AAFA,KAAK,QAAQ,WAAW,SAAS,cAAc,GAC3C,KAAK,YAAU,KAAK,SAAS,MAAM,GACvC,KAAK,aAAa;CACpB;CAKA,QAAQ;EACN,KAAK,QAAQ,EAAE;CACjB;CAKA,eAAe;EACb,AAAI,KAAK,YAAU,KAAK,SAAS,MAAM;CACzC;CAMA,UAAU;EACR,IAAM,KAAQ,KAAK,QAAQ,WAAW,SAAS,aAAa,GAAA,CACzD,KAAK,CAAC,CACN,WAAW,QAAU,EAAE,GACpB,IAAW,CAAC,CAAC,KAAK,QAAQ,WAAW,SAAS,cAAc,2BAA2B;EAC7F,OAAO,CAAC,KAAQ,CAAC;CACnB;CAMA,WAAW,GAAM;EACV,MACL,EAAkB,cAAc,EAAa,CAAI,CAAC,GAClD,KAAK,aAAa;CACpB;CAMA,WAAW,GAAM;EACV,MACL,EAAkB,cAAc,CAAI,GACpC,KAAK,aAAa;CACpB;CAMA,YAAY,GAAI;EACd,KAAK,QAAQ,EAAe,KAAM,EAAE,CAAC;CACvC;CAMA,cAAc;EACZ,OAAO,GAAe,KAAK,QAAQ,CAAC;CACtC;CAMA,OAAO;EACL,AAAI,KAAK,aACP,KAAK,sBAAsB,GAC3B,KAAK,SAAS,KAAK,GACnB,KAAK,QAAQ,OAAO,iBAAiB,GACrC,KAAK,QAAQ,OAAO,kBAAkB,GACtC,KAAK,QAAQ,aAAa,UAAU,KAAK,QAAQ,CAAC;CAEtD;CAEA,OAAO;EACL,AAAI,KAAK,aACP,KAAK,sBAAsB,GAC3B,KAAK,SAAS,KAAK,GACnB,KAAK,QAAQ,OAAO,iBAAiB,GACrC,KAAK,QAAQ,OAAO,kBAAkB,GACtC,KAAK,QAAQ,aAAa,UAAU,KAAK,QAAQ,CAAC;CAEtD;CAGA,wBAAwB;EAClB,KAAK,mBAAmB,SAC5B,aAAa,KAAK,cAAc,GAChC,KAAK,iBAAiB,MACtB,KAAK,UAAU,WAAW;CAC5B;CAEA,UAAU;EACR,OAAO,KAAK,WAAW,KAAK,SAAS,QAAQ,IAAI;CACnD;CAEA,UAAU;EACR,OAAO,KAAK,WAAW,KAAK,SAAS,QAAQ,IAAI;CACnD;CAEA,eAAe;EACb,OAAO,KAAK,WAAW,KAAK,SAAS,aAAa,IAAI;CACxD;CAEA,eAAe;EACb,OAAO,KAAK,WAAW,KAAK,SAAS,aAAa,IAAI;CACxD;CAEA,uBAAuB;EACrB,OAAO,KAAK,UAAU,oBAAoB,KAAK;CACjD;CAEA,yBAAyB,GAAU;EAGjC,OAFI,CAAC,KAAY,CAAC,KAAK,WAAiB,MACxC,KAAK,SAAS,kBAAkB,CAAQ,GACjC;CACT;CAMA,OAAgB;EAA2B,AAAzB,GAAW,GAAc,KAAK,aAAa;CAAG;CAChE,SAAgB;EAA2B,AAAzB,GAAa,GAAY,KAAK,aAAa;CAAG;CAChE,YAAgB;EAA4B,AAA1B,GAAgB,GAAU,KAAK,aAAa;CAAG;CACjE,gBAAgB;EAA4B,AAA1B,GAAoB,GAAM,KAAK,aAAa;CAAG;CACjE,cAAgB;EAA4B,AAA1B,GAAkB,GAAQ,KAAK,aAAa;CAAG;CACjE,YAAgB;EAA4B,AAA1B,GAAgB,GAAU,KAAK,aAAa;CAAG;CACjE,cAAgB;EAA4B,AAA1B,GAAkB,GAAQ,KAAK,aAAa;CAAG;CACjE,gBAAgB;EAA4B,AAA1B,GAAoB,GAAM,KAAK,aAAa;CAAG;CACjE,eAAgB;EAA4B,AAA1B,GAAmB,GAAO,KAAK,aAAa;CAAG;CACjE,cAAgB;EAA4B,AAA1B,GAAkB,GAAQ,KAAK,aAAa;CAAG;CACjE,SAAgB;EAA4B,AAA1B,GAAa,GAAa,KAAK,aAAa;CAAG;CACjE,UAAgB;EAA4B,AAA1B,GAAc,GAAY,KAAK,aAAa;CAAG;CACjE,WAAgB;EAA+B,AAA7B,GAA0B,GAAG,KAAK,aAAa;CAAG;CACpE,WAAgB;EAA+B,AAA7B,GAAwB,GAAK,KAAK,aAAa;CAAG;CACpE,aAAgB;EAA4D,AAA1D,GAAuB,KAAK,QAAQ,WAAW,QAAQ,GAAG,KAAK,aAAa;CAAG;CACjG,kBAAkB;EAA2B,AAAzB,GAAsB,GAAG,KAAK,aAAa;CAAG;CAClE,QAAkB;EAAE,KAAK,QAAQ,MAAM;CAAG;CAK1C,YAAY,GAAS;EAKnB,IAJA,GAAkB,CAAO,GAIrB,MAAY,OAAO;GACrB,IAAM,IAAM,WAAW,aAAa;GACpC,IAAI,GAAK,aAAa,GAAG;IACvB,IAAM,IAAY,EAAI,WAAW,CAAC,CAAC,CAAC,yBAC9B,IACJ,EAAU,aAAa,IACK,EAAW,QAAQ,KAAK,IAClB,EAAU,eAAiB,QAAQ,KAAK;IAE5E,IAAI,KAAO,CAA6B,EAAK,QAAQ,UAAU;KAE7D,IAAM,IAAO,GADA,EAAI,eAAe,EACJ;KAC5B,IAAI,GAAM;MACR,KAAK,QAAQ,OAAO,6BAA6B,GAAK,CAAI;MAC1D;KACF;IACF;GACF;EACF;EAEA,KAAK,aAAa;CACpB;CAKA,UAAU,GAAO;EAA0B,AAAxB,GAAgB,CAAK,GAAG,KAAK,aAAa;CAAG;CAKhE,UAAU,GAAO;EAA0B,AAAxB,GAAgB,CAAK,GAAG,KAAK,aAAa;CAAG;CAKhE,SAAS,GAAM;EAAwB,AAAtB,GAAe,CAAI,GAAG,KAAK,aAAa;CAAG;CAK5D,SAAS,GAAM;EAA0D,AAAxD,GAAe,GAAM,KAAK,QAAQ,WAAW,QAAQ,GAAG,KAAK,aAAa;CAAG;CAS9F,WAAW;EAET,AADA,EAAkB,sBAAsB,GACxC,KAAK,aAAa;CACpB;CAQA,WAAW,GAAK,GAAM,IAAe,IAAO;EAC1C,IAAM,IAAM,WAAW,aAAa;EACpC,IAAI,CAAC,KAAO,EAAI,eAAe,GAAG;EAClC,IAAM,IAAU,EAAY,CAAG;EAC1B,OAGL;OADgB,EAAI,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,GAG7C;QADA,EAAkB,cAAc,CAAO,GACnC,GAAc;KAChB,IAAM,IAAO,KAAK,kBAAkB;KACpC,AAAI,MACqB,EAAO,aAAa,UAAU,QAAQ,GACtC,EAAO,aAAa,OAAO,qBAAqB;IAE3E;UACK;IACL,IAAM,IAAc,KAAK,YAAY,KAAQ,CAAO;IACpD,EAAkB,cAAc,YAAY,KAAK,YAAY,CAAO,EAAE,GAAG,IAAe,mDAA+C,GAAG,GAAG,EAAY,KAAK;GAChK;GACA,KAAK,aAAa;EADlB;CAEF;CAKA,SAAS;EAEP,AADA,EAAkB,QAAQ,GAC1B,KAAK,aAAa;CACpB;CAOA,YAAY,GAAK,IAAM,IAAI,IAAQ,IAAI;EACrC,IAAM,IAAU,EAAY,GAAK,EAAE,WAAW,GAAK,CAAC;EACpD,IAAI,CAAC,GAAS;EAMd,IAAM,IAAQ;GAJZ,MAAQ;GACR,QAAQ;GACR,OAAQ;EAEW,EAAE,MAAU,IAC3B,IAAY,IAAQ,WAAW,EAAM,KAAK;EAEhD,AADA,EAAkB,cAAc,aAAa,KAAK,YAAY,CAAO,EAAE,SAAS,KAAK,YAAY,CAAG,EAAE,oBAAoB,EAAU,EAAE,GACtI,KAAK,aAAa;CACpB;CAOA,YAAY,GAAM;EACX,MACL,EAAkB,cAAc,CAAI,GACpC,KAAK,aAAa;CACpB;CAOA,YAAY,GAAM,GAAM;EAEtB,AADA,GAAY,GAAM,GAAM,EAAE,WAAW,KAAK,QAAQ,QAAQ,eAAe,CAAC,GAC1E,KAAK,aAAa;CACpB;CAMA,oBAAoB;EAClB,IAAM,IAAM,WAAW,aAAa;EACpC,IAAI,CAAC,KAAO,EAAI,eAAe,GAAG,OAAO;EACzC,IAAI,IAAO,EAAI,WAAW,CAAC,CAAC,CAAC;EAC7B,OAAO,IAAM;GACX,IAAI,EAAK,aAAa,KAAK,OAAO;GAClC,IAAO,EAAK;EACd;EACA,OAAO;CACT;CAOA,YAAY,GAAK;EACf,OAAO,OAAO,KAAO,EAAE,CAAC,CACrB,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,MAAK,QAAQ,CAAC,CACzB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,KAAK,MAAM;CAC3B;AAGF,GC3uBM,MAAe,MAAU,OAAO,KAAS,WAAY,GAAU,CAAI,IAAI,GAMzE,IAAoB,MAOlB,KAAK,iGACL,KAAY,MAChB,kGAAkG,GAAG,yBAAyB,EAAM,SAEhI,oBAAW,IAAI,IAAI;CAEvB,CAAC,QAAiB,EAAS,yGAAqG,CAAC;CACjI,CAAC,UAAiB,EAAS,0IAAkH,CAAC;CAC9I,CAAC,aAAiB,EAAS,kGAAwF,CAAC;CACpH,CAAC,iBAAiB,EAAS,6LAAuL,CAAC;CACnN,CAAC,eAAiB,EAAS,sIAAgI,CAAC;CAC5J,CAAC,aAAiB,EAAS,2IAAqI,CAAC;CAEjK,CAAC,cAAiB,EAAS,0IAAkH,CAAC;CAC9I,CAAC,gBAAiB,EAAS,0IAAkH,CAAC;CAC9I,CAAC,eAAiB,EAAS,0IAAkH,CAAC;CAC9I,CAAC,iBAAiB,EAAS,0IAAkH,CAAC;CAE9I,CAAC,WAAiB,EAAS,uWAAiT,CAAC;CAC7U,CAAC,WAAiB,EAAS,6PAA+N,CAAC;CAC3P,CAAC,UAAiB,EAAS,iLAAuJ,CAAC;CACnL,CAAC,WAAiB,EAAS,iLAAuJ,CAAC;CAEnL,CAAC,QAAiB,EAAS,+EAA2E,CAAC;CACvG,CAAC,QAAiB,EAAS,iFAA6E,CAAC;CAEzG,CAAC,SAAiB,EAAS,gDAAwC,CAAC;CACpE,CAAC,QAAiB,EAAS,qJAAiJ,CAAC;CAC7K,CAAC,SAAiB,EAAS,6IAA2H,CAAC;CACvJ,CAAC,SAAiB,EAAS,wGAA4F,CAAC;CACxH,CAAC,SAAiB,EAAS,iPAAuM,CAAC;CACnO,CAAC,SAAiB,EAAS,sPAA0N,CAAC;CACtP,CAAC,QAAiB,EAAS,8LAA8J,CAAC;CAE1L,CAAC,QAAiB,EAAS,6EAAyE,CAAC;CACrG,CAAC,UAAiB,EAAS,wKAAoJ,CAAC;CAEhL,CAAC,aAAiB,EAAS,kFAAwE,CAAC;CACpG,CAAC,aAAiB,EAAS,4DAAwD,CAAC;CACpF,CAAC,YAAiB,EAAS,4YAAgV,CAAC;CAC5W,CAAC,WAAiB,EAAS,yJAA+H,CAAC;CAC3J,CAAC,iBAAiB,EAAS,iJAA2I,CAAC;CACvK,CAAC,aAAiB,EAAS,yHAA+G,CAAC;CAC3I,CAAC,UAAiB,EAAS,4FAA8E,CAAC;CAC1G,CAAC,gBAAiB,EAAS,wIAAsH,CAAC;CAClJ,CAAC,eAAiB,EAAS,wKAAoK,CAAC;CAChM,CAAC,aAAiB,EAAS,qPAA+M,CAAC;CAC3O,CAAC,SAAiB,EAAS,qKAAyJ,CAAC;AACvL,CAAC,GAEK,qBAAU,IAAI,IAAI;CACtB,CAAC,QAAiB,SAAS;CAC3B,CAAC,UAAiB,WAAW;CAC7B,CAAC,aAAiB,cAAc;CAChC,CAAC,iBAAiB,kBAAkB;CACpC,CAAC,eAAiB,gBAAgB;CAClC,CAAC,aAAiB,cAAc;CAChC,CAAC,cAAiB,eAAe;CACjC,CAAC,gBAAiB,iBAAiB;CACnC,CAAC,eAAiB,gBAAgB;CAClC,CAAC,iBAAiB,kBAAkB;CACpC,CAAC,WAAiB,YAAY;CAC9B,CAAC,WAAiB,YAAY;CAC9B,CAAC,UAAiB,WAAW;CAC7B,CAAC,WAAiB,YAAY;CAC9B,CAAC,QAAiB,gBAAgB;CAClC,CAAC,QAAiB,iBAAiB;CACnC,CAAC,SAAiB,UAAU;CAC5B,CAAC,QAAiB,SAAS;CAC3B,CAAC,SAAiB,UAAU;CAC5B,CAAC,QAAiB,SAAS;CAC3B,CAAC,UAAiB,WAAW;CAC7B,CAAC,SAAiB,eAAe;CACjC,CAAC,QAAiB,UAAU;CAC5B,CAAC,aAAiB,SAAS;CAC3B,CAAC,aAAiB,gBAAgB;CAClC,CAAC,YAAiB,aAAa;CAC/B,CAAC,iBAAiB,kBAAkB;CACpC,CAAC,aAAiB,2BAA2B;CAC7C,CAAC,UAAiB,qBAAqB;CACvC,CAAC,gBAAiB,0BAA0B;CAC5C,CAAC,eAAiB,SAAS;CAC3B,CAAC,aAAiB,eAAe;CACjC,CAAC,SAAiB,UAAU;AAC9B,CAAC,GAEY,KAAb,MAAqB;CAInB,YAAY,GAAS;EAUnB,AATA,KAAK,UAAU,GACf,KAAK,UAAU,EAAQ,SAEvB,KAAK,KAAK,MAEV,KAAK,aAAa,CAAC,GAEnB,KAAK,sBAAsB,CAAC,GAE5B,KAAK,cAAc;CACrB;CAMA,aAAa;EAiBX,OAhBA,KAAK,KAAK,EAAc,OAAO;GAC7B,OAAO;GACP,MAAM;GACN,oBAAoB;GAEpB,cAAc;EAChB,CAAC,GAGD,KAAK,WAAW,KAAK,mBAAmB,GACxC,KAAK,cAAc,GACnB,KAAK,iBAAiB,GACtB,KAAK,UAAU,IAAI,KAChB,KAAK,QAAQ,WAAW,CAAC,EAAA,CAAG,KAAK,CAAC,CAChC,IAAI,EAAW,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAC5D,GACO;CACT;CAEA,UAAU;EAQR,AAPI,KAAK,eAAa,qBAAqB,KAAK,WAAW,GAC3D,KAAK,cAAc,MACnB,KAAK,WAAW,SAAS,MAAM,EAAE,CAAC,GAClC,KAAK,aAAa,CAAC,GACf,KAAK,IAAI,cACX,KAAK,GAAG,OAAO,GAEjB,KAAK,KAAK;CACZ;CAMA,gBAAgB;EACd,IAAM,IAAU,KAAK,QAAQ,WAAW,CAAC,GAGnC,IAAW,SAAS,uBAAuB;EAkBjD,AAjBA,EAAQ,SAAS,MAAU;GACzB,IAAM,IAAU,EAAc,OAAO,EAAE,OAAO,eAAe,CAAC;GAc9D,AAbA,EAAM,SAAS,MAAS;IACtB,IAAM,IAAS,GAAY,CAAI;IAC/B,IAAI,CAAC,GAAQ;KACX,QAAQ,KAAK,iCAAiC,EAAK,kCAAkC;KACrF;IACF;IACA,IAAI;IAKJ,AAJA,AAGK,IAHD,EAAO,SAAS,WAAe,KAAK,cAAc,CAAM,IACnD,EAAO,SAAS,SAAa,KAAK,kBAAkB,CAAM,IAC1D,EAAO,SAAS,gBAAoB,KAAK,mBAAmB,CAAM,IACjE,KAAK,cAAc,CAAM,GACnC,EAAQ,YAAY,CAAE;GACxB,CAAC,GACD,EAAS,YAAY,CAAO;EAC9B,CAAC,GACD,KAAK,GAAG,YAAY,CAAQ;CAC9B;CAOA,kBAAkB,GAAK;EACrB,IAGM,IAAO,EAAc,OAAO,EAAE,OAAO,uBAAuB,CAAC,GAM7D,IAAM,EAAc,UAAU;GAClC,MAAM;GACN,OANqB,KAAK,QAAQ,eAE/B,KAAK,QAAQ,sBAAsB,yBACpC;GAIF,OAAO,KAAK,QAAQ,OAAO,QAAQ,EAAI,SAAS,EAAI,WAAW;GAC/D,YAAY,EAAI;GAChB,cAAc,KAAK,QAAQ,OAAO,QAAQ,EAAI,SAAS,EAAI,WAAW,EAAI;GAC1E,iBAAiB;GACjB,iBAAiB;EACnB,CAAC;EAGD,AAAI,KAAK,WAEP,EAAI,YAAY,aADC,KAAK,QAAQ,oBAAoB,MACZ,sCAGtC,EAAI,YAAY;EAIlB,IAAM,IAAQ,EAAc,OAAO;GACjC,OAAO;GACP,MAAM;GACN,cAAc;EAChB,CAAC,GACK,IAAO,EAAc,OAAO,EAAE,OAAO,gBAAgB,CAAC,GACtD,IAAQ,EAAc,OAAO,EAAE,OAAO,iBAAiB,CAAC;EAC9D,EAAM,cAAc,KAAK,QAAQ,OAAO,QAAQ,oBAAoB;EAEpE,IAAM,IAAQ,CAAC;EACf,KAAK,IAAI,IAAI,GAAG,KAAK,IAAM,KACzB,KAAK,IAAI,IAAI,GAAG,KAAK,IAAM,KAAK;GAC9B,IAAM,IAAO,EAAc,OAAO;IAChC,OAAO;IACP,YAAY,OAAO,CAAC;IACpB,YAAY,OAAO,CAAC;GACtB,CAAC;GAED,AADA,EAAM,KAAK,CAAI,GACf,EAAK,YAAY,CAAI;EACvB;EAIF,AADA,EAAM,YAAY,CAAI,GACtB,EAAM,YAAY,CAAK;EAEvB,IAAI,IAAS,IAEP,KAAgB,GAAM,MAAS;GAMnC,AALA,EAAM,SAAS,MAAS;IACtB,IAAM,IAAI,CAAC,EAAK,QAAQ,KAClB,IAAI,CAAC,EAAK,QAAQ;IACxB,EAAK,UAAU,OAAO,UAAU,KAAK,KAAQ,KAAK,CAAI;GACxD,CAAC,GACD,EAAM,cAAe,KAAQ,IAAQ,GAAG,EAAK,KAAK,MAAU,KAAK,QAAQ,OAAO,QAAQ,oBAAoB;EAC9G,GAEM,UAAkB;GACtB,IAAS;GACT,IAAM,IAAO,EAAI,sBAAsB;GAKvC,AADA,EAAM,MAAM,aAAa,UACzB,EAAM,MAAM,UAAU;GACtB,IAAM,IAAK,EAAM,aACX,IAAK,EAAM,cAEb,IAAO,EAAK,MACZ,IAAO,EAAK,SAAS;GAOzB,AANI,IAAO,IAAK,WAAW,aAAa,MAAG,IAAO,KAAK,IAAI,GAAG,WAAW,aAAa,IAAK,CAAC,IACxF,IAAO,IAAK,WAAW,cAAc,MAAG,IAAO,EAAK,MAAM,IAAK,IAEnE,EAAM,MAAM,OAAO,GAAG,EAAK,KAC3B,EAAM,MAAM,MAAO,GAAG,EAAI,KAC1B,EAAM,MAAM,aAAa,IACzB,EAAI,aAAa,iBAAiB,MAAM;EAC1C,GAEM,UAAmB;GAIvB,AAHA,IAAS,IACT,EAAM,MAAM,UAAU,QACtB,EAAI,aAAa,iBAAiB,OAAO,GACzC,EAAa,GAAG,CAAC;EACnB,GAEM,IAAK,EAAG,GAAK,UAAU,MAAM;GAEjC,AADA,EAAE,gBAAgB,GACd,IAAQ,EAAW,IAAQ,EAAU;EAC3C,CAAC,GAEK,IAAK,EAAG,GAAM,cAAc,MAAM;GACtC,IAAM,IAAgE,EAAE,QAAS,QAAQ,gBAAgB;GACpG,KACL,EAAa,CAAC,EAAK,QAAQ,KAAK,CAAC,EAAK,QAAQ,GAAG;EACnD,CAAC,GAEK,IAAK,EAAG,GAAM,oBAAoB,EAAa,GAAG,CAAC,CAAC,GAEpD,IAAK,EAAG,GAAM,UAAU,MAAM;GAClC,IAAM,IAAgE,EAAE,QAAS,QAAQ,gBAAgB;GACzG,IAAI,CAAC,GAAM;GACX,IAAM,IAAO,CAAC,EAAK,QAAQ,KACrB,IAAO,CAAC,EAAK,QAAQ;GAG3B,AAFA,EAAW,GACX,KAAK,QAAQ,OAAO,cAAc,GAClC,EAAI,OAAO,KAAK,SAAS,GAAM,CAAI;EACrC,CAAC,GAEK,IAAK,EAAG,UAAU,eAAe;GAAE,AAAI,KAAQ,EAAW;EAAG,CAAC;EAUpE,OANA,KAAK,WAAW,KAAK,GAAI,GAAI,GAAI,GAAI,SAAU;GAC7C,AAAI,EAAM,cAAY,EAAM,OAAO;EACrC,CAAC,GAED,EAAK,YAAY,CAAG,GACpB,SAAS,KAAK,YAAY,CAAK,GACO;CACxC;CAQA,mBAAmB,GAAK;EACtB,IAAM,IAAU;GAEd;GAAW;GAAW;GAAW;GAAW;GAAW;GAAW;GAAW;GAE7E;GAAW;GAAW;GAAW;GAAW;GAAW;GAAW;GAAW;GAE7E;GAAW;GAAW;GAAW;GAAW;GAAW;GAAW;GAAW;EAC/E,GAEI,IAAe,EAAI,gBAAgB,WAEjC,IAAO,EAAc,OAAO,EAAE,OAAO,uBAAuB,CAAC,GAG7D,IADiB,KAAK,QAAQ,eACF,KAAK,QAAQ,sBAAsB,yBAA0B,UAGzF,IAAW,EAAc,UAAU;GACvC,MAAM;GACN,OAAO,GAAG,EAAU;GACpB,OAAO,KAAK,QAAQ,OAAO,QAAQ,EAAI,SAAS,EAAI,WAAW;GAC/D,YAAY,EAAI;GAChB,cAAc,KAAK,QAAQ,OAAO,QAAQ,EAAI,SAAS,EAAI,WAAW,EAAI;EAC5E,CAAC,GAEK,IAAI;EAKV,EAAS,YAJO,EAAI,SAAS,cACzB,kGAAkG,EAAE,uGACpG,kGAAkG,EAAE;EAGxG,IAAM,IAAQ,EAAc,QAAQ,EAAE,OAAO,iBAAiB,CAAC;EAE/D,AADA,EAAM,MAAM,aAAa,GACzB,EAAS,YAAY,CAAK;EAG1B,IAAM,IAAW,EAAc,UAAU;GACvC,MAAM;GACN,OAAO,GAAG,EAAU;GACpB,OAAO,EAAI,SAAS,cACf,KAAK,QAAQ,OAAO,QAAQ,mBAAmB,sBAC/C,KAAK,QAAQ,OAAO,QAAQ,wBAAwB;GACzD,iBAAiB;GACjB,iBAAiB;EACnB,CAAC;EACD,EAAS,YAAY;EAGrB,IAAM,IAAQ,EAAc,OAAO,EAAE,OAAO,iBAAiB,CAAC;EAC9D,EAAM,MAAM,UAAU;EAEtB,IAAM,IAAW,EAAc,OAAO,EAAE,OAAO,oBAAoB,CAAC,GAC9D,IAAe,MAAM,QAAQ,KAAK,QAAQ,aAAa,IAAI,KAAK,QAAQ,gBAAgB,CAAC;EAE/F,CADmB,mBAAG,IAAI,IAAI,CAAC,GAAG,GAAc,GAAG,CAAO,CAAC,CACnD,CAAC,CAAC,SAAS,MAAU;GAC3B,IAAM,IAAK,EAAc,OAAO;IAAE,OAAO;IAAmB,OAAO;IAAO,cAAc;GAAM,CAAC;GAE/F,AADA,EAAG,MAAM,aAAa,GACtB,EAAS,YAAY,CAAE;EACzB,CAAC;EAED,IAAM,IAAY,EAAc,OAAO,EAAE,OAAO,kBAAkB,CAAC,GAC7D,IAA8C,EAAc,SAAS;GAAE,MAAM;GAAS,OAAO;GAAc,OAAO,KAAK,QAAQ,OAAO,QAAQ,eAAe;EAAe,CAAC,GAC7K,IAAc,EAAc,QAAQ,CAAC,GAAG,CAAC,KAAK,QAAQ,OAAO,QAAQ,eAAe,cAAc,CAAC;EAKzG,AAJA,EAAU,YAAY,CAAU,GAChC,EAAU,YAAY,CAAW,GAEjC,EAAM,YAAY,CAAQ,GAC1B,EAAM,YAAY,CAAS;EAG3B,IAAI,IAAS,IAET,IAAa,MAEX,WAAsB;GAC1B,IAAM,IAAM,WAAW,aAAa;GACpC,IAAa,GAAK,aAAa,EAAI,WAAW,CAAC,CAAC,CAAC,WAAW,IAAI;EAClE,GAEM,WAAyB;GACxB,OACL,IAAI;IACF,IAAM,IAAM,WAAW,aAAa;IACpC,IAAI,CAAC,GAAK;IAEV,AADA,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAU;GACzB,QAAY,CAEZ;EACF,GAEM,WAAkB;GAItB,AAFA,KAAK,oBAAoB,SAAS,MAAO;IAAE,AAAI,MAAO,KAAY,EAAG;GAAG,CAAC,GACzE,GAAc,GACd,IAAS;GAGT,IAAM,IAAO,EAAS,sBAAsB,GAExC,IAAO,EAAK;GAKhB,AAJI,IAAO,MAAY,WAAW,eAAY,IAAO,EAAK,QAAQ,MAClE,EAAM,MAAM,MAAO,GAAG,EAAK,SAAS,EAAE,KACtC,EAAM,MAAM,OAAO,GAAG,KAAK,IAAI,GAAG,CAAI,EAAE,KACxC,EAAM,MAAM,UAAU,SACtB,EAAS,aAAa,iBAAiB,MAAM;EAC/C,GAEM,UAAmB;GAKvB,AAJA,IAAS,IACT,EAAM,MAAM,UAAU,QACtB,EAAM,MAAM,MAAO,IACnB,EAAM,MAAM,OAAO,IACnB,EAAS,aAAa,iBAAiB,OAAO;EAChD,GAEM,KAAc,MAAU;GAO5B,AANA,IAAe,GACf,EAAM,MAAM,aAAa,GACzB,EAAW,QAAQ,GACnB,GAAiB,GACjB,EAAI,OAAO,KAAK,SAAS,CAAK,GAC9B,KAAK,QAAQ,OAAO,qBAAqB,GACzC,EAAW;EACb,GAEM,KAAK,EAAG,GAAU,UAAU,MAAM;GAItC,AAHA,EAAE,eAAe,GACjB,GAAiB,GACjB,EAAI,OAAO,KAAK,SAAS,CAAY,GACrC,KAAK,QAAQ,OAAO,qBAAqB;EAC3C,CAAC,GAEK,KAAK,EAAG,GAAU,cAAc,MAAM;GAE1C,EAAE,eAAe;EACnB,CAAC,GAEK,IAAM,EAAG,GAAU,UAAU,MAAM;GAEvC,AADA,EAAE,gBAAgB,GACd,IAAQ,EAAW,IAAQ,GAAU;EAC3C,CAAC,GAEK,IAAK,EAAG,GAAU,cAAc,MAAM;GAE1C,EAAE,eAAe;EACnB,CAAC,GAEK,KAAM,EAAG,GAAU,UAAU,MAAM;GACvC,IAAM,IAA6B,EAAE,QAAS,QAAQ,kBAAkB;GACxE,AAAI,KAAI,EAAuC,EAAI,QAAQ,KAAK;EAClE,CAAC,GAEK,KAAK,EAAG,GAAY,WAAW,MAAM;GACzC,EAA4C,EAAE,OAAQ,KAAK;EAC7D,CAAC,GAEK,KAAK,EAAG,UAAU,UAAU,MAAM;GAEtC,AAAI,KAAU,CAAC,EAAK,SAA8B,EAAE,MAAO,KAAK,CAAC,EAAM,SAA8B,EAAE,MAAO,KAAG,EAAW;EAC9H,CAAC,GAEK,KAAK,EAAG,GAAO,UAAU,MAAM,EAAE,gBAAgB,CAAC,GAIlD,UAAuB;GAAE,AAAI,KAAQ,EAAW;EAAG;EAwBzD,OAvBA,SAAS,iBAAiB,UAAU,GAAgB;GAAE,SAAS;GAAM,SAAS;EAAK,CAAC,GACpF,WAAW,iBAAiB,UAAY,GAAgB,EAAE,SAAS,GAAK,CAAC,GAEzE,KAAK,WAAW,KAAK,IAAI,IAAI,GAAK,GAAI,IAAK,IAAI,IAAI,UAC3C,SAAS,oBAAoB,UAAU,GAAgB,EAAE,SAAS,GAAK,CAAC,SACxE,WAAW,oBAAoB,UAAY,CAAc,SAEzD;GAAE,AAAI,EAAM,cAAY,EAAM,OAAO;EAAG,CAChD,GAGA,KAAK,oBAAoB,KAAK,CAAU,GACxC,KAAK,WAAW,WAAW;GACzB,IAAM,IAAM,KAAK,oBAAoB,QAAQ,CAAU;GACvD,AAAI,MAAQ,MAAI,KAAK,oBAAoB,OAAO,GAAK,CAAC;EACxD,CAAC,GAKD,EAAK,YAAY,CAAQ,GACzB,EAAK,YAAY,CAAQ,GACzB,SAAS,KAAK,YAAY,CAAK,GACO;CACxC;CAOA,cAAc,GAAK;EACjB,IAAM,IAAS,EAAI,SAAS,eACvB,KAAK,QAAQ,gBAAgB,CAAC,IAC9B,EAAI,SAAS,CAAC,GAGb,IAAS,EAAc,UAAU;GACrC,OAFU,EAAI,cAAc,aAAa,EAAI,gBAAgB;GAG7D,OAAO,KAAK,QAAQ,OAAO,QAAQ,EAAI,SAAS,EAAI,WAAW;GAC/D,YAAY,EAAI;GAChB,cAAc,KAAK,QAAQ,OAAO,QAAQ,EAAI,SAAS,EAAI,WAAW,EAAI;EAC5E,CAAC,GAIK,IAAc,EAAc,UAAU;GAAE,OAAO;GAAI,UAAU;GAAI,QAAQ;EAAG,GAAG,CAD7D,KAAK,QAAQ,OAAO,QAAQ,EAAI,OAAO,kBAAkB,EAAI,eAAe,MACC,CAAC;EAGtG,AAFA,EAAO,YAAY,CAAW,GAE9B,EAAM,SAAS,MAAS;GACtB,IAAM,IAAY,OAAO,KAAS,WAAY,EAAK,QAAW,GAC1D;GACJ,AACE,IADE,OAAO,KAAS,WAET,EAAI,SAAS,oBACd,KAAK,QAAQ,OAAO,QAAQ,iBAAiB,EAAK,UAElD,EAAK,QAJL;GAMV,IAAM,IAAY,OAAO,KAAS,YAAa,CAAC,CAAC,EAAK,UAChD,IAAW,EAAE,SAAM;GACzB,AAAI,MAAU,EAAM,WAAW;GAC/B,IAAM,IAAM,EAAc,UAAU,GAAO,CAAC,CAAK,CAAC;GAGlD,AADI,EAAI,SAAS,gBAAgB,CAAC,MAAU,EAAI,MAAM,aAAa,IACnE,EAAO,YAAY,CAAG;EACxB,CAAC;EAOD,IAAI,IAAc,MACZ,IAAa,EAAG,GAAQ,mBAAmB;GAC/C,IAAM,IAAM,WAAW,aAAa;GACpC,IAAc,GAAK,aAAa,EAAI,WAAW,CAAC,CAAC,CAAC,WAAW,IAAI;EACnE,CAAC,GAEK,IAAW,EAAG,GAAQ,WAAW,MAAM;GAC3C,IAAM,IAA0C,EAAE,OAAQ,OACpD,IAAgD,EAAE,OAAQ,QAA0C,EAAE,OAAQ;GAChH,OAAC,KAAS,EAAY,WAG1B;QAFA,KAAK,QAAQ,OAAO,cAAc,GAE9B,GACF,IAAI;KACF,IAAM,IAAM,WAAW,aAAa;KACpC,AAAI,MAAO,EAAI,gBAAgB,GAAG,EAAI,SAAS,CAAW;IAC5D,QAAY,CAAkD;IAGhE,AADA,EAAI,OAAO,KAAK,SAAS,CAAK,GAC9B,KAAK,QAAQ,OAAO,qBAAqB;GAHuB;EAIlE,CAAC;EAGD,OADA,KAAK,WAAW,KAAK,GAAY,CAAQ,GACA;CAC3C;CAMA,cAAc,GAAQ;EAOpB,IAAM,IAAM,EAAc,UAAU;GAClC,MAAM;GACN,OAAO,GAPc,KAAK,QAAQ,eACF,KAAK,QAAQ,sBAAsB,yBAA0B,WACjF,EAAO,YAAY,IAAI,EAAO,cAAc;GAMxD,OAAO,KAAK,QAAQ,OAAO,QAAQ,EAAO,SAAS,EAAO,WAAW;GACrE,YAAY,EAAO;GACnB,cAAc,KAAK,QAAQ,OAAO,QAAQ,EAAO,SAAS,EAAO,WAAW,EAAO;GAGnF,GAAI,OAAO,EAAO,YAAa,aAAa,EAAE,gBAAgB,QAAQ,IAAI,CAAC;EAC7E,CAAC,GAGK,IAAW,KAAK,QAAQ,oBAAoB;EAElD,IADiB,KAAK,UACR;GACZ,IAAM,IAAS,GAAQ,IAAI,EAAO,IAAI,KAAK,GAAQ,IAAI,EAAO,IAAI,KAAK;GACvE,AAAI,IACF,EAAI,YAAY,aAAa,EAAS,GAAG,EAAO,6BACvC,EAAS,IAAI,EAAO,IAAI,IACjC,EAAI,YAAY,EAAS,IAAI,EAAO,IAAI,IAExC,EAAI,cAAc,EAAO,QAAQ,EAAO;EAE5C,OAAO,AAAI,EAAS,IAAI,EAAO,IAAI,IAEjC,EAAI,YAAY,EAAS,IAAI,EAAO,IAAI,IAC/B,EAAS,IAAI,EAAO,IAAI,IACjC,EAAI,YAAY,EAAS,IAAI,EAAO,IAAI,IAExC,EAAI,cAAc,EAAO,QAAQ,EAAO;EAG1C,IAAM,IAAW,EAAG,GAAK,UAAU,MAAU;GAM3C,AALA,EAAM,eAAe,GAErB,KAAK,QAAQ,OAAO,cAAc,GAClC,EAAO,OAAO,KAAK,OAAO,GAC1B,KAAK,QAAQ,OAAO,qBAAqB,GACzC,KAAK,QAAQ;EACf,CAAC;EAGD,OADA,KAAK,WAAW,KAAK,CAAQ,GACY;CAC3C;CAWA,YAAY;EAEV,OADK,KAAK,KAC2B,MAAM,KAAK,KAAK,GAAG,iBAAiB,gBAAgB,CAAC,IADrE,CAAC;CAExB;CAGA,aAAa;EACX,OAAO,KAAK,UAAU,CAAC,CAAC,QACrB,MAAO,CAAoC,EAAI,QAClD;CACF;CAWA,oBAAoB,GAAS;EAC3B,IAAM,IAAM,KAAK,UAAU,GACrB,IAAY,KAAK,WAAW;EAClC,IAAI,CAAC,EAAU,QAAQ;EACvB,IAAM,IAAU,KAAW,EAAU,SAAS,CAAO,IACjD,IACA,EAAU,MAAM,MAAO,EAAG,aAAa,UAAU,MAAM,GAAG,KAAK,EAAU;EAC7E,EAAI,SAAS,MAAO,EAAG,aAAa,YAAY,MAAO,IAAS,MAAM,IAAI,CAAC;CAC7E;CAGA,mBAAmB;EACZ,KAAK,OACV,KAAK,oBAAoB,GACzB,KAAK,WAAW,KACd,EAAG,KAAK,IAAI,YAAY,MAAM,KAAK,kBAAgD,CAAE,CAAC,GAGtF,EAAG,KAAK,IAAI,YAAY,MAAM;GAC5B,IAAM,IAA6B,EAAE,QAAS,UAAU,gBAAgB;GACxE,AAAI,KAAI,KAAK,oBAAgD,CAAG;EAClE,CAAC,CACH;CACF;CAQA,kBAAkB,GAAO;EACvB,IAAI,CAAC;GAAC;GAAc;GAAa;GAAQ;EAAK,CAAC,CAAC,SAAS,EAAM,GAAG,GAAG;EACrE,IAAM,IAAW,KAAK,WAAW,GAC3B,IACoB,EAAM,QAAS,UAAU,gBAAgB,GAE7D,IAAM,IAAU,EAAS,QAAQ,CAAO,IAAI;EAClD,IAAI,MAAQ,IAAI;EAEhB,IAAI;EACJ,IAAI,EAAM,QAAQ,QAChB,IAAO,EAAS;OACX,IAAI,EAAM,QAAQ,OACvB,IAAO,EAAS,GAAG,EAAE;OAChB;GAEL,IAAM,IAAM,KAAK,QAAQ,cAAc;GAEvC,IAAO,GAAU,KADA,EAAM,QAAQ,iBAAkB,IACX,KAAJ,KAAU,EAAS,UAAU,EAAS;EAC1E;EACK,MACL,EAAM,eAAe,GACrB,KAAK,oBAAoB,CAAI,GAC7B,EAAK,MAAM;CACb;CAMA,qBAAqB;EACnB,IAAI,CAAC,KAAK,QAAQ,gBAAgB,OAAO;EAIzC,IAAI,MAAsB,MAAM,OAAO;EACvC,IAAI,SAAS,cAAc,wCAAwC,GAEjE,OADA,IAAoB,IACb;EAIT,IAAM,IAAQ,MAAM,KAAK,SAAS,iBAAiB,0BAAwB,CAAC,CAAC,CAC1E,QAAQ,MAAM,EAAE,OAAO,oBAAoB,CAAC,CAC5C,KAAK,MAAsC,EAAG,QAAQ,EAAE,CAAC,CAAC,KAAK,GAAG;EAErE,OADA,IAAoB,qDAAqD,KAAK,CAAK,GAC5E;CACT;CAMA,UAAU;EAIR,AADI,KAAK,eAAa,qBAAqB,KAAK,WAAW,GAC3D,KAAK,cAAc,4BAA4B;GAE7C,AADA,KAAK,cAAc,MACnB,KAAK,WAAW;EAClB,CAAC;CACH;CAEA,aAAa;EACX,IAAI,CAAC,KAAK,IAAI;EACd,IAAM,IAAS,KAAK,2BAAW,IAAI,IAAI;EAmBvC,AAhBA,KAAK,GAAG,iBAAiB,kBAAkB,CAAC,CAAC,SAAS,MAAQ;GAC5D,IAAM,IAAM,EAAO,IAAgC,EAAK,QAAQ,GAAG;GACnE,IAAI,KAAO,OAAO,EAAI,YAAa,YAAY;IAC7C,IAAM,IAAS,CAAC,CAAC,EAAI,SAAS,KAAK,OAAO;IAE1C,AADA,EAAI,UAAU,OAAO,UAAU,CAAM,GACrC,EAAI,aAAa,gBAAgB,OAAO,CAAM,CAAC;GACjD;GACA,AAAI,KAAO,OAAO,EAAI,cAAe,eACF,EAAM,WAAW,CAAC,CAAC,EAAI,WAAW,KAAK,OAAO;EAEnF,CAAC,GAGD,KAAK,oBAAoB,GAGzB,KAAK,GAAG,iBAAiB,kBAAkB,CAAC,CAAC,SAAS,MAAW;GAC/D,IAAM,IAAM,EAAO,IAAgC,EAAQ,QAAQ,GAAG;GACtE,IAAI,CAAC,KAAO,OAAO,EAAI,YAAa,YAAY;GAEhD,IAAI,KAAO,EAAI,SAAS,KAAK,OAAO,KAAK,GAAA,CAAI,QAAQ,SAAS,EAAE,CAAC,CAAC,KAAK;GAEvE,AACE,MAAM,KAAK,QAAQ,qBACd,KAAK,QAAQ,eAAe,MAC5B;GAGP,IAAM,IAAwC,GACxC,IAAU,MAAM,KAAK,EAAI,OAAO,CAAC,CAAC,MACrC,MAAQ,EAAI,OAAO,YAAY,MAAM,EAAI,YAAY,CACxD;GACA,EAAI,QAAQ,IAAU,EAAQ,QAAQ;EACxC,CAAC;CACH;CAKA,OAAO;EACL,AAAI,KAAK,OAAI,KAAK,GAAG,MAAM,UAAU;CACvC;CAKA,OAAO;EACL,AAAI,KAAK,OAAI,KAAK,GAAG,MAAM,UAAU;CACvC;CAOA,UAAU;EAcR,AAbA,AAAgE,KAAK,iBAA7C,qBAAqB,KAAK,WAAW,GAAsB,OACnF,KAAK,WAAW,SAAS,MAAM,EAAE,CAAC,GAClC,KAAK,aAAa,CAAC,GACf,KAAK,OAAI,KAAK,GAAG,YAAY,KACjC,KAAK,WAAW,KAAK,mBAAmB,GACxC,KAAK,cAAc,GAGnB,KAAK,iBAAiB,GACtB,KAAK,UAAU,IAAI,KAChB,KAAK,QAAQ,WAAW,CAAC,EAAA,CAAG,KAAK,CAAC,CAChC,IAAI,EAAW,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAC5D,GACA,KAAK,QAAQ;CACf;AACF,GC90BM,KACJ,OAAO,OAAS,OAAe,OAAO,KAAK,aAAc,aACrD,IAAI,KAAK,UAAU,KAAA,GAAW,EAAE,aAAa,OAAO,CAAC,IACrD;AASN,SAAS,GAAY,GAAM;CACzB,IAAM,IAAU,EAAK,KAAK;CAC1B,IAAI,CAAC,GAAS,OAAO;CACrB,IAAI,IAAY;EACd,IAAI,IAAQ;EACZ,KAAK,IAAM,KAAO,GAAW,QAAQ,CAAO,GAC1C,AAAI,EAAI,cAAY;EAEtB,OAAO;CACT;CAEA,OAAO,EAAQ,MAAM,KAAK,CAAC,CAAC;AAC9B;AAOA,IAAM,qBAAa,IAAI,IAAI,gNAK3B,CAAC;AAcD,SAAS,GAAa,GAAM,GAAO,GAAM;CACvC,KAAK,IAAI,IAAQ,EAAK,YAAY,GAAO,IAAQ,EAAM,aACrD,IAAI,EAAM,aAAa,GAAG;EACxB,IAAM,IAA4B,EAAO;EAEzC,AADA,EAAM,KAAK,CAAI,GACf,EAAK,KAAK,CAAI;CAChB,OAAO,IAAI,EAAM,aAAa,GAAG;EAC/B,IAAM,IAAQ,GAAW,IAA4B,EAAO,OAAO;EAGnE,AAFI,KAAO,EAAM,KAAK,IAAI,GAC1B,GAAa,GAAO,GAAO,CAAI,GAC3B,KAAO,EAAM,KAAK,IAAI;CAC5B;AAEJ;AAQA,SAAS,GAAS,GAAM;CACtB,IAAI,EAAK,aAAa,GAAG;EACvB,IAAM,IAA4B,EAAM;EACxC,OAAO;GAAE,OAAO;GAAM,MAAM;EAAK;CACnC;CACwB,IAAM,IAAQ,CAAC,GACT,IAAO,CAAC;CAEtC,OADA,GAAa,GAAM,GAAO,CAAI,GACvB;EAAE,OAAO,EAAM,KAAK,EAAE;EAAG,MAAM,EAAK,KAAK,EAAE;CAAE;AACtD;AAQA,SAAS,GAAiB,GAAI,GAAS,GAAO;CAC5C,IAAI,CAAC,GAAO;EACV,EAAG,UAAU,OAAO,iBAAiB,mBAAmB;EACxD;CACF;CACA,AAAI,IAAU,KACZ,EAAG,UAAU,IAAI,mBAAmB,GACpC,EAAG,UAAU,OAAO,eAAe,KAC1B,KAAW,IAAQ,MAC5B,EAAG,UAAU,IAAI,eAAe,GAChC,EAAG,UAAU,OAAO,mBAAmB,KAEvC,EAAG,UAAU,OAAO,iBAAiB,mBAAmB;AAE5D;AAEA,IAAa,KAAb,MAAuB;CAIrB,YAAY,GAAS;EAenB,AAdA,KAAK,UAAU,GACf,KAAK,UAAU,EAAQ,SAEvB,KAAK,KAAK,MACV,KAAK,aAAa,CAAC,GAEnB,KAAK,eAAe,MAEpB,KAAK,eAAe,MAMpB,KAAK,8BAAc,IAAI,QAAQ;CACjC;CAMA,aAAa;EAIX,IAHA,KAAK,KAAK,EAAc,OAAO,EAAE,OAAO,eAAe,CAAC,GAGpD,KAAK,QAAQ,cAAc,IAAO;GACpC,IAAM,IAAS,EAAc,OAAO;IAClC,OAAO;IACP,OAAO,KAAK,QAAQ,OAAO,UAAU;IACrC,eAAe;GACjB,CAAC;GAED,AADA,KAAK,YAAY,CAAM,GACvB,KAAK,GAAG,YAAY,CAAM;EAC5B;EAIA,AADA,KAAK,eAAe,EAAc,QAAQ;GAAE,OAAO;GAAiB,MAAM;GAAU,aAAa;GAAU,eAAe;EAAO,CAAC,GAClI,KAAK,eAAe,EAAc,QAAQ;GAAE,OAAO;GAAiB,aAAa;GAAU,eAAe;EAAO,CAAC;EAClH,IAAM,IAAO,EAAc,OAAO;GAAE,OAAO;GAAkB,cAAc;EAAoB,CAAC;EAMhG,OALA,EAAK,YAAY,KAAK,YAAY,GAClC,EAAK,YAAY,KAAK,YAAY,GAClC,KAAK,GAAG,YAAY,CAAI,GAExB,KAAK,OAAO,GACL;CACT;CAEA,UAAU;EAQR,AAPA,KAAK,WAAW,SAAS,MAAM,EAAE,CAAC,GAClC,KAAK,aAAa,CAAC,GACnB,AAEE,KAAK,oBADL,KAAK,eAAe,SAAS,MAAM,EAAE,CAAC,GAChB,OAExB,KAAK,IAAI,OAAO,GAChB,KAAK,KAAK;CACZ;CAMA,YAAY,GAAQ;EAClB,IAAI,IAAS,GACT,IAAS,GAKP,IAAc,KAAK,QAAQ,WAAW,WAEtC,KAAc,MAAY;GAC9B,IAAM,IAAQ,IAAU,GAKlB,IAAS,MAAM,KAAK,EAAY,QAAQ,CAAC,CAC5C,QAAO,MAAS,CAAC,EAAM,UAAU,SAAS,aAAa,CAAC,CAAC,CACzD,QAAQ,GAAK,MAAU,IAAkC,EAAO,cAAc,CAAC,GAC5E,IAAU,KAAK,IAAI,KAAK,QAAQ,aAAa,KAAK,IAAS,EAAY;GAC7E,EAAY,MAAM,SAAS,GAAG,KAAK,IAAI,GAAS,IAAS,CAAK,EAAE;EAClE,GAGM,KAAe,MAAU,EAAW,EAAM,OAAO,GAEjD,UAAkB;GAGtB,AAFA,SAAS,oBAAoB,aAAa,CAAW,GACrD,SAAS,oBAAoB,WAAW,CAAS,GACjD,KAAK,iBAAiB;EACxB,GAEM,KAAe,MAAU;GAe7B,AAdA,IAAS,EAAM,SACf,IAAS,EAAY,cAKrB,KAAK,QAAQ,WAAW,SAAS,MAAM,YAAY,IACnD,SAAS,iBAAiB,aAAa,CAAW,GAClD,SAAS,iBAAiB,WAAW,CAAS,GAE9C,KAAK,iBAAiB,OACd,SAAS,oBAAoB,aAAa,CAAW,SACrD,SAAS,oBAAoB,WAAW,CAAS,CACzD,GACA,EAAM,eAAe;EACvB,GAGM,KAAe,MAAU;GAC7B,IAAM,IAAQ,EAAM,QAAQ;GAC5B,AAAI,MAAS,EAAM,eAAe,GAAG,EAAW,EAAM,OAAO;EAC/D,GAEM,UAAmB;GAGvB,AAFA,SAAS,oBAAoB,aAAa,CAAW,GACrD,SAAS,oBAAoB,YAAY,CAAU,GACnD,KAAK,iBAAiB;EACxB,GAEM,KAAgB,MAAU;GAC9B,IAAM,IAAQ,EAAM,QAAQ;GACvB,MACL,IAAS,EAAM,SACf,IAAS,EAAY,cAErB,KAAK,QAAQ,WAAW,SAAS,MAAM,YAAY,IACnD,SAAS,iBAAiB,aAAa,GAAa,EAAE,SAAS,GAAM,CAAC,GACtE,SAAS,iBAAiB,YAAY,CAAU,GAChD,KAAK,iBAAiB,OACd,SAAS,oBAAoB,aAAa,CAAW,SACrD,SAAS,oBAAoB,YAAY,CAAU,CAC3D;EACF,GAEM,IAAK,EAAG,GAAQ,aAAa,CAAW,GACxC,IAAK,EAAG,GAAQ,cAAc,CAAY;EAChD,KAAK,WAAW,KAAK,GAAI,CAAE;CAC7B;CAyBA,UAAU;EACR,IAAM,IAAW,KAAK,QAAQ,WAAW,UACrC,IAAQ,GACR,IAAQ,GAEN,IAAO,CAAC,GAER,IAAQ,CAAC,GACX,IAAS;EAEb,KAAK,IAAI,IAAO,EAAS,YAAY,GAAM,IAAO,EAAK,aAAa;GAClE,IAAM,IAAM,KAAK,YAAY,IAAI,CAAI;GAIrC,IAAI,KAAO,EAAI,SAAS,EAAK,eAAe,KAAK;IAE/C,AADA,KAAS,EAAI,OACb,KAAS,EAAI;IACb;GACF;GACA,IAAM,EAAE,UAAO,YAAS,GAAS,CAAI;GAGrC,AAFA,EAAK,KAAK;IAAE;IAAM,KAAK;IAAM,MAAM;IAAO,OAAO;GAAO,CAAC,GACzD,EAAM,KAAK,CAAK,GAChB,KAAU,EAAM,SAAS;EAC3B;EAEA,IAAI,EAAK,QAAQ;GACf,IAAM,IAAS,KAAK,YAAY,GAAM,EAAM,KAAK,IAAI,CAAC;GACtD,EAAK,SAAS,GAAO,MAAM;IACzB,IAAM,IAAQ;KACZ,KAAK,EAAM;KACX,OAAO,EAAO;KAGd,OAAO,EAAM,IAAI,WAAW,MAAM,EAAE,CAAC,CAAC;IACxC;IAGA,AAFA,KAAK,YAAY,IAAI,EAAM,MAAM,CAAK,GACtC,KAAS,EAAM,OACf,KAAS,EAAM;GACjB,CAAC;EACH;EAEA,OAAO;GAAE;GAAO;EAAM;CACxB;CAYA,YAAY,GAAM,GAAQ;EACxB,IAAI,CAAC,IAAY,OAAO,EAAK,KAAK,MAAM,GAAY,EAAE,IAAI,CAAC;EAC3D,IAAM,IAAa,MAAM,EAAK,MAAM,CAAC,CAAC,KAAK,CAAC,GACxC,IAAI;EACR,KAAK,IAAM,KAAO,GAAW,QAAQ,CAAM,GACpC,MAAI,YACT;UAAO,IAAI,EAAK,SAAS,KAAK,EAAI,SAAS,EAAK,IAAI,EAAE,CAAC,QAAO;GAC9D,EAAO,EAAE;EADqD;EAGhE,OAAO;CACT;CAEA,SAAS;EACP,IAAI,CAAC,KAAK,gBAAgB,CAAC,KAAK,cAAc;EAC9C,IAAM,EAAE,UAAO,aAAU,KAAK,QAAQ,GAChC,IAAW,KAAK,QAAQ,YAAY,GACpC,IAAW,KAAK,QAAQ,YAAY,GAEpC,IAAK,KAAK,QAAQ,OAAO;EAU/B,AATA,KAAK,aAAa,cAAc,IAC5B,EAAG,WAAW,GAAO,CAAQ,IAC7B,EAAG,MAAM,CAAK,GAClB,KAAK,aAAa,cAAc,IAC5B,EAAG,WAAW,GAAO,CAAQ,IAC7B,EAAG,MAAM,CAAK,GAGlB,GAAiB,KAAK,cAAc,GAAO,CAAQ,GACnD,GAAiB,KAAK,cAAc,GAAO,CAAQ;CACrD;CAMA,eAAe;EACb,OAAO,KAAK,QAAQ,CAAC,CAAC;CACxB;CAMA,eAAe;EACb,OAAO,KAAK,QAAQ,CAAC,CAAC;CACxB;AACF,GCrXa,KAAb,MAAuB;CAIrB,YAAY,GAAS;EAGnB,AAFA,KAAK,UAAU,GACf,KAAK,UAAU,EAAQ,SACvB,KAAK,aAAa,CAAC;CACrB;CAEA,aAAa;EAIX,AAFA,KAAK,gCAAgB,IAAI,IAAI,GAE7B,KAAK,cAAc;EACnB,IAAM,IAAW,KAAK,QAAQ,WAAW;EAkBzC,OAjBA,KAAK,WAAW,KACd,EAAG,GAAU,UAAa,MAAM,KAAK,SAAS,CAAC,CAAC,GAChD,EAAG,GAAU,aAAa,MAAM,KAAK,YAAY,CAAC,CAAC,GACnD,EAAG,GAAU,SAAa,MAAM,KAAK,QAAQ,CAAC,CAAC,CACjD,GAIA,KAAK,oBAAoB,IAAI,kBAAkB,MAAc;GAC3D,KAAK,IAAM,KAAY,GACrB,KAAK,IAAM,KAAQ,EAAS,cAC1B,KAAK,oBAAoB,CAAI;EAGnC,CAAC,GACD,KAAK,kBAAkB,QAAQ,GAAU;GAAE,WAAW;GAAM,SAAS;EAAK,CAAC,GAEpE;CACT;CAEA,UAAU;EAaR,AAZA,KAAK,WAAW,SAAS,MAAM,EAAE,CAAC,GAClC,KAAK,aAAa,CAAC,GACnB,AAEE,KAAK,uBADL,KAAK,kBAAkB,WAAW,GACT,OAGvB,KAAK,kBACP,KAAK,cAAc,SAAS,GAAG,MAAY,IAAI,gBAAgB,CAAO,CAAC,GACvE,KAAK,cAAc,MAAM,IAGvB,KAAK,oBACP,KAAK,gBAAgB,SAAS,EAAE,oBAAiB,IAAI,gBAAgB,CAAU,CAAC,GAChF,KAAK,gBAAgB,MAAM;CAE/B;CAMA,oBAAoB,GAAM;EACxB,IAAI,CAAC,KAAK,eAAe,MAAM;EAC/B,IAAM,IAAiC,CAAC;EAMxC,AALI,EAAK,aAAa,QACpB,EAAK,KAA6B,CAAK,IACN,EAAM,oBACvC,EAAK,KAAK,GAA2B,EAAM,iBAAiB,KAAK,CAAC,GAEpE,EAAK,SAAS,MAAQ;GACpB,IAAM,IAAM,EAAI,aAAa,KAAK,KAAK;GACvC,AAAI,EAAI,WAAW,OAAO,KAAK,KAAK,cAAc,IAAI,CAAG,MACvD,IAAI,gBAAgB,CAAG,GACvB,KAAK,cAAc,OAAO,CAAG;EAEjC,CAAC;CACH;CAaA,eAAe,GAAM;EACnB,OAAO,EAEJ,QAAQ,kCAAkC,EAAE,CAAC,CAE7C,QAAQ,yBAAyB,EAAE,CAAC,CAEpC,QAAQ,uBAAuB,EAAE,CAAC,CAElC,QAAQ,mCAAmC,EAAE,CAAC,CAE9C,QAAQ,yBAAyB,EAAE,CAAC,CAEpC,QAAQ,yBAAyB,GAAI,MAAU;GAC9C,IAAM,IAAU,EAAM,MAAM,GAAG,CAAC,CAC7B,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CACpB,QAAQ,MAAM,KAAK,CAAC,SAAS,KAAK,CAAC,KAAK,CAAC,kCAAkC,KAAK,CAAC,CAAC,CAAC,CACnF,KAAK,IAAI;GACZ,OAAO,IAAU,WAAW,EAAQ,KAAK;EAC3C,CAAC,CAAC,CAED,QAAQ,kCAAkC,EAAE;CACjD;CASA,iBAAiB,GAAM;EACrB,IAAM,IAAM,IAAI,UAAU,CAAC,CAAC,gBAAgB,SAAS,EAAK,UAAU,WAAW,GAOzE,IAAa,MAAM,KAAK,EAAI,iBAAiB,WAAW,CAAC;EAC/D,KAAK,IAAI,IAAI,EAAW,SAAS,GAAG,KAAK,GAAG,KAAK;GAC/C,IAAM,IAAK,EAAW;GAGtB,IAFI,CAAC,EAAG,cAEJ,EAAG,cAAc,4FAA4F,GAAG;GAEpH,IAAM,IAAS,EAAG;GAClB,OAAO,EAAG,aAAY,EAAO,aAAa,EAAG,YAAY,CAAE;GAC3D,EAAG,OAAO;EACZ;EASA,OAPA,EAAI,iBAAiB,GAAG,CAAC,CAAC,SAAS,MAAO;GAGxC,AAFA,EAAG,gBAAgB,OAAO,GAC1B,EAAG,gBAAgB,IAAI,GACvB,MAAM,KAAK,EAAG,UAAU,CAAC,CACtB,QAAQ,MAAM,EAAE,KAAK,WAAW,OAAO,KAAK,EAAE,KAAK,WAAW,OAAO,CAAC,CAAC,CACvE,SAAS,MAAM,EAAG,gBAAgB,EAAE,IAAI,CAAC;EAC9C,CAAC,GACM,EAAI,KAAK;CAClB;CASA,iBAAiB,GAAM;EACrB,IAAM,IAAM,IAAI,UAAU,CAAC,CAAC,gBAAgB,SAAS,EAAK,UAAU,WAAW,GACzE,oBAAa,IAAI,IAAI;GAAC;GAAQ;GAAO;GAAO;GAAU;GAAO;GAAW;GAAW;EAAM,CAAC;EAMhG,OALA,EAAI,iBAAiB,GAAG,CAAC,CAAC,SAAS,MAAO;GACxC,MAAM,KAAK,EAAG,UAAU,CAAC,CACtB,QAAQ,MAAM,CAAC,EAAW,IAAI,EAAE,IAAI,CAAC,CAAC,CACtC,SAAS,MAAM,EAAG,gBAAgB,EAAE,IAAI,CAAC;EAC9C,CAAC,GACM,EAAI,KAAK;CAClB;CAQA,4BAA4B,GAAM;EAChC,IAAM,IAAM,IAAI,UAAU,CAAC,CAAC,gBAAgB,SAAS,EAAK,UAAU,WAAW;EAC/E,KAAK,IAAM,KAAM,EAAI,iBAAiB,0BAAwB,GAAG;GAC/D,IAAM,IAAK,EAAG,QAAQ,IAAI,GACpB,IAAK,GAAI,QAAQ,IAAI;GACvB,OAAC,KAAM,CAAC,KAAM,EAAG,UAAU,SAAS,cAAc,IAGtD;IAFA,EAAG,UAAU,IAAI,cAAc,GAC/B,EAAG,gBAAgB,UAAU,GAC7B,EAAG,aAAa,mBAAmB,OAAO;IAC1C,KAAK,IAAM,KAAQ,MAAM,KAAK,EAAG,UAAU,GACzC,AAAK;KAAC;KAAQ;KAAW;IAAiB,CAAC,CAAC,SAAS,EAAK,IAAI,KAC5D,EAAG,gBAAgB,EAAK,IAAI;GAHU;EAM5C;EACA,OAAO,EAAI,KAAK;CAClB;CAUA,sBAAsB,GAAM;EAG1B,OAAO,CAFK,IAAI,UAAU,CAAC,CAAC,gBAAgB,SAAS,EAAK,UAAU,WAE1D,CAAC,CAAC,KAAK,cAAc,+FAAW;CAC5C;CAOA,cAAc,GAAK;EACjB,KAAK,cAAc,CAAC,CAAC;CACvB;CAEA,SAAS,GAAO;EACd,IAAM,IAAgB,EAAM,iBAAqC,WAAY;EAC7E,IAAI,CAAC,GAAe;EAGpB,IAAM,IAAa,KAAK;EACxB,KAAK,cAAc;EAGnB,IAAM,KAAY,KAAK,QAAQ,gBAAgB,KAAK,OAAO;EAC3D,IAAI,IAAW,GAAG;GAChB,IAAM,IAAO,EAAc,QAAQ,YAAY,KAAK,IAC9C,IAAO,EAAc,QAAQ,WAAW,KAAK,IAC7C,IAAO,KAAK,IAAI,EAAK,QAAQ,EAAK,MAAM;GAC9C,IAAI,IAAO,GAAU;IACnB,EAAM,eAAe;IACrB,IAAM,IAAU,mBAAmB,EAAK,sBAAsB,KAAK,QAAQ,gBAAgB,EAAE;IAE7F,AADA,KAAK,QAAQ,aAAa,cAAc;KAAE;KAAM;KAAU;IAAQ,CAAC,GACnE,QAAQ,KAAK,gBAAgB,GAAS;IACtC;GACF;EACF;EAGA,IAAI,EAAc,OAAO;GACvB,IAAM,IAAa,MAAM,KAAK,EAAc,KAAK,CAAC,CAAC,QAChD,MAAS,EAAK,SAAS,UAAU,EAAK,KAAK,WAAW,QAAQ,CACjE;GACA,IAAI,EAAW,SAAS,GAAG;IACzB,EAAM,eAAe;IACrB,IAAM,IAAQ,EAAW,KAAK,MAAS,EAAK,UAAU,CAAC,CAAC,CAAC,OAAO,OAAO;IACvE,KAAK,kBAAkB,CAAK;IAC5B;GACF;EACF;EAWA,IARI,OAAO,KAAK,QAAQ,WAAY,cAClC,KAAK,QAAQ,QAAQ;GACnB,MAAM,EAAc,QAAQ,YAAY,KAAK;GAC7C,MAAM,EAAc,MAAM,SAAS,WAAW,IAAI,EAAc,QAAQ,WAAW,IAAI;EACzF,CAAC,GAIC,KAAc,KAAK,QAAQ,kBAAkB;GAQ/C,AAPA,EAAM,eAAe,GAMrB,EAAY,cALC,EAAc,QAAQ,YACnB,CAAC,CACd,MAAM,OAAO,CAAC,CACd,KAAK,MAAS,MAAM,KAAK,YAAY,CAAI,KAAK,OAAO,KAAK,CAAC,CAC3D,KAAK,EACqB,CAAC,GAC9B,KAAK,QAAQ,OAAO,qBAAqB;GACzC;EACF;EAOA,IAAI,KAAK,QAAQ,kBAAkB,IAAO;GACxC,IAAM,IAAU,EAAc,MAAM,SAAS,WAAW,GAClD,IAAO,IAAU,EAAc,QAAQ,WAAW,IAAI,IACtD,IAAqB,CAAC,KAAW,KAAK,sBAAsB,CAAI,GAChE,IAAO,EAAc,QAAQ,YAAY;GAC/C,IAAI,KAAQ,KAAsB,GAAW,CAAI,GAAG;IAIlD,AAHA,EAAM,eAAe,GAErB,EAAY,cADM,EAAa,EAAe,CAAI,CAChB,CAAC,GACnC,KAAK,QAAQ,OAAO,qBAAqB;IACzC;GACF;EACF;EAGA,IAAI,KAAK,QAAQ,mBAAmB,MAAS,EAAc,MAAM,SAAS,WAAW,GAAG;GACtF,EAAM,eAAe;GACrB,IAAM,IAAM,EAAc,QAAQ,WAAW,GAEvC,IAAgB,iBAAiB,KAAK,CAAG,KAAK,cAAc,KAAK,CAAG,KAAK,UAAU,KAAK,CAAG,GAC3F,IAAkB,mDAAmD,KAAK,CAAG,GAC/E,IAAO;GAOX,AANI,IAAe,IAAO,KAAK,eAAe,CAAI,IACzC,MAAiB,IAAO,KAAK,iBAAiB,CAAI,IAC3D,IAAO,KAAK,4BAA4B,CAAI,GAC5C,IAAO,EAAa,CAAI,GACpB,KAAK,QAAQ,yBAAsB,IAAO,KAAK,iBAAiB,CAAI,IACxE,EAAY,cAAc,CAAI,GAC9B,KAAK,QAAQ,OAAO,qBAAqB;EAC3C;CAGF;CAMA,YAAY,GAAO;EACZ,EAAM,gBACG,MAAM,KAAK,EAAM,aAAa,SAAS,CAAC,CAC9C,CAAC,CAAC,SAAS,OAAO,MACxB,EAAM,eAAe,GACrB,EAAM,aAAa,aAAa;CAEpC;CAEA,QAAQ,GAAO;EACb,IAAM,IAAK,EAAM;EACjB,IAAI,CAAC,GAAI,OAAO,QAAQ;EAExB,IAAM,IAAa,MAAM,KAAK,EAAG,KAAK,CAAC,CAAC,QAAQ,MAAM,EAAE,KAAK,WAAW,QAAQ,CAAC;EACjF,IAAI,EAAW,SAAS,GAAG;GAKzB,AAJA,EAAM,eAAe,GACrB,EAAM,gBAAgB,GAEtB,KAAK,mBAAmB,EAAM,SAAS,EAAM,OAAO,GACpD,KAAK,kBAAkB,CAAU;GACjC;EACF;EAEA,IAAI,KAAK,QAAQ,kBAAkB,IAAO;GACxC,IAAM,IAAS,MAAM,KAAK,EAAG,KAAK,CAAC,CAAC,MAAM,MAAM,SAAS,KAAK,EAAE,IAAI,KAAK,EAAE,SAAS,eAAe;GACnG,AAAI,MACF,EAAM,eAAe,GACrB,EAAM,gBAAgB,GACtB,KAAK,mBAAmB,EAAM,SAAS,EAAM,OAAO,GACpD,KAAK,oBAAoB,CAAM;EAEnC;CACF;CAQA,oBAAoB,GAAM;EACxB,IAAM,KAAY,KAAK,QAAQ,gBAAgB,KAAK,OAAO;EAC3D,IAAI,IAAW,KAAK,EAAK,OAAO,GAAU;GACxC,IAAM,IAAU,iBAAiB,EAAK,KAAK,KAAK,EAAK,KAAK,sBAAsB,KAAK,QAAQ,gBAAgB,EAAE;GAE/G,AADA,KAAK,QAAQ,aAAa,cAAc;IAAE,MAAM,EAAK;IAAM;IAAU;GAAQ,CAAC,GAC9E,QAAQ,KAAK,gBAAgB,GAAS;GACtC;EACF;EACA,IAAM,IAAS,IAAI,WAAW;EAW9B,AAVA,EAAO,UAAU,MAAM;GAGrB,AADA,EAAY,cADC,EAAa,EAAsC,EAAE,OAAO,UAAW,EAAE,CACzD,CAAC,GAC9B,KAAK,QAAQ,OAAO,qBAAqB;EAC3C,GACA,EAAO,gBAAgB;GACrB,IAAM,IAAU,yCAAyC,EAAK,KAAK;GAEnE,AADA,QAAQ,KAAK,gBAAgB,GAAS,GACtC,KAAK,QAAQ,aAAa,cAAc,EAAE,WAAQ,CAAC;EACrD,GACA,EAAO,WAAW,CAAI;CACxB;CAYA,kBAAkB,GAAO;EACvB,IAAI,CAAC,KAAS,EAAM,WAAW,GAAG;EAElC,IAAI,OAAO,KAAK,QAAQ,iBAAkB,YAAY;GACpD,KAAK,kBAAkB,CAAK;GAC5B;EACF;EAGA,IAAM,oBAAc,IAAI,IAAI;GAAC;GAAc;GAAgB;GAAa;GAAe;EAAgB,CAAC,GAClG,KAAY,KAAK,QAAQ,gBAAgB,KAAK,OAAO;EAC3D,EAAM,SAAS,MAAS;GACtB,IAAI,CAAC,GAAM,MAAM,WAAW,QAAQ,GAAG;GACvC,IAAI,EAAY,IAAI,EAAK,IAAI,GAAG;IAC9B,IAAM,IAAU,iBAAiB,EAAK,KAAK;IAE3C,AADA,KAAK,QAAQ,aAAa,cAAc;KAAE;KAAM;IAAQ,CAAC,GACzD,QAAQ,KAAK,gBAAgB,CAAO;IACpC;GACF;GACA,IAAI,EAAK,OAAO,GAAU;IACxB,IAAM,IAAU,UAAU,EAAK,KAAK,gBAAgB,KAAK,QAAQ,gBAAgB,EAAE;IAEnF,AADA,KAAK,QAAQ,aAAa,cAAc;KAAE;KAAM;IAAQ,CAAC,GACzD,QAAQ,KAAK,gBAAgB,GAAS;IACtC;GACF;GAEA,IAAM,IAAM,EAAK,KAAK,QAAQ,YAAY,EAAE;GAC5C,KAAK,oBAAoB,CAAI,CAAC,CAAC,MAAM,MAAY;IAC/C,KAAK,QAAQ,OAAO,sBAAsB,GAAS,CAAG;GACxD,CAAC,CAAC,CAAC,OAAO,MAAQ;IAChB,IAAM,IAAU,UAAU,EAAK,KAAK;IAEpC,AADA,KAAK,QAAQ,aAAa,cAAc;KAAE;KAAM;KAAS,OAAO;IAAI,CAAC,GACrE,QAAQ,KAAK,gBAAgB,GAAS,CAAG;GAC3C,CAAC;EACH,CAAC;CACH;CAOA,YAAY,GAAG;EACb,OAAO,OAAO,CAAC,CAAC,CACb,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,MAAK,QAAQ,CAAC,CACzB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,KAAK,MAAM;CAC3B;CAgBA,MAAM,kBAAkB,GAAO;EAC7B,IAAM,IAAU;GACd,SAAS,KAAK;GACd,cAAc,GAAM,MAAU,KAAK,mBAAmB,GAAM,CAAK;EACnE,GAEI;EACJ,IAAI;GACF,IAAS,KAAK,QAAQ,cAAc,GAAO,CAAO;EACpD,SAAS,GAAO;GACd,KAAK,mBAAmB,GAAO,CAAK;GACpC;EACF;EAGA,IAAI,MAAW,KAAA,GAAW;EAI1B,IAAM,IAAS,EAAM,KAAK,MAAS,KAAK,yBAAyB,CAAI,CAAC,GAElE;EACJ,IAAI;GACF,IAAO,MAAM;EACf,SAAS,GAAO;GACd,EAAO,SAAS,GAAO,MAAM,KAAK,YAAY,GAAO,EAAM,IAAI,CAAK,CAAC;GACrE;EACF;EAEA,IAAM,IAAO,MAAM,QAAQ,CAAI,IAAI,IAAO,CAAC,CAAI;EAC/C,EAAO,SAAS,GAAO,MAAM;GAC3B,IAAM,IAAM,EAAK;GACjB,AAAI,OAAO,KAAQ,YAAY,IAAK,KAAK,eAAe,GAAO,CAAG,IAG7D,KAAK,YAAY,GAAO,EAAM,IAAI,gBAAI,MAAM,gCAAgC,CAAC;EACpF,CAAC;CACH;CAQA,yBAAyB,GAAM;EAC7B,IAAM,IAAQ,SAAS,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,KAAK,cAAc,KAAK,cAAc,KAAK,KACvF,IAAa,IAAI,gBAAgB,CAAI;EAE3C,AADA,KAAK,kBAAkB,KAAK,mCAAmB,IAAI,IAAI,GACvD,KAAK,gBAAgB,IAAI,GAAO;GAAE;GAAY;EAAK,CAAC;EAEpD,IAAM,IAAM,KAAK,YAAY,EAAK,KAAK,QAAQ,YAAY,EAAE,CAAC;EAI9D,OAHA,EAAY,cACV,aAAa,KAAK,YAAY,CAAU,EAAE,SAAS,EAAI,wDAAwD,EAAM,GAAG,GAC1H,KAAK,QAAQ,OAAO,qBAAqB,GAClC;CACT;CAGA,iBAAiB,GAAO;EACtB,OACE,KAAK,QAAQ,WAAW,UAAU,cAAc,uBAAuB,EAAM,GAAG,KAAK;CAEzF;CAOA,eAAe,GAAO,GAAK;EACzB,IAAM,IAAM,KAAK,iBAAiB,CAAK,GACjC,IAAQ,KAAK,iBAAiB,IAAI,CAAK;EAC7C,IAAI,GAAK;GACP,IAAM,IAAO,EAAY,GAAK,EAAE,WAAW,GAAK,CAAC;GACjD,IAAI,GAIF,AAHA,EAAI,aAAa,OAAO,CAAI,GAC5B,EAAI,UAAU,OAAO,oBAAoB,GACzC,EAAI,gBAAgB,gBAAgB,GACpC,EAAI,MAAM,eAAe,sBAAsB;QAC1C;IACL,KAAK,YAAY,GAAO,GAAO,MAAM,gBAAI,MAAM,uBAAuB,GAAK,CAAC;IAC5E;GACF;EACF;EAKA,AAJI,MACF,IAAI,gBAAgB,EAAM,UAAU,GACpC,KAAK,gBAAgB,OAAO,CAAK,IAEnC,KAAK,QAAQ,OAAO,qBAAqB;CAC3C;CAUA,YAAY,GAAO,GAAM,GAAO;EAC9B,IAAM,IAAM,KAAK,iBAAiB,CAAK;EACvC,AAAI,MACF,EAAI,UAAU,OAAO,oBAAoB,GACzC,EAAI,UAAU,IAAI,iBAAiB,GACnC,EAAI,MAAM,eAAe,sBAAsB;EAEjD,IAAM,IAAU,UAAU,GAAM,QAAQ,UAAU;EAElD,AADA,QAAQ,KAAK,gBAAgB,GAAS,CAAK,GAC3C,KAAK,QAAQ,aAAa,cAAc;GACtC;GACA;GACA;GACA,aAAa;IAGX,AAFA,GAAK,OAAO,GACZ,KAAK,iBAAiB,OAAO,CAAK,GAC9B,KAAM,KAAK,kBAAkB,CAAC,CAAI,CAAC;GACzC;EACF,CAAC;CACH;CAGA,mBAAmB,GAAO,GAAO;EAC/B,IAAM,IAAU;EAEhB,AADA,QAAQ,KAAK,gBAAgB,GAAS,CAAK,GAC3C,KAAK,QAAQ,aAAa,cAAc;GAAE,MAAM,EAAM;GAAI;GAAS;EAAM,CAAC;CAC5E;CAQA,mBAAmB,GAAM,GAAO;EAC9B,IAAI,CAAC,KAAK,iBAAiB;EAC3B,IAAM,IAAU,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,CAAK,KAAK,CAAC,CAAC;EAC3D,KAAK,IAAM,CAAC,GAAO,MAAU,KAAK,iBAAiB;GACjD,IAAI,EAAM,SAAS,GAAM;GACzB,IAAM,IAAM,KAAK,iBAAiB,CAAK;GACvC,AAAI,KAAK,EAAI,MAAM,YAAY,wBAAwB,OAAO,CAAO,CAAC;GACtE;EACF;CACF;CAUA,MAAM,oBAAoB,GAAM;EAC9B,IAAM,IAAY,KAAK,QAAQ,gBACzB,IAAU,OAAO,KAAc,aACjC,MAAM,EAAU,GAAM,EAAE,SAAS,KAAK,QAAQ,CAAC,IAC/C,MAAM,KAAK,eAAe,CAAI,GAC5B,IAAO,KAAK,eAAe,CAAO,GAClC,IAAU,IAAI,gBAAgB,CAAI;EAExC,OADA,KAAK,cAAc,IAAI,GAAS,CAAO,GAChC;CACT;CAQA,cAAc,GAAM;EAElB,OADK,KAAK,eAAe,OAClB,EAAK,QAAQ,yBAAyB,MAAQ,KAAK,cAAc,IAAI,CAAG,KAAK,CAAG,IADjD;CAExC;CAOA,eAAe,GAAS;EACtB,IAAM,CAAC,GAAQ,KAAO,EAAQ,MAAM,GAAG,GACjC,IAAO,UAAU,KAAK,CAAM,CAAC,GAAG,MAAM,aACtC,IAAS,KAAK,CAAG,GACjB,IAAM,IAAI,WAAW,EAAO,MAAM;EACxC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAO,QAAQ,KAAK,EAAI,KAAK,EAAO,WAAW,CAAC;EACpE,OAAO,IAAI,KAAK,CAAC,CAAG,GAAG,EAAE,MAAM,EAAK,CAAC;CACvC;CAUA,eAAe,GAAM;EACnB,IAAM,IAAU,MACV,IAAU;EAEhB,OAAO,IAAI,SAAS,GAAS,MAAW;GACtC,IAAM,IAAY,IAAI,gBAAgB,CAAI,GACpC,IAAM,IAAI,MAAM;GA6CtB,AA3CA,EAAI,eAAe;IACjB,IAAI,gBAAgB,CAAS;IAE7B,IAAI,EAAE,UAAO,cAAW;IACxB,CAAI,IAAQ,KAAW,IAAS,OAC1B,KAAS,KACX,IAAS,KAAK,MAAO,IAAS,IAAW,CAAK,GAC9C,IAAQ,MAER,IAAQ,KAAK,MAAO,IAAQ,IAAW,CAAM,GAC7C,IAAS;IAIb,IAAM,IAAS,SAAS,cAAc,QAAQ;IAE9C,AADA,EAAO,QAAQ,GACf,EAAO,SAAS;IAChB,IAAM,IAAM,EAAO,WAAW,IAAI;IAClC,IAAI,CAAC,GAAK;KAGR,IAAM,IAAS,IAAI,WAAW;KAG9B,AAFA,EAAO,UAAU,MAAM,EAA+B,EAAE,OAAO,MAAO,GACtE,EAAO,gBAAgB,EAAO,gBAAI,MAAM,mBAAmB,CAAC,GAC5D,EAAO,cAAc,CAAI;KACzB;IACF;IACA,EAAI,UAAU,GAAK,GAAG,GAAG,GAAO,CAAM;IAGtC,IAAM,IAAO,EAAO,UAAU,cAAc,CAAO;IACnD,EAAQ,EAAK,WAAW,iBAAiB,IAAI,IAAO,EAAO,UAAU,cAAc,CAAO,CAAC;GAC7F,GAEA,EAAI,gBAAgB;IAClB,IAAI,gBAAgB,CAAS;IAE7B,IAAM,IAAS,IAAI,WAAW;IAG9B,AAFA,EAAO,UAAU,MAAM,EAA+B,EAAE,OAAO,MAAO,GACtE,EAAO,gBAAgB,EAAO,gBAAI,MAAM,mBAAmB,CAAC,GAC5D,EAAO,cAAc,CAAI;GAC3B,GAEA,EAAI,MAAM;EACZ,CAAC;CACH;CAQA,mBAAmB,GAAG,GAAG;EACvB,IAAI;EACJ,IAAI,SAAS,qBACX,IAAQ,SAAS,oBAAoB,GAAG,CAAC;OACpC,IAAI,SAAS,wBAAwB;GAC1C,IAAM,IAAM,SAAS,uBAAuB,GAAG,CAAC;GAChD,AAAI,MACF,IAAQ,SAAS,YAAY,GAC7B,EAAM,SAAS,EAAI,YAAY,EAAI,MAAM,GACzC,EAAM,SAAS,EAAI;EAEvB;EACA,IAAI,CAAC,GAAO;EACZ,IAAM,IAAM,WAAW,aAAa;EACpC,AAAI,MACF,EAAI,gBAAgB,GACpB,EAAI,SAAS,CAAK;CAEtB;CAWA,YAAY,GAAK;EACf,OAAO,EACJ,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,MAAK,QAAQ,CAAC,CACzB,WAAW,KAAK,QAAQ;CAC7B;AACF,GCnuBM,KAAgB;AAYtB,SAAS,GAAS,GAAM;CACtB,IAAM,IAAS,SAAS,iBAAiB,GAAM,WAAW,SAAS;CACnE,KAAK,IAAI,IAAO,EAAO,SAAS,GAAG,GAAM,IAAO,EAAO,SAAS,GAC9D,IAAI,GAAc,KAA0B,EAAM,IAAI,GAAG,OAAO;CAElE,OAAO;AACT;;;ACVA,IAAa,KAAe;CAC1B;EAAE,MAAM;EAAe,OAAO;CAAO;CACrC;EAAE,MAAM;EAAe,OAAO;CAAQ;CACtC;EAAE,MAAM;EAAe,OAAO;CAAU;CACxC;EAAE,MAAM;EAAe,OAAO;CAAU;CACxC;EAAE,MAAM;EAAe,OAAO,MDOP;GAIvB,YAAY,GAAS;IAGnB,AAFA,KAAK,UAAU,GACf,KAAK,UAAU,EAAQ,SACvB,KAAK,aAAa,CAAC;GACrB;GAEA,aAAa;IACX,IAAM,IAAW,KAAK,QAAQ,WAAW,UACnC,IAAc,KAAK,QAAQ,eAAe;IAChD,AAAI,MACF,EAAS,QAAQ,cAAc;IAGjC,IAAM,UAAe,KAAK,QAAQ,GAC5B,IAAK,EAAG,GAAU,SAAS,CAAM,GACjC,IAAK,EAAG,GAAU,SAAS,CAAM,GACjC,IAAK,EAAG,GAAU,QAAQ,CAAM;IAGtC,OAFA,KAAK,WAAW,KAAK,GAAI,GAAI,CAAE,GAC/B,KAAK,QAAQ,GACN;GACT;GAEA,UAAU;IAER,AADA,KAAK,WAAW,SAAS,MAAM,EAAE,CAAC,GAClC,KAAK,aAAa,CAAC;GACrB;GAEA,UAAU;IACR,IAAM,IAAW,KAAK,QAAQ,WAAW,UACnC,IAAY,SAAS,kBAAkB,GACvC,IAAU,CAAC,GAAS,CAAQ,KAChC,CAAC,EAAS,cAAc,mCAAmC;IAC7D,EAAS,UAAU,OAAO,kBAAkB,KAAW,CAAC,CAAS;GACnE;EACF;CC7C4C;AAC5C;;;ACnBA,SAAgB,GAAK,GAAK;CACxB,OAAO,EAAI,EAAI,SAAS;AAC1B;AAQA,SAAgB,GAAM,GAAK;CACzB,OAAO,EAAI;AACb;AASA,SAAgB,GAAQ,GAAK,IAAI,GAAG;CAClC,OAAO,EAAI,MAAM,GAAG,EAAI,SAAS,CAAC;AACpC;AASA,SAAgB,GAAK,GAAK,IAAI,GAAG;CAC/B,OAAO,EAAI,MAAM,CAAC;AACpB;AAQA,SAAgB,GAAQ,GAAK;CAC3B,OAAO,EAAI,KAAK;AAClB;AAQA,SAAgB,GAAO,GAAK;CAC1B,OAAO,CAAC,GAAG,IAAI,IAAI,CAAG,CAAC;AACzB;AASA,SAAgB,GAAM,GAAK,GAAG;CAC5B,IAAM,IAAS,CAAC;CAChB,KAAK,IAAI,IAAI,GAAG,IAAI,EAAI,QAAQ,KAAK,GACnC,EAAO,KAAK,EAAI,MAAM,GAAG,IAAI,CAAC,CAAC;CAEjC,OAAO;AACT;AASA,SAAgB,GAAQ,GAAK,GAAO;CAClC,OAAO,EAAI,QAAQ,GAAQ,MAAS;EAClC,IAAM,IAAM,EAAM,CAAI;EAKtB,OAJK,EAAO,OACV,EAAO,KAAO,CAAC,IAEjB,EAAO,EAAI,CAAC,KAAK,CAAI,GACd;CACT,GAAG,CAAC,CAAC;AACP;AASA,SAAgB,GAAI,GAAK,GAAW;CAClC,OAAO,EAAI,MAAM,CAAS;AAC5B;AASA,SAAgB,GAAI,GAAK,GAAW;CAClC,OAAO,EAAI,KAAK,CAAS;AAC3B;;;AC1GA,SAAS,IAAK;CACZ,OAAO,WAAW,WAAW,aAAa;AAC5C;AAEA,IAAa,KAAM;CAEjB,IAAI,WAAW;EAAE,OAAO,WAAW,KAAK,EAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,EAAG,CAAC;CAAG;CAEtE,IAAI,OAAO;EAAE,OAAO,YAAY,KAAK,EAAG,CAAC;CAAG;CAE5C,IAAI,WAAW;EAAE,OAAO,iCAAiC,KAAK,EAAG,CAAC;CAAG;CAErE,IAAI,SAAS;EAAE,OAAO,QAAQ,KAAK,EAAG,CAAC;CAAG;CAE1C,IAAI,QAAQ;EAAE,OAAO,YAAY,KAAK,EAAG,CAAC;CAAG;CAE7C,IAAI,WAAW;EAAE,OAAO,iEAAiE,KAAK,EAAG,CAAC;CAAG;CAErG,IAAI,UAAU;EACZ,OAAO,kBAAkB,eAAe,WAAW,WAAW,kBAAkB,KAAK;CACvF;CAEA,IAAI,cAAc;EAAE,OAAO,YAAY,KAAK,EAAG,CAAC,IAAI,YAAY;CAAW;AAC7E,GCrBM,KAAoB,EAAE,GAAG,EAAe,GAyBxC,oBAAY,IAAI,QAAQ,GAExB,KAAa;CAQjB,OAAO,GAAU,IAAU,CAAC,GAAG;EAE7B,IAAM,IADW,GAAgB,CACb,CAAC,CAAC,KAAK,MAAO;GAChC,IAAI,EAAU,IAAI,CAAE,GAAG,OAAO,EAAU,IAAI,CAAE;GAC9C,IAAM,IAAM,IAAI,GAAoC,GAAK,CAAO;GAGhE,OAFA,EAAI,WAAW,GACf,EAAU,IAAI,GAAI,CAAG,GACd;EACT,CAAC;EACD,OAAO,EAAK,WAAW,IAAI,EAAK,KAAK;CACvC;CAMA,QAAQ,GAAU;EAChB,GAAgB,CAAQ,CAAC,CAAC,SAAS,MAAO;GACxC,IAAM,IAAM,EAAU,IAAI,CAAE;GAC5B,AAAI,MACF,EAAI,QAAQ,GACZ,EAAU,OAAO,CAAE;EAEvB,CAAC;CACH;CAOA,YAAY,GAAU;EACpB,IAAM,IAAK,OAAO,KAAa,WAAW,SAAS,cAAc,CAAQ,IAAI;EAC7E,OAAO,KAAK,EAAU,IAAI,CAAE,KAAY;CAC1C;CAGA,IAAI,WAAW;EAAE,OAAO,EAAE,GAAG,EAAe;CAAG;CAG/C,YAAY,GAAW;EAAE,OAAO,OAAO,GAAgB,CAAS;CAAG;CAGnE,gBAAgB;EAEd,AADA,OAAO,KAAK,CAAc,CAAC,CAAC,SAAS,MAAM,OAAO,EAAe,EAAE,GACnE,OAAO,OAAO,GAAgB,EAAiB;CACjD;CAOA,eAAe,GAAM,GAAa;EAAE,GAAe,IAAI,GAAM,CAAW;CAAG;CAW3E,IAAI,GAAQ,IAAU,CAAC,GAAG;EACxB,IAAI,CAAC,KAAU,OAAO,EAAO,QAAS,UACpC,MAAU,UAAU,yEAAyE;EAU/F,OARI,EAAe,IAAI,EAAO,IAAI,KAChC,QAAQ,KAAK,wBAAwB,EAAO,KAAK,yCAAyC,GACnF,SAEL,MAAM,QAAQ,EAAO,OAAO,KAC9B,EAAO,QAAQ,SAAS,MAAM,EAAe,CAAC,CAAC,GAEjD,EAAe,IAAI,EAAO,MAAM;GAAE;GAAQ;EAAQ,CAAC,GAC5C;CACT;CAOA,UAAU,GAAM;EAAE,OAAO,EAAe,IAAI,CAAI;CAAG;CAQnD,eAAe,GAAQ;EAA0B,OAAxB,EAAe,CAAM,GAAU;CAAM;CAS9D,eAAe,GAAM,GAAQ;EAAgC,OAA9B,GAAe,GAAM,CAAM,GAAU;CAAM;CAG1E,qBAAqB,GAAS;EAC5B,IAAI,CAAC,GAAS,MAAM,OAAO,EAAQ,OAAQ,YACzC,MAAU,UAAU,sEAAsE;EAE5F,IAAM,IAAW,EAAe,eAC1B,IAAQ,EAAS,WAAW,MAAS,EAAK,OAAO,EAAQ,EAAE;EAGjE,OAFI,KAAS,IAAG,EAAS,KAAS,IAC7B,EAAS,KAAK,CAAO,GACnB;CACT;CAGA;CAGA,SAAS;AACX;AAUA,SAAS,GAAgB,GAAU;CAUjC,OATI,OAAO,KAAa,WACf,MAAM,KAAK,SAAS,iBAAiB,CAAQ,CAAC,IAEnD,aAAoB,UACf,CAAC,CAAQ,IAEd,aAAoB,YAAY,MAAM,QAAQ,CAAQ,IACvB,MAAM,KAAK,CAAQ,IAE/C,CAAC;AACV;;;ACpKA,GAAc,EAAY"}
|
|
1
|
+
{"version":3,"file":"autumnnote.core.es.js","names":["root","BLOCK_TAGS","Style.bold","Style.italic","Style.underline","Style.strikethrough","Style.superscript","Style.subscript","Style.justifyLeft","Style.justifyCenter","Style.justifyRight","Style.justifyFull","Style.insertUnorderedList","Style.insertOrderedList","Style.indent","Style.outdent","Style.execCommand","Style.fontSize","Style.fontName","Style.formatBlock","Style.lineHeight","Style.isInlineCode","Style.isInChecklist","Style.foreColor","Style.backColor","packageVersion"],"sources":["../src/js/core/func.js","../src/js/core/dom.js","../src/js/core/range.js","../src/js/editing/insert.js","../src/js/editing/Style.js","../src/js/module/Buttons.js","../src/js/settings.js","../src/js/i18n/en.js","../src/js/i18n/index.js","../src/js/core/sanitise.js","../src/js/renderer.js","../src/js/Context.js","../src/js/editing/History.js","../src/js/editing/Table.js","../src/js/core/key.js","../src/js/editing/Typing.js","../src/js/core/count.js","../src/js/core/markdown.js","../src/js/core/detectLang.js","../src/js/module/Editor.js","../src/js/module/Toolbar.js","../src/js/module/Statusbar.js","../src/js/module/Clipboard.js","../src/js/module/Placeholder.js","../src/js/presets/core.js","../package.json","../src/js/core/lists.js","../src/js/core/env.js","../src/js/factory.js","../src/js/core.js"],"sourcesContent":["/**\n * func.js - General utility / functional helpers\n * Inspired by Summernote's func.js\n */\n\n/**\n * Clamp a value between min and max.\n * @param {number} val\n * @param {number} min\n * @param {number} max\n * @returns {number}\n */\nexport function clamp(val, min, max) {\n return Math.min(Math.max(val, min), max);\n}\n\n/**\n * Debounce a function call.\n * @param {Function} fn\n * @param {number} delay - milliseconds\n * @returns {Function}\n */\nexport function debounce(fn, delay) {\n let timer;\n return function (...args) {\n clearTimeout(timer);\n timer = setTimeout(() => fn.apply(this, args), delay);\n };\n}\n\n/**\n * Create a wrapper that limits how often `fn` can be invoked while ensuring the last call in a burst is executed.\n * @param {Function} fn - Function to be throttled.\n * @param {number} limit - Time globalThis in milliseconds during which at most one call is allowed.\n * @returns {Function} A wrapper function that invokes `fn` at most once per `limit` milliseconds; calls preserve `this` and original arguments and schedule a trailing invocation for the final call in a burst.\n */\nexport function throttle(fn, limit) {\n let lastCall = -Infinity;\n let trailingTimer = null;\n return function (...args) {\n const now = performance.now();\n const elapsed = now - lastCall;\n if (elapsed >= limit) {\n lastCall = now;\n clearTimeout(trailingTimer);\n trailingTimer = null;\n return fn.apply(this, args);\n }\n // Ensure the final event in a burst is not dropped\n clearTimeout(trailingTimer);\n trailingTimer = setTimeout(() => {\n lastCall = performance.now();\n trailingTimer = null;\n fn.apply(this, args);\n }, limit - elapsed);\n };\n}\n\n/**\n * Compose multiple functions right-to-left.\n * @param {...Function} fns\n * @returns {Function}\n */\nexport function compose(...fns) {\n return (x) => fns.reduceRight((v, f) => f(v), x);\n}\n\n/**\n * Identity function.\n * @template T\n * @param {T} x\n * @returns {T}\n */\nexport function identity(x) {\n return x;\n}\n\n/**\n * Determines if a value is null or undefined.\n * @param {*} val\n * @returns {boolean}\n */\nexport function isNil(val) {\n return val === null || val === undefined;\n}\n\n/**\n * Determines if a value is a string.\n * @param {*} val\n * @returns {boolean}\n */\nexport function isString(val) {\n return typeof val === 'string';\n}\n\n/**\n * Determines if a value is a function.\n * @param {*} val\n * @returns {boolean}\n */\nexport function isFunction(val) {\n return typeof val === 'function';\n}\n\n/**\n * Deep-merge two plain objects. Returns a new object.\n * Arrays are cloned (shallow copy) rather than shared by reference so that\n * mutations to the merged result do not bleed back into the source object\n * (e.g. mutating `instance.options.fontFamilies` should not affect\n * `AutumnNote.defaults.fontFamilies`).\n * @param {object} target\n * @param {object} source\n * @returns {object}\n */\nexport function mergeDeep(target, source) {\n // Start with a shallow copy of target; clone any arrays to avoid shared refs\n const output = {};\n for (const key of Object.keys(target)) {\n output[key] = Array.isArray(target[key]) ? [...target[key]] : target[key];\n }\n if (isPlainObject(target) && isPlainObject(source)) {\n for (const key of Object.keys(source)) {\n if (isPlainObject(source[key])) {\n // When target[key] is null / undefined / a non-object (e.g. the `mention: null`\n // default), merge into an empty object instead of passing null to the next\n // recursive call — which would silently drop all source properties.\n const base = isPlainObject(target[key]) ? target[key] : {};\n output[key] = mergeDeep(base, source[key]);\n } else if (Array.isArray(source[key])) {\n output[key] = [...source[key]];\n } else {\n output[key] = source[key];\n }\n }\n }\n return output;\n}\n\n/**\n * Checks if value is a plain object.\n * @param {*} val\n * @returns {boolean}\n */\nexport function isPlainObject(val) {\n return val !== null && typeof val === 'object' && !Array.isArray(val);\n}\n\n/**\n * Convert a DOMRect (or similar bounding object) to a plain object bounding box.\n * Guards against missing/null rect (e.g. in AirMode).\n * @param {DOMRect|null|undefined} rect\n * @returns {{ top: number, left: number, width: number, height: number, bottom: number, right: number }|null}\n */\nexport function rect2bnd(rect) {\n if (!rect) return null;\n return {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n bottom: rect.bottom,\n right: rect.right,\n };\n}\n","/**\n * dom.js - DOM manipulation utilities\n * Inspired by Summernote's dom.js — rewritten for vanilla JS without jQuery\n */\n\n// ---------------------------------------------------------------------------\n// Node type helpers\n// ---------------------------------------------------------------------------\n\nexport const ELEMENT_NODE = 1;\nexport const TEXT_NODE = 3;\n\n/** @param {Node} node */\nexport const isElement = (node) => node?.nodeType === ELEMENT_NODE;\n/** @param {Node} node */\nexport const isText = (node) => node?.nodeType === TEXT_NODE;\n/** @param {Node} node */\nexport const isVoid = (node) => isElement(node) && /^(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/i.test(node.nodeName);\n/** @param {Node} node */\nexport const isPara = (node) => isElement(node) && /^(p|div|li|h[1-6]|blockquote|td|th|pre)$/i.test(node.nodeName);\n/** @param {Node} node */\nexport const isLi = (node) => isElement(node) && /^(li)$/i.test(node.nodeName);\n/** @param {Node} node */\nexport const isList = (node) => isElement(node) && /^(ul|ol)$/i.test(node.nodeName);\n/** @param {Node} node */\nexport const isTable = (node) => isElement(node) && node.nodeName.toUpperCase() === 'TABLE';\n/** @param {Node} node */\nexport const isInline = (node) =>\n isElement(node) &&\n /^(a|abbr|acronym|b|bdo|big|br|button|cite|code|dfn|em|i|img|input|kbd|label|map|object|output|q|s|samp|select|small|span|strong|sub|sup|textarea|time|tt|u|var)$/i.test(node.nodeName);\n/** @param {Node} node */\nexport const isEditable = (node) => isElement(node) && /** @type {HTMLElement} */ (node).isContentEditable;\n/** @param {Node} node */\nexport const isAnchor = (node) => isElement(node) && node.nodeName.toUpperCase() === 'A';\n/** @param {Node} node */\nexport const isImage = (node) => isElement(node) && node.nodeName.toUpperCase() === 'IMG';\n\n// ---------------------------------------------------------------------------\n// Tree traversal\n// ---------------------------------------------------------------------------\n\n/**\n * Walk up the DOM tree from node, returning the first element matching predicate (inclusive).\n * @param {Node} node\n * @param {(node: Node) => boolean} predicate\n * @param {Node} [stopAt] - stop traversal at this ancestor (exclusive)\n * @returns {Node|null}\n */\nexport function closest(node, predicate, stopAt) {\n let cur = node;\n while (cur && cur !== stopAt) {\n if (predicate(cur)) return cur;\n cur = cur.parentNode;\n }\n return null;\n}\n\n/**\n * Returns the nearest ancestor that is a paragraph-like block.\n * @param {Node} node\n * @param {Node} [editable]\n * @returns {Node|null}\n */\nexport function closestPara(node, editable) {\n return closest(node, isPara, editable);\n}\n\n/**\n * Returns all ancestors of node up to (but not including) stopAt.\n * @param {Node} node\n * @param {Node} [stopAt]\n * @returns {Node[]}\n */\nexport function ancestors(node, stopAt) {\n const result = [];\n let cur = node.parentNode;\n while (cur && cur !== stopAt) {\n result.push(cur);\n cur = cur.parentNode;\n }\n return result;\n}\n\n/**\n * Returns all children of node as an Array.\n * @param {Node} node\n * @returns {Node[]}\n */\nexport function children(node) {\n return Array.from(node.childNodes);\n}\n\n/**\n * Returns the previous sibling element (skipping text/comment nodes).\n * @param {Node} node\n * @returns {Element|null}\n */\nexport function prevElement(node) {\n let sibling = node.previousSibling;\n while (sibling && !isElement(sibling)) {\n sibling = sibling.previousSibling;\n }\n return /** @type {Element|null} */ (sibling);\n}\n\n/**\n * Returns the next sibling element.\n * @param {Node} node\n * @returns {Element|null}\n */\nexport function nextElement(node) {\n let sibling = node.nextSibling;\n while (sibling && !isElement(sibling)) {\n sibling = sibling.nextSibling;\n }\n return /** @type {Element|null} */ (sibling);\n}\n\n// ---------------------------------------------------------------------------\n// DOM mutation helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an element with optional attributes and children.\n * @param {string} tag\n * @param {Record<string, string>} [attrs]\n * @param {(Node|string)[]} [childNodes]\n * @returns {HTMLElement}\n */\nexport function createElement(tag, attrs = {}, childNodes = []) {\n const el = document.createElement(tag);\n for (const [k, v] of Object.entries(attrs)) {\n el.setAttribute(k, v);\n }\n for (const child of childNodes) {\n if (typeof child === 'string') {\n el.appendChild(document.createTextNode(child));\n } else {\n el.appendChild(child);\n }\n }\n return el;\n}\n\n/**\n * Removes a node from its parent.\n * @param {Node} node\n */\nexport function remove(node) {\n if (node?.parentNode) {\n /** @type {ChildNode} */ (node).remove();\n }\n}\n\n/**\n * Unwraps a node — replaces the node with its children.\n * @param {Node} node\n */\nexport function unwrap(node) {\n const parent = node.parentNode;\n if (!parent) return;\n while (node.firstChild) {\n parent.insertBefore(node.firstChild, node);\n }\n /** @type {ChildNode} */ (node).remove();\n}\n\n/**\n * Wraps a node with a wrapper element.\n * @param {Node} node\n * @param {HTMLElement} wrapper\n * @returns {HTMLElement} the wrapper\n */\nexport function wrap(node, wrapper) {\n node.parentNode.insertBefore(wrapper, node);\n wrapper.appendChild(node);\n return wrapper;\n}\n\n/**\n * Insert node after reference node.\n * @param {Node} newNode\n * @param {Node} refNode\n */\nexport function insertAfter(newNode, refNode) {\n if (refNode.nextSibling) {\n refNode.parentNode.insertBefore(newNode, refNode.nextSibling);\n } else {\n refNode.parentNode.appendChild(newNode);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Content helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the text content of a node (safe).\n * @param {Node} node\n * @returns {string}\n */\nexport function nodeValue(node) {\n return isText(node) ? node.nodeValue : node.textContent || '';\n}\n\n/**\n * Determine whether a DOM node contains no visible content.\n *\n * Text nodes are considered empty when their `nodeValue` is empty. Void elements (e.g., `img`, `br`, `input`) are considered non-empty. An element with exactly one `<br>` child is treated as empty. For other elements, emptiness means trimmed `textContent` is empty and there are no descendant `img`, `video`, `hr`, or `table` elements.\n * @param {Node} node - Node to inspect for visible content.\n * @returns {boolean} `true` if the node has no visible content, `false` otherwise.\n */\nexport function isEmpty(node) {\n if (isText(node)) return !node.nodeValue;\n if (isVoid(node)) return false;\n if (node.childNodes.length === 1 && node.firstChild?.nodeName === 'BR') return true;\n return !node.textContent.trim() && !/** @type {Element} */ (node).querySelector('img, video, hr, table');\n}\n\n/**\n * Returns the outerHTML of an element.\n * @param {Element} el\n * @returns {string}\n */\nexport function outerHtml(el) {\n return el.outerHTML;\n}\n\n// ---------------------------------------------------------------------------\n// Selection / editing helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Places the caret at the end of a contenteditable element.\n * @param {HTMLElement} el\n */\nexport function placeCaret(el) {\n const range = document.createRange();\n range.selectNodeContents(el);\n range.collapse(false);\n const sel = globalThis.getSelection();\n if (sel) {\n sel.removeAllRanges();\n sel.addRange(range);\n }\n}\n\n/**\n * Returns true if the node is inside a contenteditable root.\n * @param {Node} node\n * @returns {boolean}\n */\n/**\n * Moves a list the browser left as a direct child of another list into the item\n * it belongs to.\n *\n * `execCommand('indent')` nests a sublist as a *sibling* of the item it\n * indents — `<ul><li>a</li><ul><li>b</li></ul></ul>` — which is invalid HTML\n * that no engine repairs on re-parse. The damage is not cosmetic: a sublist\n * that is not inside an `<li>` belongs to no item, so Markdown export dropped\n * it and a round trip deleted the indented item from the document.\n *\n * Idempotent, so it is safe to run after any list mutation.\n * @param {Element|Document|null} root - subtree to repair, in place\n */\nexport function repairListNesting(root) {\n if (!root?.querySelectorAll) return;\n for (const list of root.querySelectorAll('ul > ul, ul > ol, ol > ul, ol > ol')) {\n const prev = list.previousElementSibling;\n if (prev && prev.nodeName === 'LI') {\n prev.appendChild(list);\n } else if (list.parentNode) {\n // A sublist with no item before it — give it one rather than dropping it.\n const li = list.ownerDocument.createElement('li');\n list.parentNode.insertBefore(li, list);\n li.appendChild(list);\n }\n }\n}\n\nexport function isInsideEditable(node) {\n return !!closest(node, isEditable);\n}\n\n// ---------------------------------------------------------------------------\n// Event helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Adds an event listener and returns a disposer function.\n * @param {EventTarget} target\n * @param {string} type\n * @param {EventListener} handler\n * @param {AddEventListenerOptions} [options]\n * @returns {() => void} disposer\n */\nexport function on(target, type, handler, options) {\n target.addEventListener(type, handler, options);\n return () => target.removeEventListener(type, handler, options);\n}\n\n/**\n * Installs a keyboard focus trap inside a dialog container.\n * - Tab / Shift+Tab cycles focus within the container's focusable children.\n * - Escape calls `onEscape` and removes the trap listener.\n *\n * Returns a disposer function that removes the listener (call on dialog close).\n *\n * @param {HTMLElement} container - the dialog element to trap focus inside\n * @param {() => void} onEscape - called when Escape is pressed\n * @returns {() => void} disposer\n */\nexport function trapFocus(container, onEscape) {\n const FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\n const getFocusable = () => Array.from(container.querySelectorAll(FOCUSABLE)).filter(\n (el) => !el.closest('[style*=\"display: none\"]') && !el.closest('[style*=\"display:none\"]'),\n );\n\n const handler = (e) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n onEscape?.();\n return;\n }\n if (e.key !== 'Tab') return;\n const els = getFocusable();\n if (!els.length) return;\n const first = els[0];\n const last = els.at(-1);\n if (e.shiftKey) {\n if (document.activeElement === first) {\n e.preventDefault();\n /** @type {HTMLElement} */ (last).focus();\n }\n } else if (document.activeElement === last) {\n e.preventDefault();\n /** @type {HTMLElement} */ (first).focus();\n }\n };\n\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n}\n\n/**\n * Makes a dialog box draggable by its handle element.\n * On first drag the box is pinned to its current viewport coordinates via\n * `position:fixed`, freeing it from the parent flex container's centering.\n * The position is clamped to the visible viewport.\n *\n * @param {HTMLElement} handle Element the user grabs (title bar / header)\n * @param {HTMLElement} box Element that actually moves\n * @returns {Function} Cleanup function (removes the mousedown listener)\n */\nexport function makeDraggable(handle, box) {\n handle.style.cursor = 'grab';\n\n const onMousedown = (e) => {\n if (e.button !== 0) return;\n // Don't start drag when clicking on interactive children of the handle\n if (/** @type {Element} */ (e.target).closest('button, input, select, textarea, a')) return;\n\n e.preventDefault();\n\n // First drag: snapshot position and pin to viewport with position:fixed\n if (!box.dataset.anDragPinned) {\n const r = box.getBoundingClientRect();\n box.style.position = 'fixed';\n box.style.margin = '0';\n box.style.left = `${r.left}px`;\n box.style.top = `${r.top}px`;\n box.dataset.anDragPinned = '1';\n }\n\n const startX = e.clientX - Number.parseFloat(box.style.left);\n const startY = e.clientY - Number.parseFloat(box.style.top);\n\n handle.style.cursor = 'grabbing';\n\n const onMove = (ev) => {\n const bw = box.offsetWidth;\n const bh = box.offsetHeight;\n box.style.left = `${Math.max(0, Math.min(ev.clientX - startX, globalThis.innerWidth - bw))}px`;\n box.style.top = `${Math.max(0, Math.min(ev.clientY - startY, globalThis.innerHeight - bh))}px`;\n };\n\n const onUp = () => {\n handle.style.cursor = 'grab';\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n };\n\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n };\n\n handle.addEventListener('mousedown', onMousedown);\n return () => handle.removeEventListener('mousedown', onMousedown);\n}\n","/**\n * range.js - Selection and Range utilities\n * Inspired by Summernote's range.js — rewritten as vanilla JS\n */\n\nimport { isElement, closest } from './dom.js';\n\n// ---------------------------------------------------------------------------\n// WrappedRange — a convenience wrapper over the native Range API\n// ---------------------------------------------------------------------------\n\nexport class WrappedRange {\n /**\n * @param {Node} sc - start container\n * @param {number} so - start offset\n * @param {Node} ec - end container\n * @param {number} eo - end offset\n */\n constructor(sc, so, ec, eo) {\n this.sc = sc;\n this.so = so;\n this.ec = ec;\n this.eo = eo;\n }\n\n /** @returns {boolean} */\n isCollapsed() {\n return this.sc === this.ec && this.so === this.eo;\n }\n\n /** @returns {Range} */\n toNativeRange() {\n const range = document.createRange();\n try {\n range.setStart(this.sc, this.so);\n range.setEnd(this.ec, this.eo);\n } catch (_e) {\n void _e; // guard against detached nodes\n }\n return range;\n }\n\n /**\n * Select this wrapped range in the globalThis.\n */\n select() {\n const sel = globalThis.getSelection();\n if (!sel) return;\n sel.removeAllRanges();\n sel.addRange(this.toNativeRange());\n }\n\n /**\n * Returns the common ancestor element of this range.\n * @returns {Element|null}\n */\n commonAncestor() {\n const native = this.toNativeRange();\n const ancestor = native.commonAncestorContainer;\n return /** @type {Element|null} */ (isElement(ancestor) ? ancestor : ancestor.parentElement);\n }\n\n /**\n * Returns the nearest paragraph/block ancestor within the editable area.\n * @param {HTMLElement} editable\n * @returns {Element|null}\n */\n blockNode(editable) {\n return /** @type {Element|null} */ (closest(this.sc, (n) => isElement(n) && n !== editable, editable));\n }\n\n /**\n * Returns either the selected text string or empty string.\n * @returns {string}\n */\n toString() {\n return this.toNativeRange().toString();\n }\n\n /**\n * Returns the bounding DOMRect of the range (or null).\n * @returns {DOMRect|null}\n */\n getClientRects() {\n const rects = this.toNativeRange().getClientRects();\n return rects.length > 0 ? rects[rects.length - 1] : null;\n }\n\n /**\n * Inserts a node at the start of this range.\n * @param {Node} node\n */\n insertNode(node) {\n const native = this.toNativeRange();\n native.insertNode(node);\n }\n\n}\n\n// ---------------------------------------------------------------------------\n// Factory helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a WrappedRange from a native Range object.\n * @param {Range} range\n * @returns {WrappedRange}\n */\nexport function fromNativeRange(range) {\n return new WrappedRange(\n range.startContainer,\n range.startOffset,\n range.endContainer,\n range.endOffset,\n );\n}\n\n/**\n * Returns a WrappedRange for the current globalThis selection,\n * optionally restricted to a given editable element.\n * @param {HTMLElement} [editable]\n * @returns {WrappedRange|null}\n */\nexport function currentRange(editable) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const native = sel.getRangeAt(0);\n // Optionally check that the selection is inside the editable element\n if (editable && !editable.contains(native.commonAncestorContainer)) {\n return null;\n }\n return fromNativeRange(native);\n}\n\n/**\n * Creates a WrappedRange that covers the entire content of an element.\n * @param {HTMLElement} el\n * @returns {WrappedRange}\n */\nexport function rangeFromElement(el) {\n return new WrappedRange(el, 0, el, el.childNodes.length);\n}\n\n/**\n * Creates a collapsed range (cursor) at the given node / offset.\n * @param {Node} node\n * @param {number} offset\n * @returns {WrappedRange}\n */\nexport function collapsedRange(node, offset = 0) {\n return new WrappedRange(node, offset, node, offset);\n}\n\n// ---------------------------------------------------------------------------\n// Utility helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if the current selection is inside the given element.\n * @param {HTMLElement} el\n * @returns {boolean}\n */\nexport function isSelectionInside(el) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return false;\n return el.contains(sel.getRangeAt(0).commonAncestorContainer);\n}\n\n/**\n * Saves the current selection, executes fn, then restores the selection.\n * @param {Function} fn\n */\nexport function withSavedRange(fn) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) {\n fn(null);\n return;\n }\n const saved = sel.getRangeAt(0).cloneRange();\n fn(fromNativeRange(saved));\n sel.removeAllRanges();\n sel.addRange(saved);\n}\n\n/**\n * Splits the text node at the given offset and returns the two halves.\n * @param {Text} textNode\n * @param {number} offset\n * @returns {[Text, Text]}\n */\nexport function splitText(textNode, offset) {\n const after = textNode.splitText(offset);\n return [textNode, after];\n}\n","/**\n * insert.js — native replacements for the insertion `execCommand`s.\n *\n * Stage 1 of docs/EXEC_COMMAND_MIGRATION.md. `insertHTML`, `insertText` and\n * `insertHorizontalRule` are the easiest commands to leave behind: they do not\n * have to reason about overlapping inline formatting the way `bold` or\n * `fontName` do, so a Range-based implementation is a straight substitution\n * rather than a rewrite of the formatting model.\n *\n * Each function returns `false` when there is no usable selection, which is the\n * caller's signal to fall back to `document.execCommand`. That keeps the\n * compatibility adapter the migration doc asks for: nothing silently stops\n * working while the native paths are proven in browsers.\n *\n * The HTML given to `insertHTMLNative` is inserted as-is — callers sanitise\n * first, exactly as they did before.\n */\n\n/**\n * The nearest ancestor that makes `node` editable, if there is one.\n *\n * Reads the attribute and falls back to the property, rather than using\n * `isContentEditable`: jsdom implements neither `isContentEditable` nor the\n * property/attribute reflection, so an editable built with\n * `el.contentEditable = 'true'` is only visible through the property there, and\n * one built from markup only through the attribute.\n * @param {Node|null} node\n * @returns {Element|null}\n */\nfunction _editableHost(node) {\n let cur = node && node.nodeType === 1 ? /** @type {Element} */ (node) : node?.parentElement;\n while (cur) {\n const flag = cur.getAttribute?.('contenteditable') ?? /** @type {HTMLElement} */ (cur).contentEditable;\n if (flag === 'false') return null;\n // 'inherit' is the browser's answer for ordinary elements: keep climbing.\n if (flag != null && flag !== 'inherit') return cur;\n cur = cur.parentElement;\n }\n return null;\n}\n\n/**\n * The current selection range, but only when it is somewhere these functions\n * may write to.\n *\n * With an explicit `editable` that means inside it; without one it means inside\n * *some* contenteditable host. The second check matters: `Style.execCommand`\n * does not know which editor it is acting for, and `document.execCommand` is\n * itself a no-op when the selection sits outside editable content. Without the\n * check a stale selection elsewhere in the page would have the native path\n * cheerfully insert into it.\n * @param {HTMLElement|Document} [editable]\n * @returns {Range|null}\n */\nfunction _usableRange(editable) {\n const sel = globalThis.getSelection?.();\n if (!sel || sel.rangeCount === 0) return null;\n const range = sel.getRangeAt(0);\n if (editable && editable !== document) {\n const root = /** @type {HTMLElement} */ (editable);\n return root.contains(range.commonAncestorContainer) ? range : null;\n }\n return _editableHost(range.commonAncestorContainer) ? range : null;\n}\n\n/**\n * Collapses the selection immediately after `node`.\n * @param {Node} node\n */\nfunction _caretAfter(node) {\n const sel = globalThis.getSelection?.();\n if (!sel) return;\n const range = document.createRange();\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * Replaces the selection with `html`.\n * @param {string} html - already sanitised by the caller\n * @param {HTMLElement} [editable] - restricts the operation to this subtree\n * @returns {boolean} false when there is no usable selection\n */\nexport function insertHTMLNative(html, editable) {\n const range = _usableRange(editable);\n if (!range) return false;\n\n const template = document.createElement('template');\n template.innerHTML = html;\n const fragment = template.content;\n // Held before insertion: appending the fragment empties it.\n const lastNode = fragment.lastChild;\n\n range.deleteContents();\n range.insertNode(fragment);\n\n if (lastNode) _caretAfter(lastNode);\n return true;\n}\n\n/**\n * Replaces the selection with literal text.\n *\n * A newline becomes a `<br>`, which is what execCommand did and what\n * contenteditable expects — a raw \"\\n\" in a text node renders as a space.\n * @param {string} text\n * @param {HTMLElement} [editable]\n * @returns {boolean} false when there is no usable selection\n */\nexport function insertTextNative(text, editable) {\n const range = _usableRange(editable);\n if (!range) return false;\n\n range.deleteContents();\n\n const value = String(text);\n const fragment = document.createDocumentFragment();\n\n // Inside preformatted content a newline is a newline; everywhere else it has\n // to become a <br>, because a raw \"\\n\" in a text node renders as a space.\n if (!value.includes('\\n') || _inPreformatted(range.startContainer, editable)) {\n fragment.appendChild(document.createTextNode(value));\n } else {\n value.split('\\n').forEach((line, i) => {\n if (i > 0) fragment.appendChild(document.createElement('br'));\n if (line) fragment.appendChild(document.createTextNode(line));\n });\n }\n\n const lastNode = fragment.lastChild;\n range.insertNode(fragment);\n if (lastNode) _caretAfter(lastNode);\n return true;\n}\n\n/**\n * Inserts a soft line break without relying on execCommand('insertLineBreak').\n * Kept as a named operation so callers do not have to encode editing semantics\n * as an HTML string.\n * @param {HTMLElement} [editable]\n * @returns {boolean} false when there is no usable selection\n */\nexport function insertLineBreakNative(editable) {\n return insertTextNative('\\n', editable);\n}\n\n/**\n * True when `node` sits in content that preserves whitespace.\n *\n * Checks the tag first because jsdom does not apply the UA stylesheet's\n * `white-space: pre` to `<pre>`, so the computed style alone would miss it.\n * @param {Node} node\n * @param {HTMLElement} [editable]\n * @returns {boolean}\n */\nfunction _inPreformatted(node, editable) {\n let cur = node.nodeType === 1 ? /** @type {Element} */ (node) : node.parentElement;\n while (cur && cur !== editable) {\n if (cur.tagName === 'PRE' || cur.tagName === 'TEXTAREA') return true;\n const ws = globalThis.getComputedStyle?.(cur)?.whiteSpace;\n if (ws && ws.startsWith('pre')) return true;\n cur = cur.parentElement;\n }\n return false;\n}\n\n/**\n * Inserts a horizontal rule at the selection.\n *\n * The rule is placed after the block the caret is in rather than inside it, and\n * a paragraph follows it so there is somewhere to type — a bare `<hr>` at the\n * end of the document leaves the caret with nowhere to go.\n * @param {HTMLElement} [editable]\n * @returns {boolean} false when there is no usable selection\n */\nexport function insertHorizontalRuleNative(editable) {\n const range = _usableRange(editable);\n if (!range) return false;\n\n const hr = document.createElement('hr');\n range.deleteContents();\n\n const block = _closestBlock(range.startContainer, editable);\n if (block && block.parentNode) {\n block.parentNode.insertBefore(hr, block.nextSibling);\n } else {\n range.insertNode(hr);\n }\n\n let after = hr.nextElementSibling;\n if (!after || after.tagName === 'HR') {\n const p = document.createElement('p');\n p.appendChild(document.createElement('br'));\n hr.parentNode?.insertBefore(p, hr.nextSibling);\n after = p;\n }\n\n const sel = globalThis.getSelection?.();\n if (sel) {\n const caret = document.createRange();\n caret.setStart(after, 0);\n caret.collapse(true);\n sel.removeAllRanges();\n sel.addRange(caret);\n }\n return true;\n}\n\nconst BLOCK_TAGS = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE', 'PRE', 'LI']);\n\n/**\n * Nearest block-level ancestor of `node`, stopping at `editable`.\n * @param {Node} node\n * @param {HTMLElement} [editable]\n * @returns {Element|null}\n */\nfunction _closestBlock(node, editable) {\n let cur = node.nodeType === 1 ? /** @type {Element} */ (node) : node.parentElement;\n while (cur && cur !== editable) {\n if (BLOCK_TAGS.has(cur.tagName)) return cur;\n cur = cur.parentElement;\n }\n return null;\n}\n","/**\n * Style.js - Inline / block style detection and application utilities\n * Rewritten from Summernote's approach using vanilla JS + execCommand fallback\n */\n\nimport { closest, isElement, isPara, repairListNesting } from '../core/dom.js';\nimport { currentRange } from '../core/range.js';\nimport {\n insertHTMLNative, insertTextNative, insertLineBreakNative, insertHorizontalRuleNative,\n} from './insert.js';\n\n// ---------------------------------------------------------------------------\n// execCommand wrappers (still the most compatible way in contenteditable)\n// ---------------------------------------------------------------------------\n\n/**\n * Applies a document execCommand.\n * @param {string} cmd\n * @param {string} [value]\n * @returns {boolean}\n */\nexport function execCommand(cmd, value = null) {\n // Stage 1 of the execCommand migration: the three insertion commands have\n // native Range-based implementations. They are tried first and report false\n // when there is no usable selection, in which case the deprecated command\n // still runs — the compatibility adapter docs/EXEC_COMMAND_MIGRATION.md calls\n // for, so nothing stops working while the native paths are proven.\n if (cmd === 'insertHTML' && insertHTMLNative(String(value ?? ''))) return true;\n if (cmd === 'insertText' && insertTextNative(String(value ?? ''))) return true;\n if (cmd === 'insertLineBreak' && insertLineBreakNative()) return true;\n if (cmd === 'insertHorizontalRule' && insertHorizontalRuleNative()) return true;\n return document.execCommand(cmd, false, value);\n}\n\n// ---------------------------------------------------------------------------\n// Inline style helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Bolds / unbolds the selection.\n */\nexport const bold = () => execCommand('bold');\n\n/**\n * Italicises / un-italicises the selection.\n */\nexport const italic = () => execCommand('italic');\n\n/**\n * Underlines / un-underlines the selection.\n * Falls back to manual DOM manipulation when inside <code> where\n * execCommand's state detection is unreliable.\n */\nexport function underline() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n let container = sel.getRangeAt(0).commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n // Check if we're inside a <u> (DOM truth), to guard against unreliable queryCommandState\n const uEl = /** @type {Element|null} */ (container)?.closest('u');\n const nativeState = document.queryCommandState('underline');\n if (uEl && !nativeState) {\n // Browser doesn't recognise the underline state (e.g. inside <code>).\n // Manually unwrap the <u> element.\n const parent = uEl.parentNode;\n while (uEl.firstChild) parent.insertBefore(uEl.firstChild, uEl);\n uEl.remove();\n return;\n }\n execCommand('underline');\n}\n\n/**\n * Strikethrough / removes strikethrough.\n * Falls back to manual DOM manipulation inside nested formats where\n * execCommand's state detection is unreliable (mirrors underline() logic).\n */\nexport function strikethrough() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n // Use startContainer for consistent detection across collapsed and range\n // selections — commonAncestorContainer can miss ancestor <s>/<strike> tags\n // when the selection spans across nested inline elements.\n let sc = sel.getRangeAt(0).startContainer;\n if (sc.nodeType === 3) sc = sc.parentElement;\n const sEl = /** @type {Element|null} */ (sc)?.closest('s') || /** @type {Element|null} */ (sc)?.closest('strike');\n const nativeState = document.queryCommandState('strikeThrough');\n if (sEl && !nativeState) {\n // Browser doesn’t recognise the strikethrough state (e.g. inside <code>\n // or deeply nested inline formats). Manually unwrap the <s>/<strike>.\n const parent = sEl.parentNode;\n while (sEl.firstChild) parent.insertBefore(sEl.firstChild, sEl);\n sEl.remove();\n return;\n }\n execCommand('strikeThrough');\n}\n\n/**\n * Superscript toggle.\n */\nexport const superscript = () => execCommand('superscript');\n\n/**\n * Subscript toggle.\n */\nexport const subscript = () => execCommand('subscript');\n\n/**\n * Sets the foreground colour of the selected text.\n * @param {string} color - CSS colour string\n */\nexport const foreColor = (color) => execCommand('foreColor', color);\n\n/**\n * Sets the background (highlight) colour of the selected text.\n * @param {string} color - CSS colour string\n */\nexport const backColor = (color) => execCommand('hiliteColor', color);\n\n/**\n * Sets the font name for the selection.\n * @param {string} name\n */\nexport const fontName = (name) => execCommand('fontName', name);\n\n/**\n * Sets the font size (in pt or with unit) for the selection.\n * Uses a span-based approach to set px sizes precisely.\n * @param {string} size - e.g. '14px'\n * @param {HTMLElement|Document} [editable] - scoping element to avoid touching nodes outside this editor\n */\nexport function fontSize(size, editable = document) {\n const sel = globalThis.getSelection();\n const wasCollapsed = !sel?.rangeCount || sel.getRangeAt(0).collapsed;\n\n // B-I-3/4: For a collapsed (caret) selection the browser's execCommand\n // 'fontSize' leaves an internal \"pending\" state of size-7 (=48px) instead of\n // creating a <font> element, so the very next typed character comes out at\n // 48px. Fix: bypass execCommand entirely for collapsed selections and directly\n // insert a span with the requested size, placing the cursor inside it.\n // Only applies when there IS an active selection (sel.rangeCount > 0); when\n // there is no selection at all (e.g. jsdom unit tests) fall through to the\n // execCommand path so the font-replacement logic still runs.\n if (wasCollapsed && sel?.rangeCount > 0) {\n try {\n const range = sel.getRangeAt(0);\n const span = document.createElement('span');\n span.style.fontSize = size;\n const zwsNode = document.createTextNode('\\u200B');\n span.appendChild(zwsNode);\n range.insertNode(span);\n const nr = document.createRange();\n nr.setStart(zwsNode, zwsNode.textContent.length);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n } catch (_) { void _; /* ignore range errors on unusual DOM structures */ }\n return;\n }\n\n // Non-collapsed selection (or no selection — handles jsdom test setup where\n // <font size=\"7\"> elements are injected directly without a live selection):\n // use execCommand placeholder approach then replace <font> with <span>.\n execCommand('fontSize', '7');\n const scope = editable instanceof HTMLElement ? editable : document;\n const newSpans = [];\n scope.querySelectorAll('font[size=\"7\"]').forEach((el) => {\n const span = document.createElement('span');\n span.style.fontSize = size;\n el.parentNode.insertBefore(span, el);\n while (el.firstChild) span.appendChild(el.firstChild);\n el.remove();\n newSpans.push(span);\n });\n\n // Re-select all replaced content so toolbar getValue() reads the new size\n // (B-I-1/2: without this re-selection the toolbar dropdown stays on the old\n // value until the next selectionchange event).\n if (!wasCollapsed && sel && newSpans.length > 0) {\n const first = newSpans[0];\n const last = newSpans.at(-1);\n try {\n const nr = document.createRange();\n const startNode = first.firstChild || first;\n const endNode = last.lastChild || last;\n nr.setStart(startNode, 0);\n nr.setEnd(endNode, endNode.nodeType === Node.TEXT_NODE ? endNode.textContent.length : endNode.childNodes.length);\n sel.removeAllRanges();\n sel.addRange(nr);\n } catch (_) { void _; /* ignore range errors on unusual DOM structures */ }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Block style helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Wraps the selection in the given block tag (p, h1-h6, blockquote, pre).\n * @param {string} tagName\n */\nexport const formatBlock = (tagName) => execCommand('formatBlock', `<${tagName}>`);\n\n/**\n * Left-aligns the current block.\n */\nexport const justifyLeft = () => execCommand('justifyLeft');\n\n/**\n * Center-aligns the current block.\n */\nexport const justifyCenter = () => execCommand('justifyCenter');\n\n/**\n * Right-aligns the current block.\n */\nexport const justifyRight = () => execCommand('justifyRight');\n\n/**\n * Fully justifies the current block.\n */\nexport const justifyFull = () => execCommand('justifyFull');\n\n/**\n * Indents the list or block.\n */\nexport function indent() {\n execCommand('indent');\n // execCommand leaves the new sublist as a sibling of the item it indented.\n // Repair it here rather than teaching every consumer of the HTML about a\n // shape the spec does not allow — see repairListNesting.\n repairListNesting(_selectionListRoot());\n}\n\n/**\n * The outermost list containing the selection, or null when there is none.\n * @returns {Element|null}\n */\nfunction _selectionListRoot() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return null;\n let node = sel.getRangeAt(0).commonAncestorContainer;\n if (node.nodeType === 3) node = node.parentElement;\n let outermost = null;\n for (let cur = /** @type {Element|null} */ (node); cur; cur = cur.parentElement) {\n if (cur.nodeName === 'UL' || cur.nodeName === 'OL') outermost = cur;\n }\n return outermost;\n}\n\n/**\n * Outdents the list or block.\n * G.5: When cursor is inside a checklist item, \"outdent\" means converting\n * that item back to a regular <p> element rather than calling execCommand\n * (which would destroy the ul > li checklist structure).\n */\nexport function outdent() {\n const sel = globalThis.getSelection();\n if (sel?.rangeCount) {\n let container = sel.getRangeAt(0).commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n const checkLi = /** @type {Element|null} */ (container)?.closest('.an-checklist li');\n if (checkLi) {\n _checklistItemToP(/** @type {HTMLElement} */ (checkLi));\n return;\n }\n }\n if (_outdentNestedItem()) return;\n execCommand('outdent');\n}\n\n/**\n * Lifts the list item holding the caret out of its sublist, in the DOM.\n *\n * `execCommand('outdent')` does not agree across engines here. Firefox\n * dissolves the item into the one above it — `<li>a<ul><li>b</li></ul></li>`\n * becomes `<li>a<br>b</li>`, so three items turn into two and the Markdown\n * comes out as a hard line break inside the first. Chromium restores the item.\n * Indent is symmetric on every engine now, so outdent has to be too.\n *\n * Only the nested case is handled here; outdenting a top-level item into a\n * paragraph still goes through execCommand, where the engines agree.\n * @returns {boolean} false when the caret is not in a nested list item\n */\nfunction _outdentNestedItem() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return false;\n\n let node = sel.getRangeAt(0).startContainer;\n if (node.nodeType === 3) node = node.parentElement;\n const li = /** @type {Element|null} */ (node)?.closest?.('li');\n if (!li) return false;\n\n const sublist = li.parentElement;\n if (!sublist || (sublist.nodeName !== 'UL' && sublist.nodeName !== 'OL')) return false;\n\n const outerItem = sublist.parentElement;\n if (!outerItem || outerItem.nodeName !== 'LI' || !outerItem.parentNode) return false;\n\n // Items below this one stay below it, nested under it — outdenting one item\n // must not promote the rest of the sublist with it.\n const following = [];\n for (let next = li.nextElementSibling; next; next = next.nextElementSibling) following.push(next);\n if (following.length) {\n const carrier = li.ownerDocument.createElement(sublist.nodeName.toLowerCase());\n following.forEach((item) => carrier.appendChild(item));\n li.appendChild(carrier);\n }\n\n outerItem.parentNode.insertBefore(li, outerItem.nextSibling);\n if (!sublist.children.length) sublist.remove();\n return true;\n}\n\n/**\n * Convert a checklist <li> into a paragraph and move any following items into a new checklist.\n *\n * Preserves inline markup from the converted item, strips zero-width space anchors,\n * and replaces empty content with a non‑breaking space. If there are list items\n * after the converted item they are moved into a new <ul class=\"an-checklist\">\n * inserted immediately after the original list. The original <li> is removed and\n * the original list is removed if it becomes empty. Attempts to place the caret\n * at the start of the newly created <p>.\n * @param {HTMLElement} checkLi - The checklist `<li>` element to convert to a `<p>`.\n */\nfunction _checklistItemToP(checkLi) {\n const checkUl = checkLi.closest('.an-checklist');\n if (!checkUl) return;\n\n const allLis = Array.from(checkUl.children);\n const liIndex = allLis.indexOf(checkLi);\n const afterLis = allLis.slice(liIndex + 1);\n\n // Build <p> preserving inline formatting (bold/italic/links) from the item's content\n const p = document.createElement('p');\n for (const child of checkLi.childNodes) {\n if (child.nodeType === 1 && /** @type {Element} */ (child).tagName === 'INPUT') continue;\n p.appendChild(child.cloneNode(true));\n }\n // Strip ZWS anchors left over from checklist markup\n p.innerHTML = p.innerHTML.replaceAll('\\u200B', '');\n if (!p.hasChildNodes() || !p.textContent.trim()) {\n p.innerHTML = '';\n p.appendChild(document.createTextNode('\\u00a0'));\n }\n\n // Move items after the current li into a new checklist\n if (afterLis.length > 0) {\n const newUl = document.createElement('ul');\n newUl.className = 'an-checklist';\n afterLis.forEach(li => newUl.appendChild(li));\n checkUl.parentNode.insertBefore(newUl, checkUl.nextSibling);\n }\n\n // Insert <p> after checkUl (before any newUl)\n checkUl.parentNode.insertBefore(p, checkUl.nextSibling);\n\n // Remove current li from checkUl; delete checkUl if now empty\n checkLi.remove();\n if (checkUl.children.length === 0) checkUl.remove();\n\n // Place caret at start of the new <p>\n try {\n const nr = document.createRange();\n const firstChild = p.firstChild;\n nr.setStart(firstChild?.nodeType === 3 ? firstChild : p, 0);\n nr.collapse(true);\n const s = globalThis.getSelection();\n if (s) { s.removeAllRanges(); s.addRange(nr); }\n } catch {}\n}\n\n/**\n * Inserts an unordered (bulleted) list, or converts the current list to `<ul>`.\n *\n * When the cursor is already inside a list, direct DOM manipulation is used to\n * transition between list types — `execCommand` alone cannot handle checklist →\n * UL/OL conversions because it has no awareness of the `an-checklist` class or\n * the checkbox `<input>` elements.\n *\n * Transition paths:\n * - **Checklist → UL**: strips `an-checklist` class and all checkbox inputs;\n * converts `<ol>` container to `<ul>` via `changeTagName()` if needed.\n * - **OL → UL**: swaps the container tag via `changeTagName()`.\n * - **UL → paragraphs**: falls back to `execCommand('insertUnorderedList')`\n * which toggles the list off (browser-native behaviour).\n * - **No list → UL**: falls back to `execCommand('insertUnorderedList')`.\n */\n/**\n * Helper to get the closest ul/ol element containing the current selection.\n * @returns {Element|null}\n */\nfunction getSelectedList() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return null;\n let container = sel.getRangeAt(0).commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n return /** @type {Element|null} */ (container)?.closest('ul, ol') || null;\n}\n\n/**\n * Strips the checklist class and checkbox inputs from a list element.\n * @param {Element} listEl\n */\nfunction stripChecklist(listEl) {\n listEl.classList.remove('an-checklist');\n listEl.querySelectorAll('input[type=\"checkbox\"]').forEach(cb => cb.remove());\n}\n\nexport function insertUnorderedList() {\n const listEl = getSelectedList();\n if (listEl) {\n if (listEl.classList.contains('an-checklist')) {\n // Checklist → UL: strip checkboxes and class, swap tag if needed\n stripChecklist(listEl);\n if (listEl.tagName === 'OL') {\n changeTagName(listEl, 'ul');\n }\n } else if (listEl.tagName === 'OL') {\n // OL → UL: swap container tag\n changeTagName(listEl, 'ul');\n } else {\n // Already UL → toggle off via execCommand\n execCommand('insertUnorderedList');\n }\n } else {\n // Not in a list → create new UL via execCommand\n execCommand('insertUnorderedList');\n }\n}\n\n/**\n * Inserts an ordered (numbered) list, or converts the current list to `<ol>`.\n *\n * When the cursor is already inside a list, direct DOM manipulation is used to\n * transition between list types — `execCommand` alone cannot handle checklist →\n * UL/OL conversions because it has no awareness of the `an-checklist` class or\n * the checkbox `<input>` elements.\n *\n * Transition paths:\n * - **Checklist → OL**: strips `an-checklist` class and all checkbox inputs;\n * converts container to `<ol>` via `changeTagName()`.\n * - **UL → OL**: swaps the container tag via `changeTagName()`.\n * - **OL → paragraphs**: falls back to `execCommand('insertOrderedList')`\n * which toggles the list off (browser-native behaviour).\n * - **No list → OL**: falls back to `execCommand('insertOrderedList')`.\n */\nexport function insertOrderedList() {\n const listEl = getSelectedList();\n if (listEl) {\n if (listEl.classList.contains('an-checklist')) {\n // Checklist → OL: strip checkboxes and class, swap to <ol>\n stripChecklist(listEl);\n changeTagName(listEl, 'ol');\n } else if (listEl.tagName === 'UL') {\n // UL → OL: swap container tag\n changeTagName(listEl, 'ol');\n } else {\n // Already OL → toggle off via execCommand\n execCommand('insertOrderedList');\n }\n } else {\n // Not in a list → create new OL via execCommand\n execCommand('insertOrderedList');\n }\n}\n\n// ---------------------------------------------------------------------------\n// Line-height helper\n// ---------------------------------------------------------------------------\n\n/**\n * Set the line-height on every block-level element that intersects the current selection.\n *\n * If the selection is collapsed, the nearest enclosing block element receives the style.\n * For a non-collapsed selection, all unique block ancestors of text nodes that intersect the range are updated;\n * if none are found, the nearest block ancestor of the range's common ancestor is updated.\n * @param {string} value - Line-height value to apply; typically a unitless multiplier (for example, \"1.5\").\n */\nexport function lineHeight(value) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n\n const range = sel.getRangeAt(0);\n const BLOCK_TAGS = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI', 'BLOCKQUOTE', 'PRE', 'TD', 'TH']);\n\n const nearestBlock = (node) => {\n let el = node instanceof Element ? node : node.parentElement;\n while (el) {\n if (BLOCK_TAGS.has(el.tagName)) return el;\n el = el.parentElement;\n }\n return null;\n };\n\n if (range.collapsed) {\n const block = nearestBlock(range.startContainer);\n if (block) block.style.lineHeight = value;\n return;\n }\n\n // For a range selection, collect all unique block ancestors of text nodes\n const blocks = new Set();\n const iter = document.createTreeWalker(\n range.commonAncestorContainer,\n NodeFilter.SHOW_TEXT,\n { acceptNode: (node) => range.intersectsNode(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP },\n );\n let textNode;\n while ((textNode = iter.nextNode())) {\n const block = nearestBlock(textNode);\n if (block) blocks.add(block);\n }\n if (blocks.size === 0) {\n const block = nearestBlock(range.commonAncestorContainer);\n if (block) blocks.add(block);\n }\n blocks.forEach((block) => { block.style.lineHeight = value; });\n}\n\n// ---------------------------------------------------------------------------\n// Style query helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the computed styles relevant to the current cursor position.\n * @param {HTMLElement} editable\n * @returns {object} styleMap\n */\nexport function currentStyle(editable) {\n const range = currentRange(editable);\n if (!range) return {};\n\n const container = range.isCollapsed()\n ? range.sc\n : range.commonAncestor();\n\n const el = /** @type {Element|null} */ (isElement(container) ? container : container.parentElement);\n if (!el) return {};\n\n const computed = globalThis.getComputedStyle(el);\n\n return {\n bold: document.queryCommandState('bold'),\n italic: document.queryCommandState('italic'),\n underline: document.queryCommandState('underline'),\n strikethrough: document.queryCommandState('strikeThrough'),\n superscript: document.queryCommandState('superscript'),\n subscript: document.queryCommandState('subscript'),\n fontSize: computed.fontSize,\n fontFamily: computed.fontFamily,\n color: computed.color,\n backgroundColor: computed.backgroundColor,\n textAlign: computed.textAlign,\n lineHeight: computed.lineHeight,\n formatBlock: (closest(el, isPara, editable) || { nodeName: 'p' }).nodeName.toLowerCase(),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Inline code toggle\n// ---------------------------------------------------------------------------\n\n/**\n * Wraps the selection in an inline <code> element, or unwraps it if the\n * cursor is already inside a <code> that is not inside a <pre>.\n * @param {HTMLElement} [_editable]\n */\nexport function toggleInlineCode(_editable) {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n const range = sel.getRangeAt(0);\n let container = range.commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n const codeEl = /** @type {Element|null} */ (container)?.closest('code');\n if (codeEl && !codeEl.closest('pre')) {\n // Unwrap — save range endpoints relative to surrounding text so we can\n // restore the selection after normalize() merges adjacent text nodes.\n const parent = codeEl.parentNode;\n // Note the sibling before the code element so we can re-anchor later.\n const prevSibling = codeEl.previousSibling;\n const movedChildren = Array.from(codeEl.childNodes);\n while (codeEl.firstChild) parent.insertBefore(codeEl.firstChild, codeEl);\n codeEl.remove();\n // Normalize only the immediate parent to merge adjacent text nodes without\n // invalidating distant selection anchors (full editable.normalize() can\n // cause selection offsets to shift, making subsequent format toggles miss).\n parent?.normalize();\n // Restore selection to the text that was inside the unwrapped <code>.\n if (movedChildren.length > 0) {\n try {\n // After normalize, find the merged text node that contains the content.\n const firstMoved = movedChildren[0];\n const lastMoved = movedChildren.at(-1);\n const nr = document.createRange();\n // Use the (possibly merged) live node if still in the DOM.\n const anchorNode = firstMoved.parentNode === parent\n ? firstMoved\n : (prevSibling ? prevSibling.nextSibling : parent.firstChild);\n if (anchorNode) {\n nr.setStart(anchorNode, 0);\n const endAnchor = (lastMoved.parentNode === parent) ? lastMoved : anchorNode;\n nr.setEnd(endAnchor, endAnchor.nodeType === Node.TEXT_NODE ? endAnchor.textContent.length : endAnchor.childNodes.length);\n sel.removeAllRanges();\n sel.addRange(nr);\n }\n } catch (_) { void _; /* ignore */ }\n }\n } else {\n if (range.collapsed) return;\n try {\n const code = document.createElement('code');\n range.surroundContents(code);\n // Re-select wrapped content so subsequent format toggles work\n const newRange = document.createRange();\n newRange.selectNodeContents(code);\n sel.removeAllRanges();\n sel.addRange(newRange);\n } catch {\n // surroundContents fails across element boundaries — extract and rewrap\n const frag = range.extractContents();\n const code = document.createElement('code');\n code.appendChild(frag);\n range.insertNode(code);\n // Re-select wrapped content\n const newRange = document.createRange();\n newRange.selectNodeContents(code);\n sel.removeAllRanges();\n sel.addRange(newRange);\n }\n }\n}\n\n/**\n * Returns true when the cursor / selection is inside an inline <code>\n * (not nested in a <pre>).\n * Uses startContainer for reliable cross-browser detection regardless of\n * whether the selection is collapsed or a range (commonAncestorContainer\n * can behave inconsistently for range selections on some browsers).\n * @returns {boolean}\n */\nexport function isInlineCode() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return false;\n let sc = sel.getRangeAt(0).startContainer;\n if (sc.nodeType === 3) sc = sc.parentElement;\n const code = /** @type {Element|null} */ (sc)?.closest('code');\n return !!(code && !code.closest('pre'));\n}\n\n// ---------------------------------------------------------------------------\n// Checklist (task list)\n// ---------------------------------------------------------------------------\n\n/**\n * Changes the tag name of an element in the DOM while preserving attributes and children.\n * @param {Element} el\n * @param {string} newTagName\n * @returns {HTMLElement}\n */\nfunction changeTagName(el, newTagName) {\n const newEl = document.createElement(newTagName);\n for (const attr of el.attributes) {\n newEl.setAttribute(attr.name, attr.value);\n }\n while (el.firstChild) {\n newEl.appendChild(el.firstChild);\n }\n el.parentNode.replaceChild(newEl, el);\n return newEl;\n}\n\n/**\n * Ensures all list items under the list element have a checkbox.\n * @param {Element} listEl\n */\nfunction ensureCheckboxes(listEl) {\n listEl.querySelectorAll('li').forEach(li => {\n const existingCb = li.querySelector('input[type=\"checkbox\"]');\n if (!existingCb) {\n const cb = document.createElement('input');\n cb.type = 'checkbox';\n cb.contentEditable = 'false';\n li.insertBefore(cb, li.firstChild);\n }\n });\n}\n\n/**\n * Toggle a checklist at the current selection or caret.\n */\nexport function toggleChecklist() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n const range = sel.getRangeAt(0);\n let container = range.commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n\n const listEl = /** @type {Element|null} */ (container)?.closest('ul, ol');\n if (listEl) {\n if (listEl.classList.contains('an-checklist')) {\n // Transition from Checklist to Paragraphs (Toggle off checklist entirely)\n const parent = listEl.parentNode;\n if (parent) {\n const lis = Array.from(listEl.children);\n let /** @type {HTMLParagraphElement|null} */ firstP = null;\n lis.forEach(li => {\n const p = document.createElement('p');\n for (const child of li.childNodes) {\n if (child.nodeType === 1 && /** @type {Element} */ (child).tagName === 'INPUT') continue;\n p.appendChild(child.cloneNode(true));\n }\n p.innerHTML = p.innerHTML.replaceAll('\\u200b', '').replaceAll('\\u200B', '');\n if (!p.hasChildNodes() || !p.textContent.trim()) {\n p.innerHTML = '';\n p.appendChild(document.createTextNode('\\u00a0'));\n }\n listEl.before(p);\n if (!firstP) firstP = p;\n });\n listEl.remove();\n \n if (firstP) {\n const nr = document.createRange();\n nr.setStart(firstP.firstChild || firstP, 0);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n }\n }\n } else {\n // Transition from standard UL/OL to Checklist\n const targetUl = changeTagName(listEl, 'ul');\n targetUl.classList.add('an-checklist');\n ensureCheckboxes(targetUl);\n \n // Place caret inside the first LI\n const firstLi = targetUl.querySelector('li');\n if (firstLi) {\n const nr = document.createRange();\n nr.selectNodeContents(firstLi);\n nr.collapse(false);\n sel.removeAllRanges();\n sel.addRange(nr);\n }\n }\n } else {\n // Selection is not in a list: build the checklist directly via DOM\n // manipulation. execCommand('insertUnorderedList') is intentionally\n // avoided here — its behaviour on collapsed/empty selections and\n // non-standard blocks (e.g. <section>) is too inconsistent across\n // browsers (and a no-op in jsdom), which left toggleChecklist() as a\n // silent no-op in those cases.\n // The editable root itself is a <div> and must never be treated as a\n // \"block\" to convert/replace/remove — otherwise selections that include\n // raw text nodes sitting directly inside it (e.g. the first line typed\n // into an empty editor) would destroy the .an-editable element.\n const editableRoot = /** @type {Element|null} */ (container)?.closest('[contenteditable=\"true\"]');\n const isCollapsed = range.collapsed;\n if (isCollapsed) {\n // Find the nearest block-level ancestor (p, div, li, h1-h6, blockquote,\n // etc.) and convert it into a single checklist item.\n const BLOCK_TAGS = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE', 'LI']);\n let block = /** @type {Element|null} */ (container);\n while (block?.parentNode && block !== editableRoot && !BLOCK_TAGS.has(block.tagName)) {\n block = /** @type {Element|null} */ (block.parentNode);\n }\n if (block === editableRoot) block = null;\n // Fallback: if no block element found (e.g. cursor directly in editable\n // root), insert a fresh item with a zero-width-space so the cursor ends\n // up inside it.\n const itemText = (block && BLOCK_TAGS.has(block.tagName))\n ? Array.from(block.childNodes)\n .map((n) => n.textContent)\n .join('')\n .replaceAll('\\u00a0', ' ')\n : '';\n\n const newUl = document.createElement('ul');\n newUl.className = 'an-checklist';\n const li = document.createElement('li');\n const checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.contentEditable = 'false';\n li.appendChild(checkbox);\n li.appendChild(document.createTextNode(itemText || '\\u200B'));\n newUl.appendChild(li);\n\n if (block && BLOCK_TAGS.has(block.tagName)) {\n block.parentNode.replaceChild(newUl, block);\n } else {\n // Cursor directly in editable root — insert via Range API.\n const nativeRange = sel.getRangeAt(0);\n nativeRange.deleteContents();\n nativeRange.insertNode(newUl);\n }\n\n // Move caret to the text node inside the new <li>.\n const textNode = li.lastChild;\n const nr = document.createRange();\n const offset = textNode.nodeType === Node.TEXT_NODE ? textNode.textContent.length : 0;\n nr.setStart(textNode, offset);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n return;\n }\n\n // Non-collapsed selection — convert each intersected block element into\n // a checklist item using direct DOM manipulation.\n const rawSelText = sel.toString().replace(/[\\u00a0\\u200B]/g, ' ').trim();\n if (!rawSelText) return;\n\n const BLOCK_TAGS_MULTI = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE', 'PRE', 'LI']);\n\n // Collect block-level ancestors of every node in the selection, in order.\n const blocks = [];\n const seenBlocks = new Set();\n const commonAncestor = range.commonAncestorContainer;\n const iter = document.createNodeIterator(\n commonAncestor.nodeType === Node.TEXT_NODE ? commonAncestor.parentNode : commonAncestor,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT,\n null,\n );\n let node;\n while ((node = iter.nextNode())) {\n if (!range.intersectsNode(node)) continue;\n let blockEl = /** @type {Element|null} */ (node.nodeType === Node.TEXT_NODE ? node.parentElement : node);\n while (blockEl && blockEl !== editableRoot && !BLOCK_TAGS_MULTI.has(blockEl.tagName)) {\n blockEl = blockEl.parentElement;\n }\n if (blockEl === editableRoot) blockEl = null;\n if (blockEl && !seenBlocks.has(blockEl)) {\n seenBlocks.add(blockEl);\n blocks.push(blockEl);\n }\n }\n\n if (blocks.length === 0) return;\n\n // Build checklist and replace collected blocks.\n const newUl = document.createElement('ul');\n newUl.className = 'an-checklist';\n /** @type {Text|null} */ let lastTextNode = null;\n blocks.forEach((block) => {\n const li = document.createElement('li');\n const cb = document.createElement('input');\n cb.type = 'checkbox';\n cb.contentEditable = 'false';\n li.appendChild(cb);\n // Preserve plain text content; ZWS/NBSP are stripped for display.\n const blockText = Array.from(block.childNodes)\n .map((n) => n.textContent)\n .join('')\n .replace(/[\\u00a0\\u200B]/g, ' ')\n .trim();\n const tn = document.createTextNode(blockText || '\\u200B');\n li.appendChild(tn);\n newUl.appendChild(li);\n lastTextNode = tn;\n });\n\n // Insert the new list before the first block, then remove all source blocks.\n const firstBlock = blocks[0];\n firstBlock.parentNode.insertBefore(newUl, firstBlock);\n blocks.forEach((block) => block.remove());\n\n // Move caret to end of the last checklist item.\n if (lastTextNode) {\n const nr = document.createRange();\n nr.setStart(lastTextNode, lastTextNode.textContent.length);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n }\n }\n}\n\n/**\n * Returns true when the cursor is inside a checklist item.\n * @returns {boolean}\n */\nexport function isInChecklist() {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return false;\n let container = sel.getRangeAt(0).commonAncestorContainer;\n if (container.nodeType === 3) container = container.parentElement;\n return !!(/** @type {Element|null} */ (container)?.closest('.an-checklist li'));\n}\n","/**\n * Buttons.js - Toolbar button definitions and factories\n * All buttons are plain objects describing their appearance and action.\n * They are rendered by the Toolbar module.\n */\n\nimport * as Style from '../editing/Style.js';\n\n// ---------------------------------------------------------------------------\n// Dropdown definition helper\n// ---------------------------------------------------------------------------\n\n/**\n * @typedef {object} DropdownDef\n * @property {string} name - unique identifier\n * @property {'select'} type - discriminator for Toolbar renderer\n * @property {string} tooltip\n * @property {Array<string|{value:string,label:string,disabled?:boolean}>} [items] - overridden at render time from options\n * @property {Function} action - called with (context, value)\n * @property {Function} [getValue] - called with (context) to get current value\n * @property {string} [selectClass] - extra CSS class(es) for the <select>\n * @property {string} [placeholder] - placeholder text for the empty option\n */\n\n// ---------------------------------------------------------------------------\n// Button factory helpers\n// ---------------------------------------------------------------------------\n\n/**\n * @typedef {object} ButtonDef\n * @property {string} name - unique identifier\n * @property {string} icon - SVG or HTML icon markup / text\n * @property {string} tooltip - tooltip string\n * @property {Function} action - called with (context) when clicked\n * @property {Function} [isActive] - called with (context) to determine active state\n * @property {Function} [isDisabled] - called with (context) to determine disabled state\n * @property {string} [className] - extra CSS class(es)\n */\n\n/**\n * Creates a simple button definition.\n * @param {string} name\n * @param {string} icon\n * @param {string} tooltip\n * @param {Function} action\n * @param {Function} [isActive]\n * @param {Function} [isDisabled]\n * @returns {ButtonDef}\n */\nfunction btn(name, icon, tooltip, action, isActive, isDisabled) {\n // `icon` is an identifier (e.g. 'bold', 'italic'). Rendering to\n // visual markup (FontAwesome or fallback) is done in Toolbar._createButton\n return { name, icon, tooltip, action, isActive, isDisabled };\n}\n\n// ---------------------------------------------------------------------------\n// Global button registry\n// ---------------------------------------------------------------------------\n\n/**\n * Global registry for custom buttons registered via AutumnNote.registerButton()\n * or via a plugin's `buttons` array. Toolbar resolves string names from here.\n * @type {Map<string, object>}\n */\nexport const _buttonRegistry = new Map();\n\n/**\n * Registers a button definition in the global registry so it can be referenced\n * by string name in toolbar configuration: `toolbar: [['myBtn', boldBtn]]`.\n * @param {object} btnDef - Any ToolbarItemDef-compatible object with a `name` string.\n */\nexport function registerButton(btnDef) {\n if (!btnDef || typeof btnDef.name !== 'string') {\n console.warn('[AutumnNote] registerButton: btnDef must have a string `name` property.');\n return;\n }\n if (_buttonRegistry.has(btnDef.name)) {\n console.warn(`[AutumnNote] registerButton: overwriting existing button \"${btnDef.name}\".`);\n }\n _buttonRegistry.set(btnDef.name, btnDef);\n}\n\n/**\n * Looks up a button definition by name from the global registry.\n * Returns undefined when not found.\n * @param {string} name\n * @returns {object|undefined}\n */\nexport function getButton(name) {\n return _buttonRegistry.get(name);\n}\n\n// ---------------------------------------------------------------------------\n// Style buttons\n// ---------------------------------------------------------------------------\n\nexport const boldBtn = btn('bold', 'bold', 'Bold (Ctrl+B)', () => Style.bold(), () => document.queryCommandState('bold'));\nexport const italicBtn = btn('italic', 'italic', 'Italic (Ctrl+I)', () => Style.italic(), () => document.queryCommandState('italic'));\nexport const underlineBtn = btn('underline', 'underline', 'Underline (Ctrl+U)', () => Style.underline(), () => {\n // queryCommandState('underline') is unreliable inside <code> elements;\n // also check for a <u> ancestor in the DOM using startContainer for\n // consistent behaviour across both collapsed and range selections.\n if (document.queryCommandState('underline')) return true;\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return false;\n let sc = sel.getRangeAt(0).startContainer;\n if (sc.nodeType === 3) sc = sc.parentElement;\n return !!(/** @type {Element} */ (sc)?.closest('u'));\n});\nexport const strikeBtn = btn('strikethrough', 'strikethrough', 'Strikethrough', () => Style.strikethrough(), () => document.queryCommandState('strikeThrough'));\nexport const superscriptBtn = btn('superscript', 'superscript', 'Superscript', () => Style.superscript(), () => document.queryCommandState('superscript'));\nexport const subscriptBtn = btn('subscript', 'subscript', 'Subscript', () => Style.subscript(), () => document.queryCommandState('subscript'));\n\n// ---------------------------------------------------------------------------\n// Alignment buttons\n// ---------------------------------------------------------------------------\n\nexport const alignLeftBtn = btn('alignLeft', 'align-left', 'Align Left', () => Style.justifyLeft());\nexport const alignCenterBtn = btn('alignCenter', 'align-center', 'Align Center', () => Style.justifyCenter());\nexport const alignRightBtn = btn('alignRight', 'align-right', 'Align Right', () => Style.justifyRight());\nexport const alignJustifyBtn = btn('alignJustify', 'align-justify', 'Justify', () => Style.justifyFull());\n\n// ---------------------------------------------------------------------------\n// List buttons\n// ---------------------------------------------------------------------------\n\nexport const ulBtn = btn('ul', 'list-ul', 'Unordered List', () => Style.insertUnorderedList());\nexport const olBtn = btn('ol', 'list-ol', 'Ordered List', () => Style.insertOrderedList());\n\n// ---------------------------------------------------------------------------\n// Indent buttons\n// ---------------------------------------------------------------------------\n\nexport const indentBtn = btn('indent', 'indent', 'Indent', () => Style.indent());\nexport const outdentBtn = btn('outdent', 'outdent', 'Outdent', () => Style.outdent());\n\n// ---------------------------------------------------------------------------\n// Undo / redo buttons\n// ---------------------------------------------------------------------------\n\nexport const undoBtn = btn('undo', 'undo', 'Undo (Ctrl+Z)', (_ctx) => _ctx.invoke('editor.undo'), undefined, (ctx) => !ctx.invoke('editor.canUndo'));\nexport const redoBtn = btn('redo', 'redo', 'Redo (Ctrl+Y)', (_ctx) => _ctx.invoke('editor.redo'), undefined, (ctx) => !ctx.invoke('editor.canRedo'));\n\n// ---------------------------------------------------------------------------\n// Insert media — HR, Link, Image\n// ---------------------------------------------------------------------------\n\nexport const hrBtn = btn('hr', 'minus', 'Horizontal Rule', () => Style.execCommand('insertHorizontalRule'));\nexport const linkBtn = btn('link', 'link', 'Insert Link', (ctx) => ctx.invoke('linkDialog.show'));\nexport const imageBtn = btn('image', 'image', 'Insert Image', (ctx) => ctx.invoke('imageDialog.show'));\nexport const videoBtn = btn('video', 'video', 'Insert Video', (ctx) => ctx.invoke('videoDialog.show'));\nexport const emojiBtn = btn('emoji', 'emoji', 'Insert Emoji', (ctx) => ctx.invoke('emojiDialog.show'));\nexport const iconBtn = btn('icon', 'icon', 'Insert FA Icon', (ctx) => ctx.invoke('iconDialog.show'));\n\n/** @type {ButtonDef & { type: 'grid' }} */\nexport const tableBtn = {\n name: 'table',\n type: 'grid',\n icon: 'table',\n tooltip: 'Insert Table',\n action: (ctx, rows, cols) => {\n ctx.invoke('editor.insertTable', cols, rows);\n ctx.invoke('editor.afterCommand');\n },\n};\n\n// ---------------------------------------------------------------------------\n// Font size dropdown\n// ---------------------------------------------------------------------------\n\n/** @type {DropdownDef} */\nexport const fontSizeBtn = {\n name: 'fontSize',\n type: 'select',\n tooltip: 'Font Size',\n placeholder: 'Size',\n selectClass: 'an-select-narrow',\n items: ['8px', '10px', '11px', '12px', '13px', '14px', '16px', '18px', '20px', '24px', '28px', '32px', '36px', '48px', '72px'],\n action: (ctx, value) => Style.fontSize(value, ctx.layoutInfo.editable),\n getValue: (ctx) => {\n try {\n const sel = globalThis.getSelection();\n if (sel?.rangeCount) {\n let el = /** @type {Element|null} */ (sel.getRangeAt(0).startContainer);\n if (el?.nodeType === 3) el = el.parentElement;\n while (el?.nodeType === 1 && !/** @type {HTMLElement} */ (el).style.fontSize) el = el.parentElement;\n const size = /** @type {HTMLElement} */ (el)?.style.fontSize || '';\n if (size) return size;\n }\n // Fallback: read the base font size from the editable element itself\n const editable = ctx?.layoutInfo?.editable;\n if (editable) return editable.style.fontSize || '';\n return '';\n } catch { return ''; }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Remove format button\n// ---------------------------------------------------------------------------\n\nexport const removeFormatBtn = btn('removeFormat', 'remove-format', 'Remove Format', () => Style.execCommand('removeFormat'));\n\n// ---------------------------------------------------------------------------\n// Direction (LTR / RTL) toggle button\n// ---------------------------------------------------------------------------\n\nexport const directionBtn = btn(\n 'direction',\n 'direction',\n 'Toggle Text Direction (LTR / RTL)',\n (ctx) => {\n const editable = ctx.layoutInfo.editable;\n const current = editable.getAttribute('dir') || 'ltr';\n const next = current === 'ltr' ? 'rtl' : 'ltr';\n editable.setAttribute('dir', next);\n editable.style.textAlign = next === 'rtl' ? 'right' : 'left';\n ctx.invoke('editor.afterCommand');\n },\n);\n\n// ---------------------------------------------------------------------------\n// Font family dropdown\n// ---------------------------------------------------------------------------\n\n/** @type {DropdownDef} */\nexport const fontFamilyBtn = {\n name: 'fontFamily',\n type: 'select',\n tooltip: 'Font Family',\n action: (ctx, value) => Style.fontName(value),\n getValue: () => {\n try { return document.queryCommandValue('fontName') || ''; } catch { return ''; }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Paragraph style dropdown (Normal / H1-H6 / Quote / Code)\n// ---------------------------------------------------------------------------\n\n/** @type {DropdownDef} */\nexport const paragraphStyleBtn = {\n name: 'paragraphStyle',\n type: 'select',\n tooltip: 'Paragraph Style',\n placeholder: 'Style',\n selectClass: 'an-select-style',\n items: [\n { value: 'p', label: 'Normal' },\n { value: 'h1', label: 'H1' },\n { value: 'h2', label: 'H2' },\n { value: 'h3', label: 'H3' },\n { value: 'h4', label: 'H4' },\n { value: 'h5', label: 'H5' },\n { value: 'h6', label: 'H6' },\n { value: 'blockquote', label: 'Quote' },\n { value: 'pre', label: 'Code' },\n ],\n action: (_ctx, value) => Style.formatBlock(value),\n getValue: () => {\n try {\n const raw = document.queryCommandValue('formatBlock').toLowerCase().replace(/[<>]/g, '');\n return raw === 'div' ? 'p' : (raw || 'p');\n } catch { return ''; }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Line-height dropdown\n// ---------------------------------------------------------------------------\n\n/** @type {DropdownDef} */\nexport const lineHeightBtn = {\n name: 'lineHeight',\n type: 'select',\n tooltip: 'Line Height',\n placeholder: '\\u2195 Line',\n selectClass: 'an-select-narrow',\n items: ['1.0', '1.15', '1.5', '1.75', '2.0', '2.5', '3.0'],\n action: (_ctx, value) => Style.lineHeight(value),\n getValue: () => {\n try {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return '';\n const BLOCKS = new Set(['P','DIV','H1','H2','H3','H4','H5','H6','LI','BLOCKQUOTE','PRE','TD','TH']);\n let el = /** @type {Element|null} */ (sel.getRangeAt(0).startContainer);\n if (el?.nodeType === 3) el = el.parentElement;\n while (el && !BLOCKS.has(/** @type {Element} */ (el).tagName)) el = el.parentElement;\n if (!el) return '';\n return /** @type {HTMLElement} */ (el).style.lineHeight || getComputedStyle(/** @type {Element} */ (el)).lineHeight || '';\n } catch { return ''; }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Code view / fullscreen\n// ---------------------------------------------------------------------------\n\nexport const codeviewBtn = btn('codeview', 'code', 'HTML Code View', (ctx) => ctx.invoke('codeview.toggle'), (ctx) => ctx.invoke('codeview.isActive'));\nexport const fullscreenBtn = btn('fullscreen', 'expand', 'Fullscreen', (ctx) => ctx.invoke('fullscreen.toggle'), (ctx) => ctx.invoke('fullscreen.isActive'));\nexport const shortcutsBtn = btn('shortcuts', 'keyboard', 'Keyboard Shortcuts (Ctrl+Shift+/)', (ctx) => ctx.invoke('shortcutsDialog.show'));\nexport const findBtn = btn('find', 'search', 'Find (Ctrl+F)', (ctx) => ctx.invoke('findReplace.show', 'find'));\nexport const findReplaceBtn = btn('findReplace', 'find-replace', 'Find & Replace (Ctrl+H)', (ctx) => ctx.invoke('findReplace.show', 'replace'));\nexport const inlineCodeBtn = btn('inlineCode', 'inline-code', 'Inline Code (Ctrl+`)', (ctx) => ctx.invoke('editor.inlineCode'), () => Style.isInlineCode());\nexport const checklistBtn = btn('checklist', 'checklist', 'Checklist', (ctx) => ctx.invoke('editor.toggleChecklist'), () => Style.isInChecklist());\nexport const printBtn = btn('print', 'print', 'Print', (ctx) => ctx.invoke('editor.print'));\n\n// ---------------------------------------------------------------------------\n// Text / background colour pickers\n// ---------------------------------------------------------------------------\n\n/** @type {{ name: string, type: 'colorpicker', icon: string, tooltip: string, defaultColor: string, action: Function }} */\nexport const foreColorBtn = {\n name: 'foreColor',\n type: 'colorpicker',\n icon: 'foreColor',\n tooltip: 'Text Color',\n defaultColor: '#e11d48',\n action: (ctx, color) => Style.foreColor(color),\n};\n\n/** @type {{ name: string, type: 'colorpicker', icon: string, tooltip: string, defaultColor: string, action: Function }} */\nexport const backColorBtn = {\n name: 'backColor',\n type: 'colorpicker',\n icon: 'backColor',\n tooltip: 'Highlight Color',\n defaultColor: '#fbbf24',\n action: (ctx, color) => Style.backColor(color),\n};\n\n// ---------------------------------------------------------------------------\n// Default toolbar layout\n// ---------------------------------------------------------------------------\n\n/**\n * The default toolbar button groups.\n * Each sub-array is a button group (separated by a divider).\n */\nexport const defaultToolbar = [\n [paragraphStyleBtn, fontFamilyBtn, fontSizeBtn, lineHeightBtn],\n [undoBtn, redoBtn],\n [boldBtn, italicBtn, underlineBtn, strikeBtn, inlineCodeBtn],\n [superscriptBtn, subscriptBtn],\n [foreColorBtn, backColorBtn],\n [alignLeftBtn, alignCenterBtn, alignRightBtn, alignJustifyBtn],\n [ulBtn, olBtn, checklistBtn, indentBtn, outdentBtn],\n [hrBtn, linkBtn, imageBtn, videoBtn, tableBtn, emojiBtn, iconBtn],\n [removeFormatBtn, codeviewBtn, fullscreenBtn, findBtn, printBtn, shortcutsBtn],\n];\n\n// ---------------------------------------------------------------------------\n// Buttons namespace — all pre-built button definitions in a single object.\n// Exposed as AutumnNote.buttons so UMD / CJS consumers can access them\n// without named imports: AutumnNote.buttons.boldBtn, etc.\n// ---------------------------------------------------------------------------\n\nexport const buttons = {\n boldBtn,\n italicBtn,\n underlineBtn,\n strikeBtn,\n superscriptBtn,\n subscriptBtn,\n alignLeftBtn,\n alignCenterBtn,\n alignRightBtn,\n alignJustifyBtn,\n ulBtn,\n olBtn,\n indentBtn,\n outdentBtn,\n undoBtn,\n redoBtn,\n hrBtn,\n linkBtn,\n imageBtn,\n videoBtn,\n emojiBtn,\n iconBtn,\n tableBtn,\n fontSizeBtn,\n removeFormatBtn,\n directionBtn,\n fontFamilyBtn,\n paragraphStyleBtn,\n lineHeightBtn,\n codeviewBtn,\n fullscreenBtn,\n shortcutsBtn,\n findBtn,\n findReplaceBtn,\n inlineCodeBtn,\n checklistBtn,\n printBtn,\n foreColorBtn,\n backColorBtn,\n defaultToolbar,\n};\n","/**\n * settings.js - Default editor options\n * Inspired by Summernote's settings.js\n */\n\nimport { defaultToolbar } from './module/Buttons.js';\n\n/**\n * @typedef {object} AsnOptions\n * @property {string} [placeholder] - Placeholder text when editor is empty\n * @property {number} [height] - Editor height in px (min)\n * @property {number} [minHeight] - Minimum height in px\n * @property {number} [maxHeight] - Maximum height in px (0 = unlimited)\n * @property {boolean} [focus] - Auto-focus on init\n * @property {boolean} [resizable] - Show resize handle\n * @property {Array} [toolbar] - Toolbar button group config\n * @property {boolean} [useBootstrap] - Use Bootstrap button classes on toolbar buttons\n * @property {string} [toolbarButtonClass] - CSS classes for Bootstrap toolbar buttons\n * @property {boolean} [useFontAwesome] - Use Font Awesome icons (default: true)\n * @property {string} [fontAwesomeClass] - Font Awesome prefix class, e.g. 'fas' or 'fa-solid'\n * @property {boolean} [fontAwesomeAutoInject] - Let the icon dialog inject Font Awesome CSS from a CDN when the host page has none (default: true)\n * @property {string} [fontAwesomeCDN] - Stylesheet URL used by that injection (defaults to cdnjs FA 6 Free)\n * @property {boolean} [pasteAsPlainText] - Force plain-text paste\n * @property {boolean} [pasteCleanHTML] - Sanitise HTML on paste\n * @property {boolean} [pasteStripAttributes] - Strip class/style/data-* from pasted HTML (default: false)\n * @property {boolean} [allowImageUpload] - Allow file upload in image dialog\n * @property {number} [maxImageSize] - Max upload size in MB\n * @property {number} [tabSize] - Spaces per tab in non-list context\n * @property {number} [historyLimit] - Maximum undo/redo history steps\n * @property {number} [historyMaxBytes] - Maximum combined size (chars) of all stacked undo/redo snapshots\n * @property {string} [defaultFontFamily] - Default font family applied to the editable area on init\n * @property {string} [defaultFontSize] - Default font size applied to the editable area on init (e.g. '14px')\n * @property {string[]} [fontFamilies] - Font families shown in the font-family toolbar dropdown\n * @property {Function} [onChange] - Callback on content change\n * @property {Function} [onFocus] - Callback on focus\n * @property {Function} [onBlur] - Callback on blur\n * @property {Function} [onInit] - Callback after the editor has initialised\n * @property {Function} [onImageUpload] - Upload handler: (files, { context, setProgress }) => void | string | string[] | Promise<string|string[]>.\n * Return (or resolve to) the uploaded URL(s) and the editor inserts a placeholder\n * immediately and swaps the real URL in when it arrives. Returning nothing keeps\n * the old behaviour: the handler is responsible for inserting the image itself.\n * @property {Function} [onImageError] - Callback when an image upload error occurs\n * @property {boolean} [stickyToolbar] - Stick the toolbar to the viewport top when scrolling\n * @property {number} [stickyToolbarOffset] - Top offset in px for sticky toolbar (e.g. fixed nav height)\n * @property {string} [theme] - 'light' (default) | 'dark'\n * @property {boolean} [codeHighlight] - Auto-load Prism.js for syntax highlighting of code blocks\n * @property {string} [codeHighlightCDN] - CDN base URL for Prism assets, or your own origin to self-host (defaults to cdnjs). A trailing slash is normalised away.\n * @property {string} [cspNonce] - CSP nonce applied to dynamically injected scripts/styles\n * @property {string} [externalAssetCrossOrigin] - crossorigin value for optional external assets\n * @property {string} [externalAssetReferrerPolicy] - referrer policy for optional external assets\n * @property {boolean} [markdownPaste] - Convert pasted Markdown text to HTML (default: true)\n * @property {boolean} [readOnly] - Start editor in read-only / non-editable mode\n * @property {boolean} [spellcheck] - Enable browser spellcheck in the editable area (default: true)\n * @property {string} [direction] - Text direction: 'ltr' (default) | 'rtl'\n * @property {string} [toolbarOverflow] - Toolbar overflow strategy: 'wrap' (default) | 'scroll'\n * @property {boolean} [autoSave] - Auto-save content to localStorage on change\n * @property {string} [autoSaveKey] - localStorage key used for auto-save (default: 'autumnnote-autosave')\n * @property {number} [autoSaveDelay] - Debounce delay for auto-save writes in milliseconds\n * @property {object|null} [autoSaveAdapter] - Optional async persistence adapter with save/load/remove methods\n * @property {number} [maxChars] - Maximum character count (0 = unlimited). Shows warning in statusbar.\n * @property {number} [maxWords] - Maximum word count (0 = unlimited). Shows warning in statusbar.\n * @property {boolean} [tableHeaderRow] - Insert a header row (<thead><th>) when creating tables\n * @property {Function} [onPaste] - Callback fired on every paste: ({ text, html }) => void\n * @property {Function} [onPasteError] - Callback fired when pasted or dropped content cannot be processed\n * @property {Function} [onSelectionChange] - Callback fired on cursor/selection change: (context) => void\n * @property {string[]} [colorSwatches] - Custom brand colour swatches prepended to the colour-picker palette\n * @property {Function} [onDestroy] - Callback fired when the editor is destroyed: (context) => void\n * @property {Function} [onCharLimitReached] - Callback fired when the character limit is hit: (context) => void\n * @property {Function} [onWordLimitReached] - Callback fired when the word limit is hit: (context) => void\n * @property {string} [focusColor] - Custom focus ring colour, e.g. '#f97316'. Overrides the default blue.\n * @property {boolean} [autoSaveRestore] - Show a restore banner when a previously auto-saved draft exists\n * @property {number} [autoSaveRestoreTimeout] - Maximum age in days for a draft to be offered for restore (0 = no expiry)\n * @property {Function} [onAutoSaveRestore] - Callback fired after the user chooses to restore a draft\n * @property {boolean} [markdownShortcuts] - Convert markdown syntax typed inline to HTML\n * @property {boolean} [bubbleToolbar] - Show a mini floating toolbar above text selections\n * @property {string[]} [bubbleToolbarItems] - Button names for the bubble toolbar\n * @property {object|null} [mention] - @mention configuration (onSearch, minChars, ...)\n * @property {boolean} [slashMenu] - Show a \"/\" command palette for quick block insertion (default true)\n * @property {string} [lang] - Display language or partial locale object override\n */\n\nexport const defaultOptions = {\n placeholder: '',\n height: 200,\n minHeight: 100,\n maxHeight: 0,\n focus: false,\n resizable: true,\n toolbar: defaultToolbar,\n // UI integration options\n // If `useBootstrap` is true, toolbar buttons will use the Bootstrap button classes\n // (set `toolbarButtonClass` to customize). Works with Bootstrap 4 and 5.\n useBootstrap: false,\n toolbarButtonClass: 'btn btn-sm btn-light',\n // Icon options — uses Font Awesome by default. Consumers must include Font Awesome CSS.\n useFontAwesome: true,\n // Default FontAwesome prefix — 'fas' for FA5, 'fa-solid' for FA6. Change if needed.\n fontAwesomeClass: 'fas',\n // The icon dialog needs FA glyphs to render its grid. When the host page ships\n // no Font Awesome of its own, it pulls the stylesheet from a CDN. Set to false\n // on pages with a strict CSP, an offline deployment, or a no-third-party-request\n // policy — the dialog still works, it just renders without glyphs unless the\n // page provides FA itself.\n fontAwesomeAutoInject: true,\n fontAwesomeCDN: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css',\n pasteAsPlainText: false,\n pasteCleanHTML: true,\n pasteStripAttributes: false,\n allowImageUpload: true,\n maxImageSize: 5,\n tabSize: 4,\n onChange: null,\n onFocus: null,\n onBlur: null,\n onInit: null,\n onImageUpload: null,\n onImageError: null,\n stickyToolbar: false,\n stickyToolbarOffset: 0,\n theme: 'light',\n codeHighlight: true,\n codeHighlightCDN: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0',\n cspNonce: '',\n externalAssetCrossOrigin: 'anonymous',\n externalAssetReferrerPolicy: 'no-referrer',\n markdownPaste: true,\n historyLimit: 100,\n // Max combined size (chars) of all stacked undo/redo snapshots. Guards\n // against documents with many large embedded images holding dozens of\n // full-size copies in memory despite historyLimit.\n historyMaxBytes: 10 * 1024 * 1024,\n // Default font family applied to the editor and shown in the dropdown when no explicit font is set\n defaultFontFamily: 'Arial',\n // Default font size applied to the editor and shown in the size dropdown when no explicit size is set\n defaultFontSize: '14px',\n // Font families shown in the toolbar font-family dropdown\n fontFamilies: [\n 'Arial',\n 'Arial Black',\n 'Comic Sans MS',\n 'Courier New',\n 'Georgia',\n 'Impact',\n 'Tahoma',\n 'Times New Roman',\n 'Trebuchet MS',\n 'Verdana',\n ],\n // Read-only mode — disables all editing when true\n readOnly: false,\n // Enable/disable browser spell-check on the editable area\n spellcheck: true,\n // Text direction: 'ltr' (default) or 'rtl'\n direction: 'ltr',\n // How the toolbar handles overflow: 'wrap' (default, wraps to next line) or 'scroll' (single scrollable row)\n toolbarOverflow: 'wrap',\n // Auto-save content to localStorage on every change\n autoSave: false,\n // localStorage key used when autoSave is enabled\n autoSaveKey: 'autumnnote-autosave',\n autoSaveDelay: 400,\n autoSaveAdapter: null,\n // Maximum character count (0 = unlimited)\n maxChars: 0,\n // Maximum word count (0 = unlimited)\n maxWords: 0,\n // Insert a header row (<thead>) when creating new tables\n tableHeaderRow: false,\n // Callback fired on every cursor/selection change inside the editor\n onSelectionChange: null,\n // Custom brand colour swatches to prepend to the toolbar colour-picker palette\n colorSwatches: [],\n // Callback fired after a paste event: function({ text, html })\n onPaste: null,\n // Callback fired for rejected/failed paste and drop payloads: function({ message, size?, maxBytes? })\n onPasteError: null,\n // Callback fired just before the editor instance is destroyed\n onDestroy: null,\n // Callback fired when the character limit is reached: function(context)\n onCharLimitReached: null,\n // Callback fired when the word limit is reached: function(context)\n onWordLimitReached: null,\n // Custom focus ring colour — overrides the default blue when set.\n // Accepts any valid CSS colour string, e.g. '#f97316', 'hsl(25,90%,55%)'.\n focusColor: null,\n // Display language for the editor UI.\n // Built-in values: 'en' (default), 'vi', 'ja', 'zh', 'fr', 'de', 'es', 'ko'.\n // Pass a partial or full locale object to override individual strings.\n lang: 'en',\n\n // Auto-save restore: show a banner when a draft exists in localStorage.\n // Requires autoSave: true. Set autoSaveRestoreTimeout to the max age in days\n // (0 = no expiry). onAutoSaveRestore(html, context) fires after restore.\n autoSaveRestore: false,\n autoSaveRestoreTimeout: 7,\n onAutoSaveRestore: null,\n\n // Markdown input shortcuts: convert markdown syntax typed inline to HTML.\n // e.g. \"## \" at line start → <h2>, \"**bold**\" → <strong>\n markdownShortcuts: true,\n\n // \"/\" command palette for quick block insertion (headings, lists, table, image, ...).\n // Triggers only when \"/\" is the first character typed on an otherwise-empty line.\n slashMenu: true,\n // Additional slash-menu commands supplied by applications/plugins.\n slashCommands: [],\n\n // Optional import/export adapters keyed by format name.\n documentAdapters: {},\n // Optional collaboration bridge notified with local HTML changes.\n collaborationAdapter: null,\n\n // Optional image processor (for example a Web Worker bridge). Receives a\n // File and returns a data URL; Clipboard's canvas pipeline remains fallback.\n imageProcessor: null,\n // Add stable data-an-block-id attributes to top-level document blocks.\n blockIds: false,\n\n // Maximum paste size in bytes (default 5 MB). Pastes larger than this are silently dropped.\n maxPasteSize: 5 * 1024 * 1024,\n // Minimum image dimension in px during resize (width and height). Prevents images from being\n // resized below this value.\n minImageSize: 20,\n\n // Bubble toolbar: show a mini floating toolbar above text selections.\n bubbleToolbar: false,\n bubbleToolbarItems: ['bold', 'italic', 'underline', 'link', 'foreColor', 'hiliteColor', 'removeFormat'],\n\n // @mention support. mention.onSearch(query, callback) must be provided to activate.\n // mention.minChars defaults to 0 — dropdown opens immediately on trigger character.\n mention: null,\n};\n","/**\n * en.js - English locale (canonical reference)\n * All other locales deep-merge against this to fill missing keys.\n */\n\n/** @type {import('../../../types/index.js').AsnLocale} */\nexport const en = {\n toolbar: {\n bold: 'Bold (Ctrl+B)',\n italic: 'Italic (Ctrl+I)',\n underline: 'Underline (Ctrl+U)',\n strikethrough: 'Strikethrough',\n superscript: 'Superscript',\n subscript: 'Subscript',\n alignLeft: 'Align Left',\n alignCenter: 'Align Center',\n alignRight: 'Align Right',\n alignJustify: 'Justify',\n ul: 'Unordered List',\n ol: 'Ordered List',\n checklist: 'Checklist',\n indent: 'Indent',\n outdent: 'Outdent',\n undo: 'Undo (Ctrl+Z)',\n redo: 'Redo (Ctrl+Y)',\n hr: 'Horizontal Rule',\n link: 'Insert Link',\n image: 'Insert Image',\n video: 'Insert Video',\n emoji: 'Insert Emoji',\n icon: 'Insert FA Icon',\n table: 'Insert Table',\n fontSize: 'Font Size',\n fontSizePlaceholder: 'Size',\n removeFormat: 'Remove Format',\n direction: 'Toggle Text Direction (LTR / RTL)',\n fontFamily: 'Font Family',\n paragraphStyle: 'Paragraph Style',\n paragraphStylePlaceholder: 'Style',\n lineHeight: 'Line Height',\n lineHeightPlaceholder: '\\u2195 Line',\n codeview: 'HTML Code View',\n fullscreen: 'Fullscreen',\n shortcuts: 'Keyboard Shortcuts (Ctrl+Shift+/)',\n find: 'Find (Ctrl+F)',\n findReplace: 'Find & Replace (Ctrl+H)',\n inlineCode: 'Inline Code (Ctrl+`)',\n print: 'Print',\n foreColor: 'Text Color',\n backColor: 'Highlight Color',\n chooseTextColor: 'Choose text color',\n chooseHighlightColor: 'Choose highlight color',\n customColor: 'Custom color',\n insertTableLabel: 'Insert Table',\n /** Map of paragraph-style value → label (only values needing translation) */\n paragraphItems: {\n p: 'Normal',\n blockquote: 'Quote',\n pre: 'Code',\n },\n },\n\n linkDialog: {\n ariaLabel: 'Insert link',\n title: 'Insert Link',\n url: 'URL',\n urlPlaceholder: 'https://',\n displayText: 'Display Text',\n textPlaceholder: 'Link text',\n openInNewTab: 'Open in new tab',\n insertBtn: 'Insert',\n cancelBtn: 'Cancel',\n },\n\n imageDialog: {\n ariaLabel: 'Insert image',\n title: 'Insert Image',\n imageUrl: 'Image URL',\n urlPlaceholder: 'https://example.com/image.png',\n altText: 'Alt Text',\n altPlaceholder: 'Describe the image',\n alignment: 'Alignment',\n alignNone: 'None',\n alignLeft: 'Left',\n alignCenter: 'Center',\n alignRight: 'Right',\n uploadLabel: 'Or upload a file',\n insertBtn: 'Insert',\n cancelBtn: 'Cancel',\n },\n\n videoDialog: {\n ariaLabel: 'Insert video',\n title: 'Insert Video',\n videoUrl: 'Video URL',\n urlPlaceholder: 'YouTube, Vimeo, or direct .mp4 URL',\n widthLabel: 'Width (px)',\n widthPlaceholder: '560',\n insertBtn: 'Insert',\n cancelBtn: 'Cancel',\n /** @param {string} type */\n detected: (type) => `Detected: ${type}`,\n unknownFormat: 'Unknown format \\u2014 will try direct video embed',\n invalidUrl: 'Invalid URL \\u2014 please enter a valid video link.',\n },\n\n emojiDialog: {\n ariaLabel: 'Insert emoji',\n title: 'Insert Emoji',\n searchPlaceholder: 'Search emojis\\u2026',\n all: 'All',\n cancelBtn: 'Cancel',\n close: 'Close',\n categories: {\n smileys: 'Smileys',\n people: 'People',\n animals: 'Animals',\n food: 'Food',\n travel: 'Travel',\n objects: 'Objects',\n symbols: 'Symbols',\n },\n },\n\n iconDialog: {\n ariaLabel: 'Insert FA icon',\n title: 'Insert FA Icon',\n searchPlaceholder: 'Search icons\\u2026',\n all: 'All',\n style: 'Style',\n size: 'Size',\n color: 'Color',\n useColor: ' Use color',\n selectHint: 'Select an icon',\n insertBtn: 'Insert FA Icon',\n cancelBtn: 'Cancel',\n close: 'Close',\n categories: {\n popular: 'Popular',\n interface: 'Interface',\n navigation: 'Navigation',\n media: 'Media',\n communication: 'Communication',\n files: 'Files',\n people: 'People',\n objects: 'Objects',\n },\n },\n\n findReplace: {\n findTitle: 'Find',\n findReplaceTitle: 'Find & Replace',\n findPlaceholder: 'Find\\u2026',\n searchAriaLabel: 'Search text',\n caseSensitive: '\\u00a0Case sensitive',\n wholeWord: 'Whole Word',\n prevBtn: '\\u2190 Prev',\n nextBtn: 'Next \\u2192',\n replacePlaceholder: 'Replace with\\u2026',\n replaceAriaLabel: 'Replace with',\n replaceBtn: 'Replace',\n replaceAllBtn: 'Replace All',\n noResults: 'No results',\n useRegex: 'Use Regular Expression',\n close: '\\u00d7',\n },\n\n autoSaveRestore: {\n found: 'Draft found. Restore?',\n foundAt: 'Draft from {date}. Restore?',\n restore: 'Restore',\n discard: 'Discard',\n },\n\n shortcutsDialog: {\n title: 'Keyboard Shortcuts',\n ariaLabel: 'Keyboard Shortcuts',\n close: 'Close',\n shortcuts: [\n {\n category: 'Text Formatting',\n items: [\n { keys: 'Ctrl + B', action: 'Bold' },\n { keys: 'Ctrl + I', action: 'Italic' },\n { keys: 'Ctrl + U', action: 'Underline' },\n { keys: 'Ctrl + K', action: 'Insert / edit link' },\n ],\n },\n {\n category: 'History',\n items: [\n { keys: 'Ctrl + Z', action: 'Undo' },\n { keys: 'Ctrl + Y / Ctrl + Shift + Z', action: 'Redo' },\n ],\n },\n {\n category: 'Selection & Navigation',\n items: [\n { keys: 'Ctrl + A', action: 'Select all content' },\n { keys: 'Tab', action: 'Indent list item / insert spaces' },\n { keys: 'Shift + Tab', action: 'Outdent list item' },\n ],\n },\n {\n category: 'Clipboard',\n items: [\n { keys: 'Ctrl + Shift + V', action: 'Paste as plain text' },\n ],\n },\n {\n category: 'Find & Replace',\n items: [\n { keys: 'Ctrl + F', action: 'Find in document' },\n { keys: 'Ctrl + H', action: 'Find & Replace' },\n ],\n },\n {\n category: 'Editor',\n items: [\n { keys: 'Ctrl + Shift + /', action: 'Show this keyboard shortcuts dialog' },\n ],\n },\n ],\n },\n\n contextMenu: {\n cut: 'Cut',\n copy: 'Copy',\n paste: 'Paste',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n textColor: 'Text Color',\n highlightColor: 'Highlight Color',\n copyFormat: 'Copy Format',\n pasteFormat: 'Paste Format',\n removeFormat: 'Remove Format',\n link: 'Insert Link',\n image: 'Insert Image',\n video: 'Insert Video',\n table: 'Insert Table',\n back: 'Back',\n noHighlight: 'No highlight',\n customColor: 'Custom color',\n customColorLabel: 'Custom\\u2026',\n },\n\n statusbar: {\n resizeHandle: 'Resize editor',\n /** @param {number} n */\n words: (n) => `Words: ${n}`,\n /** @param {number} n @param {number} max */\n wordsLimit: (n, max) => `Words: ${n}/${max}`,\n /** @param {number} n */\n chars: (n) => `Chars: ${n}`,\n /** @param {number} n @param {number} max */\n charsLimit: (n, max) => `Chars: ${n}/${max}`,\n },\n\n tooltips: {\n link: {\n ariaLabel: 'Link actions',\n openLink: 'Open link',\n copyUrl: 'Copy URL',\n editLink: 'Edit link',\n removeLink: 'Remove link',\n },\n image: {\n ariaLabel: 'Image actions',\n label: 'Image',\n floatLeft: 'Float Left',\n noFloat: 'No Float',\n alignCenter: 'Align Center',\n floatRight: 'Float Right',\n originalSize: 'Original Size',\n rotateLeft: 'Rotate Left',\n rotateRight: 'Rotate Right',\n cropImage: 'Crop Image',\n addCaption: 'Add / Edit Caption',\n deleteImage: 'Delete Image',\n },\n code: {\n ariaLabel: 'Code block actions',\n label: 'Code',\n syntaxLanguage: 'Syntax Language',\n syntaxAriaLabel: 'Syntax language',\n copyCode: 'Copy Code',\n toggleWordWrap: 'Toggle Word Wrap',\n enableWordWrap: 'Enable Word Wrap',\n disableWordWrap: 'Disable Word Wrap',\n convertToParagraph: 'Convert to Paragraph',\n deleteCodeBlock: 'Delete Code Block',\n lineNumbers: 'Toggle Line Numbers',\n },\n table: {\n ariaLabel: 'Table actions',\n label: 'Table',\n selectCells: 'Select Cells',\n addRowAbove: 'Add Row Above',\n addRowBelow: 'Add Row Below',\n deleteRow: 'Delete Row',\n addColumnLeft: 'Add Column Left',\n addColumnRight: 'Add Column Right',\n deleteColumn: 'Delete Column',\n mergeCells: 'Merge Cells',\n unmergeCells: 'Unmerge Cells',\n columnWidth: 'Column Width',\n rowHeight: 'Row Height',\n tableBorderWidth: 'Table Border Width',\n tableBorderColor: 'Table Border Color',\n deleteTable: 'Delete Table',\n cellAlignLeft: 'Align Left',\n cellAlignCenter: 'Align Center',\n cellAlignRight: 'Align Right',\n cellAlignJustify: 'Align Justify',\n toggleHeaderRow: 'Toggle Header Row',\n cellBackground: 'Cell Background',\n noShading: 'No Shading',\n noBorderColor: 'No Border Color',\n columnWidthPx: 'Column Width (px)',\n rowHeightPx: 'Row Height (px)',\n tableBorderWidthPx: 'Table Border Width (px)',\n cancelBtn: 'Cancel',\n applyBtn: 'Apply',\n sortAsc: 'Sort Ascending',\n sortDesc: 'Sort Descending',\n exportCSV: 'Export as CSV',\n cellPadding: 'Cell Padding',\n cellPaddingPx: 'Cell Padding (px)',\n },\n video: {\n ariaLabel: 'Video actions',\n label: 'Video',\n floatLeft: 'Float Left',\n noFloat: 'No Float',\n alignCenter: 'Align Center',\n floatRight: 'Float Right',\n originalSize: 'Original Size',\n previewVideo: 'Preview Video',\n exitPreview: 'Exit Preview',\n deleteVideo: 'Delete Video',\n },\n },\n\n errors: {\n /** @param {string} type */\n imageFormat: (type) =>\n `Format \"${type}\" is not supported for display in web browsers. Please convert to JPEG, PNG, or WebP first.`,\n /** @param {number} maxSize */\n imageSize: (maxSize) =>\n `Image file is too large. Maximum allowed size is ${maxSize} MB.`,\n },\n\n slashMenu: {\n noResults: 'No matching commands',\n heading1: 'Heading 1',\n heading2: 'Heading 2',\n heading3: 'Heading 3',\n bulletList: 'Bullet List',\n numberedList: 'Numbered List',\n checklist: 'Checklist',\n blockquote: 'Blockquote',\n codeBlock: 'Code Block',\n horizontalRule: 'Horizontal Rule',\n table: 'Table',\n image: 'Image',\n },\n};\n","/**\n * i18n/index.js — Locale registry and resolver for autumn-note-ce.\n *\n * Only English ships in the ESM bundle. Bundling all eight locales cost every\n * consumer ~15 KB gzip even when they only ever rendered English, so the other\n * locales are opt-in via subpath imports:\n *\n * import AutumnNote from 'autumnnote';\n * import { vi } from 'autumnnote/i18n/vi';\n *\n * AutumnNote.registerLocale('vi', vi);\n * AutumnNote.create('#editor', { lang: 'vi' });\n *\n * The UMD/CDN build cannot tree-shake, so it pre-registers every locale and\n * `lang: 'vi'` keeps working there with no extra imports.\n *\n * Usage:\n * lang: 'en' → built-in English (always available)\n * lang: '<code>' → a locale previously passed to registerLocale()\n * lang: { ... } → custom locale object, deep-merged over English\n */\n\nimport { mergeDeep } from '../core/func.js';\nimport { en } from './en.js';\n\n/**\n * Locales available to `lang: '<code>'`. Starts with English only; other codes\n * are added through {@link registerLocale}.\n * @type {Record<string, Partial<AsnLocale>>}\n */\nexport const locales = { en };\n\n/**\n * Registers a locale so it can be selected by code.\n *\n * @param {string} code - Language code, e.g. 'vi'.\n * @param {Partial<AsnLocale>} locale - Locale object; missing keys fall back to English.\n * @returns {void}\n */\nexport function registerLocale(code, locale) {\n if (typeof code !== 'string' || !code) {\n throw new TypeError('[AutumnNote] registerLocale: code must be a non-empty string.');\n }\n if (!locale || typeof locale !== 'object') {\n throw new TypeError(`[AutumnNote] registerLocale: locale for \"${code}\" must be an object.`);\n }\n locales[code] = locale;\n}\n\n/**\n * Resolve a locale object from a lang option value.\n *\n * @param {string | Partial<AsnLocale> | null | undefined} lang\n * @returns {AsnLocale} A fully-populated locale (always contains every key from en.js).\n */\nexport function resolveLocale(lang) {\n // Default / English shortcut (no merge needed)\n if (!lang || lang === 'en') return en;\n\n if (typeof lang === 'string') {\n const partial = locales[lang];\n if (!partial) {\n // Unregistered code → English, but say why: silently rendering English\n // after asking for another language is confusing to debug.\n console.warn(\n `[AutumnNote] Locale \"${lang}\" is not registered, falling back to English. ` +\n `Import it first: import { ${lang} } from 'autumnnote/i18n/${lang}'; ` +\n `AutumnNote.registerLocale('${lang}', ${lang});`,\n );\n return en;\n }\n return mergeDeep(mergeDeep({}, en), partial);\n }\n\n if (typeof lang === 'object') {\n // Custom locale object supplied directly by the user\n return mergeDeep(mergeDeep({}, en), lang);\n }\n\n return en;\n}\n\n/**\n * @typedef {Object} AsnLocale (see types/index.d.ts for the full definition)\n */\n","/**\n * sanitise.js - Shared HTML and URL sanitisation utilities\n *\n * Single source of truth used by Editor, Clipboard, Codeview, and renderer.\n * DOM-parser based — no regex-based stripping of HTML (avoids bypass tricks).\n */\n\n/**\n * Tags that are unconditionally removed from editor content.\n *\n * Beyond the obvious script hosts this covers two SVG/MathML-specific classes:\n *\n * - SMIL animation (`animate`, `set`, `animateTransform`, `animateMotion`)\n * can rewrite an attribute *after* sanitisation finishes, so\n * `<svg><a><animate attributeName=\"href\" values=\"javascript:…\">` survives an\n * attribute-level filter untouched and still navigates on click. The editor\n * only ever emits static `<svg>` icons, so animation is pure attack surface.\n *\n * - `mglyph` / `malignmark` / `annotation-xml` are HTML integration points\n * inside the MathML namespace. They make the parser switch namespaces\n * mid-tree, which is what lets a crafted fragment re-parse into different\n * markup than it serialised from (mXSS). The rest of MathML is left alone so\n * pasted formulae survive.\n */\nconst PROHIBITED_TAGS = [\n 'script', 'style', 'iframe', 'object', 'embed', 'form', 'base', 'template',\n 'link', 'meta', 'noscript', 'portal', 'frame', 'frameset', 'applet',\n 'animate', 'set', 'animatetransform', 'animatemotion',\n 'mglyph', 'malignmark', 'annotation-xml',\n];\n\n/** Tags whose element wrapper is stripped but content (child nodes) is preserved. */\nconst UNWRAP_TAGS = new Set(['button']);\n\n/** Attributes whose values must be sanitised as URLs. */\nconst URL_ATTRS = ['href', 'src', 'action', 'formaction', 'xlink:href', 'poster', 'background', 'srcset'];\n\n/**\n * URL attributes that address media rather than navigation, so they are\n * validated against SAFE_MEDIA_PROTOCOLS regardless of which element carries\n * them (unlike `src`, whose meaning depends on the owning tag).\n */\nconst MEDIA_URL_ATTRS = new Set(['poster', 'background', 'srcset']);\n\n/**\n * Attributes removed outright: the editor never emits them and their only\n * effect is an outbound request the author did not ask for. `ping` fires a\n * POST beacon to arbitrary hosts when a link is clicked.\n */\nconst BEACON_ATTRS = new Set(['ping']);\n\n/** Inline style properties the editor's own toolbar/table features persist on saved content. */\nconst ALLOWED_STYLE_PROPS = new Set([\n 'color', 'background-color', 'font-size', 'line-height',\n 'text-align', 'vertical-align',\n 'width', 'min-width', 'height', 'min-height',\n 'border-width', 'border-style', 'border-color', 'padding',\n // The code block's word-wrap toggle persists as `white-space: pre-wrap` on\n // the <pre>. Dropping it meant the setting was lost through every path that\n // re-sanitises — setHTML, paste, and auto-save restore.\n 'white-space',\n]);\n\n/**\n * Value patterns that are never safe regardless of property.\n * `image-set()` and `src()` are covered alongside `url()` — all three fetch an\n * external resource, so allowing them would let pasted content phone home.\n */\nconst DANGEROUS_STYLE_VALUE_RE = /url\\s*\\(|image-set\\s*\\(|src\\s*\\(|expression\\s*\\(|@import|javascript:|vbscript:|behavior\\s*:|-moz-binding/i;\n\n/** Trusted hosts for iframe embeds when allowIframes is enabled. */\nconst TRUSTED_IFRAME_HOSTS = new Set([\n 'www.youtube.com',\n 'youtube.com',\n 'm.youtube.com',\n 'www.youtube-nocookie.com',\n 'youtube-nocookie.com',\n 'player.vimeo.com',\n]);\n\nconst SAFE_LINK_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);\nconst SAFE_MEDIA_PROTOCOLS = new Set(['http:', 'https:', 'blob:']);\nconst SAFE_RASTER_DATA_RE = /^data:image\\/(?:png|jpe?g|gif|webp|avif|bmp);base64,[a-z0-9+/=\\s]+$/i;\nconst URL_BASE = 'https://autumnnote.invalid/';\n\n/**\n * Produce a sanitized HTML string with dangerous elements and attributes removed.\n *\n * Removes disallowed tags and wrappers, strips event-handler attributes, rejects\n * `javascript:`/`vbscript:` URLs and most `data:` URIs, restricts iframe `src`\n * to trusted hosts when enabled, and permits only checklist checkboxes as inputs.\n *\n * @param {string} html - HTML fragment to sanitize.\n * @param {Object} [options]\n * @param {boolean} [options.allowIframes=false] - If true, `iframe` elements are not removed but their `src` is restricted to trusted hosts and `srcdoc` is removed.\n * @returns {string} The sanitized HTML fragment.\n */\nexport function sanitiseHTML(html, options) {\n return sanitiseToBody(html, options).innerHTML;\n}\n\n/**\n * The same sanitisation as {@link sanitiseHTML}, but handing back the parsed\n * `<body>` instead of its serialisation.\n *\n * A caller that is about to put the result into the DOM can adopt these nodes\n * directly and skip a serialise plus a re-parse — on a 217 KiB document that is\n * ~14 ms of the ~45 ms `setHTML` used to take. It is also the safer of the two\n * shapes: re-parsing a sanitised string is the step mXSS turns against you (see\n * the note on namespace-switching tags above), and adopting never re-parses.\n *\n * `sanitiseHTML` is unchanged and still the right entry point when a string is\n * what you need.\n *\n * @param {string} html - HTML fragment to sanitize.\n * @param {Object} [options]\n * @param {boolean} [options.allowIframes=false] - If true, `iframe` elements are not removed but their `src` is restricted to trusted hosts and `srcdoc` is removed.\n * @returns {HTMLElement} The sanitized `<body>` of a detached document.\n */\nexport function sanitiseToBody(html, { allowIframes = false } = {}) {\n const doc = new DOMParser().parseFromString(`<body>${html || ''}</body>`, 'text/html');\n\n // Single querySelectorAll pass — collect all elements once to avoid\n // repeated full-tree traversals for each category of check.\n const allElements = Array.from(doc.querySelectorAll('*'));\n\n // Build the prohibited tag set for fast O(1) lookup\n const prohibited = new Set(\n allowIframes ? PROHIBITED_TAGS.filter((t) => t !== 'iframe') : PROHIBITED_TAGS,\n );\n\n for (const el of allElements) {\n const tag = el.tagName.toLowerCase();\n\n // Unwrap elements whose wrapper is unsafe but whose content should be kept\n if (UNWRAP_TAGS.has(tag)) {\n el.replaceWith(...el.childNodes);\n continue;\n }\n\n // Remove outright dangerous elements\n if (prohibited.has(tag)) {\n el.remove();\n continue;\n }\n\n // Invalid embeds are removed rather than retained as empty iframes.\n if (tag === 'iframe') {\n const src = el.getAttribute('src');\n if (!src || !isTrustedIframeSrc(src)) {\n el.remove();\n continue;\n }\n }\n\n // Strip dangerous attributes\n for (const attr of Array.from(el.attributes)) {\n // Remove all event handlers (onclick, onload, onerror, …)\n if (attr.name.startsWith('on')) {\n el.removeAttribute(attr.name);\n continue;\n }\n // Filter the style attribute down to an allowlisted set of safe\n // properties (see ALLOWED_STYLE_PROPS) — not a blanket strip, since\n // the editor's own toolbar/table features persist inline styles\n // (text color/highlight, font size, line height, table alignment/\n // sizing/borders) that must survive sanitisation.\n if (attr.name === 'style') {\n const cleaned = sanitiseStyleValue(attr.value);\n if (cleaned) el.setAttribute('style', cleaned);\n else el.removeAttribute('style');\n continue;\n }\n // Drop tracking-beacon attributes outright\n if (BEACON_ATTRS.has(attr.name)) {\n el.removeAttribute(attr.name);\n continue;\n }\n // Sanitise URL attributes\n if (URL_ATTRS.includes(attr.name)) {\n const val = attr.value.trim();\n const isMediaSource = MEDIA_URL_ATTRS.has(attr.name) ||\n (attr.name === 'src' && ['IMG', 'VIDEO', 'AUDIO', 'SOURCE'].includes(el.tagName));\n const allowData = el.tagName === 'IMG';\n const safe = attr.name === 'srcset'\n ? isSafeSrcset(val, { allowData })\n : isSafeUrl(val, { media: isMediaSource, allowData });\n if (!safe) {\n el.removeAttribute(attr.name);\n continue;\n }\n }\n // Strip iframe HTML-injection vectors; limit src to trusted hosts\n if (el.tagName === 'IFRAME') {\n if (attr.name === 'srcdoc') {\n el.removeAttribute(attr.name);\n continue;\n }\n if (attr.name === 'src' && !isTrustedIframeSrc(attr.value)) {\n el.removeAttribute(attr.name);\n }\n }\n }\n\n if (tag === 'a' && el.getAttribute('target') === '_blank') {\n el.setAttribute('rel', 'noopener noreferrer');\n }\n\n // Allow only input[type=\"checkbox\"] inside ul.an-checklist li\n if (tag === 'input') {\n const inChecklist = el.closest('ul.an-checklist') !== null &&\n el.closest('li') !== null;\n if (!inChecklist || el.getAttribute('type') !== 'checkbox') {\n el.remove();\n } else {\n for (const attr of Array.from(el.attributes)) {\n if (!['type', 'checked', 'contenteditable'].includes(attr.name)) {\n el.removeAttribute(attr.name);\n }\n }\n }\n }\n }\n\n return doc.body;\n}\n\n/**\n * Filters a style attribute value down to an allowlisted set of CSS\n * properties (ALLOWED_STYLE_PROPS), dropping any declaration whose value\n * contains a dangerous construct — url(), expression(), an \"import\" rule,\n * javascript:/vbscript:, IE behavior/-moz-binding — regardless of property.\n * @param {string} value\n * @returns {string} The filtered declaration list, or '' if nothing survives.\n */\nfunction sanitiseStyleValue(value) {\n const kept = [];\n for (const decl of (value || '').split(';')) {\n const idx = decl.indexOf(':');\n if (idx === -1) continue;\n const prop = decl.slice(0, idx).trim().toLowerCase();\n const val = decl.slice(idx + 1).trim();\n if (!prop || !val) continue;\n if (!ALLOWED_STYLE_PROPS.has(prop)) continue;\n if (DANGEROUS_STYLE_VALUE_RE.test(val)) continue;\n kept.push(`${prop}: ${val}`);\n }\n return kept.join('; ');\n}\n\n/**\n * Validates every candidate URL in a `srcset` attribute.\n *\n * Per the HTML srcset grammar a candidate URL is a run of non-whitespace\n * characters — commas may appear *inside* it, which is why `data:` URLs work\n * there — optionally followed by a width (`300w`) or density (`2x`) descriptor.\n * Splitting on whitespace and skipping descriptor tokens therefore yields the\n * URL set. Anything unparseable makes the whole attribute fail, since a\n * partially-trusted candidate list is not something we can express.\n *\n * @param {string} value\n * @param {{ allowData?: boolean }} [options]\n * @returns {boolean}\n */\nfunction isSafeSrcset(value, { allowData = false } = {}) {\n const tokens = (value || '').trim().split(/\\s+/).filter(Boolean);\n for (const token of tokens) {\n if (/^[\\d.]+[xw],?$/i.test(token)) continue; // width/density descriptor\n const url = token.replace(/,+$/, ''); // trailing comma = candidate separator\n if (!url) continue;\n if (!isSafeUrl(url, { media: true, allowData })) return false;\n }\n return true;\n}\n\n/**\n * Returns true if iframe src points to an approved video host.\n * Relative, protocol-relative and invalid URLs are rejected.\n * @param {string} src\n * @returns {boolean}\n */\nfunction isTrustedIframeSrc(src) {\n const trimmed = (src || '').trim();\n if (!trimmed) return false;\n if (trimmed.startsWith('//') || trimmed.startsWith('/')) return false;\n try {\n const url = new URL(trimmed);\n if (url.protocol !== 'https:') return false;\n return TRUSTED_IFRAME_HOSTS.has(url.hostname.toLowerCase());\n } catch {\n return false;\n }\n}\n\n/**\n * Sanitises a URL string, rejecting dangerous protocols.\n *\n * Blocked protocols: javascript:, vbscript:\n * Optionally blocked: data: (safe to allow for img/src base64 embeds)\n *\n * @param {string} url\n * @param {{ allowData?: boolean, media?: boolean }} [opts]\n * @returns {string|null} The original URL if safe, null if rejected.\n */\nexport function sanitiseUrl(url, { allowData = false, media = allowData } = {}) {\n const trimmed = (url || '').trim();\n if (!trimmed && url == null) return null;\n return isSafeUrl(trimmed, { media, allowData }) ? url : null;\n}\n\n/**\n * Validate a URL using the browser URL parser so ASCII whitespace/control\n * characters cannot disguise a dangerous protocol (for example java\\nscript:).\n * @param {string} value\n * @param {{media?: boolean, allowData?: boolean}} [options]\n * @returns {boolean}\n */\nfunction isSafeUrl(value, { media = false, allowData = false } = {}) {\n const trimmed = (value || '').trim();\n if (!trimmed) return true;\n if (allowData && SAFE_RASTER_DATA_RE.test(trimmed)) return true;\n\n try {\n const parsed = new URL(trimmed, URL_BASE);\n const protocols = media ? SAFE_MEDIA_PROTOCOLS : SAFE_LINK_PROTOCOLS;\n return protocols.has(parsed.protocol);\n } catch {\n return false;\n }\n}\n","/**\n * renderer.js - Builds the editor DOM structure\n * Inspired by Summernote's renderer.js\n */\n\nimport { createElement } from './core/dom.js';\nimport { sanitiseHTML } from './core/sanitise.js';\n\n/**\n * Renders the editor layout around the original element.\n *\n * Structure:\n * <div class=\"an-container\">\n * <div class=\"an-toolbar\">...</div>\n * <div class=\"an-editable\" contenteditable=\"true\">...</div>\n * <div class=\"an-statusbar\">...</div>\n * </div>\n *\n * @param {HTMLElement} targetEl - the original element to replace/wrap\n * @param {import('./settings.js').AsnOptions} options\n * @returns {{ container: HTMLElement, editable: HTMLElement }}\n */\nexport function renderLayout(targetEl, options) {\n const container = createElement('div', { class: 'an-container' });\n\n // Editable area\n const editable = createElement('div', {\n class: 'an-editable',\n contenteditable: options.readOnly ? 'false' : 'true',\n spellcheck: String(options.spellcheck !== false),\n 'aria-multiline': 'true',\n 'aria-label': 'Rich text editor',\n role: 'textbox',\n });\n\n // Restore auto-saved content when available; fall back to element content\n let initialContent = '';\n if (options.autoSave && options.autoSaveKey) {\n try { initialContent = localStorage.getItem(options.autoSaveKey) || ''; } catch (_) { void _; }\n }\n if (!initialContent) {\n initialContent = targetEl.tagName === 'TEXTAREA'\n ? ((/** @type {HTMLTextAreaElement} */ (targetEl)).value || '').trim()\n : (targetEl.innerHTML || '').trim();\n }\n editable.innerHTML = sanitiseHTML(initialContent, { allowIframes: true });\n\n // Apply default font family so the editable renders in the configured font\n const defaultFont = options.defaultFontFamily || options.fontFamilies?.[0];\n if (defaultFont) {\n editable.style.fontFamily = defaultFont;\n }\n\n // Apply default font size so the size dropdown shows the correct value on startup\n if (options.defaultFontSize) {\n editable.style.fontSize = options.defaultFontSize;\n }\n\n // Apply height options.\n // `height` sets the initial visible height (takes priority).\n // `minHeight` is the drag-resize floor — only applied when no explicit `height` is given.\n if (options.height) {\n editable.style.minHeight = `${options.height}px`;\n } else if (options.minHeight) {\n editable.style.minHeight = `${options.minHeight}px`;\n }\n if (options.maxHeight) {\n editable.style.maxHeight = `${options.maxHeight}px`;\n }\n\n container.appendChild(editable);\n\n // Apply theme — also add to body so floating elements (dialogs, tooltips,\n // popovers) appended to document.body inherit the CSS rules.\n if (options.theme === 'dark') {\n container.classList.add('an-theme-dark');\n document.body.classList.add('an-theme-dark');\n } else if (options.theme === 'auto') {\n container.classList.add('an-theme-auto');\n document.body.classList.add('an-theme-auto');\n }\n\n // Read-only mode\n if (options.readOnly) {\n container.classList.add('an-disabled');\n editable.querySelectorAll('ul.an-checklist input[type=\"checkbox\"]').forEach((cb) => {\n cb.setAttribute('disabled', '');\n });\n }\n\n // Text direction\n if (options.direction === 'rtl') {\n editable.setAttribute('dir', 'rtl');\n container.classList.add('an-dir-rtl');\n }\n\n // Toolbar overflow\n if (options.toolbarOverflow === 'scroll') {\n container.classList.add('an-toolbar-overflow-scroll');\n }\n\n // Configure sticky toolbar\n if (options.stickyToolbar) {\n container.classList.add('an-sticky-toolbar');\n if (options.stickyToolbarOffset) {\n container.style.setProperty('--an-sticky-top', `${options.stickyToolbarOffset}px`);\n }\n }\n\n // Custom focus ring colour\n if (options.focusColor) {\n container.style.setProperty('--an-focus-color', options.focusColor);\n }\n\n // Hide the original element; keep it in DOM for form submission\n targetEl.style.display = 'none';\n targetEl.after(container);\n\n return { container, editable };\n}\n","/**\n * Context.js - Central hub for the editor instance\n * Holds references to all sub-modules and manages inter-module communication.\n * Inspired by Summernote's Context.js\n */\n\nimport { mergeDeep } from './core/func.js';\nimport { registerButton } from './module/Buttons.js';\nimport { defaultOptions } from './settings.js';\nimport { resolveLocale } from './i18n/index.js';\nimport { renderLayout } from './renderer.js';\nimport { on } from './core/dom.js';\n\n/** Module registry shared across all Context instances (populated via AutumnNote.registerModule). */\nexport const _customModules = new Map();\n\n/**\n * @typedef {object} ModuleDef\n * @property {string} name - Key the module is registered and invoked under.\n * @property {new (ctx: Context) => { initialize: () => any, destroy?: () => void }} Class\n * @property {(options: any) => boolean} [enabled] - Option gate. Omitted means always on.\n * Consulted at mount and again after updateOptions(), so a runtime toggle\n * starts or tears the module down instead of silently disagreeing with the\n * option value.\n */\n\n/**\n * Module table for every Context created from here on.\n *\n * Context deliberately imports no module of its own: whichever entry point the\n * consumer loaded installs the table. That is what lets `autumnnote/core` leave\n * the dialogs, tooltips and pickers out of the bundle entirely rather than\n * merely not registering them.\n * @type {ModuleDef[]}\n */\nlet _moduleDefs = [];\n\n/**\n * Installs the module table. Called by each entry point at import time.\n * @param {ModuleDef[]} defs\n */\nexport function setModuleDefs(defs) {\n _moduleDefs = Array.isArray(defs) ? defs : [];\n}\n\n/** The table currently installed. */\nexport function getModuleDefs() {\n return _moduleDefs;\n}\n\n/** Global plugin registry (populated via AutumnNote.use()). Applied to every new Context. */\nexport const _globalPlugins = new Map();\n\nexport class Context {\n /**\n * @param {HTMLElement} targetEl - The element to replace with the editor\n * @param {import('./settings.js').AsnOptions} [userOptions]\n */\n constructor(targetEl, userOptions = {}) {\n this.targetEl = targetEl;\n this.options = mergeDeep(defaultOptions, userOptions);\n\n /** @type {import('./i18n/index.js').AsnLocale} */\n this.locale = resolveLocale(this.options.lang);\n\n /** @type {{ container: HTMLElement, editable: HTMLElement, toolbar?: HTMLElement, statusbar?: HTMLElement }} */\n this.layoutInfo = /** @type {any} */ ({});\n\n /** @type {Map<string, Function[]>} */\n this._listeners = new Map();\n\n /** @type {Map<string, object>} */\n this._modules = new Map();\n\n /** @type {Map<string, { plugin: object, publicApi: * }>} */\n this._plugins = new Map();\n\n this._disposers = [];\n this._alive = false;\n this._autoSaveTimer = null;\n this._pendingAutoSave = null;\n this._suppressedRemoteHTML = null;\n /** @type {Promise<void>|null} Settles when destroy()'s closing auto-save finishes */\n this._destroyPromise = null;\n /** @type {null|(() => void)} Set by the public factory to release its WeakMap entry. */\n this._releaseInstance = null;\n }\n\n // ---------------------------------------------------------------------------\n // Initialisation\n // ---------------------------------------------------------------------------\n\n initialize() {\n // 1. Render the DOM skeleton\n const { container, editable } = renderLayout(this.targetEl, this.options);\n this.layoutInfo.container = container;\n this.layoutInfo.editable = editable;\n\n // 2. Register core modules\n this._registerModules();\n\n // 3. Attach toolbar/statusbar to container\n const toolbar = this._modules.get('toolbar');\n if (toolbar?.el) {\n container.insertBefore(toolbar.el, editable);\n this.layoutInfo.toolbar = toolbar.el;\n }\n\n const statusbar = this._modules.get('statusbar');\n if (statusbar?.el) {\n container.appendChild(statusbar.el);\n this.layoutInfo.statusbar = statusbar.el;\n }\n\n // 4. Bind editor-level events\n this._bindEditorEvents(editable);\n\n // 5. Auto-focus if requested\n if (this.options.focus) {\n editable.focus();\n }\n\n this._alive = true;\n\n // Initial toolbar sync so dropdowns show the correct font on load\n this.invoke('toolbar.refresh');\n\n // Apply plugins registered globally via AutumnNote.use()\n this._applyGlobalPlugins();\n\n if (typeof this.options.onInit === 'function') {\n this.options.onInit(this);\n }\n\n return this;\n }\n\n _registerModules() {\n const register = (name, ModuleClass) => {\n const instance = new ModuleClass(this);\n this._modules.set(name, instance);\n instance.initialize();\n };\n\n for (const { name, Class, enabled } of _moduleDefs) {\n if (typeof enabled === 'function' && !enabled(this.options)) continue;\n register(name, Class);\n }\n\n // Custom modules registered via AutumnNote.registerModule()\n if (_customModules.size > 0) {\n for (const [name, ModuleClass] of _customModules) {\n register(name, ModuleClass);\n }\n }\n }\n\n /**\n * Registers or tears down option-gated modules so they match the current\n * option values. Called after `updateOptions()` so toggling e.g.\n * `bubbleToolbar` at runtime actually takes effect.\n */\n _syncOptionalModules() {\n for (const { name, Class, enabled } of _moduleDefs) {\n if (typeof enabled !== 'function') continue;\n const shouldRun = enabled(this.options);\n const isRunning = this._modules.has(name);\n if (shouldRun === isRunning) continue;\n\n if (shouldRun) {\n const instance = new Class(this);\n this._modules.set(name, instance);\n instance.initialize();\n } else {\n const instance = this._modules.get(name);\n if (typeof instance?.destroy === 'function') instance.destroy();\n this._modules.delete(name);\n }\n }\n }\n\n /**\n * Registers and initialises a custom module on this instance.\n * @param {string} name\n * @param {new (ctx: this) => any} ModuleClass\n * @returns {this}\n */\n registerModule(name, ModuleClass) {\n if (this._modules.has(name)) return this;\n const instance = new ModuleClass(this);\n instance.initialize();\n this._modules.set(name, instance);\n return this;\n }\n\n registerSlashCommand(command) {\n if (!command?.id || typeof command.run !== 'function') {\n throw new TypeError('[AutumnNote] Slash command requires an id and run(context) function.');\n }\n const commands = this.options.slashCommands || (this.options.slashCommands = []);\n const index = commands.findIndex((item) => item.id === command.id);\n if (index >= 0) commands[index] = command;\n else commands.push(command);\n this.invoke('slashMenu.refresh');\n return this;\n }\n\n /**\n * Installs a plugin on this editor instance.\n * If called after create(), buttons are registered immediately but the toolbar\n * must be rebuilt via ctx.invoke('toolbar.rebuild') to render new buttons.\n * @param {object} plugin - { name, version?, buttons?, install?, uninstall? }\n * @param {object} [options] - Forwarded to plugin.install(context, options)\n * @returns {this}\n */\n use(plugin, options = {}) {\n if (Array.isArray(plugin.buttons)) {\n plugin.buttons.forEach((b) => registerButton(b));\n }\n this._installPlugin(plugin, options);\n return this;\n }\n\n /**\n * Returns the public API returned by plugin.install(), or null.\n * @param {string} name\n * @returns {*}\n */\n getPlugin(name) {\n return this._plugins.get(name)?.publicApi ?? null;\n }\n\n _installPlugin(plugin, pluginOptions = {}) {\n const { name } = plugin;\n if (!name || typeof name !== 'string') {\n console.warn('[AutumnNote] Plugin must have a string `name` property.');\n return;\n }\n if (this._plugins.has(name)) {\n console.warn(`[AutumnNote] Plugin \"${name}\" already installed on this instance. Skipping.`);\n return;\n }\n const publicApi = (typeof plugin.install === 'function')\n ? plugin.install(this, pluginOptions) ?? null\n : null;\n this._plugins.set(name, { plugin, publicApi });\n }\n\n _applyGlobalPlugins() {\n if (_globalPlugins.size === 0) return;\n for (const { plugin, options } of _globalPlugins.values()) {\n this._installPlugin(plugin, options);\n }\n }\n\n _bindEditorEvents(editable) {\n // Keep the original textarea/input value in sync immediately on every input.\n // This guarantees form.submit() sees fresh data even before debounced change.\n const d0 = on(editable, 'input', () => this._syncToTarget());\n const d1 = on(editable, 'focus', () => {\n this.layoutInfo.container.classList.add('an-focused');\n if (typeof this.options.onFocus === 'function') {\n this.options.onFocus(this);\n }\n });\n const d2 = on(editable, 'blur', () => {\n this.layoutInfo.container.classList.remove('an-focused');\n this._syncToTarget();\n if (typeof this.options.onBlur === 'function') {\n this.options.onBlur(this);\n }\n });\n // Sync textarea/input value on every change so form.submit() always gets fresh content\n const d3 = this.on('change', (html) => this._syncToTarget(html));\n const dRemote = this.on('change', (html) => {\n if (this.options.blockIds) { this.ensureBlockIds(); html = this.getHTML(); }\n if (html === this._suppressedRemoteHTML) { this._suppressedRemoteHTML = null; return; }\n this.options.collaborationAdapter?.onLocalChange?.(html, this);\n });\n this._disposers.push(d0, d1, d2, d3, dRemote);\n\n // Auto-save to localStorage on every change (also writes :asrmeta for restore banner)\n if (this.options.autoSave && this.options.autoSaveKey) {\n const d4 = this.on('change', (html) => this._scheduleAutoSave(html));\n this._disposers.push(d4);\n }\n }\n\n _scheduleAutoSave(html) {\n this._pendingAutoSave = html;\n clearTimeout(this._autoSaveTimer);\n this._autoSaveTimer = setTimeout(() => this.flushAutoSave(), this.options.autoSaveDelay ?? 400);\n }\n\n async flushAutoSave() {\n clearTimeout(this._autoSaveTimer);\n this._autoSaveTimer = null;\n if (this._pendingAutoSave == null) return;\n const html = this._pendingAutoSave;\n this._pendingAutoSave = null;\n const key = this.options.autoSaveKey;\n const savedAt = Date.now();\n try {\n const adapter = this.options.autoSaveAdapter;\n if (typeof adapter?.save === 'function') {\n await adapter.save({ key, html, savedAt, context: this });\n } else {\n localStorage.setItem(key, html);\n localStorage.setItem(key + ':asrmeta', JSON.stringify({ savedAt }));\n }\n this.triggerEvent('autoSave', { key, html, savedAt });\n } catch (error) {\n this.triggerEvent('autoSaveError', { key, error });\n }\n }\n\n async loadAutoSave() {\n const adapter = this.options.autoSaveAdapter;\n if (typeof adapter?.load === 'function') {\n return adapter.load({ key: this.options.autoSaveKey, context: this });\n }\n try { return localStorage.getItem(this.options.autoSaveKey); } catch (_) { return null; }\n }\n\n // ---------------------------------------------------------------------------\n // Module invocation\n // ---------------------------------------------------------------------------\n\n /**\n * Invokes a method on a registered module.\n * Format: 'moduleName.methodName'\n * @param {string} path - e.g. 'editor.bold'\n * @param {...*} args\n * @returns {*}\n */\n invoke(path, ...args) {\n const [moduleName, methodName] = path.split('.');\n const module = this._modules.get(moduleName);\n if (!module) {\n console.warn(`[AutumnNote] invoke: module \"${moduleName}\" not found (path: \"${path}\")`);\n return undefined;\n }\n if (typeof module[methodName] !== 'function') {\n console.warn(`[AutumnNote] invoke: method \"${methodName}\" not found on module \"${moduleName}\" (path: \"${path}\")`);\n return undefined;\n }\n return module[methodName](...args);\n }\n\n // ---------------------------------------------------------------------------\n // Event system\n // ---------------------------------------------------------------------------\n\n /**\n * Subscribes to an editor event.\n * @param {string} eventName\n * @param {Function} handler\n * @returns {() => void} unsubscribe\n */\n on(eventName, handler) {\n if (!this._listeners.has(eventName)) {\n this._listeners.set(eventName, []);\n }\n this._listeners.get(eventName).push(handler);\n return () => this.off(eventName, handler);\n }\n\n /**\n * Unsubscribes from an editor event.\n * @param {string} eventName\n * @param {Function} handler\n */\n off(eventName, handler) {\n const handlers = this._listeners.get(eventName);\n if (!handlers) return;\n const idx = handlers.indexOf(handler);\n if (idx !== -1) handlers.splice(idx, 1);\n }\n\n /**\n * Triggers an editor event.\n * @param {string} eventName\n * @param {...*} args\n */\n triggerEvent(eventName, ...args) {\n const handlers = this._listeners.get(eventName) || [];\n handlers.forEach((h) => h(...args));\n\n // Also call options callback if present (e.g. onChange)\n const cbName = 'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);\n if (typeof this.options[cbName] === 'function') {\n this.options[cbName](...args);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Public editor API\n // ---------------------------------------------------------------------------\n\n /** Updates runtime-safe options without recreating the editor. */\n updateOptions(overrides = {}) {\n const next = mergeDeep(this.options, overrides);\n Object.keys(this.options).forEach((key) => delete this.options[key]);\n Object.assign(this.options, next);\n\n const { container, editable } = this.layoutInfo;\n if (Object.hasOwn(overrides, 'readOnly')) this.setDisabled(Boolean(this.options.readOnly));\n if (Object.hasOwn(overrides, 'spellcheck')) editable.spellcheck = this.options.spellcheck !== false;\n if (Object.hasOwn(overrides, 'placeholder')) editable.dataset.placeholder = this.options.placeholder || '';\n if (Object.hasOwn(overrides, 'direction')) {\n const rtl = this.options.direction === 'rtl';\n editable.setAttribute('dir', rtl ? 'rtl' : 'ltr');\n container.classList.toggle('an-dir-rtl', rtl);\n }\n if (Object.hasOwn(overrides, 'height') || Object.hasOwn(overrides, 'minHeight')) {\n const height = this.options.height || this.options.minHeight || 0;\n editable.style.minHeight = height ? `${height}px` : '';\n }\n if (Object.hasOwn(overrides, 'maxHeight')) {\n editable.style.maxHeight = this.options.maxHeight ? `${this.options.maxHeight}px` : '';\n }\n if (Object.hasOwn(overrides, 'toolbar')) this.invoke('toolbar.rebuild');\n // Start/stop option-gated modules (bubbleToolbar, mention, slashMenu, ...)\n // so toggling them here behaves the same as passing them to create().\n this._syncOptionalModules();\n this.invoke('statusbar.update');\n this.triggerEvent('optionsChange', { ...overrides });\n return this;\n }\n\n /**\n * Returns the current HTML content of the editor.\n * Zero-width spaces (U+200B) inserted by inline editing helpers are stripped\n * from the output so they don't leak into the consumer's HTML.\n * @returns {string}\n */\n getHTML() {\n const html = this.invoke('editor.getHTML');\n return typeof html === 'string' ? html.replace(//g, '') : html;\n }\n\n /**\n * Sets the HTML content of the editor.\n * @param {string} html\n */\n setHTML(html) {\n this.invoke('editor.setHTML', html);\n }\n\n /**\n * Returns the plain text content of the editor.\n * @returns {string}\n */\n getText() {\n return this.invoke('editor.getText');\n }\n\n /**\n * Sets the editor content as plain text (HTML-escaped).\n * @param {string} text\n */\n setText(text) {\n this.invoke('editor.setText', text);\n }\n\n /**\n * Clears the editor content.\n */\n clear() {\n this.invoke('editor.clear');\n }\n\n /**\n * Resets the undo/redo history stack.\n * Useful after programmatically loading a new document via setHTML() / setMarkdown()\n * so that Ctrl+Z cannot undo back to the previous document.\n */\n clearHistory() {\n this.invoke('editor.clearHistory');\n }\n\n /**\n * Returns the number of available undo steps.\n * @returns {number}\n */\n getUndoCount() {\n return this.invoke('editor.getUndoCount') ?? 0;\n }\n\n /**\n * Returns the number of available redo steps.\n * @returns {number}\n */\n getRedoCount() {\n return this.invoke('editor.getRedoCount') ?? 0;\n }\n\n /**\n * Returns true when the editor has no meaningful content.\n * @returns {boolean}\n */\n isEmpty() {\n return this.invoke('editor.isEmpty');\n }\n\n /**\n * Inserts HTML at the current cursor position.\n * @param {string} html\n */\n insertHTML(html) {\n this.invoke('editor.insertHTML', html);\n }\n\n /**\n * Inserts plain text at the current cursor position.\n * @param {string} text\n */\n insertText(text) {\n this.invoke('editor.insertText', text);\n }\n\n /**\n * Sets editor content from a Markdown string.\n * @param {string} md\n */\n setMarkdown(md) {\n this.invoke('editor.setMarkdown', md);\n }\n\n /**\n * Returns the editor content as Markdown.\n * @returns {string}\n */\n getMarkdown() {\n return this.invoke('editor.getMarkdown');\n }\n\n getSelectionBookmark() {\n return this.invoke('editor.getSelectionBookmark') ?? null;\n }\n\n restoreSelectionBookmark(bookmark) {\n return this.invoke('editor.restoreSelectionBookmark', bookmark);\n }\n\n async importDocument(format, data) {\n const adapter = this.options.documentAdapters?.[format];\n let html;\n if (typeof adapter?.import === 'function') html = await adapter.import(data, this);\n else if (format === 'html') html = String(data ?? '');\n else if (format === 'markdown') { this.setMarkdown(String(data ?? '')); return this; }\n else if (format === 'text') { this.setText(String(data ?? '')); return this; }\n else throw new Error(`[AutumnNote] No importer registered for \"${format}\".`);\n this.setHTML(html);\n return this;\n }\n\n async exportDocument(format) {\n const adapter = this.options.documentAdapters?.[format];\n if (typeof adapter?.export === 'function') return adapter.export(this, this.getHTML());\n if (format === 'html') return this.getHTML();\n if (format === 'markdown') return this.getMarkdown();\n if (format === 'text') return this.getText();\n throw new Error(`[AutumnNote] No exporter registered for \"${format}\".`);\n }\n\n ensureBlockIds() {\n const blocks = this.layoutInfo.editable.children;\n for (const block of blocks) {\n if (!block.hasAttribute('data-an-block-id')) {\n const id = globalThis.crypto?.randomUUID?.() || `an-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n block.setAttribute('data-an-block-id', id);\n }\n }\n return this;\n }\n\n getDocument() {\n if (this.options.blockIds) this.ensureBlockIds();\n return { version: 1, html: this.getHTML(), markdown: this.getMarkdown() };\n }\n\n loadDocument(documentData) {\n this.setHTML(documentData?.html || '');\n this.clearHistory();\n return this;\n }\n\n applyRemoteHTML(html) {\n this.setHTML(html);\n this._suppressedRemoteHTML = this.getHTML();\n this.clearHistory();\n return this;\n }\n\n /**\n * Returns the current word count of the editor content.\n * @returns {number}\n */\n getWordCount() {\n return this.invoke('statusbar.getWordCount') ?? 0;\n }\n\n /**\n * Returns the current character count of the editor content.\n * @returns {number}\n */\n getCharCount() {\n return this.invoke('statusbar.getCharCount') ?? 0;\n }\n\n /**\n * Downloads the editor content as an HTML file.\n * @param {string} [filename='document.html']\n */\n downloadHTML(filename = 'document.html') {\n this._download(this.getHTML(), filename, 'text/html');\n }\n\n /**\n * Downloads the editor content as a plain-text file.\n * @param {string} [filename='document.txt']\n */\n downloadText(filename = 'document.txt') {\n this._download(this.getText(), filename, 'text/plain');\n }\n\n /**\n * Downloads the editor content as a Markdown file.\n * @param {string} [filename='document.md']\n */\n downloadMarkdown(filename = 'document.md') {\n this._download(this.getMarkdown(), filename, 'text/markdown');\n }\n\n /**\n * Creates a temporary Blob URL and triggers a browser file download.\n * @param {string} content\n * @param {string} filename\n * @param {string} mimeType\n */\n _download(content, filename, mimeType) {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n a.style.display = 'none';\n document.body.appendChild(a);\n a.click();\n a.remove();\n URL.revokeObjectURL(url);\n }\n\n /**\n * Opens the editor content in a new globalThis and triggers the browser print dialog.\n * @param {string} [title='']\n */\n print(title = '') {\n const content = this.getHTML();\n const safeTitle = (title || '').replace(/[<>&\"']/g, (c) => `&#${c.charCodeAt(0)};`);\n const markup = '<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\">' +\n `<title>${safeTitle}</title>` +\n '<style>' +\n 'body{font-family:system-ui,-apple-system,\"Segoe UI\",Roboto,Arial,sans-serif;font-size:14px;line-height:1.6;padding:20mm;color:#111827;}' +\n 'ul.an-checklist{list-style:none;padding-left:0;}' +\n 'ul.an-checklist li{padding-left:24px;position:relative;margin:2px 0;}' +\n 'ul.an-checklist li input[type=\"checkbox\"]{position:absolute;left:0;top:3px;}' +\n 'code{background:#f3f4f6;border-radius:3px;padding:.1em .35em;font-family:monospace;}' +\n 'pre{background:#f3f4f6;padding:.75em 1em;border-radius:4px;overflow-x:auto;}' +\n 'table{border-collapse:collapse;}td,th{border:1px solid #d1d5db;padding:4px 8px;}' +\n '</style>' +\n `</head><body>${content}</body></html>`;\n const blob = new Blob([markup], { type: 'text/html' });\n const url = URL.createObjectURL(blob);\n const w = globalThis.open(url, '_blank');\n if (!w) { URL.revokeObjectURL(url); return; } // popup blocked by browser\n w.addEventListener('load', () => {\n w.print();\n URL.revokeObjectURL(url);\n });\n }\n\n /**\n * Returns an array of heading objects representing the table of contents.\n * Each entry has: level (1-6), text (heading text), element (DOM element).\n * @returns {{ level: number, text: string, element: HTMLElement }[]}\n */\n getTableOfContents() {\n const headings = Array.from(\n this.layoutInfo.editable.querySelectorAll('h1,h2,h3,h4,h5,h6')\n );\n return headings.map((el) => ({\n level: parseInt(el.tagName[1], 10),\n text: el.textContent?.trim() ?? '',\n element: /** @type {HTMLElement} */ (el),\n }));\n }\n\n /**\n * Moves focus into the editable area.\n */\n focus() {\n this.layoutInfo.editable.focus();\n }\n\n /**\n * Removes focus from the editable area.\n */\n blur() {\n this.layoutInfo.editable.blur();\n }\n\n /**\n * Returns true when the editor is currently in fullscreen mode.\n * @returns {boolean}\n */\n isFullscreen() {\n return this.invoke('fullscreen.isActive') === true;\n }\n\n /**\n * Sets whether the editor is disabled (readonly).\n * @param {boolean} disabled\n */\n setDisabled(disabled) {\n const editable = this.layoutInfo.editable;\n if (disabled) {\n editable.setAttribute('contenteditable', 'false');\n this.layoutInfo.container.classList.add('an-disabled');\n editable.querySelectorAll('ul.an-checklist input[type=\"checkbox\"]').forEach((cb) => {\n cb.setAttribute('disabled', '');\n });\n } else {\n editable.setAttribute('contenteditable', 'true');\n this.layoutInfo.container.classList.remove('an-disabled');\n editable.querySelectorAll('ul.an-checklist input[type=\"checkbox\"]').forEach((cb) => {\n cb.removeAttribute('disabled');\n });\n }\n }\n\n // ---------------------------------------------------------------------------\n // Destroy\n // ---------------------------------------------------------------------------\n\n /**\n * Completely removes the editor and restores the original element.\n *\n * Teardown itself is synchronous; the returned promise only settles once the\n * closing auto-save has finished, so `await editor.destroy()` is worth doing\n * when using an async `autoSaveAdapter`. Ignoring the return value is safe.\n * @returns {Promise<void>}\n */\n destroy() {\n if (!this._alive) return this._destroyPromise ?? Promise.resolve();\n\n // Start the final auto-save before tearing anything down. `_listeners` is\n // deliberately kept alive until this settles, otherwise the closing\n // autoSave/autoSaveError event fires into an already-cleared listener map\n // and an async adapter's last write completes silently.\n const pendingFlush = this._pendingAutoSave != null\n ? this.flushAutoSave().catch(() => {})\n : null;\n\n this._modules.forEach((module) => {\n if (typeof module.destroy === 'function') module.destroy();\n });\n this._modules.clear();\n\n for (const { plugin } of this._plugins.values()) {\n if (typeof plugin.uninstall === 'function') {\n try { plugin.uninstall(this); } catch (_) { void _; }\n }\n }\n this._plugins.clear();\n\n this._disposers.forEach((d) => d());\n this._disposers = [];\n\n const container = this.layoutInfo.container;\n const wasDark = container?.classList.contains('an-theme-dark');\n const wasAuto = container?.classList.contains('an-theme-auto');\n if (container?.parentNode) {\n // Restore original element\n this.targetEl.style.display = '';\n container.remove();\n }\n // Clean up body theme classes if no other editors of that type remain\n if (wasDark && !document.querySelector('.an-container.an-theme-dark')) {\n document.body.classList.remove('an-theme-dark');\n }\n if (wasAuto && !document.querySelector('.an-container.an-theme-auto')) {\n document.body.classList.remove('an-theme-auto');\n }\n\n if (typeof this.options.onDestroy === 'function') {\n this.options.onDestroy(this);\n }\n\n this._alive = false;\n this._releaseInstance?.();\n this._releaseInstance = null;\n\n // Resolves once the closing auto-save (if any) has finished. Callers using\n // an async autoSaveAdapter can `await editor.destroy()` to be sure the last\n // write landed before unloading.\n this._destroyPromise = Promise.resolve(pendingFlush).then(() => {\n this._listeners.clear();\n });\n return this._destroyPromise;\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Syncs editor HTML back into the original textarea/input for form submission.\n */\n _syncToTarget(html) {\n if (this.targetEl.tagName === 'TEXTAREA' || this.targetEl.tagName === 'INPUT') {\n /** @type {HTMLInputElement} */ (this.targetEl).value = typeof html === 'string' ? html : this.getHTML();\n }\n }\n}\n","/**\n * History.js - Undo / redo stack for editor content\n * Inspired by Summernote's History module, rewritten without jQuery\n */\n\n/**\n * Number of characters two strings share from the start.\n * @param {string} a\n * @param {string} b\n * @returns {number}\n */\nfunction _commonPrefixLength(a, b) {\n const max = Math.min(a.length, b.length);\n let i = 0;\n while (i < max && a.charCodeAt(i) === b.charCodeAt(i)) i++;\n return i;\n}\n\nexport class History {\n /**\n * @param {HTMLElement} editable - the contenteditable element\n * @param {number} [limit=100] - maximum number of undo/redo states\n * @param {number} [maxBytes=10485760] - maximum combined size (chars) of all\n * stacked snapshots (html + tokenized image data). Oldest states are\n * evicted first when exceeded, even if `limit` hasn't been reached —\n * documents with many large embedded images can otherwise hold dozens of\n * full-size copies in memory despite the step-count limit.\n */\n constructor(editable, limit = 100, maxBytes = 10 * 1024 * 1024) {\n this.editable = editable;\n this._limit = limit;\n this._maxBytes = maxBytes;\n this._bytes = 0;\n /** @type {Array<{html: string, images?: Record<string,string>, sel: {start: number, end: number}|null}>} */\n this.stack = [];\n this.stackOffset = -1;\n this._savePoint();\n }\n\n /**\n * Approximate in-memory size (chars) of one stacked snapshot: the tokenized\n * HTML string plus every image data URL it references.\n * @param {{html: string, images?: Record<string,string>}} entry\n * @returns {number}\n */\n _entrySize(entry) {\n let size = entry.html.length;\n if (entry.images) {\n for (const key in entry.images) size += entry.images[key].length;\n }\n return size;\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n _serialize() {\n return this.editable.innerHTML;\n }\n\n /**\n * Serializes the current selection as character offsets from the start of\n * the editable element, so it can be restored after innerHTML replacement.\n * @returns {{ start: number, end: number }|null}\n */\n _serializeSelection() {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const range = sel.getRangeAt(0);\n if (!this.editable.contains(range.startContainer)) return null;\n return {\n start: this._charOffset(range.startContainer, range.startOffset),\n end: this._charOffset(range.endContainer, range.endOffset),\n };\n }\n\n /**\n * Returns the character offset of (node, offset) from the beginning of\n * the editable's text content.\n *\n * Measured with a Range rather than by looking for `node` among the text\n * nodes: a selection is often anchored on an *element* — `setStartAfter` on\n * an inserted node leaves it that way, which is what the native insertion\n * path produces — and searching for it among text nodes never matches, so\n * every such position used to serialise as 0. Undo then threw the caret to\n * the top of the document after any insertion.\n * @param {Node} node\n * @param {number} offset\n * @returns {number}\n */\n _charOffset(node, offset) {\n try {\n const range = document.createRange();\n range.selectNodeContents(this.editable);\n range.setEnd(node, offset);\n // Range.toString() concatenates exactly the text nodes _restoreSelection\n // walks, so the two agree on what an offset means.\n return range.toString().length;\n } catch (_) {\n void _; // position outside the editable — treat as the start\n return 0;\n }\n }\n\n /**\n * Restores a previously serialized selection inside the editable.\n * @param {{ start: number, end: number }|null} saved\n */\n _restoreSelection(saved) {\n if (!saved) return;\n let startNode = null, startOff = 0;\n let endNode = null, endOff = 0;\n let count = 0;\n const walker = document.createTreeWalker(this.editable, NodeFilter.SHOW_TEXT, null);\n let cur;\n while ((cur = walker.nextNode())) {\n const len = /** @type {Text} */ (cur).length;\n if (!startNode && count + len >= saved.start) {\n startNode = cur;\n startOff = saved.start - count;\n }\n if (!endNode && count + len >= saved.end) {\n endNode = cur;\n endOff = saved.end - count;\n break;\n }\n count += len;\n }\n if (!startNode) {\n // Offset exceeds content (e.g. undo to a shorter state): place at end\n const lastWalker = document.createTreeWalker(this.editable, NodeFilter.SHOW_TEXT, null);\n let lastNode = null;\n while ((lastNode = lastWalker.nextNode())) { startNode = lastNode; }\n startOff = startNode ? /** @type {Text} */ (startNode).length : 0;\n endNode = startNode;\n endOff = startOff;\n }\n if (!endNode) { endNode = startNode; endOff = startOff; }\n try {\n const range = document.createRange();\n range.setStart(startNode, startOff);\n range.setEnd(endNode, endOff);\n const sel = globalThis.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n } catch (_) {\n void _; // detached node — fall back to placing cursor at start of editable\n try {\n const fb = document.createRange();\n fb.setStart(this.editable, 0);\n fb.collapse(true);\n const s = globalThis.getSelection();\n if (s) { s.removeAllRanges(); s.addRange(fb); }\n } catch (_2) { void _2; /* fully give up */ }\n }\n }\n\n _savePoint() {\n // Trim future history if we're mid-stack\n if (this.stackOffset < this.stack.length - 1) {\n for (const entry of this.stack.slice(this.stackOffset + 1)) {\n this._bytes -= this._entrySize(entry);\n }\n this.stack = this.stack.slice(0, this.stackOffset + 1);\n }\n const raw = this._serialize();\n const { html, images } = this._tokenizeImages(raw);\n const entry = { html, images, sel: this._serializeSelection() };\n this.stack.push(entry);\n this._bytes += this._entrySize(entry);\n\n // Evict oldest states first, whichever budget (step count or byte size)\n // is exceeded — always keep at least the just-pushed current state.\n while (this.stack.length > 1 && (this.stack.length > this._limit || this._bytes > this._maxBytes)) {\n this._bytes -= this._entrySize(this.stack.shift());\n }\n // The newly-pushed current state is always the final entry. Recompute the\n // offset from the resulting stack instead of incrementing conditionally:\n // a single oversized snapshot may evict several older entries at once.\n this.stackOffset = this.stack.length - 1;\n }\n\n /**\n * Restores a snapshot and puts the caret somewhere useful.\n *\n * A state captured before the editor was ever focused — the one `reset()`\n * pushes after `setHTML` — carries no selection, and without a fallback the\n * first undo after loading content dropped the caret at the top of the\n * document. The fallback is the position where this state and the one being\n * left first differ, which is exactly where the undone edit happened.\n * @param {{html: string, images?: Record<string,string>, sel: {start: number, end: number}|null}} point\n */\n _restore(point) {\n if (!point) return;\n const before = this.editable.textContent || '';\n this.editable.innerHTML = this._detokenizeImages(point);\n\n let sel = point.sel;\n if (!sel) {\n const at = _commonPrefixLength(before, this.editable.textContent || '');\n sel = { start: at, end: at };\n }\n this._restoreSelection(sel);\n }\n\n // ---------------------------------------------------------------------------\n // Base64 tokenisation — keeps snapshot strings small so that the\n // per-keystroke `recordUndo` string comparison stays fast even when the\n // editor contains large embedded images.\n // ---------------------------------------------------------------------------\n\n /**\n * Replaces every `data:…;base64,…` occurrence in `html` with a compact\n * token `__asn_img_0__`, `__asn_img_1__`, … and returns the tokenized\n * string together with a map from token → original data URL.\n * @param {string} html\n * @returns {{ html: string, images: Object<string,string> }}\n */\n _tokenizeImages(html) {\n // Fast-path: skip regex entirely when there are no data URIs (common case)\n if (!html.includes('data:')) return { html, images: /** @type {Record<string,string>} */ ({}) };\n const images = /** @type {Record<string,string>} */ ({});\n let index = 0;\n const tokenized = html.replace(/data:[^;]+;base64,[^\"' >]*/g, (match) => {\n const token = `__asn_img_${index}__`;\n images[token] = match;\n index++;\n return token;\n });\n return { html: tokenized, images };\n }\n\n /**\n * Restores a snapshot by replacing tokens back with their data URLs.\n * @param {{ html: string, images?: Object<string,string> }} point\n * @returns {string}\n */\n _detokenizeImages(point) {\n if (!point.images || Object.keys(point.images).length === 0) return point.html;\n return point.html.replace(/__asn_img_\\d+__/g, (token) => point.images[token] || token);\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n /**\n * Records the current editor state as a history checkpoint.\n */\n recordUndo() {\n const current = this._serialize();\n const { html: tokenized } = this._tokenizeImages(current);\n const prev = this.stack[this.stackOffset];\n if (prev?.html === tokenized) return; // No change\n this._savePoint();\n }\n\n /**\n * Undo to the previous state.\n */\n undo() {\n if (this.stackOffset <= 0) return;\n this.stackOffset--;\n this._restore(this.stack[this.stackOffset]);\n }\n\n /**\n * Redo to the next state.\n */\n redo() {\n if (this.stackOffset >= this.stack.length - 1) return;\n this.stackOffset++;\n this._restore(this.stack[this.stackOffset]);\n }\n\n /**\n * Resets the history stack (e.g. on editor destroy or full content replace).\n */\n reset() {\n this.stack = [];\n this.stackOffset = -1;\n this._bytes = 0;\n this._savePoint();\n }\n\n /** @returns {boolean} */\n canUndo() {\n return this.stackOffset > 0;\n }\n\n /** @returns {boolean} */\n canRedo() {\n return this.stackOffset < this.stack.length - 1;\n }\n\n /** @returns {number} */\n getUndoCount() {\n return Math.max(0, this.stackOffset);\n }\n\n /** @returns {number} */\n getRedoCount() {\n return Math.max(0, this.stack.length - 1 - this.stackOffset);\n }\n}\n","/**\n * Table.js - Table creation and manipulation utilities\n * Inspired by Summernote's table handling\n */\n\nimport { createElement } from '../core/dom.js';\n\n// ---------------------------------------------------------------------------\n// Table creation\n// ---------------------------------------------------------------------------\n\n/**\n * Build an HTML table with the given number of columns and rows, optionally including a header row.\n * @param {number} cols - Number of columns in each row.\n * @param {number} rows - Total number of rows to create (including header when `headerRow` is true).\n * @param {{ headerRow?: boolean }} [opts] - Options: `headerRow` creates a `<thead>` when true.\n * @returns {HTMLTableElement} The constructed `<table>` element with a `<tbody>` and optional `<thead>`; each cell contains a `<br>` placeholder.\n */\nexport function createTable(cols, rows, opts = {}) {\n const { headerRow = false } = opts;\n const table = createElement('table', { class: 'an-table' });\n\n if (headerRow && rows > 0) {\n const thead = createElement('thead');\n const tr = createElement('tr');\n for (let c = 0; c < cols; c++) {\n const th = createElement('th', {}, [document.createElement('br')]);\n tr.appendChild(th);\n }\n thead.appendChild(tr);\n table.appendChild(thead);\n }\n\n const bodyRows = headerRow ? Math.max(rows - 1, 1) : rows;\n const tbody = createElement('tbody');\n table.appendChild(tbody);\n\n for (let r = 0; r < bodyRows; r++) {\n const tr = createElement('tr');\n for (let c = 0; c < cols; c++) {\n const td = createElement('td', {}, [document.createElement('br')]);\n tr.appendChild(td);\n }\n tbody.appendChild(tr);\n }\n return /** @type {HTMLTableElement} */ (table);\n}\n\n/**\n * Insert a table at the current selection and place the caret into its first cell.\n * @param {number} cols - Number of columns for the new table.\n * @param {number} rows - Number of rows for the new table.\n * @param {{ headerRow?: boolean }} [opts] - Options for table creation.\n */\nexport function insertTable(cols, rows, opts = {}) {\n if (cols <= 0 || rows <= 0) return;\n const table = createTable(cols, rows, opts);\n\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n try {\n range.deleteContents();\n } catch (_) {\n return;\n }\n\n // Walk up to find the nearest block-level ancestor to insert after\n const BLOCK = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE', 'LI', 'PRE']);\n let anchor = /** @type {Element|null} */ (range.startContainer);\n if (anchor?.nodeType === 3) anchor = anchor.parentElement;\n while (anchor && !BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentElement) {\n anchor = anchor.parentElement;\n }\n\n if (anchor && BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentNode) {\n anchor.after(table);\n // Ensure there's a paragraph after the table for cursor landing\n if (!table.nextElementSibling) {\n const p = document.createElement('p');\n p.appendChild(document.createElement('br'));\n table.after(p);\n }\n // Remove the anchor block if it was empty (common case: cursor in blank paragraph)\n if (!anchor.textContent.trim() && !anchor.querySelector('img, video, table')) {\n anchor.remove();\n }\n } else {\n try {\n range.insertNode(table);\n } catch (_) {\n return;\n }\n }\n\n // Place cursor in the first cell\n const firstCell = table.querySelector('td, th');\n if (firstCell) {\n const nr = document.createRange();\n nr.setStart(firstCell, 0);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n }\n}\n","/**\n * key.js - Keyboard key code constants\n * Inspired by Summernote's key.js\n */\n\nexport const key = {\n BACKSPACE: 'Backspace',\n TAB: 'Tab',\n ENTER: 'Enter',\n ESCAPE: 'Escape',\n SPACE: ' ',\n PAGE_UP: 'PageUp',\n PAGE_DOWN: 'PageDown',\n END: 'End',\n HOME: 'Home',\n LEFT: 'ArrowLeft',\n UP: 'ArrowUp',\n RIGHT: 'ArrowRight',\n DOWN: 'ArrowDown',\n DELETE: 'Delete',\n // Numbers\n NUM0: '0',\n NUM1: '1',\n NUM2: '2',\n NUM3: '3',\n NUM4: '4',\n NUM5: '5',\n NUM6: '6',\n NUM7: '7',\n NUM8: '8',\n // Letters\n B: 'b',\n E: 'e',\n I: 'i',\n J: 'j',\n K: 'k',\n L: 'l',\n R: 'r',\n S: 's',\n U: 'u',\n V: 'v',\n Y: 'y',\n Z: 'z',\n SLASH: '/',\n PERIOD: '.',\n};\n\n/**\n * Returns true if the event matches the given key\n * @param {KeyboardEvent} event\n * @param {string} keyName - one of key.*\n * @returns {boolean}\n */\nexport function isKey(event, keyName) {\n return event.key === keyName || event.key === keyName.toUpperCase();\n}\n\n/**\n * Returns true if the event is a modifier key press (Ctrl/Cmd + key)\n * @param {KeyboardEvent} event\n * @param {string} keyName\n * @returns {boolean}\n */\nexport function isModifier(event, keyName) {\n return (event.ctrlKey || event.metaKey) && isKey(event, keyName);\n}\n","/**\n * Typing.js - Keyboard typing event handling (Enter, Tab, Backspace behaviour)\n * Inspired by Summernote's Typing module\n */\n\nimport { key, isKey } from '../core/key.js';\nimport { closestPara, isLi, placeCaret } from '../core/dom.js';\nimport { execCommand, indent, outdent } from './Style.js';\nimport { currentRange } from '../core/range.js';\n\n// ---------------------------------------------------------------------------\n// Module-level predicates — defined once, not re-created on every keypress.\n// Previously these were arrow functions inside handleKeydown() which fires\n// at ~120+ events/sec during normal typing.\n// ---------------------------------------------------------------------------\nconst _FA_PATTERN = /\\bfa-/;\nconst isFAIcon = (n) => !!(n?.nodeName === 'I' && _FA_PATTERN.test(n.className || ''));\nconst isZwsAnchor = (n) => !!(n?.nodeType === Node.TEXT_NODE && (n.textContent === '\\u200B' || n.textContent === ''));\n\n/**\n * Moves the caret to the next (or previous) cell of the table holding `node`.\n *\n * Tab from the last cell appends a row, matching every comparable editor —\n * it is how a table gets filled in without reaching for the mouse. Shift+Tab\n * from the first cell has nowhere to go and stays put rather than falling\n * through to a handler that would insert whitespace.\n * @param {Node} node - the selection's start container\n * @param {HTMLElement} editable\n * @param {boolean} back - true for Shift+Tab\n * @returns {boolean} false when the caret is not in a table, so the caller\n * can carry on with its other Tab rules\n */\nfunction moveTableCell(node, editable, back) {\n const start = /** @type {Element|null} */ (\n node?.nodeType === Node.ELEMENT_NODE ? node : node?.parentElement ?? null\n );\n const cell = /** @type {HTMLTableCellElement|null} */ (start?.closest('td, th') ?? null);\n if (!cell || !editable.contains(cell)) return false;\n\n const table = cell.closest('table');\n if (!table || !editable.contains(table)) return false;\n\n const cells = /** @type {HTMLTableCellElement[]} */ (Array.from(table.querySelectorAll('td, th')));\n const index = cells.indexOf(cell);\n const target = cells[index + (back ? -1 : 1)];\n\n if (target) {\n placeCaret(target);\n return true;\n }\n if (back) return true; // first cell: consumed, but nowhere to go\n\n const added = appendRowLike(/** @type {HTMLTableRowElement|null} */ (cell.closest('tr')));\n const first = /** @type {HTMLElement|null} */ (added?.firstElementChild ?? null);\n if (first) placeCaret(first);\n return true;\n}\n\n/**\n * Appends a row with the same number of cells as `row`, after it.\n * @param {HTMLTableRowElement|null} row\n * @returns {HTMLTableRowElement|null} the new row\n */\nfunction appendRowLike(row) {\n if (!row?.parentNode) return null;\n const fresh = document.createElement('tr');\n for (const cell of row.cells) {\n // Always <td>: a new row below a header row is body content, not another\n // header.\n const td = document.createElement('td');\n td.appendChild(document.createElement('br'));\n if (cell.hasAttribute('style')) td.setAttribute('style', cell.getAttribute('style'));\n fresh.appendChild(td);\n }\n row.parentNode.insertBefore(fresh, row.nextSibling);\n return fresh;\n}\n\n/**\n * Extracts the content from `startContainer:startOffset` to the end of `li`.\n * Returns an empty fragment if the range is invalid (e.g. detached node).\n * @param {Range} nativeRange\n * @param {Element} li\n * @returns {DocumentFragment}\n */\nfunction extractAfterContent(nativeRange, li) {\n try {\n const r = document.createRange();\n r.setStart(nativeRange.startContainer, nativeRange.startOffset);\n r.setEnd(li, li.childNodes.length);\n return r.extractContents();\n } catch (_) {\n void _;\n return document.createDocumentFragment();\n }\n}\n\n/**\n * Handles special keydown behaviour inside the editor.\n * @param {KeyboardEvent} event\n * @param {HTMLElement} editable\n * @param {object} options - editor options\n * @returns {boolean} true if the event was consumed\n */\nexport function handleKeydown(event, editable, options = {}) {\n const moveCaret = (setFn) => {\n const sel = globalThis.getSelection();\n if (!sel) return false;\n const nr = document.createRange();\n setFn(nr);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n return true;\n };\n\n // -------------------------------------------------------------------------\n // Backspace key — one-press deletion of a preceding FA icon (<i> element)\n // -------------------------------------------------------------------------\n if (isKey(event, key.BACKSPACE)) {\n const sel = globalThis.getSelection();\n if (sel?.rangeCount > 0) {\n const r = sel.getRangeAt(0);\n if (r.collapsed && r.startContainer.nodeType === Node.TEXT_NODE) {\n const textNode = /** @type {ChildNode} */ (r.startContainer);\n // Case A: cursor at offset 0, preceding sibling is an FA icon\n if (r.startOffset === 0 && isFAIcon(textNode.previousSibling)) {\n event.preventDefault();\n /** @type {ChildNode} */ (textNode.previousSibling).remove();\n return true;\n }\n\n // Case B: cursor at offset 1 of a ZWS-only text node whose preceding\n // sibling is an FA icon. The ZWS is the invisible caret anchor inserted\n // by IconDialog; treat the whole Backspace as \"delete icon + its anchor\".\n if (r.startOffset === 1 && textNode.textContent === '\\u200B' &&\n isFAIcon(textNode.previousSibling)) {\n event.preventDefault();\n const parent = textNode.parentNode;\n const icon = /** @type {ChildNode} */ (textNode.previousSibling);\n const prevNode = icon.previousSibling; // node before the icon (e.g. ZWS of prior icon)\n icon.remove();\n textNode.remove();\n // Explicitly restore the cursor to the node preceding the deleted icon.\n // Without this, the browser collapses the selection to the parent element\n // (not a text node), causing the next Backspace to miss Cases A/B and\n // requiring an extra keypress when two icons are adjacent.\n const nr = document.createRange();\n if (prevNode?.nodeType === Node.TEXT_NODE) {\n nr.setStart(prevNode, prevNode.textContent.length);\n } else if (prevNode) {\n nr.setStartAfter(prevNode);\n } else if (parent) {\n nr.setStart(parent, 0);\n }\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n return true;\n }\n }\n }\n return false;\n }\n\n // -------------------------------------------------------------------------\n // ArrowLeft / ArrowRight — one-press navigation across FA icon nodes\n // -------------------------------------------------------------------------\n if (isKey(event, key.LEFT) || isKey(event, key.RIGHT)) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return false;\n\n const r = sel.getRangeAt(0);\n if (!r.collapsed) return false;\n\n const sc = r.startContainer;\n const movingLeft = isKey(event, key.LEFT);\n\n if (sc.nodeType === Node.TEXT_NODE) {\n const textNode = sc;\n\n if (movingLeft &&\n r.startOffset === 1 &&\n textNode.textContent === '\\u200B' &&\n isFAIcon(textNode.previousSibling)) {\n event.preventDefault();\n return moveCaret((nr) => nr.setStartBefore(textNode.previousSibling));\n }\n\n if (movingLeft && r.startOffset === 0 && isFAIcon(textNode.previousSibling)) {\n event.preventDefault();\n return moveCaret((nr) => nr.setStartBefore(textNode.previousSibling));\n }\n\n if (movingLeft &&\n r.startOffset === 0 &&\n isZwsAnchor(textNode.previousSibling) &&\n isFAIcon(textNode.previousSibling.previousSibling)) {\n event.preventDefault();\n return moveCaret((nr) => nr.setStartBefore(textNode.previousSibling.previousSibling));\n }\n\n if (!movingLeft &&\n r.startOffset === textNode.textContent.length &&\n isFAIcon(textNode.nextSibling)) {\n const icon = textNode.nextSibling;\n const after = icon.nextSibling;\n event.preventDefault();\n if (after?.nodeType === Node.TEXT_NODE) {\n const offset = ((after.textContent || '').startsWith('\\u200B')) ? 1 : 0;\n return moveCaret((nr) => nr.setStart(after, Math.min(offset, after.textContent.length)));\n }\n return moveCaret((nr) => nr.setStartAfter(icon));\n }\n\n if (!movingLeft &&\n r.startOffset === textNode.textContent.length &&\n isZwsAnchor(textNode.nextSibling) &&\n isFAIcon(textNode.nextSibling.nextSibling)) {\n const icon = textNode.nextSibling.nextSibling;\n const after = icon.nextSibling;\n event.preventDefault();\n if (after?.nodeType === Node.TEXT_NODE) {\n const offset = ((after.textContent || '').startsWith('\\u200B')) ? 1 : 0;\n return moveCaret((nr) => nr.setStart(after, Math.min(offset, after.textContent.length)));\n }\n return moveCaret((nr) => nr.setStartAfter(icon));\n }\n }\n\n if (sc.nodeType === Node.ELEMENT_NODE) {\n const el = sc;\n if (movingLeft && r.startOffset > 0) {\n const prev = el.childNodes[r.startOffset - 1];\n if (isFAIcon(prev)) {\n event.preventDefault();\n return moveCaret((nr) => nr.setStartBefore(prev));\n }\n if (isZwsAnchor(prev) && isFAIcon(prev.previousSibling)) {\n event.preventDefault();\n return moveCaret((nr) => nr.setStartBefore(prev.previousSibling));\n }\n }\n if (!movingLeft && r.startOffset < el.childNodes.length) {\n const next = el.childNodes[r.startOffset];\n if (isFAIcon(next)) {\n const after = next.nextSibling;\n event.preventDefault();\n if (after?.nodeType === Node.TEXT_NODE) {\n const offset = ((after.textContent || '').startsWith('\\u200B')) ? 1 : 0;\n return moveCaret((nr) => nr.setStart(after, Math.min(offset, after.textContent.length)));\n }\n return moveCaret((nr) => nr.setStartAfter(next));\n }\n if (isZwsAnchor(next) && isFAIcon(next.nextSibling)) {\n const icon = next.nextSibling;\n const after = icon.nextSibling;\n event.preventDefault();\n if (after?.nodeType === Node.TEXT_NODE) {\n const offset = ((after.textContent || '').startsWith('\\u200B')) ? 1 : 0;\n return moveCaret((nr) => nr.setStart(after, Math.min(offset, after.textContent.length)));\n }\n return moveCaret((nr) => nr.setStartAfter(icon));\n }\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Tab key — indent / outdent list items, or insert soft tab in code blocks\n // -------------------------------------------------------------------------\n if (isKey(event, key.TAB)) {\n const range = currentRange(editable);\n if (!range) return false;\n\n // Inside a table, Tab walks the cells. Without this it fell through to the\n // default branch and typed tabSize spaces into the cell — a dead key that\n // quietly edited the content.\n if (moveTableCell(range.sc, editable, event.shiftKey)) {\n event.preventDefault();\n return true;\n }\n\n const para = closestPara(range.sc, editable);\n if (para && isLi(para)) {\n event.preventDefault();\n if (event.shiftKey) {\n outdent();\n } else {\n indent();\n }\n return true;\n }\n\n // In a pre/code block, insert spaces using configured tabSize\n if (para?.nodeName.toUpperCase() === 'PRE') {\n if (event.shiftKey) return false;\n event.preventDefault();\n execCommand('insertText', ' '.repeat(options.tabSize || 4));\n return true;\n }\n\n // Default: insert * tabSize\n if (options.tabSize) {\n if (event.shiftKey) return false;\n event.preventDefault();\n execCommand('insertText', ' '.repeat(options.tabSize));\n return true;\n }\n }\n\n // -------------------------------------------------------------------------\n // Shift+Enter — insert <br> instead of opening a new block element\n // -------------------------------------------------------------------------\n if (isKey(event, key.ENTER) && event.shiftKey) {\n event.preventDefault();\n execCommand('insertLineBreak');\n return true;\n }\n\n // -------------------------------------------------------------------------\n // Enter key — keep consistent paragraph insertion\n // -------------------------------------------------------------------------\n if (isKey(event, key.ENTER) && !event.shiftKey) {\n const range = currentRange(editable);\n if (!range) return false;\n\n // Hoist sc/el once so all guards below can reuse them.\n const sc = range.sc;\n const el = /** @type {Element|null} */ (sc.nodeType === 3 ? sc.parentElement : sc);\n\n // Guard: if the cursor is inside a <i> FA icon element (zero text children,\n // rendered entirely by CSS ::before), pressing Enter would split the block\n // and leave an orphan <i> in the new paragraph — visually an \"auto-created\n // icon\". Push the cursor to just after the <i> first, then fall through so\n // the browser fires its default Enter at a safe text boundary.\n if (el?.nodeName === 'I' && /\\bfa-/.test(el.className || '')) {\n const nr = document.createRange();\n nr.setStartAfter(el);\n nr.collapse(true);\n const selI = globalThis.getSelection();\n if (selI) { selI.removeAllRanges(); selI.addRange(nr); }\n return false; // cursor is now outside <i> — let browser default handle Enter\n }\n\n // Video wrapper — Enter should create a new paragraph after the wrapper,\n // not split the wrapper's container and produce an empty video clone.\n const videoWrapper = el?.closest('.an-video-wrapper');\n if (videoWrapper) {\n event.preventDefault();\n const p = document.createElement('p');\n p.innerHTML = '\\u00a0';\n videoWrapper.parentNode.insertBefore(p, videoWrapper.nextSibling);\n const nr = document.createRange();\n nr.setStart(p, 0);\n nr.collapse(true);\n const sel = globalThis.getSelection();\n sel.removeAllRanges();\n sel.addRange(nr);\n return true;\n }\n\n // Checklist — Enter creates new item; empty item exits the list\n const checkLi = el?.closest('.an-checklist li');\n if (checkLi) {\n event.preventDefault();\n const ul = checkLi.closest('.an-checklist');\n const sel = globalThis.getSelection();\n let nativeRange = sel.getRangeAt(0);\n\n // Helper: get trimmed text content of a li, excluding the checkbox INPUT.\n // Strip both \\u00a0 (placeholder nbsp) and \\u200B (ZWS cursor anchors).\n const liText = (li) =>\n Array.from(li.childNodes)\n .filter((n) => !(n.nodeType === 1 && n.tagName === 'INPUT'))\n .map((n) => n.textContent).join('').replace(/[\\u00a0\\u200B]/g, ' ').trim();\n\n // 1. Check if the ENTIRE item is empty BEFORE any DOM mutation.\n // (Do NOT check only the \"before-cursor\" part — that check incorrectly\n // exits the list when cursor is at the start of a non-empty item.)\n if (!liText(checkLi)) {\n // Empty item — exit checklist, insert <p> after list\n const p = document.createElement('p');\n p.innerHTML = '\\u00a0';\n ul.parentNode.insertBefore(p, ul.nextSibling);\n checkLi.remove();\n if (ul.children.length === 0) ul.remove();\n const nr = document.createRange();\n nr.setStart(p.firstChild, 0);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n return true;\n }\n\n // 2. If selection is not collapsed, delete the selected content first —\n // mirrors browser-default Enter behaviour (delete selection, then split).\n if (!nativeRange.collapsed) {\n nativeRange.deleteContents();\n // nativeRange is now collapsed at the deletion point; re-read it\n if (sel.rangeCount === 0 || !checkLi.isConnected) return true;\n nativeRange = sel.getRangeAt(0);\n }\n\n // 3. Extract everything from cursor to end of li into afterFrag.\n // Use startContainer/startOffset (cursor position after potential delete),\n // NOT endContainer/endOffset which is wrong for non-collapsed ranges.\n const afterFrag = extractAfterContent(nativeRange, checkLi);\n\n // 4. Build the new checklist item with the extracted \"after\" content.\n const newLi = document.createElement('li');\n const cb = document.createElement('input');\n cb.type = 'checkbox';\n cb.setAttribute('contenteditable', 'false');\n newLi.appendChild(cb);\n\n // Append extracted \"after\" content (if any) then insert the new item.\n if (afterFrag.textContent.replace(/[\\u00a0\\u200B]/g, '').length > 0) {\n newLi.appendChild(afterFrag);\n }\n\n // Always ensure a text node exists so the cursor has a text-level\n // anchor. Use \\u200B (zero-width space) instead of an empty string:\n // Chrome does not reliably honour a Selection in an empty text node and\n // may normalise it to element-level, placing the caret before the\n // absolutely-positioned checkbox. \\u200B is stripped by getHTML().\n let cursorNode = newLi.childNodes[1]; // first child after checkbox\n if (cursorNode?.nodeType !== Node.TEXT_NODE) {\n cursorNode = document.createTextNode('\\u200B');\n newLi.appendChild(cursorNode);\n }\n checkLi.after(newLi);\n\n const nr = document.createRange();\n nr.setStart(cursorNode, 0);\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n return true;\n }\n\n const para = closestPara(range.sc, editable);\n\n // Enter in a pre/code block: insert a literal newline instead of a new block\n if (para?.nodeName.toUpperCase() === 'PRE') {\n event.preventDefault();\n execCommand('insertText', '\\n');\n return true;\n }\n\n // Pressing Enter at the end of a blockquote should exit it\n if (para?.nodeName.toUpperCase() === 'BLOCKQUOTE') {\n const native = range.toNativeRange();\n native.setEnd(para, para.childNodes.length);\n if (native.toString() === '' && range.isCollapsed()) {\n event.preventDefault();\n execCommand('formatBlock', '<p>');\n return true;\n }\n }\n }\n\n return false;\n}\n","/**\n * count.js — word and character counting for the editor.\n *\n * Shared so the statusbar and the maxWords/maxChars limits cannot disagree\n * about what a word is. They used to: the statusbar segmented with `Intl`\n * while the limit split on whitespace, which counts an entire Japanese\n * document as one word and made `maxWords` unenforceable in any script that\n * does not space its words.\n */\n\n// Cache the segmenter instance at module level to avoid per-call allocation\nconst _segmenter =\n typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function'\n ? new Intl.Segmenter(undefined, { granularity: 'word' })\n : null;\n\n/**\n * Count words in a string, CJK-aware.\n * Uses Intl.Segmenter (Chromium 87+, Firefox 125+, Safari 17+) when available,\n * falling back to a simple whitespace split for older environments.\n * @param {string} text\n * @returns {number}\n */\nexport function countWords(text) {\n const trimmed = text.trim();\n if (!trimmed) return 0;\n if (_segmenter) {\n let count = 0;\n for (const seg of _segmenter.segment(trimmed)) {\n if (seg.isWordLike) count++;\n }\n return count;\n }\n // Fallback: split on whitespace\n return trimmed.split(/\\s+/).length;\n}\n\n/**\n * Elements that start a new line of text. Used to join content the way the\n * reader sees it: `textContent` glues `<p>hello</p><p>world</p>` into\n * \"helloworld\", which any word counter then reports as one word.\n */\nconst BLOCK_TAGS = new Set([\n 'ADDRESS', 'ARTICLE', 'ASIDE', 'BLOCKQUOTE', 'BR', 'DD', 'DIV', 'DL', 'DT',\n 'FIELDSET', 'FIGCAPTION', 'FIGURE', 'FOOTER', 'FORM', 'H1', 'H2', 'H3', 'H4',\n 'H5', 'H6', 'HEADER', 'HR', 'LI', 'MAIN', 'NAV', 'OL', 'P', 'PRE', 'SECTION',\n 'TABLE', 'TBODY', 'TD', 'TFOOT', 'TH', 'THEAD', 'TR', 'UL',\n]);\n\n/**\n * Appends `node`'s text into `lines` with a newline at every block boundary,\n * and into `flat` without one.\n *\n * `lines` is what `innerText` gives, minus `innerText`'s forced layout pass —\n * the counters run on every keystroke, so a reflow per character is not on.\n * `flat` is exactly what `textContent` gives, produced by the same walk so the\n * cold path does not traverse the subtree twice to get both.\n * @param {Node} node\n * @param {string[]} lines\n * @param {string[]} flat\n */\nfunction _collectText(node, lines, flat) {\n for (let child = node.firstChild; child; child = child.nextSibling) {\n if (child.nodeType === 3) {\n const data = /** @type {Text} */ (child).data;\n lines.push(data);\n flat.push(data);\n } else if (child.nodeType === 1) {\n const block = BLOCK_TAGS.has(/** @type {Element} */ (child).tagName);\n if (block) lines.push('\\n');\n _collectText(child, lines, flat);\n if (block) lines.push('\\n');\n }\n }\n}\n\n/**\n * Both readings of a subtree's text: block-aware for counting words, flat for\n * matching `textContent`.\n * @param {Node} node\n * @returns {{ lines: string, flat: string }}\n */\nexport function readText(node) {\n if (node.nodeType === 3) {\n const data = /** @type {Text} */ (node).data;\n return { lines: data, flat: data };\n }\n /** @type {string[]} */ const lines = [];\n /** @type {string[]} */ const flat = [];\n _collectText(node, lines, flat);\n return { lines: lines.join(''), flat: flat.join('') };\n}\n\n/**\n * Word and character counts for a subtree, cached per top-level child.\n *\n * `Intl.Segmenter` over a whole document was the most expensive thing the\n * editor did per keystroke. A keystroke changes one block, so a cached counter\n * re-segments only that block; the rest costs a string comparison.\n */\nexport class TextCounter {\n constructor() {\n /**\n * Keyed on the child node itself, so removed nodes fall out with no\n * bookkeeping.\n * @type {WeakMap<Node, {key: string, words: number, chars: number}>}\n */\n this._cache = new WeakMap();\n }\n\n /**\n * @param {HTMLElement} root\n * @returns {{ words: number, chars: number }}\n */\n counts(root) {\n let words = 0;\n let chars = 0;\n /** @type {{node: Node, key: string, text: string, start: number}[]} */\n const cold = [];\n /** @type {string[]} */\n const parts = [];\n let offset = 0;\n\n for (let node = root.firstChild; node; node = node.nextSibling) {\n const hit = this._cache.get(node);\n // The flat text is the change key. Read it from the node only when there\n // is an entry that could still be valid; a node with no entry is being\n // walked anyway, and that walk yields the same string for free.\n if (hit && hit.key === (node.textContent || '')) {\n words += hit.words;\n chars += hit.chars;\n continue;\n }\n const { lines, flat } = readText(node);\n cold.push({ node, key: flat, text: lines, start: offset });\n parts.push(lines);\n offset += lines.length + 1; // +1 for the newline the join inserts\n }\n\n if (cold.length) {\n const counted = _countBatch(cold, parts.join('\\n'));\n cold.forEach((child, i) => {\n const entry = {\n key: child.key,\n words: counted[i],\n // Newlines are separators, not characters the reader typed — and the\n // ones inside a <pre> were never counted either.\n chars: child.key.replaceAll('\\n', '').length,\n };\n this._cache.set(child.node, entry);\n words += entry.words;\n chars += entry.chars;\n });\n }\n\n return { words, chars };\n }\n}\n\n/**\n * Word counts for each cold child, from a single pass over their joined text.\n *\n * The children are joined with a newline, which is a word boundary in every\n * script, so no word can be counted across two of them. Segments arrive in\n * increasing offset order, so attributing each one is a walk, not a search.\n *\n * One pass rather than one call each: `Intl.Segmenter.segment()` carries enough\n * per-call setup that 1200 small calls cost roughly three times a single large\n * one, so the cold path — setHTML, paste, undo of a big edit — would otherwise\n * pay for the warm path's speed.\n * @param {{start: number, text: string}[]} cold\n * @param {string} joined\n * @returns {number[]}\n */\nfunction _countBatch(cold, joined) {\n if (!_segmenter) return cold.map((c) => countWords(c.text));\n const counts = new Array(cold.length).fill(0);\n let i = 0;\n for (const seg of _segmenter.segment(joined)) {\n if (!seg.isWordLike) continue;\n while (i < cold.length - 1 && seg.index >= cold[i + 1].start) i++;\n counts[i]++;\n }\n return counts;\n}\n","/**\n * markdown.js - Lightweight Markdown → HTML converter for paste handling.\n *\n * Handles: headings H1–H6, bold/italic/strikethrough/inline-code, fenced code\n * blocks (with language), blockquotes, unordered/ordered lists, horizontal\n * rules, links, images, and plain paragraphs.\n *\n * The HTML output MUST be passed through sanitiseHTML() before insertion.\n */\n\nimport { repairListNesting } from './dom.js';\n\n/**\n * Converts an HTML string to Markdown.\n * Handles: headings, paragraphs, bold/italic/del/code, links, images,\n * unordered/ordered lists, blockquote, pre/code blocks, tables, hr.\n * @param {string} html\n * @returns {string}\n */\nexport function htmlToMarkdown(html) {\n const doc = new DOMParser().parseFromString(`<body>${html || ''}</body>`, 'text/html');\n // Content can arrive with a sublist parked next to its item rather than\n // inside it — that is what execCommand('indent') produces, and paste carries\n // it in from other editors. A sublist in that position belongs to no item, so\n // without this the indented items are silently dropped from the output.\n repairListNesting(doc.body);\n return _domToMd(doc.body).replace(/\\n{3,}/g, '\\n\\n').trim();\n}\n\n/**\n * Convert a DOM node subtree into Markdown.\n *\n * Recursively produces a Markdown string representing the given DOM node and its descendants,\n * handling common HTML constructs such as paragraphs, headings, lists (with nested indentation),\n * blockquotes, fenced and inline code, links, images, tables, horizontal rules, and basic inline emphasis.\n *\n * @param {Node} node - The DOM node to convert.\n * @param {number} [depth=0] - Current nesting depth used to indent nested list items.\n * @returns {string} The Markdown representation of the node subtree.\n */\n/**\n * Direct child elements matching a tag name. Used instead of the CSS\n * `:scope > tag` combinator, which this project's jsdom version resolves\n * incorrectly (matches descendants at any depth, not just direct children).\n * @param {Element} el\n * @param {string} tagName\n * @returns {Element[]}\n */\nfunction _directChildren(el, tagName) {\n return Array.from(el.children).filter((c) => c.tagName === tagName.toUpperCase());\n}\n\n/**\n * Text of a code element with line breaks preserved.\n *\n * `textContent` drops `<br>` entirely, and contenteditable stores every line\n * break inside a `<pre>` as one — so a code block typed in the editor came out\n * of getMarkdown() as a single run-together line. Block-level children (some\n * browsers wrap lines in `<div>`) end a line too.\n * @param {Element} el\n * @returns {string}\n */\nfunction _codeText(el) {\n let out = '';\n for (const node of el.childNodes) {\n if (node.nodeType === 3) { out += node.textContent; continue; }\n if (node.nodeType !== 1) continue;\n const tag = node.nodeName.toLowerCase();\n if (tag === 'br') { out += '\\n'; continue; }\n if (tag === 'div' || tag === 'p') {\n if (out && !out.endsWith('\\n')) out += '\\n';\n out += _codeText(/** @type {Element} */ (node));\n out += '\\n';\n continue;\n }\n out += _codeText(/** @type {Element} */ (node));\n }\n return out;\n}\n\n/**\n * Backslash-escapes the inline Markdown syntax characters in a run of plain\n * text, so prose survives a round-trip instead of being re-read as formatting.\n *\n * Deliberately narrow: `_` is only escaped at a word boundary (intra-word\n * underscores are not emphasis, and escaping `snake_case_name` makes the\n * Markdown unreadable), and `~` only as part of a `~~` pair.\n * @param {string} text\n * @returns {string}\n */\nfunction _escapeInlineMd(text) {\n return text\n .replaceAll('\\\\', '\\\\\\\\')\n // An `&` that would read as a character reference has to become one itself,\n // otherwise the literal text \"©\" comes back as ©.\n .replace(/&(?=#\\d+;|#[xX][0-9a-fA-F]+;|[a-zA-Z][a-zA-Z0-9]*;)/g, '&')\n .replace(/!(?=\\[)/g, String.raw`\\!`)\n .replace(/([`*[\\]])/g, String.raw`\\$1`)\n .replace(/(?<!\\w)_|_(?!\\w)/g, String.raw`\\_`)\n .replace(/~(?=~)|(?<=~)~/g, String.raw`\\~`);\n}\n\n/**\n * Escapes a leading block marker so a line of prose is not re-read as a\n * heading, quote, list item, thematic break or setext underline.\n * @param {string} line\n * @returns {string}\n */\nfunction _escapeLineStart(line) {\n if (/^\\s*(?:-{2,}|={2,}|\\*{3,}|_{3,}|(?:[-*_] +){2,}[-*_])\\s*$/.test(line)) {\n return line.replace(/[-=*_]/, (c) => `\\\\${c}`);\n }\n return line\n .replace(/^(\\s*)(#{1,6})(?=\\s|$)/, (_, ws, h) => `${ws}\\\\${h}`)\n .replace(/^(\\s*)>/, (_, ws) => `${ws}\\\\>`)\n .replace(/^(\\s*)([-*+])(?=\\s)/, (_, ws, c) => `${ws}\\\\${c}`)\n .replace(/^(\\s*)(\\d+)([.)])(?=\\s)/, (_, ws, n, d) => `${ws}${n}\\\\${d}`);\n}\n\n/** Applies _escapeLineStart() to every line of a multi-line block body. */\nfunction _escapeBlockStarts(text) {\n return text.split('\\n').map(_escapeLineStart).join('\\n');\n}\n\n/**\n * Renders an `<a href>` / `<img src>` as a Markdown link destination, with the\n * element's `title` when it has one.\n *\n * A URL containing spaces or parentheses is wrapped in angle brackets, which is\n * the only form that survives re-parsing — `[x](http://e.com/a(b))` otherwise\n * closes at the inner `)`.\n * @param {Element} el\n * @param {'href'|'src'} attr\n * @returns {string}\n */\n/**\n * Renders one `<li>`'s content for a list at `depth`.\n *\n * A list item holding more than one paragraph produced a second paragraph at\n * column 0, which re-parsed as a sibling paragraph that ended the list. Any\n * continuation line is therefore indented to the child column — nested lists\n * already carry that indent from their own `depth`, so they are left as they\n * are rather than shifted twice.\n * @param {Element} li\n * @param {number} depth\n * @returns {string}\n */\nfunction _itemBody(li, depth) {\n const childIndent = ' '.repeat(depth + 1);\n return _domToMd(li, depth + 1).trim().split('\\n')\n .map((line, idx) => {\n if (idx === 0 || line.trim() === '') return line;\n return line.startsWith(childIndent) ? line : childIndent + line;\n })\n .join('\\n');\n}\n\nfunction _destination(el, attr) {\n const url = el.getAttribute(attr) || '';\n const wrapped = /[\\s()]/.test(url) ? `<${url}>` : url;\n const title = el.getAttribute('title');\n return title ? `${wrapped} \"${title.replaceAll('\"', String.raw`\\\"`)}\"` : wrapped;\n}\n\nfunction _domToMd(node, depth = 0) {\n if (node.nodeType === 3) {\n const text = node.textContent.replace(/\\s+/g, ' ');\n // Text inside <code>/<pre> is already literal in Markdown; everywhere else\n // it has to be escaped or the user's own prose turns into formatting on the\n // way back — \"2 * 3 * 4\" came back as \"2 <em> 3 </em> 4\".\n return node.parentElement?.closest('pre, code') ? text : _escapeInlineMd(text);\n }\n if (node.nodeType !== 1) return '';\n\n const el = /** @type {Element} */ (node);\n const tag = el.nodeName.toLowerCase();\n const inner = () => Array.from(el.childNodes).map(n => _domToMd(n, depth)).join('');\n\n switch (tag) {\n case 'p':\n case 'div': return `\\n\\n${_escapeBlockStarts(inner())}\\n\\n`;\n case 'br': return ' \\n';\n case 'h1': return `\\n\\n# ${inner()}\\n\\n`;\n case 'h2': return `\\n\\n## ${inner()}\\n\\n`;\n case 'h3': return `\\n\\n### ${inner()}\\n\\n`;\n case 'h4': return `\\n\\n#### ${inner()}\\n\\n`;\n case 'h5': return `\\n\\n##### ${inner()}\\n\\n`;\n case 'h6': return `\\n\\n###### ${inner()}\\n\\n`;\n case 'strong':\n case 'b': return `**${inner()}**`;\n case 'em':\n case 'i': return `*${inner()}*`;\n case 'del':\n case 's':\n case 'strike': return `~~${inner()}~~`;\n case 'sup': return `^${inner()}^`;\n case 'sub': return `~${inner()}~`;\n case 'u': return `<u>${inner()}</u>`;\n case 'span': {\n // Markdown has no native underline/color/size syntax; pass through as\n // raw inline HTML for the specific styles the editor's own toolbar\n // creates (foreColor/backColor/fontSize) — other noise spans (e.g. from\n // pasted content) are unwrapped to plain text as before.\n const style = el.getAttribute('style') || '';\n if (/\\b(color|background-color|font-size)\\s*:/.test(style)) {\n return `<span style=\"${_escAttr(style)}\">${inner()}</span>`;\n }\n return inner();\n }\n case 'code': {\n // Inside <pre> we emit raw text; outside we wrap in backticks\n if (el.closest('pre')) return inner();\n const content = inner();\n // A code span has to be fenced by more backticks than the longest run it\n // contains, and padded with spaces when it starts or ends with one —\n // otherwise `a ` b` closes at the wrong backtick and mangles the text.\n const longestRun = Math.max(0, ...Array.from(content.matchAll(/`+/g), (m) => m[0].length));\n const fence = '`'.repeat(longestRun + 1);\n const pad = /^`|`$/.test(content) ? ' ' : '';\n return `${fence}${pad}${content}${pad}${fence}`;\n }\n case 'pre': {\n const codeEl = el.querySelector('code');\n const langMatch = /language-(\\S+)/.exec(codeEl?.className || '');\n const lang = langMatch ? langMatch[1] : '';\n const content = _codeText(codeEl || el);\n // A block whose text already ends in a newline would otherwise gain a\n // blank line from the one added before the closing fence.\n return `\\n\\n\\`\\`\\`${lang}\\n${content.replace(/\\n$/, '')}\\n\\`\\`\\`\\n\\n`;\n }\n case 'blockquote': {\n const rawLines = inner().trim().split('\\n');\n // Collapse consecutive blank lines (from adjacent <p> blocks) into one.\n const lines = rawLines.filter((l, idx) => l.trim() !== '' || (rawLines[idx - 1] ?? '').trim() !== '');\n return `\\n\\n${lines.map((l) => (l.trim() === '' ? '>' : `> ${l}`)).join('\\n')}\\n\\n`;\n }\n case 'a': return `[${inner()}](${_destination(el, 'href')})`;\n case 'img': {\n const alt = _escapeInlineMd(el.getAttribute('alt') || '');\n return `})`;\n }\n case 'ul': {\n const items = _directChildren(el, 'li');\n if (!items.length) return inner();\n const indent = ' '.repeat(depth);\n const isChecklist = el.classList.contains('an-checklist');\n const lines = items.map((li) => {\n const cb = /** @type {HTMLInputElement | undefined} */ (\n _directChildren(li, 'input').find((c) => c.getAttribute('type') === 'checkbox')\n );\n let prefix = '- ';\n if (isChecklist || cb) {\n const checked = cb ? cb.checked : false;\n prefix = checked ? '- [x] ' : '- [ ] ';\n }\n return `${indent}${prefix}${_itemBody(li, depth)}`;\n }).join('\\n');\n return depth === 0 ? `\\n\\n${lines}\\n\\n` : `\\n${lines}`;\n }\n case 'ol': {\n const items = _directChildren(el, 'li');\n if (!items.length) return inner();\n const indent = ' '.repeat(depth);\n // Preserve an explicit start; markdownToHTML already emits `start` for a\n // list that does not begin at 1, so dropping it here broke the round-trip.\n const start = Number.parseInt(el.getAttribute('start') || '1', 10);\n const first = Number.isFinite(start) ? start : 1;\n const lines = items.map((li, i) => `${indent}${first + i}. ${_itemBody(li, depth)}`).join('\\n');\n return depth === 0 ? `\\n\\n${lines}\\n\\n` : `\\n${lines}`;\n }\n case 'li': return inner();\n case 'hr': return '\\n\\n---\\n\\n';\n case 'table': {\n const allRows = Array.from(el.querySelectorAll('tr'));\n if (!allRows.length) return inner();\n const theadEl = _directChildren(el, 'thead')[0];\n const firstRowIsHeader = !!theadEl || (\n allRows[0].children.length > 0 &&\n Array.from(allRows[0].children).every((c) => c.tagName === 'TH')\n );\n const cellTexts = allRows.map((tr) =>\n Array.from(tr.querySelectorAll('th, td')).map((c) =>\n _escapeInlineMd(c.textContent.trim()).replaceAll('|', String.raw`\\|`)),\n );\n const cols = Math.max(...cellTexts.map((r) => r.length));\n const padRow = (row) => { const r = [...row]; while (r.length < cols) r.push(''); return r; };\n const bodyStart = firstRowIsHeader ? 1 : 0;\n const headerCells = firstRowIsHeader ? padRow(cellTexts[0]) : new Array(cols).fill('');\n // Carry per-column alignment back into the delimiter row. markdownToHTML\n // writes it out as `text-align`, so without this a round-trip through\n // Markdown silently left every column default-aligned.\n const alignRow = Array.from({ length: cols }, (_unused, c) => {\n const cell = allRows[0]?.children[c];\n const align = /text-align:\\s*(left|center|right)/.exec(cell?.getAttribute('style') || '')?.[1];\n if (align === 'center') return ':---:';\n if (align === 'right') return '---:';\n if (align === 'left') return ':---';\n return '---';\n });\n let md = '\\n\\n';\n md += `| ${headerCells.join(' | ')} |\\n`;\n md += `| ${alignRow.join(' | ')} |\\n`;\n for (let r = bodyStart; r < cellTexts.length; r++) {\n md += `| ${padRow(cellTexts[r]).join(' | ')} |\\n`;\n }\n return md + '\\n';\n }\n default: return inner();\n }\n}\n\n/**\n * Removes a leading UTF-8 byte-order mark.\n *\n * `FileReader.readAsText` keeps the BOM, and editors on Windows write one by\n * default, so a dropped `.md` file arrived with U+FEFF glued to its first\n * character: the opening heading parsed as a paragraph and isMarkdown()\n * rejected the file outright.\n * @param {string} text\n * @returns {string}\n */\nfunction _stripBOM(text) {\n return String(text ?? '').replace(/^\\ufeff/, '');\n}\n\n/**\n * Detects whether a string likely contains Markdown syntax.\n *\n * Checks for common Markdown constructs such as ATX headings, unordered or\n * ordered list items, blockquotes, fenced code blocks, and bold emphasis.\n * @param {string} rawText - Input text to inspect for Markdown patterns.\n * @returns {boolean} `true` if any Markdown-like pattern is present, `false` otherwise.\n */\nexport function isMarkdown(rawText) {\n const text = _stripBOM(rawText);\n return /^#{1,6} [^\\s]|^[ \\t]*[-*+] [^\\s]|^[ \\t]*\\d+[.)] [^\\s]|^> ?[^\\s]|^ {0,3}(?:`{3,}|~{3,})|^\\*{2}[^*\\n]+\\*{2}/m.test(text)\n || /^.+\\n=+\\s*$/m.test(text)\n || /^.+\\n-{2,}\\s*$/m.test(text)\n || /^---[ \\t]*\\n(?:[\\s\\S]*?\\n)?(?:---|\\.\\.\\.)[ \\t]*(?:\\n|$)/.test(text)\n || /^\\|.+\\|[ \\t]*\\n\\|[ \\t:|-]+\\|/m.test(text)\n // Pipe table without outer pipes: `a | b` over `--- | ---`.\n || /^[^\\n|]*\\|[^\\n]*\\n[ \\t]*:?-+:?[ \\t]*(?:\\|[ \\t]*:?-+:?[ \\t]*)+$/m.test(text)\n // A link or image plus at least one other inline marker — either alone is\n // too weak a signal (bare URLs and \"(see note)\" are ordinary prose), but\n // together they reliably indicate Markdown rather than a plain-text body.\n || (/!?\\[[^\\]\\n]*\\]\\([^)\\n]*\\)/.test(text) && /`[^`\\n]+`|\\*\\*[^*\\n]+\\*\\*|^#{1,6} |^[-*+] /m.test(text));\n}\n\n// Blockquote line: optional up-to-3 leading spaces, '>', optional single space, rest of line.\nconst BQ_RE = /^ {0,3}>( ?)(.*)$/;\n// Indented code block: 4+ spaces or a leading tab, with actual content after it.\nconst INDENTED_CODE_RE = /^(?: {4}|\\t)\\s*\\S/;\n// Opening fence: up to 3 spaces, then 3+ backticks or 3+ tildes, then an info string.\nconst FENCE_RE = /^( {0,3})(`{3,}|~{3,})[ \\t]*([^\\s`~][^\\n]*)?$/;\n\n/**\n * Parses `line` as an opening code fence, or returns null.\n *\n * A backtick fence's info string may not contain a backtick (CommonMark) —\n * without that rule ```` ```` `` wrongly reads as a fence whose language is a\n * backtick, and a line like \"``a ` b``\" reads as a fence instead of a code span.\n * @param {string} line\n * @returns {{ marker: string, length: number, indent: number, lang: string }|null}\n */\nfunction _openingFence(line) {\n const m = FENCE_RE.exec(line);\n if (!m) return null;\n // The info-string group is optional, so it is undefined on a bare fence.\n const [, indent, fence, info = ''] = m;\n if (fence[0] === '`' && info.includes('`')) return null;\n return {\n marker: fence[0],\n length: fence.length,\n indent: indent.length,\n // Only the first word of the info string is the language.\n lang: info.trim().split(/\\s+/)[0] || '',\n };\n}\n\n/**\n * Removes up to `count` leading space-equivalents, expanding a leading tab to\n * the next 4-column stop the way CommonMark does.\n * @param {string} line\n * @param {number} count\n * @returns {string}\n */\nfunction _stripIndent(line, count) {\n let removed = 0;\n let idx = 0;\n while (idx < line.length && removed < count) {\n if (line[idx] === ' ') { removed += 1; idx += 1; continue; }\n if (line[idx] === '\\t') {\n const width = 4 - (removed % 4);\n if (removed + width > count) break;\n removed += width;\n idx += 1;\n continue;\n }\n break;\n }\n return line.slice(idx);\n}\n// Horizontal rule: 3+ of the same character (-, * or _), optionally space-separated.\nconst HR_RE = /^ {0,3}([-*_])( *\\1){2,}\\s*$/;\n// Hard-break marker — placed between paragraph lines that end in a\n// CommonMark hard-break (trailing 2+ spaces or a trailing backslash),\n// restored to <br> after _inline() runs. Distinct from _inline()'s own MARK.\nconst HARD_BREAK = String.fromCharCode(1);\n\n/**\n * Converts a Markdown string to an HTML string.\n * @param {string} text\n * @returns {string}\n */\nexport function markdownToHTML(text) {\n let lines = _stripBOM(text).replaceAll('\\r\\n', '\\n').replaceAll('\\r', '\\n').split('\\n');\n lines = _stripFrontmatter(lines);\n const refs = _extractReferenceDefinitions(lines);\n lines = refs.clean;\n _linkDefs = refs.linkDefs;\n _footnoteIds = refs.footnoteIds;\n return _parseBlocks(lines);\n}\n\n/**\n * Parses a line array into block-level HTML. Called recursively for content\n * nested inside a blockquote so nested quotes and block content (lists,\n * headings, etc.) inside `>` are parsed the same as top-level content.\n * @param {string[]} lines\n * @returns {string}\n */\nfunction _parseBlocks(lines) {\n const out = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // ---- Fenced code block ```lang / ~~~lang ... ----------------------------\n const fence = _openingFence(line);\n if (fence) {\n const closeRe = new RegExp(`^ {0,3}\\\\${fence.marker}{${fence.length},}[ \\t]*$`);\n const codeLines = [];\n i++;\n while (i < lines.length && !closeRe.test(lines[i])) {\n // CommonMark strips up to as many leading spaces as the opening fence\n // was indented by, so an indented fence keeps its code left-aligned.\n codeLines.push(_escCode(_stripIndent(lines[i], fence.indent)));\n i++;\n }\n const langAttr = fence.lang ? ` class=\"language-${_escAttr(fence.lang)}\"` : '';\n out.push(`<pre><code${langAttr}>${codeLines.join('\\n')}</code></pre>`);\n i++; // skip closing fence (no-op at EOF — an unclosed fence runs to the end)\n continue;\n }\n\n // ---- Indented code block (4 spaces or a tab) -----------------------------\n // Only reachable at a block boundary: an indented line following a\n // paragraph is consumed as a lazy continuation before it gets here, which\n // matches CommonMark's rule that indented code cannot interrupt a paragraph.\n if (INDENTED_CODE_RE.test(line)) {\n const codeLines = [];\n while (i < lines.length && (INDENTED_CODE_RE.test(lines[i]) || lines[i].trim() === '')) {\n // A trailing run of blank lines belongs to whatever follows, not to the\n // code block, so only keep blanks that have more code after them.\n if (lines[i].trim() === '') {\n let j = i;\n while (j < lines.length && lines[j].trim() === '') j++;\n if (j >= lines.length || !INDENTED_CODE_RE.test(lines[j])) break;\n for (; i < j; i++) codeLines.push('');\n continue;\n }\n codeLines.push(_escCode(_stripIndent(lines[i], 4)));\n i++;\n }\n out.push(`<pre><code>${codeLines.join('\\n')}</code></pre>`);\n continue;\n }\n\n // ---- Setext headings (Title\\n=== or Title\\n---) -------------------------\n if (line.trim() && !HR_RE.test(line) && !/^#{1,6} /.test(line) && i + 1 < lines.length) {\n if (/^=+\\s*$/.test(lines[i + 1])) {\n out.push(`<h1>${_inline(line.trim())}</h1>`);\n i += 2;\n continue;\n }\n if (/^-{2,}\\s*$/.test(lines[i + 1])) {\n out.push(`<h2>${_inline(line.trim())}</h2>`);\n i += 2;\n continue;\n }\n }\n\n // ---- Horizontal rule --- / *** / ___ / - - - / * * * ----------------------\n if (HR_RE.test(line)) {\n out.push('<hr>');\n i++;\n continue;\n }\n\n // ---- ATX Headings # – ###### -------------------------------------------\n // The title may be empty: \"# \" on its own is a valid empty heading. It also\n // has to match here, because the paragraph collector below refuses any line\n // starting with a heading marker — a line this regex rejected but that one\n // also skipped consumed nothing, and the block loop spun forever.\n const hMatch = /^(#{1,6})[ \\t]+(.*)$/.exec(line);\n if (hMatch) {\n const level = hMatch[1].length;\n // Strip an optional closing sequence of #'s (e.g. \"## Heading ##\"),\n // only when preceded by whitespace — \"Heading#\" (no space) is untouched.\n const content = hMatch[2].replace(/(?:^|\\s)#+\\s*$/, '');\n out.push(`<h${level}>${_inline(content)}</h${level}>`);\n i++;\n continue;\n }\n\n // ---- Blockquote > text --------------------------------------------------\n if (BQ_RE.test(line)) {\n const bqLines = [];\n while (i < lines.length && BQ_RE.test(lines[i])) {\n bqLines.push(BQ_RE.exec(lines[i])[2]);\n i++;\n }\n out.push(`<blockquote>${_parseBlocks(bqLines)}</blockquote>`);\n continue;\n }\n\n // ---- Checklist or Unordered list - / * / + item ----------------------\n if (/^[-*+] /.test(line)) {\n const { html: listHtml, endIdx } = _parseListBlock(lines, i);\n out.push(listHtml); i = endIdx; continue;\n }\n\n // ---- Ordered list 1. item ----------------------------------------------\n if (/^\\d+[.)] /.test(line)) {\n const { html: listHtml, endIdx } = _parseListBlock(lines, i);\n out.push(listHtml); i = endIdx; continue;\n }\n\n // ---- Blank line ----------------------------------------------------------\n if (line.trim() === '') {\n i++;\n continue;\n }\n\n // ---- GFM Table | col | col | -------------------------------------------\n // A table starts with a pipe-prefixed or pipe-containing line followed by\n // a separator row (| --- | --- |). We detect and collect all rows.\n if (_isTableStart(lines, i)) {\n const headerCells = _parseTableRow(line);\n const alignments = _parseTableRow(lines[i + 1]).map((c) => {\n if (c.startsWith(':') && c.endsWith(':')) return 'center';\n if (c.endsWith(':')) return 'right';\n if (c.startsWith(':')) return 'left';\n return null;\n });\n i += 2; // skip header + separator\n const bodyRows = [];\n while (i < lines.length && lines[i].trim() !== '' && _isTableRow(lines[i])) {\n bodyRows.push(_parseTableRow(lines[i]));\n i++;\n }\n const _cell = (tag, content, align) => {\n const s = align ? ` style=\"text-align:${align}\"` : '';\n return `<${tag}${s}>${_inline(content)}</${tag}>`;\n };\n const thCells = headerCells.map((c, idx) => _cell('th', c, alignments[idx])).join('');\n const thead = `<thead><tr>${thCells}</tr></thead>`;\n const renderRow = (row) => `<tr>${row.map((c, idx) => _cell('td', c, alignments[idx])).join('')}</tr>`;\n const tbody = bodyRows.length ? `<tbody>${bodyRows.map(renderRow).join('')}</tbody>` : '';\n out.push(`<table>${thead}${tbody}</table>`);\n continue;\n }\n\n // ---- Paragraph: collect consecutive non-block lines ---------------------\n const paraLines = [];\n while (\n i < lines.length &&\n lines[i].trim() !== '' &&\n !/^(#{1,6} |[-*+] |\\d+[.)] )/.test(lines[i]) &&\n !_openingFence(lines[i]) &&\n !BQ_RE.test(lines[i]) &&\n !HR_RE.test(lines[i]) &&\n !_isTableStart(lines, i) &&\n !(i + 1 < lines.length && /^=+\\s*$/.test(lines[i + 1])) &&\n !(i + 1 < lines.length && /^-{2,}\\s*$/.test(lines[i + 1]))\n ) {\n paraLines.push(lines[i]);\n i++;\n }\n if (paraLines.length) {\n out.push(`<p>${_inline(_joinParagraphLines(paraLines)).replaceAll(HARD_BREAK, '<br>')}</p>`);\n } else {\n // Nothing above consumed this line and the paragraph collector rejected\n // it too. That combination is a bug in one of the branches, but the loop\n // must still move: spinning here froze the page on input as ordinary as a\n // heading marker with nothing after it. Emit the line and move on.\n out.push(`<p>${_inline(line)}</p>`);\n i++;\n }\n }\n\n return out.join('');\n}\n\n// ---------------------------------------------------------------------------\n// Inline formatting\n// ---------------------------------------------------------------------------\n\n/** Reference-link and footnote definitions collected per markdownToHTML() call. */\nlet _linkDefs = new Map();\nlet _footnoteIds = new Set();\n\n/**\n * Strips a leading YAML frontmatter block (--- ... --- or --- ... ...) from\n * the line array, only when it is the very first line and the enclosed body\n * looks like YAML (key: value / list items / indented continuations) — this\n * disambiguates real frontmatter from a horizontal rule followed by prose.\n * @param {string[]} lines\n * @returns {string[]}\n */\nfunction _stripFrontmatter(lines) {\n if ((lines[0] || '').trim() !== '---') return lines;\n let closeIdx = -1;\n for (let j = 1; j < lines.length; j++) {\n const t = lines[j].trim();\n if (t === '---' || t === '...') { closeIdx = j; break; }\n }\n if (closeIdx === -1) return lines;\n\n const body = lines.slice(1, closeIdx);\n const looksLikeYAML = body.every((l) =>\n l.trim() === '' ||\n /^[ \\t]*[\\w$.-]+\\s*:(\\s|$)/.test(l) ||\n /^[ \\t]*-\\s+\\S/.test(l) ||\n /^[ \\t]+\\S/.test(l));\n if (!looksLikeYAML) return lines;\n\n let start = closeIdx + 1;\n if (lines[start] !== undefined && lines[start].trim() === '') start++;\n return lines.slice(start);\n}\n\n/**\n * Extracts GFM reference-link definitions (`[ref]: url \"title\"`) and footnote\n * definitions (`[^id]: text`) from the line array, skipping fenced code\n * regions. Returns the definition-free line array plus lookup maps.\n * @param {string[]} lines\n * @returns {{ clean: string[], linkDefs: Map<string, {href: string, title?: string}>, footnoteIds: Set<string> }}\n */\nfunction _extractReferenceDefinitions(lines) {\n const linkDefs = new Map();\n const footnoteIds = new Set();\n const clean = [];\n let inFence = false;\n const linkDefRe = /^\\[([^\\]]+)\\]:\\s*(\\S+)(?:\\s+\"([^\"]*)\")?\\s*$/;\n const footnoteDefRe = /^\\[\\^([^\\]]+)\\]:[ \\t]*(\\S.*)$/;\n\n for (const line of lines) {\n // Definitions inside a fenced block are literal code, not definitions.\n if (inFence) {\n if (/^ {0,3}(?:`{3,}|~{3,})[ \\t]*$/.test(line)) inFence = false;\n clean.push(line);\n continue;\n }\n if (_openingFence(line)) { inFence = true; clean.push(line); continue; }\n {\n const fm = footnoteDefRe.exec(line);\n if (fm) { footnoteIds.add(fm[1]); continue; }\n const lm = linkDefRe.exec(line);\n if (lm) { linkDefs.set(lm[1].trim().toLowerCase(), { href: lm[2], title: lm[3] }); continue; }\n }\n clean.push(line);\n }\n return { clean, linkDefs, footnoteIds };\n}\n\n/**\n * Joins a paragraph's source lines into one string, converting CommonMark\n * hard-break markers (a trailing backslash, or 2+ trailing spaces) on all\n * but the last line into a HARD_BREAK placeholder instead of a plain space.\n * @param {string[]} paraLines\n * @returns {string}\n */\nfunction _joinParagraphLines(paraLines) {\n let joined = '';\n for (let idx = 0; idx < paraLines.length; idx++) {\n const isLast = idx === paraLines.length - 1;\n // Leading whitespace on a continuation line is not content — CommonMark\n // strips it before joining, so an indented lazy continuation does not carry\n // its indent into the paragraph text.\n const ln = paraLines[idx].replace(/^[ \\t]+/, '');\n if (!isLast && /\\\\$/.test(ln)) { joined += ln.replace(/\\\\$/, '') + HARD_BREAK; continue; }\n if (!isLast && / {2,}$/.test(ln)) { joined += ln.replace(/ {2,}$/, '') + HARD_BREAK; continue; }\n joined += ln + (isLast ? '' : ' ');\n }\n return joined;\n}\n\n/**\n * Splits a GFM table row string into trimmed cell strings, treating an\n * escaped pipe (`\\|`) as a literal character rather than a cell separator.\n * '| a | b | c |' → ['a', 'b', 'c']; '| a\\|b | c |' → ['a|b', 'c']\n * @param {string} row\n * @returns {string[]}\n */\n/** Number of cells a GFM table row would split into. */\nfunction _countTableCells(line) {\n return _parseTableRow(line).length;\n}\n\n/**\n * True when `line` still belongs to the table being collected.\n *\n * A pipe-delimited line is a row whatever its cell count — the previous test\n * demanded more than one cell, which silently dropped every body row of a\n * single-column table into a paragraph of literal `| x |`. Without outer pipes\n * a line has to split into at least two cells to count, or any prose containing\n * a pipe would be swallowed by the table above it.\n * @param {string} line\n * @returns {boolean}\n */\nfunction _isTableRow(line) {\n if (!line.includes('|')) return false;\n return /^\\s*\\|/.test(line) || _countTableCells(line) > 1;\n}\n\n/**\n * True when `lines[i]` is a GFM table header followed by a delimiter row.\n *\n * Leading and trailing pipes are optional in GFM (`a | b` / `--- | ---` is a\n * valid table), so the delimiter row is identified by shape instead.\n *\n * The pipe-delimited form stays deliberately lenient — a ragged table whose\n * delimiter row is short still renders, columns past it just unaligned. The\n * bare form has to be stricter, matching header and delimiter cell counts:\n * without that, prose containing a pipe followed by a `---` line would be read\n * as a one-column table instead of the setext heading it is.\n * @param {string[]} lines\n * @param {number} i\n * @returns {boolean}\n */\nfunction _isTableStart(lines, i) {\n const header = lines[i];\n const delim = lines[i + 1];\n if (delim === undefined || !header.includes('|')) return false;\n\n if (/^\\|.+\\|/.test(header)) return /^\\|[\\s|:-]+\\|/.test(delim);\n\n const delimCells = _parseTableRow(delim);\n if (delimCells.length < 2 || !delimCells.every((c) => /^:?-+:?$/.test(c))) return false;\n return _countTableCells(header) === delimCells.length;\n}\n\nfunction _parseTableRow(row) {\n const trimmed = row.replace(/^\\|/, '').replace(/\\|$/, '');\n const cells = [];\n let cur = '';\n for (let i = 0; i < trimmed.length; i++) {\n if (trimmed[i] === '\\\\' && trimmed[i + 1] === '|') { cur += '|'; i++; continue; }\n if (trimmed[i] === '|') { cells.push(cur); cur = ''; continue; }\n cur += trimmed[i];\n }\n cells.push(cur);\n return cells.map((c) => c.trim());\n}\n\nfunction _parseListBlock(lines, startIdx) {\n const baseIndent = (lines[startIdx].match(/^(\\s*)/)[1]).length;\n const isOL = /^\\s*\\d+[.)] /.test(lines[startIdx]);\n const items = [];\n let firstIsCB = null;\n let loose = false;\n let pendingBlank = false;\n let i = startIdx;\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (line.trim() === '') {\n // A blank line only ends the list if what follows isn't a continuation\n // of it (another item at the same marker/indent, or indented text\n // belonging to the current item) — otherwise it marks a \"loose\" list.\n const next = lines[i + 1];\n const nextIndent = next !== undefined ? (next.match(/^(\\s*)/)[1]).length : -1;\n const nextIsSameItem = next !== undefined &&\n /^\\s*(?:[-*+]|\\d+[.)]) /.test(next) &&\n (/^\\s*\\d+[.)] /.test(next) === isOL) &&\n nextIndent === baseIndent;\n const nextIsContinuation = next !== undefined && next.trim() !== '' && nextIndent > baseIndent;\n if (!items.length || (!nextIsSameItem && !nextIsContinuation)) break;\n loose = true;\n pendingBlank = true;\n i++;\n continue;\n }\n\n const indent = (line.match(/^(\\s*)/)[1]).length;\n if (indent < baseIndent) break;\n\n if (indent === baseIndent) {\n if (!/^\\s*(?:[-*+]|\\d+[.)]) /.test(line)) break;\n if (/^\\s*\\d+[.)] /.test(line) !== isOL) break;\n const raw = isOL ? line.replace(/^\\s*\\d+[.)] /, '') : line.replace(/^\\s*[-*+] /, '');\n // Checklists are intentionally UL-only: sanitise.js's checkbox guard,\n // the injected checklist CSS, and every checklist-toggle command are\n // all hardcoded to `ul.an-checklist` with no `ol` equivalent, so an\n // ordered-list checkbox would be stripped by the sanitiser and get no\n // styling even if parsed here — \"1. [ ] item\" intentionally stays plain.\n const isCB = !isOL && /^\\[[ xX]\\]\\s+/.test(raw);\n if (firstIsCB === null) firstIsCB = isCB;\n if (isCB !== firstIsCB) break;\n const checked = isCB && raw[1].toLowerCase() === 'x';\n const text = isCB ? raw.replace(/^\\[[ xX]\\]\\s+/, '') : raw;\n items.push({ paras: [text], isCB, checked, sub: '' });\n pendingBlank = false;\n i++;\n } else {\n if (!items.length) { i++; continue; }\n\n // A fenced block belonging to this item. Without this the fence lines\n // were folded into the item's paragraph text and the inline code-span\n // rule chewed them up — \"- a\\n\\n ```js\\n x\\n ```\" came out as\n // <li><p>a</p><p><code><code>js x </code></code></p></li>, with the\n // snippet's line breaks gone.\n const dedent = (l) => _stripIndent(l, indent);\n const fence = _openingFence(dedent(line));\n if (fence) {\n const closeRe = new RegExp(`^ {0,3}\\\\${fence.marker}{${fence.length},}[ \\t]*$`);\n const blockLines = [dedent(lines[i])];\n i++;\n while (i < lines.length && !closeRe.test(dedent(lines[i]))) {\n blockLines.push(dedent(lines[i]));\n i++;\n }\n if (i < lines.length) { blockLines.push(dedent(lines[i])); i++; }\n // Appended to `sub` so it keeps its position relative to a nested list.\n items[items.length - 1].sub += _parseBlocks(blockLines);\n pendingBlank = false;\n continue;\n }\n\n if (/^\\s*(?:[-*+]|\\d+[.)]) /.test(line)) {\n const nested = _parseListBlock(lines, i);\n items[items.length - 1].sub += nested.html;\n i = nested.endIdx;\n pendingBlank = false;\n } else if (pendingBlank) {\n items[items.length - 1].paras.push(line.trim());\n pendingBlank = false;\n i++;\n } else {\n const paras = items[items.length - 1].paras;\n paras[paras.length - 1] += ' ' + line.trim();\n i++;\n }\n }\n }\n\n const hasCB = !isOL && (firstIsCB === true);\n const startMatch = isOL ? /^\\s*(\\d+)[.)] /.exec(lines[startIdx]) : null;\n const startNum = startMatch ? Number.parseInt(startMatch[1], 10) : 1;\n const open = isOL\n ? (startNum !== 1 ? `<ol start=\"${startNum}\">` : '<ol>')\n : (hasCB ? '<ul class=\"an-checklist\">' : '<ul>');\n const close = isOL ? '</ol>' : '</ul>';\n const liHTML = items.map(({ paras, isCB, checked, sub }) => {\n const cbHTML = isCB\n ? `<input type=\"checkbox\" contenteditable=\"false\"${checked ? ' checked' : ''}>`\n : '';\n const body = loose\n ? paras.map((p, idx) => `<p>${idx === 0 ? cbHTML : ''}${_inline(p)}</p>`).join('')\n : `${cbHTML}${_inline(paras[0])}`;\n return `<li>${body}${sub}</li>`;\n }).join('');\n return { html: `${open}${liHTML}${close}`, endIdx: i };\n}\n\n// Backslash-escapable punctuation. This is CommonMark's full ASCII-punctuation\n// set rather than just the characters this converter emits syntax for: the\n// escaper on the htmlToMarkdown side has to be able to neutralise a leading\n// \"- \", \"1. \" or \"---\", and those only round-trip if the parser also unescapes\n// them.\nconst ESCAPABLE_RE = /\\\\([!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_`{|}~])/g;\n// Placeholder marker for escaped literals — a NUL character can't appear in\n// real markdown text, so it's safe as a delimiter. Built at runtime (not\n// written as a literal escape) to avoid embedding a raw NUL byte in this file.\nconst MARK = String.fromCharCode(0);\n\n// Placeholder delimiter for extracted code spans. Distinct from MARK and\n// HARD_BREAK; like them it survives _esc() untouched and matches no syntax rule.\nconst CODE_MARK = String.fromCharCode(2);\n// A code span: a run of backticks, the shortest content that reaches a matching\n// run, and that run again.\nconst CODE_SPAN_RE = /(`+)([^]*?)\\1/g;\n\n/**\n * Pulls code spans out before anything else looks at the text.\n *\n * Their content is literal: no emphasis, no links, no backslash escapes, and no\n * character references — `&` inside backticks has to survive as those five\n * characters. Extracting first is the only way to tell an `<` the author\n * typed from one _esc() produced out of a raw `<`.\n * @param {string} text\n * @returns {{ text: string, codes: string[] }}\n */\nfunction _extractCodeSpans(text) {\n const codes = [];\n const replaced = text.replace(CODE_SPAN_RE, (whole, ticks, content) => {\n // An empty span (`` with nothing between) is literal text in CommonMark.\n if (content === '') return whole;\n codes.push(content);\n return `${CODE_MARK}${codes.length - 1}${CODE_MARK}`;\n });\n return { text: replaced, codes };\n}\n\n/**\n * Restores extracted code spans as `<code>` elements, escaping their content\n * as literal code.\n * @param {string} text\n * @param {string[]} codes\n * @param {string[]} literals - backslash-escaped characters, for spans containing them\n * @returns {string}\n */\nfunction _restoreCodeSpans(text, codes, literals) {\n return text.replace(new RegExp(`${CODE_MARK}(\\\\d+)${CODE_MARK}`, 'g'), (_, idx) => {\n let c = codes[Number(idx)];\n // A backslash escape is not an escape inside a code span — put the\n // backslash back so `a\\*b` shows as written.\n c = c.replace(new RegExp(`${MARK}(\\\\d+)${MARK}`, 'g'), (_m, i) => `\\\\${literals[Number(i)]}`);\n // CommonMark strips one leading and trailing space when both are present,\n // which is what lets a span hold a leading or trailing backtick.\n if (c.length > 2 && c.startsWith(' ') && c.endsWith(' ') && c.trim() !== '') c = c.slice(1, -1);\n return `<code>${_escCode(c)}</code>`;\n });\n}\n\n/**\n * Step 0 of _inline(): replaces backslash-escaped punctuation with inert\n * placeholders so later syntax regexes can't match them.\n * @param {string} text\n * @returns {{ text: string, literals: string[] }}\n */\nfunction _extractBackslashEscapes(text) {\n const literals = [];\n const replaced = text.replace(ESCAPABLE_RE, (_, ch) => {\n literals.push(ch);\n return `${MARK}${literals.length - 1}${MARK}`;\n });\n return { text: replaced, literals };\n}\n\n/**\n * Restores placeholders from _extractBackslashEscapes(), HTML-escaping each\n * literal since it's inserted directly into the output.\n * @param {string} text\n * @param {string[]} literals\n * @returns {string}\n */\nfunction _restoreBackslashEscapes(text, literals) {\n return text.replace(new RegExp(`${MARK}(\\\\d+)${MARK}`, 'g'), (_, idx) => _esc(literals[Number(idx)]));\n}\n\n// Inline link/image destination. The angle-bracket alternative comes first so a\n// URL containing `)` — `[x](<http://e.com/a(b)>)` — is taken whole instead of\n// being cut at the inner parenthesis. Matched against _esc()'d text, so the\n// brackets appear as entities.\nconst DEST = String.raw`(<.*?>(?:\\s+(?:\"[^\"]*\"|'[^']*'))?|[^)]*)`;\nconst IMAGE_RE = new RegExp(String.raw`!\\[([^\\]]*)\\]\\(${DEST}\\)`, 'g');\nconst LINK_RE = new RegExp(String.raw`\\[([^\\]]+)\\]\\(${DEST}\\)`, 'g');\n\n/**\n * Splits an inline link destination into its URL and optional title:\n * `url`, `url \"title\"`, `url 'title'`, `<url with spaces>`, `<url> \"title\"`.\n *\n * Without this the whole `url \"title\"` string landed in `href`, producing a\n * link that simply does not resolve — the title is extremely common in\n * generated Markdown, so this silently broke a lot of pasted content.\n *\n * Operates on _esc()'d text, hence the `<`/`>` comparisons.\n * @param {string} dest\n * @returns {{ href: string, title: string }}\n */\nfunction _splitDestAndTitle(dest) {\n const s = dest.trim();\n\n // Angle-bracket destination: everything up to the closing bracket is the URL,\n // so it may contain spaces and parentheses.\n const angle = /^<([\\s\\S]*?)>(?:[ \\t]*(?:\"([^\"]*)\"|'([^']*)'))?[ \\t]*$/.exec(s);\n if (angle) return { href: angle[1], title: angle[2] ?? angle[3] ?? '' };\n\n const withTitle = /^(\\S+)\\s+(?:\"([^\"]*)\"|'([^']*)')\\s*$/.exec(s);\n if (withTitle) return { href: withTitle[1], title: withTitle[2] ?? withTitle[3] ?? '' };\n\n return { href: s, title: '' };\n}\n\n/**\n * Resolves images, inline links, GFM reference-style links (explicit,\n * shortcut, and bare/implicit forms), and footnote markers. Must run on text\n * already passed through _esc() — see _inline()'s Step 1 comment.\n * @param {string} text\n * @returns {string}\n */\nfunction _resolveLinksAndFootnotes(text) {\n text = text.replace(IMAGE_RE, (_, alt, dest) => {\n const { href, title } = _splitDestAndTitle(dest);\n const titleAttr = title ? ` title=\"${_escAttrQuotes(title)}\"` : '';\n return `<img src=\"${_escAttrQuotes(href)}\" alt=\"${_escAttrQuotes(alt)}\"${titleAttr} class=\"an-image\">`;\n });\n text = text.replace(LINK_RE, (_, label, dest) => {\n const { href, title } = _splitDestAndTitle(dest);\n const titleAttr = title ? ` title=\"${_escAttrQuotes(title)}\"` : '';\n return `<a href=\"${_escAttrQuotes(href)}\"${titleAttr}>${label}</a>`;\n });\n text = text.replace(/\\[([^\\]]+)\\]\\[([^\\]]*)\\]/g, (m, label, ref) => {\n const def = _linkDefs.get(_unescAmpLtGt(ref || label).trim().toLowerCase());\n if (!def) return m;\n const titleAttr = def.title ? ` title=\"${_escAttr(def.title)}\"` : '';\n return `<a href=\"${_escAttr(def.href)}\"${titleAttr}>${label}</a>`;\n });\n text = text.replace(/\\[([^\\]]+)\\]/g, (m, label) => {\n const def = _linkDefs.get(_unescAmpLtGt(label).trim().toLowerCase());\n if (!def) return m;\n const titleAttr = def.title ? ` title=\"${_escAttr(def.title)}\"` : '';\n return `<a href=\"${_escAttr(def.href)}\"${titleAttr}>${label}</a>`;\n });\n text = text.replace(/\\[\\^([^\\]]+)\\]/g, (m, id) => (_footnoteIds.has(_unescAmpLtGt(id)) ? `<sup>[${id}]</sup>` : m));\n return text;\n}\n\n/**\n * Converts angle-bracket (`<https://...>`) and bare (`https://...`)\n * autolinks. Runs after _resolveLinksAndFootnotes() so an already-linked URL\n * isn't reprocessed, and on already-_esc()'d text (see _inline()).\n * @param {string} text\n * @returns {string}\n */\nfunction _applyAutolinks(text) {\n text = text.replace(/<(https?:\\/\\/[^\\s&]+?)>/g, (_, url) => `<a href=\"${_escAttrQuotes(url)}\">${url}</a>`);\n // Email autolink — CommonMark's `<user@host>` form gets a mailto: href.\n text = text.replace(\n /<([\\w.!#$%&'*+/=?^`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)>/g,\n (_, addr) => `<a href=\"mailto:${_escAttrQuotes(addr)}\">${addr}</a>`,\n );\n text = text.replace(/(^|[\\s(])(https?:\\/\\/[^\\s()]+)/g, (m, pre, rawUrl) => {\n const trail = /[.,;:!?)]+$/.exec(rawUrl);\n const url = trail ? rawUrl.slice(0, -trail[0].length) : rawUrl;\n if (!url) return m;\n const suffix = trail ? trail[0] : '';\n return `${pre}<a href=\"${_escAttrQuotes(url)}\">${url}</a>${suffix}`;\n });\n return text;\n}\n\n/**\n * Applies bold/italic/bold-italic (asterisk and underscore forms — underscore\n * requires a non-word-character boundary per CommonMark), strikethrough, and\n * inline code.\n * @param {string} text\n * @returns {string}\n */\nfunction _applyEmphasisAndCode(text) {\n text = text.replace(/\\*{3}([^*\\n]+?)\\*{3}/g, (_, c) => `<strong><em>${c}</em></strong>`);\n text = text.replace(/(?<!\\w)_{3}([^_\\n]+?)_{3}(?!\\w)/g, (_, c) => `<strong><em>${c}</em></strong>`);\n text = text.replace(/\\*{2}([^*\\n]+?)\\*{2}/g, (_, c) => `<strong>${c}</strong>`);\n text = text.replace(/(?<!\\w)_{2}([^_\\n]+?)_{2}(?!\\w)/g, (_, c) => `<strong>${c}</strong>`);\n text = text.replace(/\\*([^*\\n]+?)\\*/g, (_, c) => `<em>${c}</em>`);\n text = text.replace(/(?<!\\w)_([^_\\n]+?)_(?!\\w)/g, (_, c) => `<em>${c}</em>`);\n text = text.replace(/~~([^~\\n]+?)~~/g, (_, c) => `<del>${c}</del>`);\n return text;\n}\n\nfunction _inline(text) {\n // Step 0: backslash escapes (\\* \\_ \\` \\# \\[ \\] \\( \\) \\> \\\\ \\~ \\|) — replaced\n // with inert placeholders before any syntax regex below can match them, so\n // e.g. \\*not bold\\* never gets treated as emphasis. Restored at the end.\n // Backslash escapes first, so an escaped backtick cannot open a code span.\n // Code spans come out next: their content is literal, and must not be seen by\n // the entity, link or emphasis passes below.\n const { text: withoutEscapes, literals } = _extractBackslashEscapes(text);\n const { text: withoutCode, codes } = _extractCodeSpans(withoutEscapes);\n\n // Step 1: escape raw &/</> in the plain-text parts of the string exactly\n // once, up front — none of these are markdown-syntax characters used below,\n // so this doesn't interfere with matching. Capture-group content in the\n // steps below is therefore ALREADY escaped and must NOT be re-escaped;\n // attribute values captured from `text` only need quotes escaped\n // (_escAttrQuotes), since & < > are already entities. Values that come from\n // _linkDefs (sourced from the raw, unescaped line array) still need the\n // full _escAttr/_esc treatment.\n let result = _esc(withoutCode);\n\n result = _resolveLinksAndFootnotes(result);\n result = _applyAutolinks(result);\n result = _applyEmphasisAndCode(result);\n\n return _restoreCodeSpans(_restoreBackslashEscapes(result, literals), codes, literals);\n}\n\n// A complete named / decimal / hex character reference. An `&` that starts one\n// is left alone so `©` survives as a copyright sign instead of rendering\n// as the literal text \"©\". Everything the sanitiser cares about is decided\n// after this, on the parsed DOM, so preserving references does not widen what\n// can get through.\nconst ENTITY_RE = /&(?!#\\d+;|#[xX][0-9a-fA-F]+;|[a-zA-Z][a-zA-Z0-9]*;)/g;\n\nfunction _esc(v) {\n return String(v)\n .replace(ENTITY_RE, '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n}\n\n/**\n * Escaper for code content. Unlike _esc() it escapes every `&`, because a\n * character reference is not recognised inside a code span or code block —\n * `&` written in a fence has to survive as those five literal characters\n * rather than rendering as `&`.\n * @param {string} v\n * @returns {string}\n */\nfunction _escCode(v) {\n return String(v)\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n}\n\nfunction _escAttr(v) {\n return String(v)\n .replaceAll('&', '&')\n .replaceAll('\"', '"')\n .replaceAll(\"'\", ''')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n}\n\n/** Escapes only quote characters — for attribute values already run through _esc(). */\nfunction _escAttrQuotes(v) {\n return String(v).replaceAll('\"', '"').replaceAll(\"'\", ''');\n}\n\n/** Reverses _esc()'s &/</> substitutions, for matching against un-escaped _linkDefs/_footnoteIds keys. */\nfunction _unescAmpLtGt(v) {\n return String(v).replaceAll('<', '<').replaceAll('>', '>').replaceAll('&', '&');\n}\n","/**\n * detectLang.js — Heuristic programming-language detection for code snippets.\n *\n * Returns a Prism.js language identifier, or null when nothing scores clearly\n * enough to be worth guessing.\n *\n * ## Why scoring rather than an ordered if-chain\n *\n * The previous version returned on the first pattern that matched, so the\n * answer depended on the order the languages happened to be listed in. Every\n * new pattern risked stealing snippets from a language checked later, and a\n * snippet carrying signals for two languages was decided by position instead of\n * by strength of evidence — `export default { data() { … } }` came back as CSS\n * because the JavaScript rules did not cover `export default` and the CSS rule\n * happily read `a: 1` as a declaration.\n *\n * Instead every rule contributes weight to its language and the highest total\n * wins, so adding a signal makes one language more likely rather than\n * reshuffling the rest. Weights are roughly:\n *\n * 10 unmistakable — `<?php`, `#!/bin/bash`, `println!`, `fmt.Println`\n * 5 characteristic — `def f(...):`, `interface X {`, `val x: T`\n * 2 suggestive — shared with other languages, only useful to break a tie\n *\n * A language needs MIN_SCORE overall and a MIN_MARGIN lead over the runner-up;\n * otherwise the snippet is ambiguous and null is the honest answer.\n */\n\n/** Minimum winning score. Below this the evidence is one weak signal at most. */\nconst MIN_SCORE = 5;\n/** The winner must beat the runner-up by this much, or the snippet is ambiguous. */\nconst MIN_MARGIN = 2;\n\n/**\n * `[superset, base]` pairs. Valid base-language code is also valid in the\n * superset, so the superset inherits the base's score once it has shown a\n * marker of its own — `$var` + `&:hover` is SCSS even though everything around\n * it reads as ordinary CSS.\n * @type {Array<[string, string]>}\n */\nconst SUPERSETS = [\n ['typescript', 'javascript'],\n ['scss', 'css'],\n ['cpp', 'c'],\n];\n\n/**\n * @typedef {object} Rule\n * @property {string} lang - Prism language id this rule votes for.\n * @property {RegExp} re - Pattern to look for.\n * @property {number} w - Weight added when it matches.\n */\n\n/**\n * Every language this module can return. Exported so the code tooltip's picker\n * can be checked against it — a language the detector produces but the picker\n * cannot show leaves the select reading \"Plain text\" on a highlighted block.\n * @type {string[]}\n */\nexport const SUPPORTED_LANGS = [\n 'javascript', 'typescript', 'python', 'java', 'go', 'rust', 'csharp', 'kotlin',\n 'swift', 'cpp', 'c', 'ruby', 'php', 'html', 'xml', 'json', 'yaml', 'markdown',\n 'sql', 'scss', 'css', 'bash',\n];\n\n/** @type {Rule[]} */\nconst RULES = [\n // ── Unmistakable markers ───────────────────────────────────────────────────\n { lang: 'php', w: 10, re: /<\\?php\\b|<\\?=/ },\n { lang: 'bash', w: 10, re: /^#!.*\\/(?:ba|z|da|fi|k)?sh\\b/m },\n { lang: 'rust', w: 10, re: /\\b(?:println!|print!|format!|vec!|panic!)\\s*[([]/ },\n { lang: 'go', w: 10, re: /\\bfmt\\.(?:Print|Println|Printf|Sprintf|Errorf|Fprintf)\\s*\\(/ },\n { lang: 'java', w: 10, re: /\\bSystem\\.out\\.(?:print|println)\\s*\\(/ },\n { lang: 'csharp', w: 10, re: /\\bConsole\\.(?:Write|WriteLine)\\s*\\(/ },\n { lang: 'cpp', w: 10, re: /\\b(?:cout|cerr)\\s*<<|\\bcin\\s*>>|\\busing\\s+namespace\\s+std\\b|\\bstd::\\w/ },\n { lang: 'python', w: 10, re: /\\bdef[ \\t]+\\w+[ \\t]*\\([^)]*\\)[ \\t]*(?:->[^:\\n]*)?:|\\bif[ \\t]+__name__[ \\t]*==[ \\t]*['\"]__main__['\"]/ },\n { lang: 'html', w: 10, re: /^\\s*<!DOCTYPE\\s+html/i },\n { lang: 'xml', w: 10, re: /^\\s*<\\?xml\\s/i },\n\n // ── JavaScript ─────────────────────────────────────────────────────────────\n { lang: 'javascript', w: 6, re: /\\bconsole\\.(?:log|error|warn|info|debug)\\s*\\(/ },\n { lang: 'javascript', w: 6, re: /\\b(?:const|let)\\s+\\w+\\s*=|(?:^|\\n)\\s*var\\s+\\w+\\s*=/ },\n // No other language here spells a module boundary this way, so it carries\n // enough weight on its own — `export default { a: 1 }` used to tie with CSS,\n // which read the object body as a declaration block.\n { lang: 'javascript', w: 8, re: /\\bexport\\s+(?:default|const|function|class|async|\\{|\\*)|\\bmodule\\.exports\\b|\\brequire\\s*\\(\\s*['\"]/ },\n { lang: 'javascript', w: 5, re: /\\bfunction(?:[ \\t]+\\w+)?[ \\t]*\\([^)]*\\)[ \\t]*\\{|=>[ \\t]*[{([`\\w'\"]/ },\n { lang: 'javascript', w: 5, re: /\\bimport\\b[^'\"\\n]*[ \\t]from[ \\t]*['\"]/ },\n { lang: 'javascript', w: 4, re: /\\.(?:map|filter|forEach|reduce|then|catch|find|some|every)\\s*\\(/ },\n // Split rather than alternated: a one-line DOM call chain hits several of\n // these at once, and as a single rule it capped at one rule's weight and\n // scored too low to beat the ambiguity threshold.\n { lang: 'javascript', w: 4, re: /\\b(?:document|window|globalThis)\\.\\w/ },\n { lang: 'javascript', w: 4, re: /\\baddEventListener\\s*\\(|\\bquerySelector(?:All)?\\s*\\(|\\bgetElementById\\s*\\(/ },\n { lang: 'javascript', w: 3, re: /\\.(?:innerHTML|textContent|classList|dataset|style)\\b|\\bJSON\\.(?:parse|stringify)\\s*\\(/ },\n { lang: 'javascript', w: 4, re: /\\bawait\\s+\\w|\\basync\\s+(?:function|\\(|\\w+\\s*=>)|\\bnew\\s+Promise\\s*\\(/ },\n { lang: 'javascript', w: 3, re: /\\bReact\\.|\\buseState\\s*\\(|\\buseEffect\\s*\\(/ },\n\n // ── TypeScript — JS plus type syntax, so it also collects the JS points ────\n { lang: 'typescript', w: 8, re: /\\binterface\\s+\\w+(?:<[^>]*>)?\\s*(?:extends\\s[\\w<>, ]+)?\\{/ },\n { lang: 'typescript', w: 8, re: /\\btype\\s+\\w+(?:<[^>]*>)?\\s*=/ },\n { lang: 'typescript', w: 7, re: /:\\s*(?:string|number|boolean|void|never|any|unknown|object)\\b/ },\n { lang: 'typescript', w: 6, re: /\\benum\\s+\\w+\\s*\\{|\\breadonly\\s+\\w|\\bimplements\\s+\\w|\\bnamespace\\s+\\w+\\s*\\{/ },\n { lang: 'typescript', w: 6, re: /\\b(?:private|public|protected)\\s+(?:readonly\\s+)?\\w+\\s*[:?]/ },\n { lang: 'typescript', w: 5, re: /\\)\\s*:\\s*[A-Z]\\w*(?:<[^>]*>)?\\s*(?:\\{|=>)|\\)\\s*:\\s*(?:string|number|boolean|void)\\b/ },\n { lang: 'typescript', w: 4, re: /\\bfunction\\s+\\w+\\s*<[^>]+>\\s*\\(|\\bas\\s+(?:const\\b|[A-Z]\\w*)/ },\n { lang: 'typescript', w: 3, re: /\\w\\?\\s*:\\s*\\w|\\bimport\\s+type\\b|\\bsatisfies\\b/ },\n\n // ── Python ─────────────────────────────────────────────────────────────────\n { lang: 'python', w: 6, re: /(?:^|\\n)\\s*(?:from\\s+[\\w.]+\\s+import\\s|import\\s+\\w+(?:\\s*,\\s*\\w+)*\\s*$)/m },\n { lang: 'python', w: 6, re: /(?:^|\\n)\\s*class\\s+\\w+(?:\\([\\w., ]*\\))?\\s*:/ },\n { lang: 'python', w: 5, re: /(?:^|\\n)\\s*(?:with|elif|except|finally|async\\s+def)\\b[^\\n]*:/ },\n { lang: 'python', w: 5, re: /\\bself\\.\\w|\\b__init__\\b|\\bf[\"'][^\"']*\\{/ },\n { lang: 'python', w: 4, re: /(?:^|\\n)[ \\t]*for[ \\t]+\\w+[ \\t]+in[ \\t][^\\n:]*:|\\bfor[ \\t]+\\w+[ \\t]+in[ \\t]+range[ \\t]*\\(/ },\n { lang: 'python', w: 4, re: /\\bprint\\s*\\(|\\blen\\s*\\(|\\brange\\s*\\(/ },\n { lang: 'python', w: 3, re: /\\[[^\\]\\n]*\\bfor\\s+\\w+\\s+in\\s[^\\]\\n]*\\]|\\bNone\\b|\\bTrue\\b|\\bFalse\\b/ },\n { lang: 'python', w: 3, re: /\\*\\*\\w|\\bdict[ \\t]*\\(|\\blambda(?:[ \\t]+\\w+)?[ \\t]*:/ },\n\n // ── Go ─────────────────────────────────────────────────────────────────────\n { lang: 'go', w: 8, re: /(?:^|\\n)\\s*package\\s+\\w+\\s*$/m },\n { lang: 'go', w: 6, re: /\\btype\\s+\\w+\\s+struct\\s*\\{|\\btype\\s+\\w+\\s+interface\\s*\\{/ },\n { lang: 'go', w: 6, re: /\\bfunc(?:[ \\t]*\\([^)]*\\))?(?:[ \\t]+\\w+)?[ \\t]*\\([^)]*\\)[^\\n{]{0,40}\\{/ },\n { lang: 'go', w: 5, re: /\\bif\\s+err\\s*!=\\s*nil\\b|\\berr\\s*:=\\s|\\bdefer\\s+\\w/ },\n { lang: 'go', w: 4, re: /\\w+\\s*:=\\s*\\S|\\bchan\\s+\\w|\\bgo\\s+func\\b|\\bnil\\b/ },\n\n // ── Rust ───────────────────────────────────────────────────────────────────\n { lang: 'rust', w: 7, re: /\\bfn[ \\t]+\\w+(?:<[^>]*>)?[ \\t]*\\([^)]*\\)[^\\n{]{0,40}\\{/ },\n { lang: 'rust', w: 7, re: /\\blet\\s+mut\\s+\\w|\\bpub\\s+(?:fn|struct|enum|mod|use)\\b|\\bimpl\\s+\\w/ },\n { lang: 'rust', w: 5, re: /\\buse\\s+(?:std|crate|self|super)::|\\bmatch\\s+\\w+\\s*\\{[^}]*=>/ },\n { lang: 'rust', w: 4, re: /\\b(?:Option|Result|Vec|Box|Rc|Arc|HashMap)\\s*<|&(?:mut\\s+)?self\\b|\\b\\w+::<|->\\s*Result</ },\n { lang: 'rust', w: 3, re: /\\b(?:i8|i16|i32|i64|u8|u16|u32|u64|usize|isize|f32|f64)\\b|\\bunwrap\\s*\\(\\)|\\bderive\\s*\\(/ },\n\n // ── Java ───────────────────────────────────────────────────────────────────\n { lang: 'java', w: 7, re: /\\b(?:public|private|protected)\\s+(?:static\\s+)?(?:final\\s+)?(?:void|int|long|double|boolean|String|[A-Z]\\w*(?:<[^>]*>)?)\\s+\\w+\\s*[({]/ },\n { lang: 'java', w: 7, re: /\\bimport\\s+(?:java|javax|org\\.springframework)\\.[\\w.]+;/ },\n { lang: 'java', w: 6, re: /@(?:Override|Autowired|Component|Service|Controller|RestController|Entity|Test|SpringBootApplication)\\b/ },\n { lang: 'java', w: 5, re: /\\bnew\\s+(?:ArrayList|HashMap|HashSet|LinkedList|StringBuilder)\\s*<[^>]*>\\s*\\(|\\bthrows\\s+\\w*Exception/ },\n { lang: 'java', w: 4, re: /\\bpublic\\s+(?:class|interface|enum)\\s+\\w|\\bextends\\s+\\w+\\s*\\{|\\bList<\\w|\\bMap<\\w/ },\n\n // ── C# ─────────────────────────────────────────────────────────────────────\n { lang: 'csharp', w: 8, re: /\\busing\\s+System(?:\\.[\\w.]+)?\\s*;|\\bnamespace\\s+[\\w.]+\\s*[{;]/ },\n { lang: 'csharp', w: 8, re: /\\{\\s*get;\\s*(?:private\\s+)?set;\\s*\\}|\\b(?:public|private|protected|internal)\\s+(?:static\\s+)?async\\s+Task(?:<[^>]*>)?\\s+\\w/ },\n { lang: 'csharp', w: 6, re: /\\basync\\s+Task(?:<[^>]*>)?\\s+\\w|\\bawait\\s+\\w+\\.\\w+Async\\s*\\(/ },\n { lang: 'csharp', w: 5, re: /\\bIEnumerable<|\\bvar\\s+\\w+\\s*=\\s*new\\s+\\w|\\bpublic\\s+override\\b|\\[\\s*(?:HttpGet|HttpPost|Serializable|Required)\\s*\\]/ },\n { lang: 'csharp', w: 3, re: /\\.(?:Select|Where|FirstOrDefault|ToList|Any)\\s*\\(|\\bstring\\[\\]\\s+args\\b/ },\n\n // ── Kotlin ─────────────────────────────────────────────────────────────────\n { lang: 'kotlin', w: 8, re: /\\bfun\\s+\\w+\\s*\\([^)]*\\)\\s*(?::\\s*[\\w<>?.]+\\s*)?[={]|\\bdata\\s+class\\s+\\w/ },\n { lang: 'kotlin', w: 6, re: /\\bval[ \\t]+\\w+(?:[ \\t]*:[ \\t]*[\\w<>?.]+)?[ \\t]*=|\\bcompanion[ \\t]+object\\b|\\bsuspend[ \\t]+fun\\b/ },\n { lang: 'kotlin', w: 4, re: /\\bprintln\\s*\\(|\\bwhen\\s*\\([^)]*\\)\\s*\\{|\\bobject\\s+\\w+\\s*[:{]|\\?:\\s*\\w/ },\n\n // ── Swift ──────────────────────────────────────────────────────────────────\n { lang: 'swift', w: 8, re: /\\bguard\\s+(?:let|var)\\s[^\\n]*\\belse\\b|\\bfunc\\s+\\w+\\s*\\([^)]*\\)\\s*(?:async\\s+)?(?:throws\\s+)?->\\s*[\\w<>?[\\]]/ },\n { lang: 'swift', w: 6, re: /\\bprotocol[ \\t]+\\w+[^\\n{]{0,40}\\{|\\bextension[ \\t]+\\w+[^\\n{]{0,40}\\{|\\bimport[ \\t]+(?:SwiftUI|UIKit|Foundation)\\b/ },\n { lang: 'swift', w: 6, re: /\\b(?:let|var)\\s+\\w+\\s*:\\s*(?:Int|String|Double|Float|Bool|Character|Any|\\[[A-Z])|@(?:State|Binding|Published|IBOutlet|objc)\\b/ },\n { lang: 'swift', w: 4, re: /\\\\\\(\\w|\\bif[ \\t]+let[ \\t]+\\w|\\bstruct[ \\t]+\\w+[ \\t]*:[ \\t]*View\\b|\\bfunc[ \\t]+\\w+[ \\t]*\\([^)]*:[ \\t]*[A-Z]/ },\n { lang: 'swift', w: 3, re: /\\?\\?\\s*\\w|\\b\\w+\\?\\.\\w|\\bself\\.\\w+\\s*=/ },\n\n // ── C / C++ ────────────────────────────────────────────────────────────────\n { lang: 'cpp', w: 8, re: /#include\\s*<(?:iostream|vector|map|set|algorithm|string|memory|utility)>/ },\n { lang: 'cpp', w: 6, re: /\\btemplate\\s*<\\s*(?:typename|class)\\b|\\bnullptr\\b|\\bnamespace\\s+\\w+\\s*\\{/ },\n { lang: 'c', w: 8, re: /#include\\s*<(?:stdio|stdlib|string|math|time|ctype|unistd)\\.h>/ },\n { lang: 'c', w: 6, re: /\\b(?:printf|scanf|malloc|calloc|free|memcpy|strlen)\\s*\\(/ },\n { lang: 'c', w: 4, re: /\\bint\\s+main\\s*\\(\\s*(?:void|int\\s+argc|\\)\\s*\\{)/ },\n { lang: 'c', w: 3, re: /\\btypedef\\s+struct\\b|\\bsizeof\\s*\\(|\\bNULL\\b/ },\n\n // ── Ruby ───────────────────────────────────────────────────────────────────\n { lang: 'ruby', w: 8, re: /\\bdo[ \\t]*\\|[ \\t]*\\w[\\w, ]*\\|/ },\n { lang: 'ruby', w: 7, re: /\\battr_(?:accessor|reader|writer)\\s+:|\\brequire(?:_relative)?\\s+['\"]|\\bputs\\s+\\S/ },\n // Split from a single `def … end` span: two independent signals score the\n // same way here, and the span form put a lazy `[\\\\s\\\\S]*?` next to `\\\\s*`,\n // which backtracks super-linearly on input that never closes the block.\n { lang: 'ruby', w: 4, re: /(?:^|\\n)[ \\t]*def[ \\t]+\\w/ },\n { lang: 'ruby', w: 4, re: /(?:^|\\n)[ \\t]*end[ \\t]*$/m },\n { lang: 'ruby', w: 4, re: /\\bnil\\?\\b|\\b\\w+\\.new\\b|=>\\s*['\"\\w]|\\bmodule\\s+[A-Z]\\w*\\s*$/m },\n { lang: 'ruby', w: 3, re: /:\\w+[ \\t]*=>|\\bend[ \\t]*$/m },\n\n // ── PHP ────────────────────────────────────────────────────────────────────\n { lang: 'php', w: 7, re: /\\$this->\\w|\\bfunction\\s+\\w+\\s*\\([^)]*\\$\\w/ },\n { lang: 'php', w: 6, re: /\\$\\w+\\s*=\\s*\\S|\\bforeach\\s*\\(\\s*\\$\\w+\\s+as\\s+\\$/ },\n { lang: 'php', w: 5, re: /\\becho[ \\t][^;\\n]*[$'\"]|\\bnamespace[ \\t]+[\\w\\\\]+;|\\buse[ \\t]+[\\w\\\\]+\\\\\\w+;/ },\n // `public function` is PHP's spelling and nothing else's: Java and C# name a\n // return type in that position, and TypeScript class methods drop `function`\n // entirely. Weighted to clear JavaScript's generic `function name(…) {` rule,\n // which fires on the same line.\n { lang: 'php', w: 8, re: /\\b(?:public|private|protected)\\s+(?:static\\s+)?function\\s+\\w/ },\n { lang: 'php', w: 3, re: /->\\w+\\s*\\(|::\\w+\\s*\\(/ },\n\n // ── Markup and data ────────────────────────────────────────────────────────\n { lang: 'html', w: 7, re: /<(?:html|head|body|nav|section|article|header|footer|main|form)\\b[^>]*>/i },\n { lang: 'html', w: 5, re: /<(?:div|p|span|a|img|ul|ol|li|table|tr|td|input|button|h[1-6])\\b[^>]*>[\\s\\S]*<\\/(?:div|p|span|a|ul|ol|li|table|tr|td|button|h[1-6])>/i },\n { lang: 'html', w: 4, re: /<\\w+\\s+(?:class|id|href|src|type|style)\\s*=\\s*[\"']/i },\n { lang: 'xml', w: 6, re: /\\bxmlns(?::\\w+)?\\s*=\\s*[\"']|<\\/\\w+:\\w+>|<\\w+:\\w+[\\s>]/ },\n\n { lang: 'json', w: 8, re: /^\\s*[{[][\\s\\S]*\"[\\w-]+\"\\s*:\\s*(?:\"[^\"]*\"|-?\\d|\\{|\\[|true|false|null)/ },\n { lang: 'json', w: 3, re: /^\\s*\\{[\\s\\S]*\\}\\s*$|^\\s*\\[[\\s\\S]*\\]\\s*$/ },\n\n // ── YAML ───────────────────────────────────────────────────────────────────\n // Common enough in practice (CI configs, compose files, front matter) that\n // its absence made every such snippet fall through to null.\n { lang: 'yaml', w: 8, re: /^---\\s*$/m },\n { lang: 'yaml', w: 6, re: /^[ \\t]*-\\s+\\w+\\s*:\\s*\\S/m },\n { lang: 'yaml', w: 5, re: /^[a-z_][\\w-]*[ \\t]*:(?:[ \\t]*$|[ \\t]+(?:[|>][-+]?[ \\t]*$|['\"\\w[{]))/im },\n { lang: 'yaml', w: 4, re: /^[ \\t]+[a-z_][\\w-]*[ \\t]*:[ \\t]*\\S/im },\n { lang: 'yaml', w: 3, re: /^[ \\t]*-\\s+\\S/m },\n\n // ── Markdown ───────────────────────────────────────────────────────────────\n { lang: 'markdown', w: 7, re: /^#{1,6}\\s+\\S/m },\n { lang: 'markdown', w: 6, re: /^```|^\\|[^\\n|]+\\|[^\\n]*\\n\\s*\\|[\\s:|-]+\\|/m },\n { lang: 'markdown', w: 4, re: /\\[[^\\]\\n]+\\]\\([^)\\n]+\\)|!\\[[^\\]\\n]*\\]\\(/ },\n { lang: 'markdown', w: 3, re: /\\*\\*[^*\\n]+\\*\\*|^>\\s+\\S|^[-*+]\\s+\\S/m },\n\n // ── SQL ────────────────────────────────────────────────────────────────────\n { lang: 'sql', w: 9, re: /(?:^|\\n)\\s*(?:SELECT\\s+[\\w*]|INSERT\\s+INTO\\s|UPDATE\\s+\\w+\\s+SET\\s|DELETE\\s+FROM\\s)/i },\n { lang: 'sql', w: 8, re: /(?:^|\\n)\\s*(?:CREATE|ALTER|DROP)\\s+(?:TABLE|DATABASE|INDEX|VIEW|SCHEMA)\\b/i },\n { lang: 'sql', w: 4, re: /\\b(?:INNER|LEFT|RIGHT|FULL)\\s+(?:OUTER\\s+)?JOIN\\b|\\bGROUP\\s+BY\\b|\\bORDER\\s+BY\\b|\\bWITH\\s+\\w+\\s+AS\\s*\\(/i },\n\n // ── SCSS before CSS: every SCSS marker is invalid plain CSS ────────────────\n { lang: 'scss', w: 9, re: /^[ \\t]*\\$[\\w-]+[ \\t]*:[^;\\n]+;|@(?:mixin|include|extend|use|forward)[ \\t]+[\\w\"'-]/m },\n { lang: 'scss', w: 7, re: /^[ \\t]*&[\\s.:[&>+~]|#\\{[^}]*\\}/m },\n { lang: 'scss', w: 4, re: /^[ \\t]*\\/\\/[ \\t]*\\S/m },\n\n // The leading word must not be a statement keyword from another language:\n // an object or block literal reads exactly like a rule set otherwise.\n { lang: 'css', w: 6, re: /^[ \\t]*(?!(?:export|import|return|function|const|let|var|val|if|else|for|while|switch|case|class|new|public|private|protected|internal|def|func|fun|fn|pub|package|type|interface|enum|struct|impl|trait|mod|use|using|namespace|module|data|object|async|await|guard|extension|protocol|template|typedef)\\b)[.#]?[\\w-]+[^{}\\n]{0,60}\\{[^{}:]*:[^{};]+[;}]/m },\n { lang: 'css', w: 5, re: /@(?:media|supports|keyframes|font-face|import|charset)\\b/ },\n { lang: 'css', w: 4, re: /:\\s*(?:#[\\da-f]{3,8}|\\d+(?:px|rem|em|%|vh|vw)|flex|grid|block|none|absolute|relative)\\s*[;}]/i },\n { lang: 'css', w: 3, re: /::?(?:hover|focus|active|before|after|first-child|last-child|nth-child)\\b/ },\n\n // ── Bash ───────────────────────────────────────────────────────────────────\n { lang: 'bash', w: 7, re: /(?:^|\\n|&&|\\|\\|)\\s*(?:sudo\\s+)?(?:apt(?:-get)?|yum|brew|npm|pnpm|yarn|pip3?|docker|kubectl|git|systemctl|curl|wget|chmod|chown|mkdir|rm|cp|mv|tar|ssh|scp)\\s+[\\w./-]/ },\n { lang: 'bash', w: 6, re: /^\\s*(?:export|source|alias)\\s+\\w+|^\\s*\\w+=\\S+\\s*$/m },\n { lang: 'bash', w: 6, re: /\\bfi[ \\t]*$|(?:^|\\n)[ \\t]*(?:if|for|while)[ \\t][^\\n]*;[ \\t]*(?:then|do)\\b|(?:^|\\n)[ \\t]*done\\b/m },\n { lang: 'bash', w: 5, re: /\\$\\{?\\w+\\}?[/:]|\"\\$\\w|\\becho\\s+[\"'$]|\\$\\(\\w/ },\n { lang: 'bash', w: 4, re: /(?:^|\\n|\\|)\\s*(?:grep|awk|sed|cat|ls|cd|pwd|find|xargs|head|tail|sort|uniq|wc)\\s+[-\\w$'\"./]/ },\n { lang: 'bash', w: 3, re: /\\s\\|[ \\t]*\\w|\\s&&\\s|\\s2>&1|\\s-[\\w-]+\\s/ },\n];\n\n/**\n * How much of the input the rules actually run over.\n *\n * A language is identifiable from its opening lines, so scanning a whole file\n * buys nothing — and it costs a lot: several rules scan a line looking for a\n * trailing token, which is quadratic in line length. Pasting a minified bundle\n * (one 100 KB line) took over seven seconds before this cap, freezing the\n * editor. Bounding the input makes detection cost independent of file size.\n */\nconst SAMPLE_LIMIT = 4000;\n\n/**\n * First `SAMPLE_LIMIT` characters, cut back to a line boundary so the `^`/`$`\n * anchored rules do not see a line that the truncation invented.\n * @param {string} s\n * @returns {string}\n */\nfunction _sample(s) {\n if (s.length <= SAMPLE_LIMIT) return s;\n const head = s.slice(0, SAMPLE_LIMIT);\n const lastBreak = head.lastIndexOf('\\n');\n return lastBreak > 0 ? head.slice(0, lastBreak) : head;\n}\n\n/**\n * Detects the programming language of a code snippet.\n * @param {string} code\n * @returns {string|null} A Prism language id, or null when it is not clear.\n */\nexport function detectLang(code) {\n if (!code?.trim()) return null;\n const s = _sample(code.trim());\n\n /** @type {Map<string, number>} */\n const scores = new Map();\n for (const { lang, re, w } of RULES) {\n if (re.test(s)) scores.set(lang, (scores.get(lang) || 0) + w);\n }\n if (scores.size === 0) return null;\n\n // A superset language legitimately matches its base language's rules, so the\n // evidence would otherwise be split between the two and both fall under the\n // margin — or the base would win outright on shared signals alone. Fold the\n // base's score into the superset, but only once the superset has shown at\n // least one marker of its own.\n for (const [superset, base] of SUPERSETS) {\n const own = scores.get(superset);\n if (own) scores.set(superset, own + (scores.get(base) || 0));\n }\n\n const ranked = [...scores.entries()].sort((a, b) => b[1] - a[1]);\n const [winner, top] = ranked[0];\n const runnerUp = ranked[1]?.[1] ?? 0;\n\n if (top < MIN_SCORE || top - runnerUp < MIN_MARGIN) return null;\n return winner;\n}\n","/**\n * Editor.js - Core editing command module\n * Wraps all execCommand calls, undo/redo, and fires events via the context.\n * Inspired by Summernote's Editor module.\n */\n\nimport { History } from '../editing/History.js';\nimport * as Style from '../editing/Style.js';\nimport { insertTable } from '../editing/Table.js';\nimport { isModifier } from '../core/key.js';\nimport { handleKeydown } from '../editing/Typing.js';\nimport { on } from '../core/dom.js';\nimport { sanitiseHTML, sanitiseToBody, sanitiseUrl } from '../core/sanitise.js';\nimport { TextCounter } from '../core/count.js';\nimport { markdownToHTML, htmlToMarkdown } from '../core/markdown.js';\nimport { detectLang } from '../core/detectLang.js';\n\n/**\n * Blocks the caret cannot be placed after, so the editable always keeps a\n * trailing paragraph. Module-level because `_ensureTrailingParagraph` runs on\n * every keystroke and was rebuilding this set each time.\n */\nconst TRAPPING_TAGS = new Set(['PRE', 'BLOCKQUOTE', 'TABLE', 'FIGURE', 'UL', 'OL', 'HR']);\n\nexport class Editor {\n /**\n * @param {import('../Context.js').Context} context\n */\n constructor(context) {\n this.context = context;\n this.options = context.options;\n /** @type {History|null} */\n this._history = null;\n this._disposers = [];\n /** @type {number|null} Timer handle for debounced undo snapshot */\n this._snapshotTimer = null;\n /**\n * Counts for maxChars/maxWords. Created on first use so an editor without\n * a limit carries no cache.\n * @type {TextCounter|null}\n */\n this._limitCounter = null;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n initialize() {\n const editable = this.context.layoutInfo.editable;\n this._history = new History(\n editable,\n this.options.historyLimit || 100,\n this.options.historyMaxBytes || 10 * 1024 * 1024,\n );\n this._bindEvents(editable);\n return this;\n }\n\n destroy() {\n this._disposers.forEach((d) => d());\n this._disposers = [];\n this._history = null;\n clearTimeout(this._snapshotTimer);\n this._snapshotTimer = null;\n }\n\n // ---------------------------------------------------------------------------\n // Event binding\n // ---------------------------------------------------------------------------\n\n _bindEvents(editable) {\n // Keyboard shortcuts\n const onKeydown = (event) => this._onKeydown(event);\n // Catch ALL content mutations: typing, IME, spellcheck, voice, drag-drop text.\n const onInput = () => this.afterCommand();\n // Hard-enforce maxChars / maxWords before content is mutated\n const onBeforeInput = (event) => this._enforceLimit(event);\n // Refresh toolbar on selection change, scoped to this editor\n const onSelChange = () => {\n if (!this.context._alive) return;\n const sel = globalThis.getSelection();\n if (sel?.rangeCount > 0 && editable.contains(sel.anchorNode)) {\n this.context.invoke('toolbar.refresh');\n if (typeof this.options.onSelectionChange === 'function') {\n this.options.onSelectionChange(this.context);\n }\n }\n };\n\n // Checklist checkboxes are contenteditable=false so native clicks work;\n // hook afterCommand so the checked state is preserved in undo history.\n const onCheckboxClick = (e) => {\n if (e.target.type === 'checkbox' && e.target.closest('.an-checklist')) {\n this.afterCommand();\n }\n };\n\n // Guard: when cursor lands at the <li> element node of a checklist item\n // (before the checkbox), nudge it to the correct text position.\n //\n // mouseup: use caretRangeFromPoint / caretPositionFromPoint so the cursor\n // lands WHERE the user actually clicked (middle, end of text…).\n // keyup : arrow-key navigation may land at <li>[0]; move to start-of-text.\n const fixChecklistCursor = (event) => {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n const r = sel.getRangeAt(0);\n if (!r.collapsed) return;\n const sc = r.startContainer;\n\n // Only act when cursor is at the <li> element node itself (not inside\n // a text node — the browser already placed it correctly in that case).\n if (sc.nodeType !== Node.ELEMENT_NODE) return;\n const scEl = /** @type {Element} */ (sc);\n const li = scEl.matches('.an-checklist li') ? scEl : null;\n if (!li) return;\n const cb = li.querySelector('input[type=\"checkbox\"]');\n if (!cb) return;\n\n // For mouse events: ask the browser where the pointer landed so the\n // cursor respects the actual click position inside the text.\n if (event?.type === 'mouseup') {\n let caret = null;\n if (document.caretRangeFromPoint) {\n caret = document.caretRangeFromPoint(event.clientX, event.clientY);\n } else if (document.caretPositionFromPoint) {\n const cp = document.caretPositionFromPoint(event.clientX, event.clientY);\n if (cp) {\n caret = document.createRange();\n caret.setStart(cp.offsetNode, cp.offset);\n }\n }\n // If the caret from point landed inside a text node of this li, use it\n if (caret && editable.contains(caret.startContainer) &&\n caret.startContainer !== li) {\n caret.collapse(true);\n sel.removeAllRanges();\n sel.addRange(caret);\n return;\n }\n }\n\n // Fallback (keyboard nav, or caretRangeFromPoint not available / landed\n // at li again): prefer the first text node after the checkbox so the\n // cursor renders at the padding-left edge (after the visual checkbox)\n // rather than at element-level where the browser may place it at x=0.\n const nr = document.createRange();\n let anchorNode = null;\n for (const child of li.childNodes) {\n if (child !== cb && child.nodeType === Node.TEXT_NODE) {\n anchorNode = child;\n break;\n }\n }\n if (anchorNode) {\n nr.setStart(anchorNode, 0);\n } else {\n nr.setStartAfter(cb);\n }\n nr.collapse(true);\n sel.removeAllRanges();\n sel.addRange(nr);\n };\n\n const isReadOnly = () => this.context.layoutInfo.container.classList.contains('an-disabled');\n\n this._disposers.push(\n on(editable, 'keydown', onKeydown),\n on(editable, 'beforeinput', onBeforeInput),\n on(editable, 'input', onInput),\n on(document, 'selectionchange', onSelChange),\n on(editable, 'click', onCheckboxClick),\n on(editable, 'mouseup', fixChecklistCursor),\n on(editable, 'keyup', fixChecklistCursor),\n // Block drag-out and external drops in read-only mode.\n // D-1: Also block dragging of iframes and .an-video-wrapper elements in\n // edit mode — a user can inadvertently drag the iframe out of its wrapper\n // (making it playable/removable from contenteditable protection) by holding\n // the mouse and moving outside the wrapper before releasing.\n on(editable, 'dragstart', (e) => {\n if (isReadOnly()) { e.preventDefault(); return; }\n const target = /** @type {Element} */ (e.target);\n if (target && (target.nodeName === 'IFRAME' ||\n target.closest('.an-video-wrapper'))) {\n e.preventDefault();\n }\n }),\n on(editable, 'drop', (e) => { if (isReadOnly()) e.preventDefault(); }),\n );\n\n // B-V: Re-apply superscript / subscript after IME composition ends.\n // Vietnamese and other IME-based inputs fire compositionstart/end around\n // the inserted characters. During composition the browser may place the\n // provisional text outside the current <sup>/<sub> element. When\n // compositionend fires we detect whether the cursor escaped the sup/sub\n // context and re-apply the command so the composed character stays inside.\n /** @type {string|null} 'superscript' | 'subscript' | null */\n let _compositionSupSub = null;\n const onCompositionStart = () => {\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) { _compositionSupSub = null; return; }\n let node = sel.getRangeAt(0).startContainer;\n if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;\n if (node) {\n const el = /** @type {Element} */ (node);\n if (el.closest('sup')) _compositionSupSub = 'superscript';\n else if (el.closest('sub')) _compositionSupSub = 'subscript';\n else _compositionSupSub = null;\n }\n };\n const onCompositionEnd = () => {\n const tag = _compositionSupSub;\n _compositionSupSub = null;\n if (!tag) return;\n const sel = globalThis.getSelection();\n if (!sel?.rangeCount) return;\n let node = sel.getRangeAt(0).startContainer;\n if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;\n const el = /** @type {Element} */ (node);\n const inContext = tag === 'superscript' ? el?.closest('sup') : el?.closest('sub');\n if (!inContext) {\n // The composed character escaped the sup/sub — re-apply the format.\n document.execCommand(tag);\n }\n };\n this._disposers.push(\n on(editable, 'compositionstart', onCompositionStart),\n on(editable, 'compositionend', onCompositionEnd),\n );\n }\n\n _onKeydown(event) {\n const editable = this.context.layoutInfo.editable;\n\n // Let Typing module handle special keys (Tab, Enter etc.)\n if (handleKeydown(event, editable, this.options)) return;\n\n // Built-in shortcuts\n if (isModifier(event, 'z') && !event.shiftKey) {\n event.preventDefault();\n this.undo();\n return;\n }\n if ((isModifier(event, 'z') && event.shiftKey) || isModifier(event, 'y')) {\n event.preventDefault();\n this.redo();\n return;\n }\n if (isModifier(event, 'b')) { event.preventDefault(); this.bold(); return; }\n if (isModifier(event, 'i')) { event.preventDefault(); this.italic(); return; }\n if (isModifier(event, 'u')) { event.preventDefault(); this.underline(); return; }\n if (isModifier(event, 'k')) { event.preventDefault(); this.context.invoke('linkDialog.show'); return; }\n\n // Ctrl+Shift+V — paste as plain text (signals Clipboard module)\n if (isModifier(event, 'v') && event.shiftKey) {\n this.context.invoke('clipboard.setForcePlain', true);\n return; // let the native paste event fire\n }\n\n // Show keyboard shortcuts dialog: Ctrl+Shift+/\n if (event.key === '/' && event.shiftKey && event.ctrlKey && !event.metaKey) {\n event.preventDefault();\n this.context.invoke('shortcutsDialog.show');\n return;\n }\n // Find: Ctrl+F\n if (isModifier(event, 'f')) {\n event.preventDefault();\n this.context.invoke('findReplace.show', 'find');\n return;\n }\n // Ctrl+H — Find & Replace\n if (isModifier(event, 'h')) {\n event.preventDefault();\n this.context.invoke('findReplace.show', 'replace');\n }\n // Ctrl+` — Inline Code\n if (isModifier(event, '`')) {\n event.preventDefault();\n this.inlineCode();\n }\n }\n\n // ---------------------------------------------------------------------------\n // Limit enforcement\n // ---------------------------------------------------------------------------\n\n /**\n * Called from beforeinput to block typing when char/word limits are reached.\n * Deletions and non-typing input types are always allowed.\n * @param {InputEvent} event\n */\n _enforceLimit(event) {\n const maxChars = this.options.maxChars || 0;\n const maxWords = this.options.maxWords || 0;\n if (!maxChars && !maxWords) return;\n // Only editors with a limit pay for a counter of their own.\n this._limitCounter ??= new TextCounter();\n\n const type = event.inputType || '';\n // Allow deletions, undo, redo and non-insert operations\n if (type.startsWith('delete') || type === 'historyUndo' || type === 'historyRedo') return;\n // Allow paste/drop — handled after the fact by Clipboard\n if (type === 'insertFromPaste' || type === 'insertFromDrop') return;\n // Only enforce for keyboard/IME/composition insertions\n if (!type.startsWith('insert')) return;\n\n // Counted the same way the statusbar counts, so the number that stops the\n // user is the number they can see. The old split on whitespace read an\n // entire Japanese or Chinese document as one word, which left maxWords\n // unenforceable in those scripts; it also read `innerText`, forcing a\n // layout pass on every keystroke.\n const { words, chars } = this._limitCounter.counts(this.context.layoutInfo.editable);\n\n if (maxChars && chars >= maxChars) {\n event.preventDefault();\n if (typeof this.options.onCharLimitReached === 'function') {\n this.options.onCharLimitReached(this.context);\n }\n return;\n }\n\n // Word limit: block space / newline insertion when already at the limit\n if (maxWords && (event.data === ' ' || type === 'insertParagraph' || type === 'insertLineBreak')) {\n if (words >= maxWords) {\n event.preventDefault();\n if (typeof this.options.onWordLimitReached === 'function') {\n this.options.onWordLimitReached(this.context);\n }\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Post-command hook — records undo, fires change event\n // ---------------------------------------------------------------------------\n\n afterCommand() {\n // C4: Remove figure.an-figure elements whose <img> has been deleted so\n // orphaned figcaptions do not accumulate in the DOM.\n this._cleanOrphanedFigures();\n // Ensure the editable always ends with a paragraph so the user can click\n // and type after block elements that trap the cursor (pre, table, etc.).\n this._ensureTrailingParagraph();\n // Immediate: keep toolbar and statusbar in sync on every mutation.\n this.context.invoke('toolbar.refresh');\n this.context.invoke('statusbar.update');\n // Debounced: recording an undo snapshot and firing the change event require\n // a full innerHTML serialization. Batching rapid keystrokes prevents the\n // browser from re-serializing large content (e.g. embedded images) on every\n // single key press.\n this._scheduleSnapshot();\n }\n\n /**\n * Schedules a debounced undo snapshot + change event.\n * Resets the timer on each call so rapid typing produces one snapshot.\n */\n _scheduleSnapshot() {\n clearTimeout(this._snapshotTimer);\n this._snapshotTimer = setTimeout(() => {\n this._snapshotTimer = null;\n if (this._history) this._history.recordUndo();\n this.context.triggerEvent('change', this.getHTML());\n }, 400);\n }\n\n /**\n * C4: Removes figure.an-figure elements that no longer contain an <img>.\n * This happens when a user selects only the image (not the whole figure)\n * and deletes or replaces it, leaving a dangling figcaption.\n */\n _cleanOrphanedFigures() {\n const editable = this.context.layoutInfo.editable;\n editable.querySelectorAll('figure.an-figure').forEach((fig) => {\n if (!fig.querySelector('img')) {\n fig.remove();\n }\n });\n }\n\n /**\n * Ensures the editable always ends with a plain paragraph so the cursor can\n * be placed after block elements that do not naturally allow it\n * (pre, blockquote, table, figure, ul, ol, hr).\n * Without this, clicking below the last such element does nothing.\n */\n _ensureTrailingParagraph() {\n const editable = this.context.layoutInfo.editable;\n if (!editable) return;\n const last = editable.lastElementChild;\n if (!last) return;\n if (TRAPPING_TAGS.has(last.nodeName)) {\n const p = document.createElement('p');\n p.innerHTML = '<br>';\n editable.appendChild(p);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Focus management\n // ---------------------------------------------------------------------------\n\n focus() {\n const editable = this.context.layoutInfo.editable;\n editable.focus();\n }\n\n // ---------------------------------------------------------------------------\n // Content API\n // ---------------------------------------------------------------------------\n\n /**\n * Returns the editor HTML content.\n * @returns {string}\n */\n getHTML() {\n // Strip zero-width spaces inserted after icons to allow caret placement.\n const raw = this.context.layoutInfo.editable.innerHTML.replaceAll('\\u200B', '');\n // Replace any blob: URLs (lightweight DOM references to pasted/dropped images)\n // with their original data URLs so the returned HTML is fully self-contained.\n return this.context.invoke('clipboard.resolveImages', raw) ?? raw;\n }\n\n /**\n * Sets the editor HTML content.\n * @param {string} html - HTML string (will be sanitised)\n */\n setHTML(html) {\n // Adopt the sanitiser's nodes rather than its string: serialising them and\n // letting innerHTML parse them again was ~14 ms of a ~45 ms setHTML on a\n // 217 KiB document, and the re-parse is the step mXSS exploits.\n const body = sanitiseToBody(html, { allowIframes: true });\n this.context.layoutInfo.editable.replaceChildren(...body.childNodes);\n if (this._history) this._history.reset();\n this.afterCommand();\n }\n\n /**\n * Returns the editor plain text content.\n * @returns {string}\n */\n getText() {\n return this.context.layoutInfo.editable.innerText || '';\n }\n\n /**\n * Sets the editor content as plain text.\n * @param {string} text\n */\n setText(text) {\n this.context.layoutInfo.editable.textContent = text;\n if (this._history) this._history.reset();\n this.afterCommand();\n }\n\n /**\n * Clears the editor content.\n */\n clear() {\n this.setHTML('');\n }\n\n /**\n * Resets the undo/redo history stack.\n */\n clearHistory() {\n if (this._history) this._history.reset();\n }\n\n /**\n * Returns true when the editor has no meaningful content.\n * @returns {boolean}\n */\n isEmpty() {\n const text = (this.context.layoutInfo.editable.innerText || '')\n .trim()\n .replaceAll('\\u00a0', '');\n const hasMedia = !!this.context.layoutInfo.editable.querySelector('img, video, iframe, table');\n return !text && !hasMedia;\n }\n\n /**\n * Inserts HTML at the current cursor position.\n * @param {string} html\n */\n insertHTML(html) {\n if (!html) return;\n Style.execCommand('insertHTML', sanitiseHTML(html));\n this.afterCommand();\n }\n\n /**\n * Inserts plain text at the current cursor position.\n * @param {string} text\n */\n insertText(text) {\n if (!text) return;\n Style.execCommand('insertText', text);\n this.afterCommand();\n }\n\n /**\n * Sets editor content from a Markdown string.\n * @param {string} md\n */\n setMarkdown(md) {\n this.setHTML(markdownToHTML(md || ''));\n }\n\n /**\n * Returns the editor content as Markdown.\n * @returns {string}\n */\n getMarkdown() {\n return htmlToMarkdown(this.getHTML());\n }\n\n // ---------------------------------------------------------------------------\n // Undo / redo\n // ---------------------------------------------------------------------------\n\n undo() {\n if (this._history) {\n this._flushPendingSnapshot();\n this._history.undo();\n this.context.invoke('toolbar.refresh');\n this.context.invoke('statusbar.update');\n this.context.triggerEvent('change', this.getHTML());\n }\n }\n\n redo() {\n if (this._history) {\n this._flushPendingSnapshot();\n this._history.redo();\n this.context.invoke('toolbar.refresh');\n this.context.invoke('statusbar.update');\n this.context.triggerEvent('change', this.getHTML());\n }\n }\n\n /** Records a debounced change before an immediate undo/redo command. */\n _flushPendingSnapshot() {\n if (this._snapshotTimer === null) return;\n clearTimeout(this._snapshotTimer);\n this._snapshotTimer = null;\n this._history?.recordUndo();\n }\n\n canUndo() {\n return this._history ? this._history.canUndo() : false;\n }\n\n canRedo() {\n return this._history ? this._history.canRedo() : false;\n }\n\n getUndoCount() {\n return this._history ? this._history.getUndoCount() : 0;\n }\n\n getRedoCount() {\n return this._history ? this._history.getRedoCount() : 0;\n }\n\n getSelectionBookmark() {\n return this._history?._serializeSelection() ?? null;\n }\n\n restoreSelectionBookmark(bookmark) {\n if (!bookmark || !this._history) return false;\n this._history._restoreSelection(bookmark);\n return true;\n }\n\n // ---------------------------------------------------------------------------\n // Style commands (delegated to Style module)\n // ---------------------------------------------------------------------------\n\n bold() { Style.bold(); this.afterCommand(); }\n italic() { Style.italic(); this.afterCommand(); }\n underline() { Style.underline(); this.afterCommand(); }\n strikethrough() { Style.strikethrough(); this.afterCommand(); }\n superscript() { Style.superscript(); this.afterCommand(); }\n subscript() { Style.subscript(); this.afterCommand(); }\n justifyLeft() { Style.justifyLeft(); this.afterCommand(); }\n justifyCenter() { Style.justifyCenter(); this.afterCommand(); }\n justifyRight() { Style.justifyRight(); this.afterCommand(); }\n justifyFull() { Style.justifyFull(); this.afterCommand(); }\n indent() { Style.indent(); this.afterCommand(); }\n outdent() { Style.outdent(); this.afterCommand(); }\n insertUL() { Style.insertUnorderedList(); this.afterCommand(); }\n insertOL() { Style.insertOrderedList(); this.afterCommand(); }\n inlineCode() { Style.toggleInlineCode(this.context.layoutInfo.editable); this.afterCommand(); }\n toggleChecklist() { Style.toggleChecklist(); this.afterCommand(); }\n print() { this.context.print(); }\n\n /**\n * @param {string} tagName - e.g. 'h1', 'p', 'blockquote', 'pre'\n */\n formatBlock(tagName) {\n Style.formatBlock(tagName);\n\n // Auto-detect the programming language when the user formats a code block.\n // Only runs when converting TO <pre> and the block has no language yet.\n if (tagName === 'pre') {\n const sel = globalThis.getSelection();\n if (sel?.rangeCount > 0) {\n const container = sel.getRangeAt(0).commonAncestorContainer;\n const pre = /** @type {Element|null} */ (\n container.nodeType === 1\n ? /** @type {Element} */ (container).closest('pre')\n : (/** @type {Element|null} */ (container.parentElement))?.closest('pre')\n );\n if (pre && !/** @type {HTMLElement} */ (pre).dataset.language) {\n const code = pre.textContent || '';\n const lang = detectLang(code);\n if (lang) {\n this.context.invoke('codeTooltip.applyLanguage', pre, lang);\n return; // applyLanguage already calls afterCommand internally\n }\n }\n }\n }\n\n this.afterCommand();\n }\n\n /**\n * @param {string} color\n */\n foreColor(color) { Style.foreColor(color); this.afterCommand(); }\n\n /**\n * @param {string} color\n */\n backColor(color) { Style.backColor(color); this.afterCommand(); }\n\n /**\n * @param {string} name\n */\n fontName(name) { Style.fontName(name); this.afterCommand(); }\n\n /**\n * @param {string} size - e.g. '14px'\n */\n fontSize(size) { Style.fontSize(size, this.context.layoutInfo.editable); this.afterCommand(); }\n\n // ---------------------------------------------------------------------------\n // Insert helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Inserts a horizontal rule at the cursor.\n */\n insertHr() {\n Style.execCommand('insertHorizontalRule');\n this.afterCommand();\n }\n\n /**\n * Creates a link at the current selection.\n * @param {string} url\n * @param {string} text\n * @param {boolean} [openInNewTab=false]\n */\n insertLink(url, text, openInNewTab = false) {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const safeUrl = sanitiseUrl(url);\n if (!safeUrl) return;\n\n const hasText = sel.toString().trim().length > 0;\n if (hasText) {\n Style.execCommand('createLink', safeUrl);\n if (openInNewTab) {\n const link = this._getClosestAnchor();\n if (link) {\n /** @type {Element} */ (link).setAttribute('target', '_blank');\n /** @type {Element} */ (link).setAttribute('rel', 'noopener noreferrer');\n }\n }\n } else {\n const displayText = this._escapeAttr(text || safeUrl);\n Style.execCommand('insertHTML', `<a href=\"${this._escapeAttr(safeUrl)}\"${openInNewTab ? ' target=\"_blank\" rel=\"noopener noreferrer\"' : ''}>${displayText}</a>`);\n }\n this.afterCommand();\n }\n\n /**\n * Removes the link from the selected anchor.\n */\n unlink() {\n Style.execCommand('unlink');\n this.afterCommand();\n }\n\n /**\n * Inserts an image.\n * @param {string} src - URL or data-URI\n * @param {string} [alt]\n */\n insertImage(src, alt = '', align = '') {\n const safeSrc = sanitiseUrl(src, { allowData: true });\n if (!safeSrc) return;\n const styleMap = {\n left: 'float:left;margin:0 1em 1em 0',\n center: 'display:block;margin:0 auto',\n right: 'float:right;margin:0 0 1em 1em',\n };\n const style = styleMap[align] || '';\n const styleAttr = style ? ` style=\"${style}\"` : '';\n Style.execCommand('insertHTML', `<img src=\"${this._escapeAttr(safeSrc)}\" alt=\"${this._escapeAttr(alt)}\" class=\"an-image\"${styleAttr}>`);\n this.afterCommand();\n }\n\n /**\n * Inserts a video embed (iframe or <video> element).\n * The html string is already validated/built by VideoDialog.\n * @param {string} html\n */\n insertVideo(html) {\n if (!html) return;\n Style.execCommand('insertHTML', html);\n this.afterCommand();\n }\n\n /**\n * Inserts a table.\n * @param {number} cols\n * @param {number} rows\n */\n insertTable(cols, rows) {\n insertTable(cols, rows, { headerRow: this.context.options.tableHeaderRow });\n this.afterCommand();\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n _getClosestAnchor() {\n const sel = globalThis.getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n let node = sel.getRangeAt(0).startContainer;\n while (node) {\n if (node.nodeName === 'A') return node;\n node = node.parentNode;\n }\n return null;\n }\n\n /**\n * Escapes a string for safe use inside an HTML attribute value.\n * @param {string} str\n * @returns {string}\n */\n _escapeAttr(str) {\n return String(str ?? '')\n .replaceAll('&', '&')\n .replaceAll('\"', '"')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n }\n\n // --- delegated to shared sanitise.js ---\n}\n","/**\n * Toolbar.js - Builds and manages the editor toolbar UI\n * Inspired by Summernote's Toolbar module — rewritten without jQuery\n */\n\nimport { createElement, on } from '../core/dom.js';\nimport { getButton } from './Buttons.js';\n\n/** Resolve a toolbar item: string → registry lookup, object → pass-through. */\nconst _resolveBtn = (item) => (typeof item === 'string') ? getButton(item) : item;\n\n// Module-level cache for FontAwesome detection.\n// Evaluated once per page load so all Toolbar instances on the same page agree\n// on whether the HOST PAGE included FA — regardless of whether IconDialog later\n// auto-injects its own FA <link> for the icon-picker glyph rendering.\nlet _faPageLevelReady = null;\n\n// ---------------------------------------------------------------------------\n// Module-level icon lookup tables — built once, shared across all instances.\n// Previously these were re-created inside _createButton() on every button\n// render, producing O(buttons × map-size) allocations per toolbar init.\n// ---------------------------------------------------------------------------\nconst _S = 'stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';\nconst _svgWrap = (paths) =>\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" ${_S} style=\"display:block\">${paths}</svg>`;\n\nconst _SVG_MAP = new Map([\n // Format\n ['bold', _svgWrap('<path d=\"M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\"/><path d=\"M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\"/>')],\n ['italic', _svgWrap('<line x1=\"19\" y1=\"4\" x2=\"10\" y2=\"4\"/><line x1=\"14\" y1=\"20\" x2=\"5\" y2=\"20\"/><line x1=\"15\" y1=\"4\" x2=\"9\" y2=\"20\"/>')],\n ['underline', _svgWrap('<path d=\"M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3\"/><line x1=\"4\" y1=\"21\" x2=\"20\" y2=\"21\"/>')],\n ['strikethrough', _svgWrap('<path d=\"M17.3 12H6.7\"/><path d=\"M10 6.5C10 5.1 11.1 4 12.5 4c1.4 0 2.5 1.1 2.5 2.5 0 .8-.4 1.5-1 2\"/><path d=\"M14 17.5C14 19 12.9 20 11.5 20 10.1 20 9 18.9 9 17.5c0-.8.4-1.5 1-2\"/>')],\n ['superscript', _svgWrap('<path d=\"m4 19 8-8\"/><path d=\"m12 19-8-8\"/><path d=\"M20 12h-4c0-1.5.44-2 1.5-2.5S20 8.33 20 7.25C20 6 19 5 17.5 5S15 6 15 7\"/>')],\n ['subscript', _svgWrap('<path d=\"m4 5 8 8\"/><path d=\"m12 5-8 8\"/><path d=\"M20 21h-4c0-1.5.44-2 1.5-2.5S20 17.33 20 16.25C20 15 19 14 17.5 14S15 15 15 16\"/>')],\n // Alignment\n ['align-left', _svgWrap('<line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"/><line x1=\"15\" y1=\"12\" x2=\"3\" y2=\"12\"/><line x1=\"17\" y1=\"18\" x2=\"3\" y2=\"18\"/>')],\n ['align-center', _svgWrap('<line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"/><line x1=\"18\" y1=\"12\" x2=\"6\" y2=\"12\"/><line x1=\"21\" y1=\"18\" x2=\"3\" y2=\"18\"/>')],\n ['align-right', _svgWrap('<line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"/><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"/><line x1=\"21\" y1=\"18\" x2=\"7\" y2=\"18\"/>')],\n ['align-justify', _svgWrap('<line x1=\"21\" y1=\"6\" x2=\"3\" y2=\"6\"/><line x1=\"21\" y1=\"12\" x2=\"3\" y2=\"12\"/><line x1=\"21\" y1=\"18\" x2=\"3\" y2=\"18\"/>')],\n // Lists\n ['list-ul', _svgWrap('<line x1=\"9\" y1=\"6\" x2=\"20\" y2=\"6\"/><line x1=\"9\" y1=\"12\" x2=\"20\" y2=\"12\"/><line x1=\"9\" y1=\"18\" x2=\"20\" y2=\"18\"/><circle cx=\"4\" cy=\"6\" r=\"1\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"4\" cy=\"12\" r=\"1\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"4\" cy=\"18\" r=\"1\" fill=\"currentColor\" stroke=\"none\"/>')],\n ['list-ol', _svgWrap('<line x1=\"10\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"10\" y1=\"12\" x2=\"21\" y2=\"12\"/><line x1=\"10\" y1=\"18\" x2=\"21\" y2=\"18\"/><path d=\"M4 6h1V3\"/><path d=\"M4 10h2l-2 2h2\"/><path d=\"M4 16.5A1.5 1.5 0 0 1 5.5 15a1.5 1.5 0 0 1 0 3H4\"/>')],\n ['indent', _svgWrap('<polyline points=\"3 8 7 12 3 16\"/><line x1=\"21\" y1=\"12\" x2=\"11\" y2=\"12\"/><line x1=\"21\" y1=\"6\" x2=\"11\" y2=\"6\"/><line x1=\"21\" y1=\"18\" x2=\"11\" y2=\"18\"/>')],\n ['outdent', _svgWrap('<polyline points=\"7 8 3 12 7 16\"/><line x1=\"21\" y1=\"12\" x2=\"11\" y2=\"12\"/><line x1=\"21\" y1=\"6\" x2=\"11\" y2=\"6\"/><line x1=\"21\" y1=\"18\" x2=\"11\" y2=\"18\"/>')],\n // History\n ['undo', _svgWrap('<path d=\"M3 7v6h6\"/><path d=\"M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13\"/>')],\n ['redo', _svgWrap('<path d=\"M21 7v6h-6\"/><path d=\"M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13\"/>')],\n // Insert\n ['minus', _svgWrap('<line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>')],\n ['link', _svgWrap('<path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/>')],\n ['image', _svgWrap('<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/>')],\n ['video', _svgWrap('<polygon points=\"23 7 16 12 23 17 23 7\"/><rect x=\"1\" y=\"5\" width=\"15\" height=\"14\" rx=\"2\"/>')],\n ['table', _svgWrap('<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/><line x1=\"3\" y1=\"15\" x2=\"21\" y2=\"15\"/><line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"21\"/><line x1=\"15\" y1=\"3\" x2=\"15\" y2=\"21\"/>')],\n ['emoji', _svgWrap('<circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M8.5 14.5s1.5 2.5 3.5 2.5 3.5-2.5 3.5-2.5\"/><circle cx=\"9\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" stroke=\"none\"/><circle cx=\"15\" cy=\"9\" r=\"1.5\" fill=\"currentColor\" stroke=\"none\"/>')],\n ['icon', _svgWrap('<circle cx=\"8\" cy=\"8\" r=\"3\"/><circle cx=\"16\" cy=\"8\" r=\"3\"/><rect x=\"5\" y=\"13\" width=\"6\" height=\"6\" rx=\"1\"/><rect x=\"13\" y=\"13\" width=\"6\" height=\"6\" rx=\"1\"/>')],\n // View\n ['code', _svgWrap('<polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/>')],\n ['expand', _svgWrap('<polyline points=\"15 3 21 3 21 9\"/><polyline points=\"9 21 3 21 3 15\"/><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"/><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"/>')],\n // Color pickers\n ['foreColor', _svgWrap('<path d=\"M4 20L12 4L20 20\"/><line x1=\"7.5\" y1=\"14\" x2=\"16.5\" y2=\"14\"/>')],\n ['backColor', _svgWrap('<path d=\"M3 21v-4l9-9 4 4-9 9z\"/><path d=\"M12 8l4 4\"/>')],\n ['keyboard', _svgWrap('<rect x=\"2\" y=\"6\" width=\"20\" height=\"12\" rx=\"2\"/><line x1=\"6\" y1=\"10\" x2=\"6\" y2=\"10\" stroke-width=\"2.5\"/><line x1=\"10\" y1=\"10\" x2=\"10\" y2=\"10\" stroke-width=\"2.5\"/><line x1=\"14\" y1=\"10\" x2=\"14\" y2=\"10\" stroke-width=\"2.5\"/><line x1=\"18\" y1=\"10\" x2=\"18\" y2=\"10\" stroke-width=\"2.5\"/><line x1=\"8\" y1=\"14\" x2=\"16\" y2=\"14\" stroke-width=\"2\"/>')],\n ['caption', _svgWrap('<rect x=\"3\" y=\"3\" width=\"18\" height=\"11\" rx=\"2\"/><line x1=\"6\" y1=\"18\" x2=\"18\" y2=\"18\"/><line x1=\"9\" y1=\"21\" x2=\"15\" y2=\"21\"/>')],\n ['remove-format', _svgWrap('<path d=\"m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21\"/><path d=\"M22 21H7\"/><path d=\"m5 11 9 9\"/>')],\n ['direction', _svgWrap('<path d=\"M12 20V4\"/><path d=\"m9 7-3 3 3 3\"/><path d=\"M4 10h8\"/><path d=\"m15 7 3 3-3 3\"/><path d=\"M20 10h-8\"/>')],\n ['search', _svgWrap('<circle cx=\"11\" cy=\"11\" r=\"7\"/><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"/>')],\n ['find-replace', _svgWrap('<circle cx=\"10\" cy=\"10\" r=\"6\"/><line x1=\"18\" y1=\"18\" x2=\"14.35\" y2=\"14.35\"/><path d=\"M16 19h6\"/><path d=\"M19 16v6\"/>')],\n ['inline-code', _svgWrap('<path d=\"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1\"/><path d=\"M16 3h1a2 2 0 0 1 2 2v5c0 1.1.9 2 2 2a2 2 0 0 1-2 2v5a2 2 0 0 1-2 2h-1\"/>')],\n ['checklist', _svgWrap('<rect x=\"3\" y=\"4\" width=\"5\" height=\"5\" rx=\"1\"/><path d=\"m4 6.5 1 1 2-2\"/><rect x=\"3\" y=\"13\" width=\"5\" height=\"5\" rx=\"1\"/><line x1=\"10\" y1=\"6.5\" x2=\"21\" y2=\"6.5\"/><line x1=\"10\" y1=\"15.5\" x2=\"21\" y2=\"15.5\"/>')],\n ['print', _svgWrap('<path d=\"M6 9V2h12v7\"/><path d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2\"/><rect x=\"6\" y=\"14\" width=\"12\" height=\"8\"/>')],\n]);\n\nconst _FA_MAP = new Map([\n ['bold', 'fa-bold'],\n ['italic', 'fa-italic'],\n ['underline', 'fa-underline'],\n ['strikethrough', 'fa-strikethrough'],\n ['superscript', 'fa-superscript'],\n ['subscript', 'fa-subscript'],\n ['align-left', 'fa-align-left'],\n ['align-center', 'fa-align-center'],\n ['align-right', 'fa-align-right'],\n ['align-justify', 'fa-align-justify'],\n ['list-ul', 'fa-list-ul'],\n ['list-ol', 'fa-list-ol'],\n ['indent', 'fa-indent'],\n ['outdent', 'fa-outdent'],\n ['undo', 'fa-rotate-left'],\n ['redo', 'fa-rotate-right'],\n ['minus', 'fa-minus'],\n ['link', 'fa-link'],\n ['image', 'fa-image'],\n ['code', 'fa-code'],\n ['expand', 'fa-expand'],\n ['emoji', 'fa-face-smile'],\n ['icon', 'fa-icons'],\n ['foreColor', 'fa-font'],\n ['backColor', 'fa-highlighter'],\n ['keyboard', 'fa-keyboard'],\n ['remove-format', 'fa-remove-format'],\n ['direction', 'fa-arrow-right-arrow-left'],\n ['search', 'fa-magnifying-glass'],\n ['find-replace', 'fa-magnifying-glass-plus'],\n ['inline-code', 'fa-code'],\n ['checklist', 'fa-list-check'],\n ['print', 'fa-print'],\n]);\n\nexport class Toolbar {\n /**\n * @param {import('../Context.js').Context} context\n */\n constructor(context) {\n this.context = context;\n this.options = context.options;\n /** @type {HTMLElement|null} */\n this.el = null;\n /** @type {Array<() => void>} disposers */\n this._disposers = [];\n /** @type {Array<() => void>} closers for all open color picker popups */\n this._colorPickerClosers = [];\n /** @type {number|null} rAF handle for debounced refresh */\n this._refreshRaf = null;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n initialize() {\n this.el = createElement('div', {\n class: 'an-toolbar',\n role: 'toolbar',\n 'aria-orientation': 'horizontal',\n // Matches the hardcoded English label renderer.js gives the editable.\n 'aria-label': 'Editor toolbar',\n });\n // Detect FontAwesome once at toolbar build time to avoid re-querying the DOM\n // for every button rendered.\n this._faReady = this._detectFontAwesome();\n this._buildButtons();\n this._initRovingFocus();\n this._btnMap = new Map(\n (this.options.toolbar || []).flat()\n .map(_resolveBtn).filter(Boolean).map((b) => [b.name, b]),\n );\n return this;\n }\n\n destroy() {\n if (this._refreshRaf) cancelAnimationFrame(this._refreshRaf);\n this._refreshRaf = null;\n this._disposers.forEach((d) => d());\n this._disposers = [];\n if (this.el?.parentNode) {\n this.el.remove();\n }\n this.el = null;\n }\n\n // ---------------------------------------------------------------------------\n // Build\n // ---------------------------------------------------------------------------\n\n _buildButtons() {\n const toolbar = this.options.toolbar || [];\n // Build into a DocumentFragment so all groups are appended in a single\n // DOM operation, avoiding one reflow per group.\n const fragment = document.createDocumentFragment();\n toolbar.forEach((group) => {\n const groupEl = createElement('div', { class: 'an-btn-group' });\n group.forEach((item) => {\n const btnDef = _resolveBtn(item);\n if (!btnDef) {\n console.warn(`[AutumnNote] Toolbar: button \"${item}\" not found in registry. Skipped.`);\n return;\n }\n let el;\n if (btnDef.type === 'select') el = this._createSelect(btnDef);\n else if (btnDef.type === 'grid') el = this._createGridPicker(btnDef);\n else if (btnDef.type === 'colorpicker') el = this._createColorPicker(btnDef);\n else el = this._createButton(btnDef);\n groupEl.appendChild(el);\n });\n fragment.appendChild(groupEl);\n });\n this.el.appendChild(fragment);\n }\n\n /**\n * Creates a table-grid picker button with a hoverable row/col selector popup.\n * @param {import('./Buttons.js').ButtonDef} def\n * @returns {HTMLDivElement}\n */\n _createGridPicker(def) {\n const ROWS = 10;\n const COLS = 10;\n\n const wrap = createElement('div', { class: 'an-table-picker-wrap' });\n\n const useBootstrap = !!this.options.useBootstrap;\n const baseClass = useBootstrap\n ? (this.options.toolbarButtonClass || 'btn btn-sm btn-light')\n : 'an-btn';\n const btn = createElement('button', {\n type: 'button',\n class: baseClass,\n title: this.context.locale.toolbar[def.name] || def.tooltip || '',\n 'data-btn': def.name,\n 'aria-label': this.context.locale.toolbar[def.name] || def.tooltip || def.name,\n 'aria-haspopup': 'true',\n 'aria-expanded': 'false',\n });\n\n // Set icon — inline SVG (table) with optional FontAwesome fallback\n if (this._faReady) {\n const faPrefix = this.options.fontAwesomeClass || 'fas';\n btn.innerHTML = `<i class=\"${faPrefix} fa-table\" aria-hidden=\"true\"></i>`;\n } else {\n const S = 'stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';\n btn.innerHTML = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" ${S} style=\"display:block\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/><line x1=\"3\" y1=\"15\" x2=\"21\" y2=\"15\"/><line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"21\"/><line x1=\"15\" y1=\"3\" x2=\"15\" y2=\"21\"/></svg>`;\n }\n\n // Popup\n const popup = createElement('div', {\n class: 'an-table-picker-popup',\n role: 'dialog',\n 'aria-label': 'Select table size',\n });\n const grid = createElement('div', { class: 'an-table-grid' });\n const label = createElement('div', { class: 'an-table-label' });\n label.textContent = this.context.locale.toolbar.insertTableLabel || 'Insert Table';\n\n const cells = [];\n for (let r = 1; r <= ROWS; r++) {\n for (let c = 1; c <= COLS; c++) {\n const cell = createElement('div', {\n class: 'an-table-cell',\n 'data-row': String(r),\n 'data-col': String(c),\n });\n cells.push(cell);\n grid.appendChild(cell);\n }\n }\n\n popup.appendChild(grid);\n popup.appendChild(label);\n\n let isOpen = false;\n\n const setHighlight = (rows, cols) => {\n cells.forEach((cell) => {\n const r = +cell.dataset.row;\n const c = +cell.dataset.col;\n cell.classList.toggle('active', r <= rows && c <= cols);\n });\n label.textContent = (rows && cols) ? `${rows} × ${cols}` : (this.context.locale.toolbar.insertTableLabel || 'Insert Table');\n };\n\n const openPopup = () => {\n isOpen = true;\n const rect = btn.getBoundingClientRect();\n\n // Measure popup dimensions while invisible so we can set the correct\n // position before the browser paints (matches the color-picker pattern).\n popup.style.visibility = 'hidden';\n popup.style.display = 'block';\n const pw = popup.offsetWidth;\n const ph = popup.offsetHeight;\n\n let left = rect.left;\n let top = rect.bottom + 4;\n if (left + pw > globalThis.innerWidth - 8) left = Math.max(8, globalThis.innerWidth - pw - 8);\n if (top + ph > globalThis.innerHeight - 8) top = rect.top - ph - 4;\n\n popup.style.left = `${left}px`;\n popup.style.top = `${top}px`;\n popup.style.visibility = '';\n btn.setAttribute('aria-expanded', 'true');\n };\n\n const closePopup = () => {\n isOpen = false;\n popup.style.display = 'none';\n btn.setAttribute('aria-expanded', 'false');\n setHighlight(0, 0);\n };\n\n const d1 = on(btn, 'click', (e) => {\n e.stopPropagation();\n if (isOpen) closePopup(); else openPopup();\n });\n\n const d2 = on(grid, 'mouseover', (e) => {\n const cell = /** @type {HTMLElement|null} */ (/** @type {Element} */ (e.target)?.closest('.an-table-cell'));\n if (!cell) return;\n setHighlight(+cell.dataset.row, +cell.dataset.col);\n });\n\n const d3 = on(grid, 'mouseleave', () => setHighlight(0, 0));\n\n const d4 = on(grid, 'click', (e) => {\n const cell = /** @type {HTMLElement|null} */ (/** @type {Element} */ (e.target)?.closest('.an-table-cell'));\n if (!cell) return;\n const rows = +cell.dataset.row;\n const cols = +cell.dataset.col;\n closePopup();\n this.context.invoke('editor.focus');\n def.action(this.context, rows, cols);\n });\n\n const d5 = on(document, 'click', () => { if (isOpen) closePopup(); });\n\n // Append popup to body so position:fixed is truly viewport-relative,\n // unaffected by any ancestor transform / filter (same pattern as color picker).\n this._disposers.push(d1, d2, d3, d4, d5, () => {\n if (popup.parentNode) popup.remove();\n });\n\n wrap.appendChild(btn);\n document.body.appendChild(popup);\n return /** @type {HTMLDivElement} */ (wrap);\n }\n\n /**\n * Creates a split color-picker widget:\n * [icon + strip | ▾] — left applies current color, right opens swatch popup.\n * @param {{ name: string, type: 'colorpicker', tooltip: string, defaultColor: string, action: Function }} def\n * @returns {HTMLDivElement}\n */\n _createColorPicker(def) {\n const PRESETS = [\n // Grayscale\n '#000000', '#434343', '#666666', '#999999', '#b7b7b7', '#cccccc', '#efefef', '#ffffff',\n // Saturated\n '#ff0000', '#ff9900', '#ffff00', '#00ff00', '#00ffff', '#4a86e8', '#9900ff', '#ff00ff',\n // Pastel\n '#f4cccc', '#fce5cd', '#fff2cc', '#d9ead3', '#d0e0e3', '#c9daf8', '#d9d2e9', '#ead1dc',\n ];\n\n let currentColor = def.defaultColor || '#000000';\n\n const wrap = createElement('div', { class: 'an-color-picker-wrap' });\n\n const useBootstrap = !!this.options.useBootstrap;\n const baseClass = useBootstrap ? (this.options.toolbarButtonClass || 'btn btn-sm btn-light') : 'an-btn';\n\n // ---- Apply button (icon + color strip) ----\n const applyBtn = createElement('button', {\n type: 'button',\n class: `${baseClass} an-color-btn`,\n title: this.context.locale.toolbar[def.name] || def.tooltip || '',\n 'data-btn': def.name,\n 'aria-label': this.context.locale.toolbar[def.name] || def.tooltip || def.name,\n });\n\n const S = 'stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';\n const iconSvg = def.name === 'foreColor'\n ? `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" ${S} style=\"display:block\"><path d=\"M4 20L12 4L20 20\"/><line x1=\"7.5\" y1=\"14\" x2=\"16.5\" y2=\"14\"/></svg>`\n : `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" ${S} style=\"display:block\"><path d=\"M3 21v-4l9-9 4 4-9 9z\"/><path d=\"M12 8l4 4\"/></svg>`;\n\n applyBtn.innerHTML = iconSvg;\n const strip = createElement('span', { class: 'an-color-strip' });\n strip.style.background = currentColor;\n applyBtn.appendChild(strip);\n\n // ---- Arrow button (open popup) ----\n const arrowBtn = createElement('button', {\n type: 'button',\n class: `${baseClass} an-color-arrow`,\n title: def.name === 'foreColor'\n ? (this.context.locale.toolbar.chooseTextColor || 'Choose text color')\n : (this.context.locale.toolbar.chooseHighlightColor || 'Choose highlight color'),\n 'aria-haspopup': 'true',\n 'aria-expanded': 'false',\n });\n arrowBtn.innerHTML = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"8\" height=\"8\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" style=\"display:block\"><path d=\"M7 10l5 5 5-5H7z\"/></svg>`;\n\n // ---- Popup ----\n const popup = createElement('div', { class: 'an-color-popup' });\n popup.style.display = 'none';\n\n const swatches = createElement('div', { class: 'an-color-swatches' });\n const userSwatches = Array.isArray(this.options.colorSwatches) ? this.options.colorSwatches : [];\n const allColors = [...new Set([...userSwatches, ...PRESETS])];\n allColors.forEach((color) => {\n const sw = createElement('div', { class: 'an-color-swatch', title: color, 'data-color': color });\n sw.style.background = color;\n swatches.appendChild(sw);\n });\n\n const customRow = createElement('div', { class: 'an-color-custom' });\n const colorInput = /** @type {HTMLInputElement} */ (createElement('input', { type: 'color', value: currentColor, title: this.context.locale.toolbar.customColor || 'Custom color' }));\n const customLabel = createElement('span', {}, [this.context.locale.toolbar.customColor || 'Custom color']);\n customRow.appendChild(colorInput);\n customRow.appendChild(customLabel);\n\n popup.appendChild(swatches);\n popup.appendChild(customRow);\n\n // ---- State ----\n let isOpen = false;\n /** @type {Range|null} saved selection range before popup opens */\n let savedRange = null;\n\n const saveSelection = () => {\n const sel = globalThis.getSelection();\n savedRange = sel?.rangeCount ? sel.getRangeAt(0).cloneRange() : null;\n };\n\n const restoreSelection = () => {\n if (!savedRange) return;\n try {\n const sel = globalThis.getSelection();\n if (!sel) return;\n sel.removeAllRanges();\n sel.addRange(savedRange);\n } catch (_) {\n void _; // range may be stale if DOM changed while popup was open\n }\n };\n\n const openPopup = () => {\n // Close any other open color picker before opening this one\n this._colorPickerClosers.forEach((fn) => { if (fn !== closePopup) fn(); });\n saveSelection();\n isOpen = true;\n // Use fixed positioning so the popup escapes any overflow-clipping ancestor\n // (notably toolbar scroll mode, where overflow-x:auto coerces overflow-y)\n const rect = arrowBtn.getBoundingClientRect();\n const popupMinW = 184;\n let left = rect.left;\n if (left + popupMinW > globalThis.innerWidth) left = rect.right - popupMinW;\n popup.style.top = `${rect.bottom + 4}px`;\n popup.style.left = `${Math.max(4, left)}px`;\n popup.style.display = 'block';\n arrowBtn.setAttribute('aria-expanded', 'true');\n };\n\n const closePopup = () => {\n isOpen = false;\n popup.style.display = 'none';\n popup.style.top = '';\n popup.style.left = '';\n arrowBtn.setAttribute('aria-expanded', 'false');\n };\n\n const applyColor = (color) => {\n currentColor = color;\n strip.style.background = color;\n colorInput.value = color;\n restoreSelection();\n def.action(this.context, color);\n this.context.invoke('editor.afterCommand');\n closePopup();\n };\n\n const d1 = on(applyBtn, 'click', (e) => {\n e.preventDefault();\n restoreSelection();\n def.action(this.context, currentColor);\n this.context.invoke('editor.afterCommand');\n });\n\n const d2 = on(arrowBtn, 'mousedown', (e) => {\n // Prevent editor blur so selection is preserved when the popup opens\n e.preventDefault();\n });\n\n const d2b = on(arrowBtn, 'click', (e) => {\n e.stopPropagation();\n if (isOpen) closePopup(); else openPopup();\n });\n\n const d3 = on(swatches, 'mousedown', (e) => {\n // Prevent blur before the click handler fires\n e.preventDefault();\n });\n\n const d3b = on(swatches, 'click', (e) => {\n const sw = /** @type {Element} */ (e.target)?.closest('.an-color-swatch');\n if (sw) applyColor(/** @type {HTMLElement} */ (sw).dataset.color);\n });\n\n const d4 = on(colorInput, 'change', (e) => {\n applyColor(/** @type {HTMLInputElement} */ (e.target).value);\n });\n\n const d5 = on(document, 'click', (e) => {\n // popup is in document.body, not inside wrap — check both\n if (isOpen && !wrap.contains(/** @type {Node} */ (e.target)) && !popup.contains(/** @type {Node} */ (e.target))) closePopup();\n });\n\n const d6 = on(popup, 'click', (e) => e.stopPropagation());\n\n // Close the popup when the viewport scrolls or resizes so the fixed-position\n // popup doesn't drift away from the button it belongs to.\n const onScrollResize = () => { if (isOpen) closePopup(); };\n document.addEventListener('scroll', onScrollResize, { passive: true, capture: true });\n globalThis.addEventListener('resize', onScrollResize, { passive: true });\n\n this._disposers.push(d1, d2, d2b, d3, d3b, d4, d5, d6,\n () => document.removeEventListener('scroll', onScrollResize, { capture: true }),\n () => globalThis.removeEventListener('resize', onScrollResize),\n // Remove popup from body on editor destroy\n () => { if (popup.parentNode) popup.remove(); },\n );\n\n // Register this popup's closer so other color pickers can close it\n this._colorPickerClosers.push(closePopup);\n this._disposers.push(() => {\n const idx = this._colorPickerClosers.indexOf(closePopup);\n if (idx !== -1) this._colorPickerClosers.splice(idx, 1);\n });\n\n // Append popup to document.body so it escapes all overflow-clipping and\n // contain:layout ancestors (contain:layout makes the container a fixed-pos\n // containing block per the CSS Contain spec, breaking viewport coordinates).\n wrap.appendChild(applyBtn);\n wrap.appendChild(arrowBtn);\n document.body.appendChild(popup);\n return /** @type {HTMLDivElement} */ (wrap);\n }\n\n /**\n * Creates a <select> dropdown for font-family (or similar) options.\n * @param {import('./Buttons.js').DropdownDef} def\n * @returns {HTMLSelectElement}\n */\n _createSelect(def) {\n const items = (def.name === 'fontFamily')\n ? (this.options.fontFamilies || [])\n : (def.items || []);\n\n const cls = def.selectClass ? `an-select ${def.selectClass}` : 'an-select';\n const select = createElement('select', {\n class: cls,\n title: this.context.locale.toolbar[def.name] || def.tooltip || '',\n 'data-btn': def.name,\n 'aria-label': this.context.locale.toolbar[def.name] || def.tooltip || def.name,\n });\n\n // Blank \"placeholder\" option (non-selectable header)\n const placeholderText = this.context.locale.toolbar[def.name + 'Placeholder'] || def.placeholder || 'Font';\n const placeholder = createElement('option', { value: '', disabled: '', hidden: '' }, [placeholderText]);\n select.appendChild(placeholder);\n\n items.forEach((item) => {\n const value = (typeof item === 'object') ? item.value : item;\n let label;\n if (typeof item !== 'object') {\n label = item;\n } else if (def.name === 'paragraphStyle') {\n label = this.context.locale.toolbar.paragraphItems?.[item.value] || item.label;\n } else {\n label = item.label;\n }\n const isHeader = (typeof item === 'object') && !!item.disabled;\n const attrs = { value };\n if (isHeader) attrs.disabled = '';\n const opt = createElement('option', attrs, [label]);\n // Only apply fontFamily face preview on real (non-header) entries\n if (def.name === 'fontFamily' && !isHeader) opt.style.fontFamily = value;\n select.appendChild(opt);\n });\n\n // Save the editor selection when the user starts interacting with the\n // dropdown (mousedown fires before the editor loses focus). When the\n // change handler runs, focus has moved to the <select>; we restore the\n // saved range so execCommand / fontSize() act on the intended text.\n /** @type {Range|null} */\n let _savedRange = null;\n const dMousedown = on(select, 'mousedown', () => {\n const sel = globalThis.getSelection();\n _savedRange = sel?.rangeCount ? sel.getRangeAt(0).cloneRange() : null;\n });\n\n const disposer = on(select, 'change', (e) => {\n const value = /** @type {HTMLSelectElement} */ (e.target).value;\n const selectedOpt = /** @type {HTMLSelectElement} */ (e.target).options[/** @type {HTMLSelectElement} */ (e.target).selectedIndex];\n if (!value || selectedOpt.disabled) return;\n this.context.invoke('editor.focus');\n // Restore selection saved on mousedown so the action targets the correct text.\n if (_savedRange) {\n try {\n const sel = globalThis.getSelection();\n if (sel) { sel.removeAllRanges(); sel.addRange(_savedRange); }\n } catch (_) { void _; /* range may be stale if DOM changed */ }\n }\n def.action(this.context, value);\n this.context.invoke('editor.afterCommand');\n });\n\n this._disposers.push(dMousedown, disposer);\n return /** @type {HTMLSelectElement} */ (select);\n }\n\n /**\n * @param {import('./Buttons.js').ButtonDef} btnDef\n * @returns {HTMLButtonElement}\n */\n _createButton(btnDef) {\n // Determine classes based on whether the consumer wants Bootstrap styling\n const useBootstrap = !!this.options.useBootstrap;\n const baseClass = useBootstrap ? (this.options.toolbarButtonClass || 'btn btn-sm btn-light') : `an-btn`;\n const extra = btnDef.className ? ` ${btnDef.className}` : '';\n const classAttr = `${baseClass}${extra}`;\n\n const btn = createElement('button', {\n type: 'button',\n class: classAttr,\n title: this.context.locale.toolbar[btnDef.name] || btnDef.tooltip || '',\n 'data-btn': btnDef.name,\n 'aria-label': this.context.locale.toolbar[btnDef.name] || btnDef.tooltip || btnDef.name,\n // A button that reports an active state is a toggle, so its state has to\n // be exposed to assistive tech and not only through the `.active` class.\n ...(typeof btnDef.isActive === 'function' ? { 'aria-pressed': 'false' } : {}),\n });\n\n // Render icon: prefer FontAwesome if enabled; otherwise fall back to SVG or text.\n const faPrefix = this.options.fontAwesomeClass || 'fas';\n const useFaNow = this._faReady;\n if (useFaNow) {\n const faName = _FA_MAP.get(btnDef.icon) || _FA_MAP.get(btnDef.name) || null;\n if (faName) {\n btn.innerHTML = `<i class=\"${faPrefix} ${faName}\" aria-hidden=\"true\"></i>`;\n } else if (_SVG_MAP.has(btnDef.icon)) {\n btn.innerHTML = _SVG_MAP.get(btnDef.icon);\n } else {\n btn.textContent = btnDef.icon || btnDef.name;\n }\n } else if (_SVG_MAP.has(btnDef.icon)) {\n // FontAwesome absent: use SVG fallback when available\n btn.innerHTML = _SVG_MAP.get(btnDef.icon);\n } else if (_SVG_MAP.has(btnDef.name)) {\n btn.innerHTML = _SVG_MAP.get(btnDef.name);\n } else {\n btn.textContent = btnDef.icon || btnDef.name;\n }\n\n const disposer = on(btn, 'click', (event) => {\n event.preventDefault();\n // Restore focus to the editor before executing the action\n this.context.invoke('editor.focus');\n btnDef.action(this.context);\n this.context.invoke('editor.afterCommand');\n this.refresh();\n });\n\n this._disposers.push(disposer);\n return /** @type {HTMLButtonElement} */ (btn);\n }\n\n // ---------------------------------------------------------------------------\n // Keyboard navigation — WAI-ARIA toolbar pattern\n // ---------------------------------------------------------------------------\n\n /**\n * Every control the toolbar contains, in visual order. Disabled ones are\n * included so their tabindex can be cleared; `_navigable()` filters them out.\n * @returns {HTMLElement[]}\n */\n _controls() {\n if (!this.el) return [];\n return /** @type {HTMLElement[]} */ (Array.from(this.el.querySelectorAll('button, select')));\n }\n\n /** @returns {HTMLElement[]} controls that can actually receive focus */\n _navigable() {\n return this._controls().filter(\n (el) => !(/** @type {HTMLButtonElement} */ (el).disabled),\n );\n }\n\n /**\n * Enforces the roving-tabindex invariant: exactly one control sits in the tab\n * order and the rest are reached with arrow keys. The default toolbar renders\n * 39 controls, so without this a keyboard user pressed Tab 39 times to get\n * past the toolbar and into the editable area.\n *\n * @param {HTMLElement} [focused] - control that should own the tab stop;\n * omitted on refresh, where the user's current position is preserved.\n */\n _syncRovingTabindex(focused) {\n const all = this._controls();\n const navigable = this._navigable();\n if (!navigable.length) return;\n const active = (focused && navigable.includes(focused))\n ? focused\n : navigable.find((el) => el.getAttribute('tabindex') === '0') || navigable[0];\n all.forEach((el) => el.setAttribute('tabindex', el === active ? '0' : '-1'));\n }\n\n /** Wires arrow-key navigation. Called on build and again after rebuild(). */\n _initRovingFocus() {\n if (!this.el) return;\n this._syncRovingTabindex();\n this._disposers.push(\n on(this.el, 'keydown', (e) => this._onToolbarKeydown(/** @type {KeyboardEvent} */ (e))),\n // Clicking or programmatically focusing a control moves the tab stop with\n // it, so Tab always leaves from wherever the user actually is.\n on(this.el, 'focusin', (e) => {\n const el = /** @type {Element} */ (e.target)?.closest?.('button, select');\n if (el) this._syncRovingTabindex(/** @type {HTMLElement} */ (el));\n }),\n );\n }\n\n /**\n * Home/End jump to the ends; Left/Right step between controls and wrap.\n * Up/Down are deliberately left alone so `<select>` controls keep their\n * native value-changing behaviour.\n * @param {KeyboardEvent} event\n */\n _onToolbarKeydown(event) {\n if (!['ArrowRight', 'ArrowLeft', 'Home', 'End'].includes(event.key)) return;\n const controls = this._navigable();\n const current = /** @type {HTMLElement|null} */ (\n /** @type {Element} */ (event.target)?.closest?.('button, select')\n );\n const idx = current ? controls.indexOf(current) : -1;\n if (idx === -1) return;\n\n let next;\n if (event.key === 'Home') {\n next = controls[0];\n } else if (event.key === 'End') {\n next = controls.at(-1);\n } else {\n // In RTL the arrow that points at the next control is the left one.\n const rtl = this.options.direction === 'rtl';\n const forward = (event.key === 'ArrowRight') !== rtl;\n next = controls[(idx + (forward ? 1 : -1) + controls.length) % controls.length];\n }\n if (!next) return;\n event.preventDefault();\n this._syncRovingTabindex(next);\n next.focus();\n }\n\n // ---------------------------------------------------------------------------\n // FontAwesome detection (run once at initialize time)\n // ---------------------------------------------------------------------------\n\n _detectFontAwesome() {\n if (!this.options.useFontAwesome) return false;\n // Return cached result when available. This ensures that a later-initialised\n // toolbar sees the same detection state as the first one — even if IconDialog\n // has since injected its own FA <link> into <head> for the icon-picker UI.\n if (_faPageLevelReady !== null) return _faPageLevelReady;\n if (document.querySelector('.fa, .fas, .far, .fal, .fab, .fa-solid')) {\n _faPageLevelReady = true;\n return true;\n }\n // Exclude the editor-self-injected link (id='an-fontawesome-css') so it doesn't\n // count as \"the host page loaded FA\" for toolbar icon rendering purposes.\n const links = Array.from(document.querySelectorAll('link[rel=\"stylesheet\"]'))\n .filter((l) => l.id !== 'an-fontawesome-css')\n .map((l) => /** @type {HTMLLinkElement} */ (l).href || '').join(' ');\n _faPageLevelReady = /fontawesome|font-awesome|use\\.fontawesome|all\\.css/.test(links);\n return _faPageLevelReady;\n }\n\n // ---------------------------------------------------------------------------\n // State refresh (active / disabled states)\n // ---------------------------------------------------------------------------\n\n refresh() {\n // Debounce via rAF — multiple rapid calls (e.g. afterCommand + button click)\n // collapse into a single update per animation frame.\n if (this._refreshRaf) cancelAnimationFrame(this._refreshRaf);\n this._refreshRaf = requestAnimationFrame(() => {\n this._refreshRaf = null;\n this._doRefresh();\n });\n }\n\n _doRefresh() {\n if (!this.el) return;\n const btnMap = this._btnMap || new Map();\n\n // Sync button active states\n this.el.querySelectorAll('button[data-btn]').forEach((btn) => {\n const def = btnMap.get(/** @type {HTMLElement} */ (btn).dataset.btn);\n if (def && typeof def.isActive === 'function') {\n const active = !!def.isActive(this.context);\n btn.classList.toggle('active', active);\n btn.setAttribute('aria-pressed', String(active));\n }\n if (def && typeof def.isDisabled === 'function') {\n /** @type {HTMLButtonElement} */ (btn).disabled = !!def.isDisabled(this.context);\n }\n });\n\n // A button disabled just now must not be the one holding the tab stop.\n this._syncRovingTabindex();\n\n // Sync select dropdowns (e.g. font family) with current cursor position\n this.el.querySelectorAll('select[data-btn]').forEach((select) => {\n const def = btnMap.get(/** @type {HTMLElement} */ (select).dataset.btn);\n if (!def || typeof def.getValue !== 'function') return;\n // queryCommandValue returns the font name, possibly quoted — strip quotes\n let raw = (def.getValue(this.context) || '').replace(/[\"']/g, '').trim();\n // Fallback: when no selection/font set, use the configured default font\n if (!raw) {\n raw = this.options.defaultFontFamily\n || this.options.fontFamilies?.[0]\n || '';\n }\n // Try to match against available options (case-insensitive)\n const sel = /** @type {HTMLSelectElement} */ (select);\n const matched = Array.from(sel.options).find(\n (opt) => opt.value?.toLowerCase() === raw.toLowerCase()\n );\n sel.value = matched ? matched.value : '';\n });\n }\n\n /**\n * Shows the toolbar.\n */\n show() {\n if (this.el) this.el.style.display = '';\n }\n\n /**\n * Hides the toolbar.\n */\n hide() {\n if (this.el) this.el.style.display = 'none';\n }\n\n /**\n * Tears down and re-renders the toolbar in-place.\n * Call after registering new buttons post-create via context.use(plugin)\n * or AutumnNote.registerButton() to make them appear in the toolbar.\n */\n rebuild() {\n if (this._refreshRaf) { cancelAnimationFrame(this._refreshRaf); this._refreshRaf = null; }\n this._disposers.forEach((d) => d());\n this._disposers = [];\n if (this.el) this.el.innerHTML = '';\n this._faReady = this._detectFontAwesome();\n this._buildButtons();\n // rebuild() cleared the disposers, taking the keydown/focusin listeners\n // with them — re-arm navigation over the new controls.\n this._initRovingFocus();\n this._btnMap = new Map(\n (this.options.toolbar || []).flat()\n .map(_resolveBtn).filter(Boolean).map((b) => [b.name, b]),\n );\n this.refresh();\n }\n}\n","/**\n * Statusbar.js - Displays word count, character count and resize handle\n * Inspired by Summernote's Statusbar module — rewritten without jQuery\n */\n\nimport { createElement, on } from '../core/dom.js';\nimport { TextCounter } from '../core/count.js';\n\n/**\n * Toggles warning/exceeded CSS classes on a count element.\n * @param {HTMLElement} el\n * @param {number} current\n * @param {number} limit 0 = no limit\n */\nfunction _applyLimitClass(el, current, limit) {\n if (!limit) {\n el.classList.remove('an-count-warn', 'an-count-exceeded');\n return;\n }\n if (current > limit) {\n el.classList.add('an-count-exceeded');\n el.classList.remove('an-count-warn');\n } else if (current >= limit * 0.9) {\n el.classList.add('an-count-warn');\n el.classList.remove('an-count-exceeded');\n } else {\n el.classList.remove('an-count-warn', 'an-count-exceeded');\n }\n}\n\nexport class Statusbar {\n /**\n * @param {import('../Context.js').Context} context\n */\n constructor(context) {\n this.context = context;\n this.options = context.options;\n /** @type {HTMLElement|null} */\n this.el = null;\n this._disposers = [];\n /** @type {HTMLElement|null} */\n this._wordCountEl = null;\n /** @type {HTMLElement|null} */\n this._charCountEl = null;\n /** Shared counter — the same one the maxWords/maxChars limits use. */\n this._counter = new TextCounter();\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n initialize() {\n this.el = createElement('div', { class: 'an-statusbar' });\n\n // Resize handle\n if (this.options.resizable !== false) {\n const handle = createElement('div', {\n class: 'an-resize-handle',\n title: this.context.locale.statusbar.resizeHandle,\n 'aria-hidden': 'true',\n });\n this._bindResize(handle);\n this.el.appendChild(handle);\n }\n\n // Counters\n this._wordCountEl = createElement('span', { class: 'an-word-count', role: 'status', 'aria-live': 'polite', 'aria-atomic': 'true' });\n this._charCountEl = createElement('span', { class: 'an-char-count', 'aria-live': 'polite', 'aria-atomic': 'true' });\n const info = createElement('div', { class: 'an-status-info', 'aria-label': 'Editor statistics' });\n info.appendChild(this._wordCountEl);\n info.appendChild(this._charCountEl);\n this.el.appendChild(info);\n\n this.update();\n return this;\n }\n\n destroy() {\n this._disposers.forEach((d) => d());\n this._disposers = [];\n if (this._dragDisposers) {\n this._dragDisposers.forEach((d) => d());\n this._dragDisposers = null;\n }\n this.el?.remove();\n this.el = null;\n }\n\n // ---------------------------------------------------------------------------\n // Resize logic\n // ---------------------------------------------------------------------------\n\n _bindResize(handle) {\n let startY = 0;\n let startH = 0;\n // Resize the container (flex column parent) so that the editable — which\n // has flex:1 / flex-basis:0 — automatically fills the remaining space.\n // Setting height directly on a flex:1 item has no effect because the flex\n // algorithm ignores the height property when flex-basis is non-auto.\n const containerEl = this.context.layoutInfo.container;\n\n const applyDelta = (clientY) => {\n const delta = clientY - startY;\n // Compute the true minimum: fixed elements (toolbar + statusbar) must fit\n // inside the container. Sum the offsetHeight of every child that is NOT\n // the editable area, then add a small floor so the editable stays visible.\n const MIN_EDITABLE = 40;\n const fixedH = Array.from(containerEl.children)\n .filter(child => !child.classList.contains('an-editable'))\n .reduce((sum, child) => sum + /** @type {HTMLElement} */ (child).offsetHeight, 0);\n const trueMin = Math.max(this.options.minHeight || 100, fixedH + MIN_EDITABLE);\n containerEl.style.height = `${Math.max(trueMin, startH + delta)}px`;\n };\n\n // Mouse drag\n const onMouseMove = (event) => applyDelta(event.clientY);\n\n const onMouseUp = () => {\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n this._dragDisposers = null;\n };\n\n const onMouseDown = (event) => {\n startY = event.clientY;\n startH = containerEl.offsetHeight;\n // Clear the editable's inline min-height so the flex layout can compress\n // it freely once the container has a fixed height. Without this, the\n // editable's min-height (set from options.height) overflows the container\n // when the user drags the handle to a size smaller than that value.\n this.context.layoutInfo.editable.style.minHeight = '';\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n // Track drag-phase listeners so destroy() can remove them mid-drag\n this._dragDisposers = [\n () => document.removeEventListener('mousemove', onMouseMove),\n () => document.removeEventListener('mouseup', onMouseUp),\n ];\n event.preventDefault();\n };\n\n // Touch drag\n const onTouchMove = (event) => {\n const touch = event.touches[0];\n if (touch) { event.preventDefault(); applyDelta(touch.clientY); }\n };\n\n const onTouchEnd = () => {\n document.removeEventListener('touchmove', onTouchMove);\n document.removeEventListener('touchend', onTouchEnd);\n this._dragDisposers = null;\n };\n\n const onTouchStart = (event) => {\n const touch = event.touches[0];\n if (!touch) return;\n startY = touch.clientY;\n startH = containerEl.offsetHeight;\n // Same as onMouseDown: clear editable min-height so flex can compress it\n this.context.layoutInfo.editable.style.minHeight = '';\n document.addEventListener('touchmove', onTouchMove, { passive: false });\n document.addEventListener('touchend', onTouchEnd);\n this._dragDisposers = [\n () => document.removeEventListener('touchmove', onTouchMove),\n () => document.removeEventListener('touchend', onTouchEnd),\n ];\n };\n\n const d1 = on(handle, 'mousedown', onMouseDown);\n const d2 = on(handle, 'touchstart', onTouchStart);\n this._disposers.push(d1, d2);\n }\n\n // ---------------------------------------------------------------------------\n // Counter update\n // ---------------------------------------------------------------------------\n\n // Editor.afterCommand() already invokes 'statusbar.update' on every native\n // 'input' event and after every toolbar/formatting command, so a separate\n // content listener here would just re-run this on the same keystroke.\n /**\n * Word and character counts for the current content.\n * @returns {{ words: number, chars: number }}\n */\n _counts() {\n return this._counter.counts(this.context.layoutInfo.editable);\n }\n\n update() {\n if (!this._wordCountEl || !this._charCountEl) return;\n const { words, chars } = this._counts();\n const maxWords = this.options.maxWords || 0;\n const maxChars = this.options.maxChars || 0;\n\n const LS = this.context.locale.statusbar;\n this._wordCountEl.textContent = maxWords\n ? LS.wordsLimit(words, maxWords)\n : LS.words(words);\n this._charCountEl.textContent = maxChars\n ? LS.charsLimit(chars, maxChars)\n : LS.chars(chars);\n\n // Apply warning / exceeded styles\n _applyLimitClass(this._wordCountEl, words, maxWords);\n _applyLimitClass(this._charCountEl, chars, maxChars);\n }\n\n /**\n * Returns the current word count of the editor content.\n * @returns {number}\n */\n getWordCount() {\n return this._counts().words;\n }\n\n /**\n * Returns the current character count (excluding newlines) of the editor content.\n * @returns {number}\n */\n getCharCount() {\n return this._counts().chars;\n }\n}\n","/**\n * Clipboard.js - Handles paste events to strip unwanted formatting,\n * and paste/drop of image files.\n * Inspired by Summernote's Clipboard module\n */\n\nimport { on } from '../core/dom.js';\nimport { execCommand } from '../editing/Style.js';\nimport { sanitiseHTML, sanitiseUrl } from '../core/sanitise.js';\nimport { isMarkdown, markdownToHTML } from '../core/markdown.js';\n\nexport class Clipboard {\n /**\n * @param {import('../Context.js').Context} context\n */\n constructor(context) {\n this.context = context;\n this.options = context.options;\n this._disposers = [];\n }\n\n initialize() {\n /** @type {Map<string, string>} Maps blob: URL (in DOM) → data: URL (serialisable) */\n this._blobRegistry = new Map();\n /** @type {boolean} Set to true by Ctrl+Shift+V shortcut to force one-shot plain paste */\n this._forcePlain = false;\n const editable = this.context.layoutInfo.editable;\n this._disposers.push(\n on(editable, 'paste', (e) => this._onPaste(e)),\n on(editable, 'dragover', (e) => this._onDragover(e)),\n on(editable, 'drop', (e) => this._onDrop(e)),\n );\n\n // Watch for removed images so their blob: URLs are revoked immediately,\n // preventing memory leaks during long editing sessions.\n this._mutationObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of mutation.removedNodes) {\n this._revokeRemovedBlobs(node);\n }\n }\n });\n this._mutationObserver.observe(editable, { childList: true, subtree: true });\n\n return this;\n }\n\n destroy() {\n this._disposers.forEach((d) => d());\n this._disposers = [];\n if (this._mutationObserver) {\n this._mutationObserver.disconnect();\n this._mutationObserver = null;\n }\n // Release any remaining object URLs\n if (this._blobRegistry) {\n this._blobRegistry.forEach((_, blobUrl) => URL.revokeObjectURL(blobUrl));\n this._blobRegistry.clear();\n }\n // Previews for uploads still in flight when the editor went away.\n if (this._uploadPreviews) {\n this._uploadPreviews.forEach(({ previewUrl }) => URL.revokeObjectURL(previewUrl));\n this._uploadPreviews.clear();\n }\n }\n\n /**\n * Revokes blob URLs for any <img> elements removed from the DOM.\n * @param {Node} node\n */\n _revokeRemovedBlobs(node) {\n if (!this._blobRegistry?.size) return;\n const imgs = /** @type {Element[]} */ ([]);\n if (node.nodeName === 'IMG') {\n imgs.push(/** @type {Element} */ (node));\n } else if (/** @type {Element} */ (node).querySelectorAll) {\n imgs.push(.../** @type {Element} */ (node).querySelectorAll('img'));\n }\n imgs.forEach((img) => {\n const src = img.getAttribute('src') || '';\n if (src.startsWith('blob:') && this._blobRegistry.has(src)) {\n URL.revokeObjectURL(src);\n this._blobRegistry.delete(src);\n }\n });\n }\n\n // ---------------------------------------------------------------------------\n // Paste handler\n // ---------------------------------------------------------------------------\n\n /**\n * Strips Microsoft Word / Office HTML artefacts from a pasted HTML string.\n * Removes conditional comments, Office namespace elements, MsoXxx classes,\n * mso-* inline style rules, and empty paragraphs left behind by Word.\n * @param {string} html\n * @returns {string}\n */\n _cleanWordHtml(html) {\n return html\n // Conditional comments <!--[if ...]>...<![endif]-->\n .replace(/<!--\\[if[\\s\\S]*?\\[endif\\]-->/gi, '')\n // XML data blobs <xml>...</xml>\n .replace(/<xml[\\s\\S]*?<\\/xml>/gi, '')\n // XML processing instructions <?xml ... ?>\n .replace(/<\\?xml[\\s\\S]*?\\?>/gi, '')\n // Office namespace elements: <o:p>, <w:sDt>, <m:oMath>, <v:shape> …\n .replace(/<\\/?(o|w|m|v|st1):[a-z][^>]*>/gi, '')\n // MsoNormal, MsoBodyText, etc. class attributes\n .replace(/\\s+class=\"Mso[^\"]*\"/gi, '')\n // mso-* properties inside inline style attributes\n .replace(/\\s+style=\"([^\"]*)\"/gi, (_m, style) => {\n const cleaned = style.split(';')\n .map((s) => s.trim())\n .filter((s) => s && !/^mso-/i.test(s) && !/^(tab-stops|margin-[a-z]+-alt)/i.test(s))\n .join('; ');\n return cleaned ? ` style=\"${cleaned}\"` : '';\n })\n // Empty paragraphs Word sprinkles everywhere\n .replace(/<p[^>]*>\\s*( )?\\s*<\\/p>/gi, '');\n }\n\n /**\n * Detects and strips noise from social media sites (Facebook, X/Twitter, LinkedIn, etc.).\n * These React-based pages produce HTML with utility class names like `x1n2onr6` / `r-bcqeeo`,\n * `data-testid`, `data-lexical-*`, etc. We keep the semantic structure but remove all the noise.\n * @param {string} html\n * @returns {string}\n */\n _cleanSocialHtml(html) {\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, 'text/html');\n // Unwrap purely presentational wrapper spans/divs with no semantic meaning.\n // Single-pass reverse traversal: querySelectorAll returns elements in document\n // order, so iterating backwards processes innermost elements first — once a\n // child is unwrapped its parent may become unwrappable in the same pass.\n // This replaces the previous O(n²) while-loop that re-queried the whole tree\n // on every iteration.\n const candidates = Array.from(doc.querySelectorAll('span, div'));\n for (let i = candidates.length - 1; i >= 0; i--) {\n const el = candidates[i];\n if (!el.parentNode) continue; // already detached by an earlier iteration\n // Keep if it contains any semantic child element\n if (el.querySelector('a, strong, em, b, i, ul, ol, li, table, img, blockquote, pre, code, h1, h2, h3, h4, h5, h6')) continue;\n // Unwrap — replace el with its children\n const parent = el.parentNode;\n while (el.firstChild) parent.insertBefore(el.firstChild, el);\n el.remove();\n }\n // Strip class and all data-* attributes from every remaining element\n doc.querySelectorAll('*').forEach((el) => {\n el.removeAttribute('class');\n el.removeAttribute('id');\n Array.from(el.attributes)\n .filter((a) => a.name.startsWith('data-') || a.name.startsWith('aria-'))\n .forEach((a) => el.removeAttribute(a.name));\n });\n return doc.body.innerHTML;\n }\n\n /**\n * Strips presentational attributes (class, style, data-*, id) from all elements,\n * keeping only semantic structure and URL attributes.\n * Used when `pasteStripAttributes` option is true.\n * @param {string} html\n * @returns {string}\n */\n _stripAttributes(html) {\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, 'text/html');\n const KEEP_ATTRS = new Set(['href', 'src', 'alt', 'target', 'rel', 'colspan', 'rowspan', 'type']);\n doc.querySelectorAll('*').forEach((el) => {\n Array.from(el.attributes)\n .filter((a) => !KEEP_ATTRS.has(a.name))\n .forEach((a) => el.removeAttribute(a.name));\n });\n return doc.body.innerHTML;\n }\n\n /**\n * Normalizes task lists from external sources (GitHub, GitLab, etc.) so they\n * pass the sanitiser's `ul.an-checklist` guard. Runs before sanitiseHTML().\n * @param {string} html\n * @returns {string}\n */\n _normalizeExternalTaskLists(html) {\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, 'text/html');\n for (const cb of doc.querySelectorAll('input[type=\"checkbox\"]')) {\n const li = cb.closest('li');\n const ul = li?.closest('ul');\n if (!li || !ul || ul.classList.contains('an-checklist')) continue;\n ul.classList.add('an-checklist');\n cb.removeAttribute('disabled');\n cb.setAttribute('contenteditable', 'false');\n for (const attr of Array.from(cb.attributes)) {\n if (!['type', 'checked', 'contenteditable'].includes(attr.name)) {\n cb.removeAttribute(attr.name);\n }\n }\n }\n return doc.body.innerHTML;\n }\n\n /**\n * Checks whether an HTML payload has no semantic markup beyond plain\n * wrapper elements (e.g. a bare <div>/<p>). Used to decide whether a\n * markdown-shaped plain-text paste should win over an accompanying HTML\n * payload that isn't actually carrying any real rich-text formatting.\n * @param {string} html\n * @returns {boolean}\n */\n _isTriviallyPlainHtml(html) {\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, 'text/html');\n const SIGNIFICANT = 'a,img,table,ul,ol,li,blockquote,pre,code,h1,h2,h3,h4,h5,h6,strong,b,em,i,u,s,del,strike,hr,br';\n return !doc.body.querySelector(SIGNIFICANT);\n }\n\n /**\n * Forces the next paste operation to strip all HTML formatting.\n * Called by Editor when Ctrl+Shift+V is pressed.\n * @param {boolean} val\n */\n setForcePlain(val) {\n this._forcePlain = !!val;\n }\n\n _onPaste(event) {\n const clipboardData = event.clipboardData || /** @type {any} */ (globalThis).clipboardData;\n if (!clipboardData) return;\n\n // Consume and reset the one-shot plain-paste flag\n const forcePlain = this._forcePlain;\n this._forcePlain = false;\n\n // Enforce maxPasteSize limit (default 5 MB)\n const maxBytes = (this.options.maxPasteSize ?? 5) * 1024 * 1024;\n if (maxBytes > 0) {\n const text = clipboardData.getData('text/plain') || '';\n const html = clipboardData.getData('text/html') || '';\n const size = Math.max(text.length, html.length);\n if (size > maxBytes) {\n event.preventDefault();\n const message = `Pasted content (${size} bytes) exceeds the ${this.options.maxPasteSize ?? 5} MB paste size limit.`;\n this.context.triggerEvent('pasteError', { size, maxBytes, message });\n console.warn(`[AutumnNote] ${message}`);\n return;\n }\n }\n\n // 1. Image file in clipboard (screenshot, copy-image-from-browser, etc.)\n if (clipboardData.items) {\n const imageItems = Array.from(clipboardData.items).filter(\n (item) => item.kind === 'file' && item.type.startsWith('image/'),\n );\n if (imageItems.length > 0) {\n event.preventDefault();\n const files = imageItems.map((item) => item.getAsFile()).filter(Boolean);\n this._insertImageFiles(files);\n return;\n }\n }\n\n // Fire onPaste hook so consumers can observe / intercept\n if (typeof this.options.onPaste === 'function') {\n this.options.onPaste({\n text: clipboardData.getData('text/plain') || '',\n html: clipboardData.types.includes('text/html') ? clipboardData.getData('text/html') : null,\n });\n }\n\n // 2. Force plain-text only — strip all formatting\n if (forcePlain || this.options.pasteAsPlainText) {\n event.preventDefault();\n const text = clipboardData.getData('text/plain');\n const html = text\n .split(/\\r?\\n/)\n .map((line) => `<p>${this._escapeHTML(line) || '<br>'}</p>`)\n .join('');\n execCommand('insertHTML', html);\n this.context.invoke('editor.afterCommand');\n return;\n }\n\n // 3. Markdown paste — when there's no HTML on the clipboard, or the\n // accompanying HTML has no semantic markup (e.g. some terminal/clipboard\n // tools put both a markdown-shaped text/plain and a trivial <div>-wrapped\n // text/html on the clipboard). Real rich-text sources (Word, Docs, etc.)\n // always have semantic tags after cleaning, so this is unaffected.\n if (this.options.markdownPaste !== false) {\n const hasHtml = clipboardData.types.includes('text/html');\n const html = hasHtml ? clipboardData.getData('text/html') : '';\n const htmlTriviallyPlain = !hasHtml || this._isTriviallyPlainHtml(html);\n const text = clipboardData.getData('text/plain');\n if (text && htmlTriviallyPlain && isMarkdown(text)) {\n event.preventDefault();\n const converted = sanitiseHTML(markdownToHTML(text));\n execCommand('insertHTML', converted);\n this.context.invoke('editor.afterCommand');\n return;\n }\n }\n\n // 4. Sanitise HTML on paste when pasteCleanHTML is true (default)\n if (this.options.pasteCleanHTML !== false && clipboardData.types.includes('text/html')) {\n event.preventDefault();\n const raw = clipboardData.getData('text/html');\n // Detect source type and apply appropriate pre-cleaner\n const isWordContent = /<[a-z]+:[a-z]/i.test(raw) || /class=\"Mso/i.test(raw) || /\\bmso-/i.test(raw);\n const isSocialContent = /class=\"[^\"]*\\b(?:x[a-z0-9]{6,}|r-[a-z0-9]{3,})\\b/.test(raw);\n let html = raw;\n if (isWordContent) html = this._cleanWordHtml(html);\n else if (isSocialContent) html = this._cleanSocialHtml(html);\n html = this._normalizeExternalTaskLists(html);\n html = sanitiseHTML(html);\n if (this.options.pasteStripAttributes) html = this._stripAttributes(html);\n execCommand('insertHTML', html);\n this.context.invoke('editor.afterCommand');\n }\n\n // Otherwise let the browser handle paste natively\n }\n\n // ---------------------------------------------------------------------------\n // Drag & drop handlers\n // ---------------------------------------------------------------------------\n\n _onDragover(event) {\n if (!event.dataTransfer) return;\n const types = Array.from(event.dataTransfer.types || []);\n if (types.includes('Files')) {\n event.preventDefault();\n event.dataTransfer.dropEffect = 'copy';\n }\n }\n\n _onDrop(event) {\n const dt = event.dataTransfer;\n if (!dt?.files?.length) return;\n\n const imageFiles = Array.from(dt.files).filter((f) => f.type.startsWith('image/'));\n if (imageFiles.length > 0) {\n event.preventDefault();\n event.stopPropagation();\n // Place the caret at the drop coordinates before inserting\n this._placeCaretAtPoint(event.clientX, event.clientY);\n this._insertImageFiles(imageFiles);\n return;\n }\n\n if (this.options.markdownPaste !== false) {\n const mdFile = Array.from(dt.files).find((f) => /\\.md$/i.test(f.name) || f.type === 'text/markdown');\n if (mdFile) {\n event.preventDefault();\n event.stopPropagation();\n this._placeCaretAtPoint(event.clientX, event.clientY);\n this._insertMarkdownFile(mdFile);\n }\n }\n }\n\n /**\n * Reads a dropped `.md` File and inserts it converted to HTML at the\n * current caret. Skips the isMarkdown() heuristic — an explicit `.md`\n * extension/MIME type is an unambiguous signal, unlike pasted plain text.\n * @param {File} file\n */\n _insertMarkdownFile(file) {\n const maxBytes = (this.options.maxPasteSize ?? 5) * 1024 * 1024;\n if (maxBytes > 0 && file.size > maxBytes) {\n const message = `Dropped file \"${file.name}\" (${file.size} bytes) exceeds the ${this.options.maxPasteSize ?? 5} MB paste size limit.`;\n this.context.triggerEvent('pasteError', { size: file.size, maxBytes, message });\n console.warn(`[AutumnNote] ${message}`);\n return;\n }\n const reader = new FileReader();\n reader.onload = (e) => {\n const html = sanitiseHTML(markdownToHTML(/** @type {string} */ (e.target.result) || ''));\n execCommand('insertHTML', html);\n this.context.invoke('editor.afterCommand');\n };\n reader.onerror = () => {\n const message = `Failed to read dropped markdown file \"${file.name}\".`;\n console.warn(`[AutumnNote] ${message}`);\n this.context.triggerEvent('pasteError', { message });\n };\n reader.readAsText(file);\n }\n\n // ---------------------------------------------------------------------------\n // Image file processing — shared by paste and drop\n // ---------------------------------------------------------------------------\n\n /**\n * Inserts one or more image Files into the editor.\n * Delegates to `options.onImageUpload` when provided; otherwise compresses\n * and embeds as base64.\n * @param {File[]} files\n */\n _insertImageFiles(files) {\n if (!files || files.length === 0) return;\n\n if (typeof this.options.onImageUpload === 'function') {\n this._runUploadHandler(files);\n return;\n }\n\n // C2: Reject image formats that browsers cannot decode/display.\n const UNSUPPORTED = new Set(['image/tiff', 'image/x-tiff', 'image/bmp', 'image/x-bmp', 'image/x-ms-bmp']);\n const maxBytes = (this.options.maxImageSize || 5) * 1024 * 1024;\n files.forEach((file) => {\n if (!file?.type?.startsWith('image/')) return;\n if (UNSUPPORTED.has(file.type)) {\n const message = `Image format \"${file.type}\" is not supported for display in web browsers. Please convert to PNG, JPEG, or WebP first.`;\n this.context.triggerEvent('imageError', { file, message });\n console.warn('[AutumnNote]', message);\n return;\n }\n if (file.size > maxBytes) {\n const message = `Image \"${file.name}\" exceeds the ${this.options.maxImageSize || 5} MB size limit.`;\n this.context.triggerEvent('imageError', { file, message });\n console.warn(`[AutumnNote] ${message}`);\n return;\n }\n\n const alt = file.name.replace(/\\.[^.]+$/, '');\n this.compressAndRegister(file).then((blobUrl) => {\n this.context.invoke('editor.insertImage', blobUrl, alt);\n }).catch((err) => {\n const message = `Image \"${file.name}\" could not be processed.`;\n this.context.triggerEvent('imageError', { file, message, error: err });\n console.warn('[AutumnNote]', message, err);\n });\n });\n }\n\n /**\n * Escapes a value for use inside a double-quoted HTML attribute.\n * @param {string} v\n * @returns {string}\n */\n _escapeAttr(v) {\n return String(v)\n .replaceAll('&', '&')\n .replaceAll('\"', '"')\n .replaceAll('<', '<')\n .replaceAll('>', '>');\n }\n\n /**\n * Runs `options.onImageUpload` and, when it reports back, places the images\n * it uploaded.\n *\n * The handler has always been called with the dropped files; what it could\n * not do was hand the resulting URL back, so every integration that uploaded\n * to its own storage had to insert the image itself. Returning a URL — or a\n * promise of one — now inserts a placeholder immediately and swaps the real\n * URL in when it arrives.\n *\n * A handler that returns nothing keeps the old behaviour exactly: nothing is\n * inserted and no placeholder appears.\n * @param {File[]} files\n */\n async _runUploadHandler(files) {\n const helpers = {\n context: this.context,\n setProgress: (file, ratio) => this._setUploadProgress(file, ratio),\n };\n\n let result;\n try {\n result = this.options.onImageUpload(files, helpers);\n } catch (error) {\n this._reportUploadError(files, error);\n return;\n }\n\n // Legacy contract: the handler inserts the image itself.\n if (result === undefined) return;\n\n // Placeholders go in synchronously, before the promise is awaited, so the\n // image appears at the caret the moment it is dropped.\n const tokens = files.map((file) => this._insertUploadPlaceholder(file));\n\n let urls;\n try {\n urls = await result;\n } catch (error) {\n tokens.forEach((token, i) => this._failUpload(token, files[i], error));\n return;\n }\n\n const list = Array.isArray(urls) ? urls : [urls];\n tokens.forEach((token, i) => {\n const url = list[i];\n if (typeof url === 'string' && url) this._resolveUpload(token, url);\n // A handler that returned fewer URLs than files leaves the rest failed\n // rather than silently dropping a placeholder mid-document.\n else this._failUpload(token, files[i], new Error('No URL returned for this file.'));\n });\n }\n\n /**\n * Inserts a dimmed placeholder for a file being uploaded, previewing the\n * local file so the user sees what is on its way up.\n * @param {File} file\n * @returns {string} token identifying the placeholder\n */\n _insertUploadPlaceholder(file) {\n const token = `an-up-${Date.now().toString(36)}-${this._uploadSeq = (this._uploadSeq || 0) + 1}`;\n const previewUrl = URL.createObjectURL(file);\n this._uploadPreviews = this._uploadPreviews || new Map();\n this._uploadPreviews.set(token, { previewUrl, file });\n\n const alt = this._escapeAttr(file.name.replace(/\\.[^.]+$/, ''));\n execCommand('insertHTML',\n `<img src=\"${this._escapeAttr(previewUrl)}\" alt=\"${alt}\" class=\"an-image an-image-uploading\" data-an-upload=\"${token}\">`);\n this.context.invoke('editor.afterCommand');\n return token;\n }\n\n /** @param {string} token @returns {HTMLImageElement|null} */\n _findPlaceholder(token) {\n return /** @type {HTMLImageElement|null} */ (\n this.context.layoutInfo.editable?.querySelector(`img[data-an-upload=\"${token}\"]`) ?? null\n );\n }\n\n /**\n * Swaps a placeholder over to the uploaded URL.\n * @param {string} token\n * @param {string} url\n */\n _resolveUpload(token, url) {\n const img = this._findPlaceholder(token);\n const entry = this._uploadPreviews?.get(token);\n if (img) {\n const safe = sanitiseUrl(url, { allowData: true });\n if (safe) {\n img.setAttribute('src', safe);\n img.classList.remove('an-image-uploading');\n img.removeAttribute('data-an-upload');\n img.style.removeProperty('--an-upload-progress');\n } else {\n this._failUpload(token, entry?.file, new Error(`Rejected image URL: ${url}`));\n return;\n }\n }\n if (entry) {\n URL.revokeObjectURL(entry.previewUrl);\n this._uploadPreviews.delete(token);\n }\n this.context.invoke('editor.afterCommand');\n }\n\n /**\n * Marks a placeholder as failed and reports it. The preview is kept so the\n * user can still see which image did not make it; `retry` re-runs the\n * handler for that one file.\n * @param {string} token\n * @param {File|undefined} file\n * @param {unknown} error\n */\n _failUpload(token, file, error) {\n const img = this._findPlaceholder(token);\n if (img) {\n img.classList.remove('an-image-uploading');\n img.classList.add('an-image-failed');\n img.style.removeProperty('--an-upload-progress');\n }\n const message = `Image \"${file?.name ?? 'unknown'}\" could not be uploaded.`;\n console.warn('[AutumnNote]', message, error);\n this.context.triggerEvent('imageError', {\n file,\n message,\n error,\n retry: () => {\n img?.remove();\n this._uploadPreviews?.delete(token);\n if (file) this._runUploadHandler([file]);\n },\n });\n }\n\n /** Reports a handler that threw before any placeholder existed. */\n _reportUploadError(files, error) {\n const message = 'The image upload handler threw before any file was sent.';\n console.warn('[AutumnNote]', message, error);\n this.context.triggerEvent('imageError', { file: files[0], message, error });\n }\n\n /**\n * Records upload progress for a file, as a 0–1 ratio. Exposed to the handler\n * so a consumer with a progress-reporting transport can drive the indicator.\n * @param {File} file\n * @param {number} ratio\n */\n _setUploadProgress(file, ratio) {\n if (!this._uploadPreviews) return;\n const clamped = Math.max(0, Math.min(1, Number(ratio) || 0));\n for (const [token, entry] of this._uploadPreviews) {\n if (entry.file !== file) continue;\n const img = this._findPlaceholder(token);\n if (img) img.style.setProperty('--an-upload-progress', String(clamped));\n return;\n }\n }\n\n /**\n * Compresses an image File via canvas and registers the result behind a\n * lightweight blob: URL (see `resolveImages`), so callers never have to hold\n * the full base64 string in the DOM. Shared by paste/drop and ImageDialog's\n * file picker so every image-insertion path gets the same compression.\n * @param {File} file\n * @returns {Promise<string>} blob: URL usable as an <img src>\n */\n async compressAndRegister(file) {\n const processor = this.options.imageProcessor;\n const dataUrl = typeof processor === 'function'\n ? await processor(file, { context: this.context })\n : await this._compressImage(file);\n const blob = this._dataUrlToBlob(dataUrl);\n const blobUrl = URL.createObjectURL(blob);\n this._blobRegistry.set(blobUrl, dataUrl);\n return blobUrl;\n }\n\n /**\n * Replaces any blob: URLs created by this module with their original data URLs.\n * Called by Editor.getHTML() so the returned HTML is fully self-contained.\n * @param {string} html\n * @returns {string}\n */\n resolveImages(html) {\n if (!this._blobRegistry?.size) return html;\n return html.replace(/blob:[^\"'> \\t\\n\\r]*/g, (url) => this._blobRegistry.get(url) || url);\n }\n\n /**\n * Converts a data URL to a Blob (no FileReader — synchronous).\n * @param {string} dataUrl\n * @returns {Blob}\n */\n _dataUrlToBlob(dataUrl) {\n const [header, b64] = dataUrl.split(',');\n const mime = /:(.*?);/.exec(header)?.[1] ?? 'image/png';\n const binary = atob(b64);\n const arr = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) arr[i] = binary.charCodeAt(i);\n return new Blob([arr], { type: mime });\n }\n\n /**\n * Compresses an image File using a Canvas.\n * - Resizes so the longest edge is at most MAX_DIM pixels.\n * - Encodes as WebP (if supported) or JPEG at quality 0.85.\n * Falls back to plain FileReader if canvas is unavailable.\n * @param {File} file\n * @returns {Promise<string>} data URL\n */\n _compressImage(file) {\n const MAX_DIM = 1920;\n const QUALITY = 0.85;\n\n return new Promise((resolve, reject) => {\n const objectUrl = URL.createObjectURL(file);\n const img = new Image();\n\n img.onload = () => {\n URL.revokeObjectURL(objectUrl);\n\n let { width, height } = img;\n if (width > MAX_DIM || height > MAX_DIM) {\n if (width >= height) {\n height = Math.round((height * MAX_DIM) / width);\n width = MAX_DIM;\n } else {\n width = Math.round((width * MAX_DIM) / height);\n height = MAX_DIM;\n }\n }\n\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n // Canvas context unavailable (e.g. device memory limit) — fall back to\n // embedding the original file without compression.\n const reader = new FileReader();\n reader.onload = (e) => resolve(/** @type {string} */ (e.target.result));\n reader.onerror = () => reject(new Error('FileReader failed'));\n reader.readAsDataURL(file);\n return;\n }\n ctx.drawImage(img, 0, 0, width, height);\n\n // Prefer WebP for better compression; fall back to JPEG\n const webp = canvas.toDataURL('image/webp', QUALITY);\n resolve(webp.startsWith('data:image/webp') ? webp : canvas.toDataURL('image/jpeg', QUALITY));\n };\n\n img.onerror = () => {\n URL.revokeObjectURL(objectUrl);\n // Fallback: embed original without compression\n const reader = new FileReader();\n reader.onload = (e) => resolve(/** @type {string} */ (e.target.result));\n reader.onerror = () => reject(new Error('FileReader failed'));\n reader.readAsDataURL(file);\n };\n\n img.src = objectUrl;\n });\n }\n\n /**\n * Positions the caret at the given viewport coordinates.\n * Supports both Chrome (caretRangeFromPoint) and Firefox (caretPositionFromPoint).\n * @param {number} x\n * @param {number} y\n */\n _placeCaretAtPoint(x, y) {\n let range;\n if (document.caretRangeFromPoint) {\n range = document.caretRangeFromPoint(x, y);\n } else if (document.caretPositionFromPoint) {\n const pos = document.caretPositionFromPoint(x, y);\n if (pos) {\n range = document.createRange();\n range.setStart(pos.offsetNode, pos.offset);\n range.collapse(true);\n }\n }\n if (!range) return;\n const sel = globalThis.getSelection();\n if (sel) {\n sel.removeAllRanges();\n sel.addRange(range);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Escapes HTML special characters.\n * @param {string} str\n * @returns {string}\n */\n _escapeHTML(str) {\n return str\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\"', '"')\n .replaceAll(\"'\", ''');\n }\n}\n","/**\n * Placeholder.js - Shows placeholder text when the editor is empty\n * Inspired by Summernote's Placeholder module\n */\n\nimport { on } from '../core/dom.js';\n\n/**\n * Anything that is neither whitespace nor a zero-width space.\n *\n * `\\s` is exactly the set `String.prototype.trim` strips, so this matches the\n * old `textContent.replaceAll('\\u200B', '').trim().length > 0` test character\n * for character. ZWS is not whitespace and has to be listed: checklist and icon\n * insertion leave them behind as cursor anchors, and treating one as content\n * left the placeholder overlapping a visually empty editor (A-1).\n */\nconst MEANINGFUL_RE = /[^\\s\\u200B]/;\n\n/**\n * True when the subtree holds any character the reader would see.\n *\n * Stops at the first one instead of materialising the document's text and\n * copying it twice — this runs on every keystroke, where the old version cost\n * 0.2 ms on a 217 KiB document and this costs 0.0005 ms, because a non-empty\n * editor answers on its first text node.\n * @param {HTMLElement} root\n * @returns {boolean}\n */\nfunction _hasText(root) {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n if (MEANINGFUL_RE.test(/** @type {Text} */ (node).data)) return true;\n }\n return false;\n}\n\nexport class Placeholder {\n /**\n * @param {import('../Context.js').Context} context\n */\n constructor(context) {\n this.context = context;\n this.options = context.options;\n this._disposers = [];\n }\n\n initialize() {\n const editable = this.context.layoutInfo.editable;\n const placeholder = this.options.placeholder || '';\n if (placeholder) {\n editable.dataset.placeholder = placeholder;\n }\n\n const update = () => this._update();\n const d1 = on(editable, 'input', update);\n const d2 = on(editable, 'focus', update);\n const d3 = on(editable, 'blur', update);\n this._disposers.push(d1, d2, d3);\n this._update();\n return this;\n }\n\n destroy() {\n this._disposers.forEach((d) => d());\n this._disposers = [];\n }\n\n _update() {\n const editable = this.context.layoutInfo.editable;\n const isFocused = document.activeElement === editable;\n const isEmpty = !_hasText(editable) &&\n !editable.querySelector('img, table, hr, .an-video-wrapper');\n editable.classList.toggle('an-placeholder', isEmpty && !isFocused);\n }\n}\n","/**\n * presets/core.js — the smallest set that still makes a usable editor.\n *\n * Typing, the toolbar, the status bar, paste handling and the placeholder. No\n * dialogs, no floating tooltips, no emoji or icon pickers, no crop overlay.\n *\n * Nothing here imports a heavy module, which is the whole point: a build that\n * uses only this preset never reaches `presets/full.js` and the bundler drops\n * everything it lists.\n *\n * Toolbar buttons whose module is absent still render; invoking one logs a\n * warning from `Context.invoke` and does nothing. Pair this preset with a\n * toolbar that only names buttons the core modules can serve.\n */\n\nimport { Editor } from '../module/Editor.js';\nimport { Toolbar } from '../module/Toolbar.js';\nimport { Statusbar } from '../module/Statusbar.js';\nimport { Clipboard } from '../module/Clipboard.js';\nimport { Placeholder } from '../module/Placeholder.js';\n\n/**\n * @type {import('../Context.js').ModuleDef[]}\n */\nexport const CORE_MODULES = [\n { name: 'editor', Class: Editor },\n { name: 'toolbar', Class: Toolbar },\n { name: 'statusbar', Class: Statusbar },\n { name: 'clipboard', Class: Clipboard },\n { name: 'placeholder', Class: Placeholder },\n];\n\nexport { Editor, Toolbar, Statusbar, Clipboard, Placeholder };\n","{\n \"name\": \"autumnnote\",\n \"version\": \"2.7.0\",\n \"description\": \"WYSIWYG rich-text editor built with vanilla JavaScript \\u2014 zero dependencies, no jQuery. Dark mode, @mention, markdown shortcuts, bubble toolbar. React and Vue\\u00a03 wrappers included.\",\n \"type\": \"module\",\n \"main\": \"dist/autumnnote.cjs\",\n \"module\": \"dist/autumnnote.es.js\",\n \"types\": \"types/index.d.ts\",\n \"style\": \"dist/autumnnote.css\",\n \"exports\": {\n \".\": {\n \"types\": \"./types/index.d.ts\",\n \"import\": \"./dist/autumnnote.es.js\",\n \"require\": \"./dist/autumnnote.cjs\"\n },\n \"./i18n/*\": {\n \"types\": \"./types/i18n/*.d.ts\",\n \"import\": \"./src/js/i18n/*.js\"\n },\n \"./dist/autumnnote.css\": \"./dist/autumnnote.css\",\n \"./core\": {\n \"types\": \"./types/core-entry.d.ts\",\n \"import\": \"./dist/autumnnote.core.es.js\"\n }\n },\n \"sideEffects\": [\n \"*.css\",\n \"*.scss\",\n \"./src/js/index.js\",\n \"./src/js/core.js\",\n \"./src/js/index.umd.js\",\n \"./src/js/i18n/all.js\"\n ],\n \"files\": [\n \"dist\",\n \"src/js/i18n\",\n \"src/js/core/func.js\",\n \"types\"\n ],\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build && vite build --config vite.umd.config.js && vite build --config vite.cdn.config.js && vite build --config vite.core.config.js && node scripts/create-cjs-alias.mjs\",\n \"build:demo\": \"vite build --config vite.demo.config.js\",\n \"preview\": \"vite preview\",\n \"prepublishOnly\": \"npm run build\",\n \"test\": \"vitest run\",\n \"test:browser\": \"vitest run --config vitest.browser.config.js\",\n \"test:watch\": \"vitest\",\n \"lint\": \"eslint src test\",\n \"typecheck\": \"tsc --noEmit && pnpm --filter autumnnote-react typecheck && pnpm --filter autumnnote-vue typecheck\",\n \"build:cdn\": \"vite build --config vite.cdn.config.js\",\n \"analyze\": \"cross-env ANALYZE=1 vite build\",\n \"bench\": \"vitest bench\",\n \"test:coverage\": \"vitest run --coverage\",\n \"test:wrappers\": \"pnpm --filter autumnnote-react test && pnpm --filter autumnnote-vue test\",\n \"build:wrappers\": \"pnpm --filter autumnnote-react build && pnpm --filter autumnnote-vue build\",\n \"check:bundle\": \"node scripts/check-bundle-size.mjs\",\n \"check:package\": \"node scripts/check-package-files.mjs\",\n \"check\": \"pnpm lint && pnpm typecheck && pnpm test:coverage && pnpm build && pnpm test:wrappers && pnpm check:bundle && pnpm check:package && pnpm build:demo && pnpm build:wrappers\",\n \"build:core\": \"vite build --config vite.core.config.js\"\n },\n \"keywords\": [\n \"wysiwyg\",\n \"wysiwyg-editor\",\n \"editor\",\n \"rich-text\",\n \"rich-text-editor\",\n \"vanilla-js\",\n \"vanilla-javascript\",\n \"contenteditable\",\n \"text-editor\",\n \"html-editor\",\n \"no-jquery\",\n \"lightweight\",\n \"toolbar\",\n \"javascript-editor\",\n \"summernote\",\n \"summernote-alternative\",\n \"quill-alternative\",\n \"tinymce-alternative\",\n \"markdown\",\n \"mention\",\n \"bubble-toolbar\",\n \"dark-mode\",\n \"i18n\",\n \"typescript\",\n \"esm\",\n \"javascript-wysiwyg\",\n \"wysiwyg-vanilla\",\n \"froala-alternative\",\n \"ckeditor-alternative\",\n \"zero-dependencies\",\n \"react-wysiwyg\",\n \"vue-wysiwyg\",\n \"prosemirror-alternative\",\n \"trix-alternative\",\n \"slate-alternative\",\n \"vue3\",\n \"quill\",\n \"tinymce\",\n \"react\",\n \"vue\",\n \"plugin-api\",\n \"rtl\",\n \"autosave\"\n ],\n \"homepage\": \"https://autumn.konexforge.com/\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/cmm-cmm/Autumn-Note.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/cmm-cmm/Autumn-Note/issues\"\n },\n \"author\": \"Minh Pham\",\n \"license\": \"MIT\",\n \"devDependencies\": {\n \"@vitest/browser\": \"^4.1.8\",\n \"@vitest/browser-playwright\": \"^4.1.10\",\n \"@vitest/coverage-v8\": \"^4.1.8\",\n \"cross-env\": \"^10.1.0\",\n \"eslint\": \"^10.7.0\",\n \"jsdom\": \"^25.0.1\",\n \"playwright\": \"^1.61.1\",\n \"rollup-plugin-visualizer\": \"^7.0.1\",\n \"sass\": \"^1.101.0\",\n \"typescript\": \"^6.0.2\",\n \"vite\": \"^8.1.5\",\n \"vitest\": \"^4.1.8\"\n },\n \"packageManager\": \"pnpm@11.1.3\",\n \"engines\": {\n \"node\": \">=20.19.0\"\n },\n \"browserslist\": [\n \"last 2 versions\",\n \"not dead\",\n \"> 0.5%\"\n ]\n}\n","/**\n * lists.js - Array/list utility helpers\n * Inspired by Summernote's lists.js\n */\n\n/**\n * Returns the last element of an array.\n * @template T\n * @param {T[]} arr\n * @returns {T|undefined}\n */\nexport function last(arr) {\n return arr[arr.length - 1];\n}\n\n/**\n * Returns the first element of an array.\n * @template T\n * @param {T[]} arr\n * @returns {T|undefined}\n */\nexport function first(arr) {\n return arr[0];\n}\n\n/**\n * Returns a new array without the last n items.\n * @template T\n * @param {T[]} arr\n * @param {number} [n=1]\n * @returns {T[]}\n */\nexport function initial(arr, n = 1) {\n return arr.slice(0, arr.length - n);\n}\n\n/**\n * Returns a new array without the first n items.\n * @template T\n * @param {T[]} arr\n * @param {number} [n=1]\n * @returns {T[]}\n */\nexport function tail(arr, n = 1) {\n return arr.slice(n);\n}\n\n/**\n * Returns a flattened (one level) array.\n * @template T\n * @param {T[][]} arr\n * @returns {T[]}\n */\nexport function flatten(arr) {\n return arr.flat();\n}\n\n/**\n * Returns unique elements of an array (using Set).\n * @template T\n * @param {T[]} arr\n * @returns {T[]}\n */\nexport function unique(arr) {\n return [...new Set(arr)];\n}\n\n/**\n * Splits an array into chunks of size n.\n * @template T\n * @param {T[]} arr\n * @param {number} n\n * @returns {T[][]}\n */\nexport function chunk(arr, n) {\n const result = [];\n for (let i = 0; i < arr.length; i += n) {\n result.push(arr.slice(i, i + n));\n }\n return result;\n}\n\n/**\n * Groups array elements by a key function.\n * @template T\n * @param {T[]} arr\n * @param {(item: T) => string} keyFn\n * @returns {Record<string, T[]>}\n */\nexport function groupBy(arr, keyFn) {\n return arr.reduce((groups, item) => {\n const key = keyFn(item);\n if (!groups[key]) {\n groups[key] = [];\n }\n groups[key].push(item);\n return groups;\n }, {});\n}\n\n/**\n * Returns true if all elements satisfy the predicate.\n * @template T\n * @param {T[]} arr\n * @param {(item: T) => boolean} predicate\n * @returns {boolean}\n */\nexport function all(arr, predicate) {\n return arr.every(predicate);\n}\n\n/**\n * Returns true if any element satisfies the predicate.\n * @template T\n * @param {T[]} arr\n * @param {(item: T) => boolean} predicate\n * @returns {boolean}\n */\nexport function any(arr, predicate) {\n return arr.some(predicate);\n}\n","/**\n * env.js - Environment / browser detection\n * Inspired by Summernote's env.js\n *\n * Every field is a lazy getter rather than a value computed at module load.\n * This module is re-exported from the package entry point, so reading\n * `navigator` eagerly meant that merely `import`ing autumnnote threw\n * `ReferenceError: navigator is not defined` under SSR on any runtime without\n * a global `navigator` — including Node 20, which package.json still supports.\n * Nothing inside the library reads these fields, so the crash happened before\n * an editor was ever created.\n */\n\n/** @returns {string} the current user agent, or '' when there is no navigator (SSR). */\nfunction ua() {\n return globalThis.navigator?.userAgent ?? '';\n}\n\nexport const env = {\n /** True if browser is Chrome (excludes Edge, whose UA also contains \"Chrome/\") */\n get isChrome() { return /Chrome\\//.test(ua()) && !/Edg\\//.test(ua()); },\n /** True if browser is Firefox */\n get isFF() { return /Firefox\\//.test(ua()); },\n /** True if browser is Safari (not Chrome) */\n get isSafari() { return /^((?!chrome|android).)*safari/i.test(ua()); },\n /** True if browser is Edge (Chromium) */\n get isEdge() { return /Edg\\//.test(ua()); },\n /** True if running on macOS */\n get isMac() { return /Macintosh/.test(ua()); },\n /** True if running on mobile */\n get isMobile() { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua()); },\n /** True if touch is supported */\n get isTouch() {\n return 'ontouchstart' in globalThis || (globalThis.navigator?.maxTouchPoints ?? 0) > 0;\n },\n /** Modifier key name depending on platform */\n get modifierKey() { return /Macintosh/.test(ua()) ? 'metaKey' : 'ctrlKey'; },\n};\n","/**\n * factory.js — the AutumnNote object and the public re-exports, shared by every\n * entry point.\n *\n * Deliberately imports no editor module and installs no module table. Each\n * entry point does that for itself: `index.js` installs the full preset,\n * `core.js` a minimal one. Keeping the choice out of here is what lets a\n * bundler drop the modules an entry never mentions.\n */\n\nimport { Context, _customModules, _globalPlugins } from './Context.js';\nimport { registerButton, buttons } from './module/Buttons.js';\nimport { defaultOptions } from './settings.js';\nimport { registerLocale } from './i18n/index.js';\nimport { version as packageVersion } from '../../package.json';\n\n// Snapshot of factory defaults taken at module-load time (before any setDefaults() calls)\nconst _originalDefaults = { ...defaultOptions };\n\n// Re-export for tree-shaking / module consumers\nexport { Context } from './Context.js';\nexport { defaultOptions } from './settings.js';\nexport * from './core/dom.js';\nexport * from './core/range.js';\nexport * from './core/func.js';\nexport * from './core/key.js';\nexport * from './core/lists.js';\nexport * from './core/env.js';\nexport * from './core/sanitise.js';\n// Both were reachable only through an editor instance, which needs a DOM —\n// so converting or detecting on a server or in a build step meant reaching\n// into src/. They are already in the bundle; exporting them costs nothing.\nexport * from './core/markdown.js';\nexport * from './core/detectLang.js';\nexport * from './module/Buttons.js';\nexport { locales, resolveLocale, registerLocale } from './i18n/index.js';\n\n// ---------------------------------------------------------------------------\n// Main factory\n// ---------------------------------------------------------------------------\n\n/** @type {WeakMap<Element, Context>} */\nconst instances = new WeakMap();\n\nconst AutumnNote = {\n /**\n * Creates (or returns existing) editor instance on one or more elements.\n *\n * @param {string|Element|NodeList|Element[]} selector\n * @param {import('./settings.js').AsnOptions} [options]\n * @returns {Context|Context[]} single Context or array of Contexts\n */\n create(selector, options = {}) {\n const elements = resolveElements(selector);\n const ctxs = elements.map((el) => {\n if (instances.has(el)) return instances.get(el);\n const ctx = new Context(/** @type {HTMLElement} */ (el), options);\n // Context.destroy() is part of the public API, so releasing the factory\n // registry cannot depend on callers going through AutumnNote.destroy().\n // React StrictMode in particular destroys and recreates an editor on the\n // same host element during its development lifecycle.\n ctx._releaseInstance = () => {\n if (instances.get(el) === ctx) instances.delete(el);\n };\n ctx.initialize();\n instances.set(el, ctx);\n return ctx;\n });\n return ctxs.length === 1 ? ctxs[0] : ctxs;\n },\n\n /**\n * Destroys the editor(s) on the given selector.\n * @param {string|Element|NodeList|Element[]} selector\n */\n destroy(selector) {\n resolveElements(selector).forEach((el) => {\n const ctx = instances.get(el);\n if (ctx) {\n ctx.destroy();\n instances.delete(el);\n }\n });\n },\n\n /**\n * Returns the Context instance for a given element (or null).\n * @param {string|Element} selector\n * @returns {Context|null}\n */\n getInstance(selector) {\n const el = typeof selector === 'string' ? document.querySelector(selector) : selector;\n return el ? instances.get(el) || null : null;\n },\n\n /** Returns a shallow copy of the default options (read-only snapshot). */\n get defaults() { return { ...defaultOptions }; },\n\n /** Merges properties into the global defaults, applied to all future instances. */\n setDefaults(overrides) { Object.assign(defaultOptions, overrides); },\n\n /** Restores global defaults to their original factory values. */\n resetDefaults() {\n Object.keys(defaultOptions).forEach((k) => delete defaultOptions[k]);\n Object.assign(defaultOptions, _originalDefaults);\n },\n\n /**\n * Registers a custom module to be included in every new editor instance.\n * @param {string} name - unique module key used for ctx.invoke() calls\n * @param {Function} ModuleClass - class with initialize() and optional destroy()\n */\n registerModule(name, ModuleClass) { _customModules.set(name, ModuleClass); },\n\n /**\n * Installs a plugin globally — applied to every future editor instance.\n * Plugin `buttons` are registered to the global button registry immediately\n * so they are available when Toolbar initialises inside create().\n * Plugin `install()` is called after all built-in modules have initialised.\n * @param {object} plugin - { name, version?, buttons?, install?, uninstall? }\n * @param {object} [options] - Forwarded to plugin.install(context, options)\n * @returns {typeof AutumnNote}\n */\n use(plugin, options = {}) {\n if (!plugin || typeof plugin.name !== 'string') {\n throw new TypeError('[AutumnNote] AutumnNote.use: plugin must have a string `name` property.');\n }\n if (_globalPlugins.has(plugin.name)) {\n console.warn(`[AutumnNote] Plugin \"${plugin.name}\" already registered globally. Skipping.`);\n return this;\n }\n if (Array.isArray(plugin.buttons)) {\n plugin.buttons.forEach((b) => registerButton(b));\n }\n _globalPlugins.set(plugin.name, { plugin, options });\n return this;\n },\n\n /**\n * Returns true if a plugin with the given name has been registered globally.\n * @param {string} name\n * @returns {boolean}\n */\n hasPlugin(name) { return _globalPlugins.has(name); },\n\n /**\n * Registers a single button definition in the global button registry.\n * After create(), call ctx.invoke('toolbar.rebuild') to render new buttons.\n * @param {object} btnDef - ButtonDef-compatible object with a `name` string\n * @returns {typeof AutumnNote}\n */\n registerButton(btnDef) { registerButton(btnDef); return this; },\n\n /**\n * Registers a locale so `lang: '<code>'` can select it.\n * Only English ships in the ESM bundle — import others from\n * `autumnnote/i18n/<code>` and register them here.\n * @param {string} code\n * @param {object} locale\n */\n registerLocale(code, locale) { registerLocale(code, locale); return this; },\n\n /** Registers a slash-menu command for future editor instances. */\n registerSlashCommand(command) {\n if (!command?.id || typeof command.run !== 'function') {\n throw new TypeError('[AutumnNote] Slash command requires an id and run(context) function.');\n }\n const commands = defaultOptions.slashCommands;\n const index = commands.findIndex((item) => item.id === command.id);\n if (index >= 0) commands[index] = command;\n else commands.push(command);\n return this;\n },\n\n /** All pre-built button definitions — accessible in every module format including UMD/CJS. */\n buttons,\n\n /** Library version */\n version: packageVersion,\n};\n\n// ---------------------------------------------------------------------------\n// Helper\n// ---------------------------------------------------------------------------\n\n/**\n * @param {string|Element|NodeList|Element[]} selector\n * @returns {Element[]}\n */\nfunction resolveElements(selector) {\n if (typeof selector === 'string') {\n return Array.from(document.querySelectorAll(selector));\n }\n if (selector instanceof Element) {\n return [selector];\n }\n if (selector instanceof NodeList || Array.isArray(selector)) {\n return /** @type {Element[]} */ (Array.from(selector));\n }\n return [];\n}\n\nexport default AutumnNote;\n","/**\n * core.js - Minimal entry point for AutumnNote (`autumnnote/core`).\n *\n * Same API as the default entry, but only the modules a usable editor needs:\n * typing, toolbar, status bar, paste handling and the placeholder. The dialogs,\n * floating tooltips, emoji and icon pickers and the crop overlay are not\n * imported at all, so a bundler leaves them out of the output rather than\n * shipping them switched off.\n *\n * import AutumnNote from 'autumnnote/core';\n * import 'autumnnote/dist/autumnnote.css'; // same stylesheet as the full build\n *\n * AutumnNote.create('#editor', {\n * toolbar: [['bold', 'italic', 'underline'], ['ul', 'ol']],\n * });\n *\n * Toolbar buttons whose module is absent still render, but invoking one logs a\n * warning and does nothing — give this preset a toolbar naming only buttons the\n * core modules serve, or use the default entry.\n */\n\n// The stylesheet is not imported here on purpose: it is identical to the full\n// build's and is already emitted as dist/autumnnote.css, which both entries\n// point consumers at. Importing it again would only duplicate ~8 KB gzip in the\n// package for no benefit.\nimport { setModuleDefs } from './Context.js';\nimport { CORE_MODULES } from './presets/core.js';\n\nsetModuleDefs(CORE_MODULES);\n\nexport * from './factory.js';\nexport { default } from './factory.js';\n"],"mappings":"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"}
|