@scrider/formatter 1.3.5 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/schema/Registry.ts","../src/schema/BlockHandlerRegistry.ts","../src/schema/blocks/table.ts","../src/conversion/sanitize.ts","../src/conversion/adapters/types.ts","../src/schema/blocks/footnotes.ts","../src/schema/blocks/alert.ts","../src/schema/blocks/columns.ts","../src/schema/blocks/box.ts","../src/schema/utils/color.ts","../src/schema/formats/inline/background.ts","../src/schema/formats/inline/bold.ts","../src/schema/formats/inline/code.ts","../src/schema/formats/inline/color.ts","../src/schema/formats/inline/font.ts","../src/schema/formats/inline/italic.ts","../src/schema/formats/inline/kbd.ts","../src/schema/formats/inline/link.ts","../src/schema/formats/inline/mark.ts","../src/schema/formats/inline/size.ts","../src/schema/formats/inline/strike.ts","../src/schema/formats/inline/subscript.ts","../src/schema/formats/inline/superscript.ts","../src/schema/formats/inline/underline.ts","../src/schema/formats/block/align.ts","../src/schema/formats/block/blockquote.ts","../src/schema/formats/block/code-block.ts","../src/schema/formats/block/header.ts","../src/schema/formats/block/header-id.ts","../src/schema/formats/block/indent.ts","../src/schema/formats/block/list.ts","../src/schema/formats/block/table-row.ts","../src/schema/formats/block/table-col.ts","../src/schema/formats/block/table-header.ts","../src/schema/formats/block/table-col-align.ts","../src/schema/formats/embed/block.ts","../src/conversion/html/config.ts","../src/schema/formats/embed/divider.ts","../src/schema/formats/embed/footnote-ref.ts","../src/schema/formats/embed/formula.ts","../src/schema/formats/embed/image.ts","../src/schema/formats/embed/soft-break.ts","../src/schema/formats/embed/video.ts","../src/schema/defaults.ts","../src/conversion/adapters/browser.ts","../src/conversion/adapters/node.ts","../src/conversion/adapters/index.ts","../src/conversion/html/delta-to-html.ts","../src/conversion/utils/slugify.ts","../src/conversion/html/document-presentation.ts","../src/conversion/html/table-presentation.ts","../src/conversion/html/html-to-delta.ts","../src/conversion/markdown/delta-to-markdown.ts","../src/conversion/markdown/config.ts","../src/conversion/markdown/markdown-to-delta.ts","../src/conversion/markdown/table-region.ts"],"sourcesContent":["/**\n * @scrider/formatter\n * Schema, conversion and block handlers for @scrider/delta\n */\n\n// Re-export Core (convenience — use one import for everything)\nexport * from '@scrider/delta';\n\n// Schema (Registry & Formats)\nexport type { Format, FormatDefinition, FormatMatchResult, FormatScope } from './schema';\nexport type { BlockHandler, BlockContext, BlockRenderOptions } from './schema';\nexport type { TableBlockData, CellData, CellAlign } from './schema';\nexport type { FootnotesBlockData } from './schema';\nexport type { AlertBlockData, AlertType } from './schema';\nexport type { ColumnsBlockData } from './schema';\nexport type { BoxBlockData, BoxFloat, BoxOverflow, BoxOpAttributes } from './schema';\nexport {\n ALERT_TYPES,\n BOX_FLOAT_VALUES,\n BOX_OVERFLOW_VALUES,\n BlockHandlerRegistry,\n createDefaultBlockHandlers,\n createDefaultRegistry,\n defaultBlockFormats,\n defaultEmbedFormats,\n defaultFormats,\n defaultInlineFormats,\n Registry,\n tableBlockHandler,\n footnotesBlockHandler,\n alertBlockHandler,\n columnsBlockHandler,\n boxBlockHandler,\n extractBoxOpAttributes,\n} from './schema';\n\n// Individual formats (for custom registries)\nexport {\n // Inline\n backgroundFormat,\n boldFormat,\n codeFormat,\n colorFormat,\n fontFormat,\n italicFormat,\n kbdFormat,\n linkFormat,\n markFormat,\n sizeFormat,\n strikeFormat,\n subscriptFormat,\n superscriptFormat,\n underlineFormat,\n // Block\n alignFormat,\n blockquoteFormat,\n codeBlockFormat,\n headerFormat,\n headerIdFormat,\n indentFormat,\n listFormat,\n tableRowFormat,\n tableColFormat,\n tableHeaderFormat,\n tableColAlignFormat,\n // Embed\n blockFormat,\n dividerFormat,\n footnoteRefFormat,\n formulaFormat,\n imageFormat,\n softBreakFormat,\n videoFormat,\n} from './schema';\nexport type { AlignType, ListType, TableColAlignType } from './schema';\n\n// Color utilities\nexport { getNamedColors, isValidColor, isValidHexColor, toHexColor } from './schema';\n\n// Conversion (DOM adapters)\nexport type {\n DeltaToHtmlOptions,\n TableCellAlign,\n TablePresentation,\n DocumentPresentation,\n ResolvedTablePresentation,\n ResolvedDocumentPresentation,\n DOMAdapter,\n DOMDocument,\n DOMDocumentFragment,\n DOMElement,\n DOMNode,\n DOMNodeList,\n HtmlToDeltaOptions,\n SanitizeOptions,\n DeltaToMarkdownOptions,\n MarkdownToDeltaOptions,\n} from './conversion';\nexport {\n BrowserDOMAdapter,\n browserAdapter,\n cloneDelta,\n deltaToHtml,\n resolveTablePresentation,\n resolveDocumentPresentation,\n documentPresentationStyleParts,\n isZebraBodyRow,\n escapeHtml,\n getAdapter,\n htmlToDelta,\n isAdapterAvailable,\n isElement,\n isTextNode,\n NODE_TYPE,\n NodeDOMAdapter,\n nodeAdapter,\n normalizeDelta,\n sanitizeDelta,\n unescapeHtml,\n validateDelta,\n // Markdown conversion\n deltaToMarkdown,\n markdownToDelta,\n markdownToDeltaSync,\n isRemarkAvailable,\n preloadRemark,\n // Simple-table region detection\n extractTableRegion,\n isTableNewlineOp,\n // Slugify utility\n slugify,\n slugifyWithDedup,\n} from './conversion';\nexport type { TableRegion } from './conversion';\n\n/**\n * Convenience alias for ops in a \"content\" Delta (a snapshot, not a change).\n *\n * `Op` is a discriminated union of `InsertOp | RetainOp | DeleteOp` — useful\n * when describing changes that the OT layer can apply or invert. However,\n * a Delta that represents document content (e.g. `state.delta` in an editor)\n * only ever contains insert ops. Use `ContentOp` to express that intent in\n * APIs and avoid repetitive narrowing via `isInsert()` / `'insert' in op`.\n */\nexport type { InsertOp as ContentOp } from '@scrider/delta';\n","import type { AttributeMap } from '@scrider/delta';\nimport type { Format, FormatScope } from './Format';\n\n/**\n * Registry of formats\n *\n * Manages a collection of Format definitions for validation,\n * normalization, and sanitization of Delta attributes.\n *\n * @example\n * ```typescript\n * const registry = new Registry()\n * .register(boldFormat)\n * .register(italicFormat)\n * .register(colorFormat);\n *\n * // Normalize attributes\n * registry.normalize({ color: 'red' });\n * // { color: '#ff0000' }\n *\n * // Validate attributes\n * registry.validate({ header: 3 }); // true\n * registry.validate({ header: 10 }); // false\n * ```\n */\nexport class Registry {\n private formats: Map<string, Format> = new Map();\n\n /**\n * Register a format or array of formats\n *\n * @param format - Format or array of formats to register\n * @returns this for chaining\n */\n register(format: Format): this;\n register(formats: Format[]): this;\n register(formatOrFormats: Format | Format[]): this {\n const formats = Array.isArray(formatOrFormats) ? formatOrFormats : [formatOrFormats];\n\n for (const format of formats) {\n if (this.formats.has(format.name)) {\n throw new Error(`Format \"${format.name}\" is already registered`);\n }\n this.formats.set(format.name, format);\n }\n\n return this;\n }\n\n /**\n * Get a format by name\n *\n * @param name - Format name\n * @returns Format or undefined if not found\n */\n get(name: string): Format | undefined {\n return this.formats.get(name);\n }\n\n /**\n * Check if a format is registered\n *\n * @param name - Format name\n * @returns true if format exists\n */\n has(name: string): boolean {\n return this.formats.has(name);\n }\n\n /**\n * Get all formats with a specific scope\n *\n * @param scope - Format scope to filter by\n * @returns Array of formats with the given scope\n */\n getByScope(scope: FormatScope): Format[] {\n const result: Format[] = [];\n for (const format of this.formats.values()) {\n if (format.scope === scope) {\n result.push(format);\n }\n }\n return result;\n }\n\n /**\n * Get all registered format names\n *\n * @returns Array of format names\n */\n getNames(): string[] {\n return Array.from(this.formats.keys());\n }\n\n /**\n * Normalize all attributes using registered formats\n *\n * Applies normalize() for each attribute that has a registered format.\n * Unknown attributes are passed through unchanged.\n *\n * @param attributes - Attributes to normalize\n * @returns New object with normalized attributes\n */\n normalize(attributes: AttributeMap | undefined): AttributeMap | undefined {\n if (!attributes) return undefined;\n\n const result: AttributeMap = {};\n let hasChanges = false;\n\n for (const [key, value] of Object.entries(attributes)) {\n const format = this.formats.get(key);\n\n if (format?.normalize) {\n const normalized = format.normalize(value);\n result[key] = normalized;\n if (normalized !== value) {\n hasChanges = true;\n }\n } else {\n result[key] = value;\n }\n }\n\n // Return original if no changes (optimization)\n return hasChanges ? result : attributes;\n }\n\n /**\n * Validate all attributes\n *\n * @param attributes - Attributes to validate\n * @returns true if all known attributes are valid\n */\n validate(attributes: AttributeMap | undefined): boolean {\n if (!attributes) return true;\n\n for (const [key, value] of Object.entries(attributes)) {\n const format = this.formats.get(key);\n\n if (format?.validate && !format.validate(value)) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Sanitize attributes by removing invalid values\n *\n * Removes attributes that:\n * - Are not registered (unknown formats)\n * - Fail validation\n *\n * @param attributes - Attributes to sanitize\n * @param removeUnknown - If true, remove unregistered attributes (default: true)\n * @returns New object with only valid attributes\n */\n sanitize(\n attributes: AttributeMap | undefined,\n removeUnknown: boolean = true,\n ): AttributeMap | undefined {\n if (!attributes) return undefined;\n\n const result: AttributeMap = {};\n let hasKeys = false;\n\n for (const [key, value] of Object.entries(attributes)) {\n const format = this.formats.get(key);\n\n // Skip unknown formats if removeUnknown is true\n if (!format && removeUnknown) {\n continue;\n }\n\n // Skip invalid values\n if (format?.validate && !format.validate(value)) {\n continue;\n }\n\n // Normalize if possible\n if (format?.normalize) {\n result[key] = format.normalize(value);\n } else {\n result[key] = value;\n }\n hasKeys = true;\n }\n\n return hasKeys ? result : undefined;\n }\n\n /**\n * Get the number of registered formats\n */\n get size(): number {\n return this.formats.size;\n }\n}\n","import type { BlockHandler } from './BlockHandler';\n\n/**\n * Registry for BlockHandler implementations.\n *\n * Separate from Registry (FormatRegistry) — different responsibilities:\n * - Registry: attribute validation/normalization (key-value pairs, primitives)\n * - BlockHandlerRegistry: block rendering/parsing (complex structures with nested Delta)\n *\n * Connected to converters via options:\n * ```typescript\n * deltaToHtml(delta, { registry, blockHandlers });\n * htmlToDelta(html, { registry, blockHandlers });\n * ```\n *\n * @example\n * ```typescript\n * const blockHandlers = new BlockHandlerRegistry()\n * .register(tableBlockHandler);\n *\n * deltaToHtml(delta, { registry, blockHandlers });\n * ```\n */\nexport class BlockHandlerRegistry {\n private handlers = new Map<string, BlockHandler>();\n\n /**\n * Register a block handler\n *\n * @param handler - BlockHandler to register\n * @returns this for chaining\n * @throws Error if handler with same type is already registered\n */\n register(handler: BlockHandler): this {\n if (this.handlers.has(handler.type)) {\n throw new Error(`BlockHandler \"${handler.type}\" is already registered`);\n }\n this.handlers.set(handler.type, handler);\n return this;\n }\n\n /**\n * Get a handler by block type\n *\n * @param type - Block type (e.g. \"table\")\n * @returns BlockHandler or undefined if not found\n */\n get(type: string): BlockHandler | undefined {\n return this.handlers.get(type);\n }\n\n /**\n * Check if a handler is registered for a block type\n *\n * @param type - Block type\n * @returns true if handler exists\n */\n has(type: string): boolean {\n return this.handlers.has(type);\n }\n\n /**\n * Get the number of registered handlers\n */\n get size(): number {\n return this.handlers.size;\n }\n\n /**\n * Get all registered block type names\n */\n getTypes(): string[] {\n return Array.from(this.handlers.keys());\n }\n}\n","import type { Op } from '@scrider/delta';\nimport { Delta } from '@scrider/delta';\nimport type { BlockContext, BlockHandler } from '../BlockHandler';\nimport type { Registry } from '../Registry';\nimport { normalizeDelta } from '../../conversion/sanitize';\nimport type { DOMElement } from '../../conversion/adapters/types';\nimport { isElement } from '../../conversion/adapters/types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Cell alignment options\n */\nexport type CellAlign = 'left' | 'center' | 'right';\n\n/**\n * Data for a single cell in an Extended Table.\n *\n * Every non-merged cell must have `ops` — a nested Delta (Op[]).\n * Empty cells use `{ ops: [{ insert: \"\\n\" }] }`.\n */\nexport interface CellData {\n /** Nested Delta content (full rich-text) */\n ops: Op[];\n /** Number of columns this cell spans (default: 1) */\n colspan?: number;\n /** Number of rows this cell spans (default: 1) */\n rowspan?: number;\n}\n\n/**\n * Extended Table block data.\n *\n * Stored in Delta as: `{ insert: { block: <TableBlockData> } }`\n *\n * All coordinates \"r:c\" within the grid MUST be present in `cells`.\n * - `CellData` — cell with content\n * - `null` — cell absorbed by neighbor's colspan/rowspan\n * - Missing key — INVALID (validate() rejects)\n */\nexport interface TableBlockData {\n /** Block type discriminator */\n type: 'table';\n /** Number of header rows (default: 0) */\n headerRows?: number;\n /** Column widths (percentages by default) */\n colWidths?: number[];\n /** Column alignments */\n colAligns?: (CellAlign | null)[];\n /** Cells indexed by \"row:col\" */\n cells: Record<string, CellData | null>;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\n/** Pattern for cell key: \"row:col\" where row and col are non-negative integers */\nconst CELL_KEY_RE = /^(\\d+):(\\d+)$/;\n\n/**\n * Parse cell key \"r:c\" into [row, col] or null if invalid.\n */\nfunction parseCellKey(key: string): [number, number] | null {\n const match = CELL_KEY_RE.exec(key);\n if (!match) return null;\n return [parseInt(match[1]!, 10), parseInt(match[2]!, 10)];\n}\n\n/**\n * Determine grid dimensions from cell keys.\n * Returns [rows, cols] or null if no valid keys.\n */\nfunction getGridDimensions(cells: Record<string, CellData | null>): [number, number] | null {\n let maxRow = -1;\n let maxCol = -1;\n\n for (const key of Object.keys(cells)) {\n const parsed = parseCellKey(key);\n if (!parsed) return null; // invalid key format\n const [r, c] = parsed;\n if (r > maxRow) maxRow = r;\n if (c > maxCol) maxCol = c;\n }\n\n if (maxRow < 0 || maxCol < 0) return null;\n return [maxRow + 1, maxCol + 1];\n}\n\n/**\n * Validate that a CellData has valid ops (non-empty array).\n */\nfunction isValidCellData(cell: CellData): boolean {\n return (\n typeof cell === 'object' &&\n cell !== null &&\n Array.isArray(cell.ops) &&\n cell.ops.length > 0 &&\n (cell.colspan === undefined || (Number.isInteger(cell.colspan) && cell.colspan >= 1)) &&\n (cell.rowspan === undefined || (Number.isInteger(cell.rowspan) && cell.rowspan >= 1))\n );\n}\n\n/**\n * Validate that merged (null) cells correspond to cells with colspan/rowspan.\n *\n * For each cell with colspan > 1 or rowspan > 1, all covered cells must be null.\n * Conversely, every null cell must be covered by exactly one spanning cell.\n */\nfunction validateMergedCells(\n cells: Record<string, CellData | null>,\n rows: number,\n cols: number,\n): boolean {\n // Track which cells are covered by a span\n const covered = new Set<string>();\n\n // First pass: collect all cells that should be covered by spans\n for (const [key, cell] of Object.entries(cells)) {\n if (cell === null) continue;\n\n const parsed = parseCellKey(key);\n if (!parsed) return false;\n const [r, c] = parsed;\n\n const cs = cell.colspan ?? 1;\n const rs = cell.rowspan ?? 1;\n\n // Check that span doesn't exceed grid\n if (r + rs > rows || c + cs > cols) return false;\n\n // Mark covered cells (excluding the source cell itself)\n for (let dr = 0; dr < rs; dr++) {\n for (let dc = 0; dc < cs; dc++) {\n if (dr === 0 && dc === 0) continue; // skip source\n const coveredKey = `${r + dr}:${c + dc}`;\n if (covered.has(coveredKey)) return false; // double coverage\n covered.add(coveredKey);\n }\n }\n }\n\n // Second pass: verify every null cell is covered, and no non-null cell is covered\n for (const [key, cell] of Object.entries(cells)) {\n if (cell === null) {\n if (!covered.has(key)) return false; // null but not covered\n } else {\n if (covered.has(key)) return false; // non-null but covered\n }\n }\n\n return true;\n}\n\n// ============================================================================\n// Rendering Helpers\n// ============================================================================\n\n/**\n * Render a single row of an Extended Table.\n */\nfunction renderExtendedRow(\n data: TableBlockData,\n row: number,\n cols: number,\n defaultCellTag: 'th' | 'td',\n context: BlockContext,\n pretty: boolean,\n): string {\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n let html = `${ind(2)}<tr>${nl}`;\n\n for (let c = 0; c < cols; c++) {\n const key = `${row}:${c}`;\n const cell = data.cells[key];\n\n // Skip null cells (covered by colspan/rowspan)\n if (cell === null) continue;\n\n // Skip if cell is undefined (shouldn't happen in valid data)\n if (cell === undefined) continue;\n\n const cellTag = row < (data.headerRows ?? 0) ? 'th' : defaultCellTag;\n const attrs: string[] = [];\n\n // colspan/rowspan attributes\n if (cell.colspan && cell.colspan > 1) {\n attrs.push(`colspan=\"${cell.colspan}\"`);\n }\n if (cell.rowspan && cell.rowspan > 1) {\n attrs.push(`rowspan=\"${cell.rowspan}\"`);\n }\n\n // Column alignment\n if (data.colAligns) {\n const align = data.colAligns[c];\n if (align && align !== 'left') {\n attrs.push(`style=\"text-align: ${align}\"`);\n }\n }\n\n const attrStr = attrs.length > 0 ? ' ' + attrs.join(' ') : '';\n\n // Render cell content via context.renderDelta (recursive)\n let content = '';\n if (context.renderDelta) {\n content = context.renderDelta(cell.ops);\n }\n\n html += `${ind(3)}<${cellTag}${attrStr}>${content}</${cellTag}>${nl}`;\n }\n\n html += `${ind(2)}</tr>${nl}`;\n return html;\n}\n\n// ============================================================================\n// GFM Markdown Helpers\n// ============================================================================\n\n/**\n * Check whether an Extended Table can be losslessly represented as\n * a GFM Markdown table (no colspan, rowspan, colWidths).\n */\nfunction isGfmCompatible(data: TableBlockData): boolean {\n // colWidths → not representable in GFM\n if (data.colWidths && data.colWidths.some((w) => w > 0)) {\n return false;\n }\n\n // Check cells for colspan/rowspan\n for (const cell of Object.values(data.cells)) {\n if (cell === null) return false; // null means merged — not GFM\n if (cell.colspan && cell.colspan > 1) return false;\n if (cell.rowspan && cell.rowspan > 1) return false;\n }\n\n return true;\n}\n\n/**\n * Strip trailing newlines from rendered Markdown cell content.\n * Cell ops always end with `\\n`, but we don't want that inside a table cell.\n */\nfunction stripCellContent(rendered: string): string {\n return rendered.replace(/\\n+$/, '').replace(/\\n/g, ' ');\n}\n\n/**\n * Render a GFM-compatible Extended Table as a Markdown table string.\n */\nfunction renderGfmTable(data: TableBlockData, context: BlockContext): string {\n const dims = getGridDimensions(data.cells);\n if (!dims) return '';\n const [rows, cols] = dims;\n\n const headerRows = data.headerRows ?? 0;\n const lines: string[] = [];\n\n // GFM requires a header row. If headerRows === 0, synthesize an empty one.\n if (headerRows === 0) {\n const emptyParts: string[] = [];\n for (let c = 0; c < cols; c++) {\n emptyParts.push(' ');\n }\n lines.push('| ' + emptyParts.join(' | ') + ' |');\n lines.push(renderGfmSeparator(cols, data.colAligns));\n }\n\n for (let r = 0; r < rows; r++) {\n const parts: string[] = [];\n for (let c = 0; c < cols; c++) {\n const cell = data.cells[`${r}:${c}`];\n let text = '';\n if (cell && context.renderDelta) {\n text = stripCellContent(context.renderDelta(cell.ops));\n }\n // Escape pipe characters inside cell content\n parts.push(text.replace(/\\|/g, '\\\\|'));\n }\n lines.push('| ' + parts.join(' | ') + ' |');\n\n // After header row(s), insert GFM separator\n if (headerRows > 0 && r === headerRows - 1) {\n lines.push(renderGfmSeparator(cols, data.colAligns));\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Render the GFM separator row: | --- | :---: | ---: |\n */\nfunction renderGfmSeparator(cols: number, colAligns?: (CellAlign | null)[]): string {\n const sepParts: string[] = [];\n for (let c = 0; c < cols; c++) {\n const align = colAligns?.[c];\n if (align === 'center') {\n sepParts.push(':---:');\n } else if (align === 'right') {\n sepParts.push('---:');\n } else if (align === 'left') {\n sepParts.push(':---');\n } else {\n sepParts.push('---');\n }\n }\n return '| ' + sepParts.join(' | ') + ' |';\n}\n\n// ============================================================================\n// Parsing Helpers (HTML → TableBlockData)\n// ============================================================================\n\n/**\n * Collect `<tr>` rows from a `<table>` element,\n * tracking which belong to `<thead>` (header rows).\n */\nfunction collectTableRows(table: DOMElement): { rows: DOMElement[]; headerRowCount: number } {\n const rows: DOMElement[] = [];\n let headerRowCount = 0;\n\n const children = table.childNodes;\n for (let i = 0; i < children.length; i++) {\n const section = children[i];\n if (!section || !isElement(section)) continue;\n\n const sectionTag = section.tagName.toLowerCase();\n\n if (sectionTag === 'thead' || sectionTag === 'tbody' || sectionTag === 'tfoot') {\n const isHeader = sectionTag === 'thead';\n const sectionChildren = section.childNodes;\n for (let j = 0; j < sectionChildren.length; j++) {\n const row = sectionChildren[j];\n if (!row || !isElement(row) || row.tagName.toLowerCase() !== 'tr') continue;\n rows.push(row);\n if (isHeader) headerRowCount++;\n }\n } else if (sectionTag === 'tr') {\n rows.push(section);\n }\n }\n\n return { rows, headerRowCount };\n}\n\n/**\n * Extract colWidths from `<colgroup>` → `<col>` elements.\n * Returns an array of widths or undefined if no `<colgroup>`.\n */\nfunction extractColWidths(table: DOMElement): number[] | undefined {\n const children = table.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child) || child.tagName.toLowerCase() !== 'colgroup') continue;\n\n const widths: number[] = [];\n const cols = child.childNodes;\n for (let j = 0; j < cols.length; j++) {\n const col = cols[j];\n if (!col || !isElement(col) || col.tagName.toLowerCase() !== 'col') continue;\n\n let width = 0;\n const style = col.getAttribute('style') || '';\n const widthMatch = style.match(/width:\\s*([\\d.]+)(%|px)/);\n if (widthMatch?.[1]) {\n width = parseFloat(widthMatch[1]);\n } else {\n const widthAttr = col.getAttribute('width');\n if (widthAttr) {\n width = parseFloat(widthAttr) || 0;\n }\n }\n widths.push(width);\n }\n\n if (widths.length > 0) return widths;\n }\n\n return undefined;\n}\n\n/**\n * Extract text-align from a cell element's style attribute.\n */\nfunction extractCellAlign(cell: DOMElement): CellAlign | null {\n const textAlign = cell.style?.textAlign || cell.style?.getPropertyValue?.('text-align');\n if (textAlign === 'left' || textAlign === 'center' || textAlign === 'right') {\n return textAlign;\n }\n\n // Fallback: parse style string directly\n const style = cell.getAttribute('style') || '';\n const match = style.match(/text-align:\\s*(left|center|right)/);\n if (match?.[1]) {\n return match[1] as CellAlign;\n }\n\n return null;\n}\n\n/**\n * Parse a `<table>` element into TableBlockData.\n *\n * Steps:\n * 1. Iterate `<thead>` → count headerRows\n * 2. Iterate `<tbody>` / direct `<tr>` → data rows\n * 3. For each `<td>`/`<th>`:\n * - Read colspan/rowspan from attributes\n * - `context.parseElement!(td)` → ops\n * - Fill null for merged cells\n * 4. Extract colWidths from `<col>` / style\n * 5. Extract colAligns from `style=\"text-align: ...\"` on first row cells\n * 6. Return `{ type: 'table', headerRows, colWidths, colAligns, cells }`\n */\nfunction parseTableElement(table: DOMElement, context: BlockContext): TableBlockData | null {\n const { rows, headerRowCount } = collectTableRows(table);\n if (rows.length === 0) return null;\n\n const cells: Record<string, CellData | null> = {};\n const colAligns: (CellAlign | null)[] = [];\n let maxCol = 0;\n let firstRowProcessed = false;\n\n // Track which grid positions are occupied by spanning cells\n const occupied = new Set<string>();\n\n for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {\n const row = rows[rowIdx]!;\n let colIdx = 0;\n const cellChildren = row.childNodes;\n\n for (let ci = 0; ci < cellChildren.length; ci++) {\n const cell = cellChildren[ci];\n if (!cell || !isElement(cell)) continue;\n const cellTag = cell.tagName.toLowerCase();\n if (cellTag !== 'td' && cellTag !== 'th') continue;\n\n // Skip occupied positions (from previous row/col spans)\n while (occupied.has(`${rowIdx}:${colIdx}`)) {\n colIdx++;\n }\n\n // Read colspan/rowspan\n const colspanAttr = cell.getAttribute('colspan');\n const rowspanAttr = cell.getAttribute('rowspan');\n const colspan = colspanAttr ? parseInt(colspanAttr, 10) || 1 : 1;\n const rowspan = rowspanAttr ? parseInt(rowspanAttr, 10) || 1 : 1;\n\n // Parse cell content via context.parseElement\n let ops: Op[];\n if (context.parseElement) {\n ops = context.parseElement(cell);\n if (ops.length === 0) {\n ops = [{ insert: '\\n' }];\n }\n } else {\n ops = [{ insert: '\\n' }];\n }\n\n // Build CellData\n const cellData: CellData = { ops };\n if (colspan > 1) cellData.colspan = colspan;\n if (rowspan > 1) cellData.rowspan = rowspan;\n\n cells[`${rowIdx}:${colIdx}`] = cellData;\n\n // Mark spanned positions as occupied + fill null\n for (let dr = 0; dr < rowspan; dr++) {\n for (let dc = 0; dc < colspan; dc++) {\n if (dr === 0 && dc === 0) continue;\n const coveredKey = `${rowIdx + dr}:${colIdx + dc}`;\n occupied.add(coveredKey);\n cells[coveredKey] = null;\n }\n }\n\n // Also mark positions in current row for multi-column\n for (let dc = 1; dc < colspan; dc++) {\n occupied.add(`${rowIdx}:${colIdx + dc}`);\n }\n\n // Collect column alignments from first data row\n if (!firstRowProcessed) {\n const align = extractCellAlign(cell);\n // Fill for colspan\n for (let dc = 0; dc < colspan; dc++) {\n colAligns.push(align);\n }\n }\n\n const cellEndCol = colIdx + colspan - 1;\n if (cellEndCol > maxCol) maxCol = cellEndCol;\n\n colIdx += colspan;\n }\n\n // Update maxCol for any remaining occupied positions\n while (occupied.has(`${rowIdx}:${colIdx}`)) {\n colIdx++;\n }\n if (colIdx - 1 > maxCol) maxCol = colIdx - 1;\n\n if (!firstRowProcessed) firstRowProcessed = true;\n }\n\n const totalCols = maxCol + 1;\n const totalRows = rows.length;\n\n // Ensure all grid positions are present (fill missing as empty cells)\n for (let r = 0; r < totalRows; r++) {\n for (let c = 0; c < totalCols; c++) {\n const key = `${r}:${c}`;\n if (!(key in cells)) {\n cells[key] = { ops: [{ insert: '\\n' }] };\n }\n }\n }\n\n // Build result\n const result: TableBlockData = {\n type: 'table',\n cells,\n };\n\n if (headerRowCount > 0) {\n result.headerRows = headerRowCount;\n }\n\n // Extract colWidths from <colgroup>\n const colWidths = extractColWidths(table);\n if (colWidths) {\n // Ensure colWidths has correct length\n while (colWidths.length < totalCols) colWidths.push(0);\n if (colWidths.length > totalCols) colWidths.length = totalCols;\n result.colWidths = colWidths;\n }\n\n // Add colAligns if any non-null\n if (colAligns.length > 0 && colAligns.some((a) => a !== null)) {\n // Ensure correct length\n while (colAligns.length < totalCols) colAligns.push(null);\n if (colAligns.length > totalCols) colAligns.length = totalCols;\n result.colAligns = colAligns;\n }\n\n return result;\n}\n\n// ============================================================================\n// TableBlockHandler\n// ============================================================================\n\n/**\n * BlockHandler implementation for Extended Table.\n *\n * Handles validation, HTML conversion, and nested Delta access.\n * toHtml/fromHtml are implemented in E.3/E.4 stages.\n */\nexport const tableBlockHandler: BlockHandler<TableBlockData> = {\n type: 'table',\n\n validate(data: TableBlockData): boolean {\n // 1. Type check\n if (!data || typeof data !== 'object' || data.type !== 'table') {\n return false;\n }\n\n // 2. Cells must be a non-empty object\n if (!data.cells || typeof data.cells !== 'object' || Array.isArray(data.cells)) {\n return false;\n }\n\n const cellKeys = Object.keys(data.cells);\n if (cellKeys.length === 0) return false;\n\n // 3. All keys must be valid \"r:c\" format\n for (const key of cellKeys) {\n if (!CELL_KEY_RE.test(key)) return false;\n }\n\n // 4. Determine grid dimensions\n const dims = getGridDimensions(data.cells);\n if (!dims) return false;\n const [rows, cols] = dims;\n\n // 5. All coordinates within grid must be present (no holes)\n if (cellKeys.length !== rows * cols) return false;\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n if (!(`${r}:${c}` in data.cells)) return false;\n }\n }\n\n // 6. Each non-null cell must have valid CellData\n for (const [, cell] of Object.entries(data.cells)) {\n if (cell !== null && !isValidCellData(cell)) return false;\n }\n\n // 7. Validate merged cells consistency\n if (!validateMergedCells(data.cells, rows, cols)) return false;\n\n // 8. headerRows validation\n if (data.headerRows !== undefined) {\n if (!Number.isInteger(data.headerRows) || data.headerRows < 0 || data.headerRows > rows) {\n return false;\n }\n }\n\n // 9. colWidths validation\n if (data.colWidths !== undefined) {\n if (!Array.isArray(data.colWidths) || data.colWidths.length !== cols) {\n return false;\n }\n for (const w of data.colWidths) {\n if (typeof w !== 'number' || w < 0) return false;\n }\n }\n\n // 10. colAligns validation\n if (data.colAligns !== undefined) {\n if (!Array.isArray(data.colAligns) || data.colAligns.length !== cols) {\n return false;\n }\n const validAligns: (string | null)[] = ['left', 'center', 'right', null];\n for (const a of data.colAligns) {\n if (!validAligns.includes(a)) return false;\n }\n }\n\n return true;\n },\n\n // ── Conversion ──────────────────────────────────────────────\n\n toHtml(data: TableBlockData, context: BlockContext): string {\n const pretty = context.options?.pretty ?? false;\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n // Determine grid dimensions from cells\n const dims = getGridDimensions(data.cells);\n if (!dims) return '';\n const [rows, cols] = dims;\n const headerRows = data.headerRows ?? 0;\n\n let html = `<table>${nl}`;\n\n // Render <colgroup> if colWidths specified\n if (data.colWidths && data.colWidths.length > 0) {\n const widthMode = context.options?.tableWidthMode ?? 'percent';\n html += `${ind(1)}<colgroup>${nl}`;\n for (let c = 0; c < cols; c++) {\n const w = data.colWidths[c];\n if (w !== undefined && w > 0) {\n const unit = widthMode === 'pixel' ? 'px' : '%';\n html += `${ind(2)}<col style=\"width: ${w}${unit}\">${nl}`;\n } else {\n html += `${ind(2)}<col>${nl}`;\n }\n }\n html += `${ind(1)}</colgroup>${nl}`;\n }\n\n // Render <thead> if headerRows > 0\n if (headerRows > 0) {\n html += `${ind(1)}<thead>${nl}`;\n for (let r = 0; r < headerRows; r++) {\n html += renderExtendedRow(data, r, cols, 'th', context, pretty);\n }\n html += `${ind(1)}</thead>${nl}`;\n }\n\n // Render <tbody>\n const bodyStart = headerRows;\n if (bodyStart < rows) {\n html += `${ind(1)}<tbody>${nl}`;\n for (let r = bodyStart; r < rows; r++) {\n html += renderExtendedRow(data, r, cols, 'td', context, pretty);\n }\n html += `${ind(1)}</tbody>${nl}`;\n }\n\n html += `</table>`;\n return html;\n },\n\n fromHtml(element: DOMElement, context: BlockContext): TableBlockData | null {\n return parseTableElement(element, context);\n },\n\n toMarkdown(data: TableBlockData, context: BlockContext): string | null {\n // If the table is GFM-compatible (no colspan/rowspan/colWidths),\n // render as native GFM Markdown table instead of HTML\n if (isGfmCompatible(data)) {\n return renderGfmTable(data, context);\n }\n // Extended Table features → null → fallback to HTML in Markdown\n return null;\n },\n\n // ── Normalize ─────────────────────────────────────────────\n\n normalize(data: TableBlockData, registry: Registry): TableBlockData {\n const newCells: Record<string, CellData | null> = {};\n let changed = false;\n\n for (const [key, cell] of Object.entries(data.cells)) {\n if (cell !== null) {\n const normalized = normalizeDelta(new Delta(cell.ops), registry);\n if (normalized.ops !== cell.ops) {\n newCells[key] = { ...cell, ops: normalized.ops };\n changed = true;\n } else {\n newCells[key] = cell;\n }\n } else {\n newCells[key] = null;\n }\n }\n\n return changed ? { ...data, cells: newCells } : data;\n },\n\n // ── Nested Deltas ──────────────────────────────────────────\n\n getNestedDeltas(data: TableBlockData): Op[][] {\n const deltas: Op[][] = [];\n for (const cell of Object.values(data.cells)) {\n if (cell !== null) {\n deltas.push(cell.ops);\n }\n }\n return deltas;\n },\n\n setNestedDeltas(data: TableBlockData, deltas: Op[][]): TableBlockData {\n const newCells: Record<string, CellData | null> = {};\n let idx = 0;\n for (const [key, cell] of Object.entries(data.cells)) {\n if (cell !== null) {\n newCells[key] = { ...cell, ops: deltas[idx++]! };\n } else {\n newCells[key] = null;\n }\n }\n return { ...data, cells: newCells };\n },\n};\n","/**\n * Delta Sanitization\n *\n * Cleans Delta by removing unknown attributes, validating values,\n * and normalizing through Registry.\n */\n\nimport { Delta, isInsert, isRetain, isEmbedInsert, deepClone } from '@scrider/delta';\nimport type { Op, AttributeMap } from '@scrider/delta';\nimport type { Registry } from '../schema/Registry';\n\n/**\n * Options for sanitizeDelta\n */\nexport interface SanitizeOptions {\n /**\n * Remove attributes not registered in the registry\n * @default true\n */\n removeUnknown?: boolean;\n\n /**\n * Normalize attribute values (e.g., color: 'red' → '#ff0000')\n * @default true\n */\n normalize?: boolean;\n\n /**\n * Remove operations with invalid embed values\n * @default false\n */\n removeInvalidEmbeds?: boolean;\n\n /**\n * List of embed types that are allowed (if not set, all registered are allowed)\n */\n allowedEmbeds?: string[];\n}\n\nconst DEFAULT_OPTIONS: Required<SanitizeOptions> = {\n removeUnknown: true,\n normalize: true,\n removeInvalidEmbeds: false,\n allowedEmbeds: [],\n};\n\n/**\n * Sanitize a Delta using a Registry\n *\n * Performs the following operations:\n * 1. Removes attributes not registered in the registry (if removeUnknown=true)\n * 2. Removes attributes with invalid values\n * 3. Normalizes attribute values (if normalize=true)\n * 4. Optionally removes invalid embed operations\n *\n * @param delta - The Delta to sanitize\n * @param registry - The Registry to use for validation/normalization\n * @param options - Sanitization options\n * @returns A new sanitized Delta\n *\n * @example\n * ```typescript\n * const registry = createDefaultRegistry();\n * const dirty = new Delta()\n * .insert('Hello', { bold: true, unknown: 'value', color: 'red' })\n * .insert('\\n');\n *\n * const clean = sanitizeDelta(dirty, registry);\n * // { bold: true, color: '#ff0000' } - unknown removed, color normalized\n * ```\n */\nexport function sanitizeDelta(\n delta: Delta,\n registry: Registry,\n options: SanitizeOptions = {},\n): Delta {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const result = new Delta();\n\n for (const op of delta.ops) {\n const sanitizedOp = sanitizeOp(op, registry, opts);\n\n if (sanitizedOp !== null) {\n result.push(sanitizedOp);\n }\n }\n\n return result;\n}\n\n/**\n * Sanitize a single operation\n *\n * @returns Sanitized op, or null if the op should be removed\n */\nfunction sanitizeOp(op: Op, registry: Registry, options: Required<SanitizeOptions>): Op | null {\n // Handle insert operations\n if (isInsert(op)) {\n // Check embed validity\n if (isEmbedInsert(op)) {\n const embedValue = op.insert as Record<string, unknown>;\n const embedType = Object.keys(embedValue)[0];\n\n // Check if embed has a valid type\n if (!embedType) {\n return options.removeInvalidEmbeds ? null : op;\n }\n\n // Check if embed type is allowed\n if (options.allowedEmbeds.length > 0) {\n if (!options.allowedEmbeds.includes(embedType)) {\n return options.removeInvalidEmbeds ? null : op;\n }\n }\n\n // Check if embed type is registered\n if (!registry.has(embedType)) {\n return options.removeInvalidEmbeds ? null : op;\n }\n\n // Validate embed value\n const format = registry.get(embedType);\n if (format?.validate && !format.validate(embedValue[embedType])) {\n return options.removeInvalidEmbeds ? null : op;\n }\n }\n\n // Sanitize attributes\n const sanitizedAttrs = sanitizeAttributes(op.attributes, registry, options);\n\n // Return new op with sanitized attributes\n if (sanitizedAttrs === op.attributes) {\n return op; // No changes\n }\n\n const newOp: Op = { insert: op.insert };\n if (sanitizedAttrs !== undefined) {\n newOp.attributes = sanitizedAttrs;\n }\n\n return newOp;\n }\n\n // Handle retain operations\n if (isRetain(op)) {\n const sanitizedAttrs = sanitizeAttributes(op.attributes, registry, options);\n\n if (sanitizedAttrs === op.attributes) {\n return op; // No changes\n }\n\n const newOp: Op = { retain: op.retain };\n if (sanitizedAttrs !== undefined) {\n newOp.attributes = sanitizedAttrs;\n }\n\n return newOp;\n }\n\n // Delete operations pass through unchanged\n return op;\n}\n\n/**\n * Sanitize attributes using registry\n */\nfunction sanitizeAttributes(\n attributes: AttributeMap | undefined,\n registry: Registry,\n options: Required<SanitizeOptions>,\n): AttributeMap | undefined {\n if (!attributes) {\n return undefined;\n }\n\n let result: AttributeMap | undefined;\n let hasChanges = false;\n\n for (const [key, value] of Object.entries(attributes)) {\n const format = registry.get(key);\n\n // Remove unknown attributes\n if (!format && options.removeUnknown) {\n hasChanges = true;\n continue;\n }\n\n // Skip invalid values\n if (format?.validate && !format.validate(value)) {\n hasChanges = true;\n continue;\n }\n\n // Initialize result if we're keeping this attribute\n if (!result) {\n result = {};\n }\n\n // Normalize or keep as-is\n if (format?.normalize && options.normalize) {\n const normalized = format.normalize(value);\n result[key] = normalized;\n if (normalized !== value) {\n hasChanges = true;\n }\n } else {\n result[key] = value;\n }\n }\n\n // Return original if no changes (optimization)\n if (!hasChanges) {\n return attributes;\n }\n\n // Return undefined if all attributes were removed\n return result && Object.keys(result).length > 0 ? result : undefined;\n}\n\n/**\n * Normalize a Delta's attributes without removing anything\n *\n * This is a lighter operation that only normalizes values,\n * without removing unknown or invalid attributes.\n *\n * @param delta - The Delta to normalize\n * @param registry - The Registry to use for normalization\n * @returns A new Delta with normalized attributes\n */\nexport function normalizeDelta(delta: Delta, registry: Registry): Delta {\n return sanitizeDelta(delta, registry, {\n removeUnknown: false,\n normalize: true,\n removeInvalidEmbeds: false,\n });\n}\n\n/**\n * Validate a Delta against a Registry\n *\n * @param delta - The Delta to validate\n * @param registry - The Registry to use for validation\n * @returns true if all attributes in the Delta are valid\n */\nexport function validateDelta(delta: Delta, registry: Registry): boolean {\n for (const op of delta.ops) {\n // Check embeds\n if (isInsert(op) && isEmbedInsert(op)) {\n const embedValue = op.insert as Record<string, unknown>;\n const embedType = Object.keys(embedValue)[0];\n\n // Check if embed has a valid type\n if (!embedType) {\n return false;\n }\n\n // Check if embed type is registered\n if (!registry.has(embedType)) {\n return false;\n }\n\n // Validate embed value\n const format = registry.get(embedType);\n if (format?.validate && !format.validate(embedValue[embedType])) {\n return false;\n }\n }\n\n // Validate attributes (only InsertOp and RetainOp have attributes)\n if ('attributes' in op && op.attributes) {\n if (!registry.validate(op.attributes)) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * Deep clone a Delta\n *\n * @param delta - The Delta to clone\n * @returns A new Delta with cloned ops\n */\nexport function cloneDelta(delta: Delta): Delta {\n return new Delta(deepClone(delta.ops));\n}\n","/**\n * DOM Adapter Interface\n *\n * Provides a unified interface for DOM operations across different environments:\n * - Browser: uses native DOM APIs\n * - Node.js: uses jsdom\n *\n * This abstraction allows the same conversion code to work in both environments.\n */\n\n/**\n * Minimal Document interface required for HTML parsing/rendering\n */\nexport interface DOMDocument {\n createElement(tagName: string): DOMElement;\n createTextNode(text: string): DOMNode;\n createDocumentFragment(): DOMDocumentFragment;\n readonly body: DOMElement;\n}\n\n/**\n * Minimal DocumentFragment interface\n */\nexport interface DOMDocumentFragment {\n appendChild(node: DOMNode): DOMNode;\n readonly childNodes: DOMNodeList;\n readonly firstChild: DOMNode | null;\n readonly nodeType: number;\n readonly textContent: string | null;\n}\n\n/**\n * Minimal Node interface\n */\nexport interface DOMNode {\n readonly nodeType: number;\n readonly nodeName: string;\n readonly parentNode: DOMNode | null;\n readonly childNodes: DOMNodeList;\n readonly firstChild: DOMNode | null;\n readonly nextSibling: DOMNode | null;\n textContent: string | null;\n appendChild(node: DOMNode): DOMNode;\n cloneNode(deep?: boolean): DOMNode;\n}\n\n/**\n * Minimal Element interface\n */\nexport interface DOMElement extends DOMNode {\n readonly tagName: string;\n innerHTML: string;\n outerHTML: string;\n getAttribute(name: string): string | null;\n setAttribute(name: string, value: string): void;\n hasAttribute(name: string): boolean;\n removeAttribute(name: string): void;\n readonly style: DOMCSSStyleDeclaration;\n readonly classList: DOMTokenList;\n querySelector(selector: string): DOMElement | null;\n querySelectorAll(selector: string): DOMNodeList;\n}\n\n/**\n * Minimal CSSStyleDeclaration interface\n */\nexport interface DOMCSSStyleDeclaration {\n getPropertyValue(property: string): string;\n setProperty(property: string, value: string): void;\n // Common CSS properties\n color?: string;\n backgroundColor?: string;\n fontFamily?: string;\n fontSize?: string;\n fontWeight?: string;\n fontStyle?: string;\n textDecoration?: string;\n textAlign?: string;\n}\n\n/**\n * Minimal DOMTokenList interface (for classList)\n */\nexport interface DOMTokenList {\n add(...tokens: string[]): void;\n remove(...tokens: string[]): void;\n contains(token: string): boolean;\n readonly length: number;\n}\n\n/**\n * Minimal NodeList interface\n */\nexport interface DOMNodeList {\n readonly length: number;\n item(index: number): DOMNode | null;\n [index: number]: DOMNode;\n forEach(callback: (node: DOMNode, index: number) => void): void;\n}\n\n/**\n * Node type constants\n */\nexport const NODE_TYPE = {\n ELEMENT_NODE: 1,\n TEXT_NODE: 3,\n DOCUMENT_NODE: 9,\n DOCUMENT_FRAGMENT_NODE: 11,\n} as const;\n\n/**\n * DOM Adapter interface\n *\n * Provides methods for creating and manipulating DOM structures\n * in a platform-agnostic way.\n */\nexport interface DOMAdapter {\n /**\n * Parse HTML string into a document fragment\n */\n parseHTML(html: string): DOMDocumentFragment;\n\n /**\n * Serialize a node to HTML string\n */\n serializeHTML(node: DOMNode | DOMDocumentFragment): string;\n\n /**\n * Create a new document for building DOM structures\n */\n createDocument(): DOMDocument;\n\n /**\n * Check if this adapter is available in the current environment\n */\n isAvailable(): boolean;\n}\n\n/**\n * Type guard: check if node is an Element\n */\nexport function isElement(node: DOMNode): node is DOMElement {\n return node.nodeType === NODE_TYPE.ELEMENT_NODE;\n}\n\n/**\n * Type guard: check if node is a Text node\n */\nexport function isTextNode(node: DOMNode): boolean {\n return node.nodeType === NODE_TYPE.TEXT_NODE;\n}\n","import type { Op } from '@scrider/delta';\nimport { isTextInsert, Delta } from '@scrider/delta';\nimport type { BlockContext, BlockHandler } from '../BlockHandler';\nimport type { Registry } from '../Registry';\nimport { normalizeDelta } from '../../conversion/sanitize';\nimport type { DOMElement } from '../../conversion/adapters/types';\nimport { isElement } from '../../conversion/adapters/types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Footnotes block data — a collection of footnote definitions.\n *\n * Stored in Delta as: `{ insert: { block: <FootnotesBlockData> } }`\n *\n * Each note is keyed by its string identifier (e.g. \"1\", \"note\", \"my-ref\").\n * Values contain nested Delta content (rich-text).\n *\n * Placed at the end of the document, after all content.\n */\nexport interface FootnotesBlockData {\n /** Block type discriminator */\n type: 'footnotes';\n /** Map of footnote id → content (nested Delta ops) */\n notes: Record<string, { ops: Op[] }>;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\n/**\n * Validate that a note entry has valid ops (non-empty array).\n */\nfunction isValidNoteData(note: { ops: Op[] }): boolean {\n return (\n typeof note === 'object' && note !== null && Array.isArray(note.ops) && note.ops.length > 0\n );\n}\n\n// ============================================================================\n// Rendering Helpers\n// ============================================================================\n\n// ============================================================================\n// Parsing Helpers (HTML → FootnotesBlockData)\n// ============================================================================\n\n/**\n * Extract footnote id from an element's `id` attribute.\n * Expects format: \"fn-{id}\" → returns \"{id}\"\n */\nfunction extractFootnoteId(element: DOMElement): string | null {\n const id = element.getAttribute('id') || '';\n if (id.startsWith('fn-')) {\n return id.slice(3);\n }\n return null;\n}\n\n// ============================================================================\n// FootnotesBlockHandler\n// ============================================================================\n\n/**\n * BlockHandler implementation for Footnotes.\n *\n * Handles a single block embed containing all footnote definitions.\n * Each footnote has an id and nested Delta content.\n *\n * HTML: <section class=\"footnotes\"><ol><li id=\"fn-{id}\">...</li></ol></section>\n * Markdown: [^id]: content\n */\nexport const footnotesBlockHandler: BlockHandler<FootnotesBlockData> = {\n type: 'footnotes',\n\n validate(data: FootnotesBlockData): boolean {\n // 1. Type check\n if (!data || typeof data !== 'object' || data.type !== 'footnotes') {\n return false;\n }\n\n // 2. Notes must be a non-empty object\n if (!data.notes || typeof data.notes !== 'object' || Array.isArray(data.notes)) {\n return false;\n }\n\n const noteIds = Object.keys(data.notes);\n if (noteIds.length === 0) return false;\n\n // 3. All keys must be non-empty strings\n for (const id of noteIds) {\n if (typeof id !== 'string' || id.trim().length === 0) return false;\n }\n\n // 4. All values must have valid ops\n for (const note of Object.values(data.notes)) {\n if (!isValidNoteData(note)) return false;\n }\n\n return true;\n },\n\n // ── Conversion ──────────────────────────────────────────────\n\n toHtml(data: FootnotesBlockData, context: BlockContext): string {\n const pretty = context.options?.pretty ?? false;\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n const noteEntries = Object.entries(data.notes);\n if (noteEntries.length === 0) return '';\n\n let html = `<section class=\"footnotes\">${nl}`;\n html += `${ind(1)}<ol>${nl}`;\n\n for (const [id, note] of noteEntries) {\n html += `${ind(2)}<li id=\"fn-${id}\">${nl}`;\n\n // Render nested Delta content\n let content = '';\n if (context.renderDelta) {\n content = context.renderDelta(note.ops);\n }\n\n // Insert backref link inline at the end of the last <p> (before </p>)\n const backref = ` <a href=\"#fnref-${id}\" class=\"footnote-backref\">\\u21a9</a>`;\n const lastPClose = content.lastIndexOf('</p>');\n if (lastPClose !== -1) {\n content = content.slice(0, lastPClose) + backref + content.slice(lastPClose);\n } else {\n content += backref;\n }\n\n html += `${ind(3)}${content}${nl}`;\n\n html += `${ind(2)}</li>${nl}`;\n }\n\n html += `${ind(1)}</ol>${nl}`;\n html += `</section>`;\n return html;\n },\n\n fromHtml(element: DOMElement, context: BlockContext): FootnotesBlockData | null {\n // Expect <section class=\"footnotes\"> or <div class=\"footnotes\">\n const tag = element.tagName.toLowerCase();\n if (tag !== 'section' && tag !== 'div') return null;\n\n const className = element.getAttribute('class') || '';\n if (!className.includes('footnotes')) return null;\n\n // Find <ol> inside\n let ol: DOMElement | null = null;\n const children = element.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child && isElement(child) && child.tagName.toLowerCase() === 'ol') {\n ol = child;\n break;\n }\n }\n\n if (!ol) return null;\n\n const notes: Record<string, { ops: Op[] }> = {};\n\n // Parse each <li>\n const liChildren = ol.childNodes;\n for (let i = 0; i < liChildren.length; i++) {\n const li = liChildren[i];\n if (!li || !isElement(li) || li.tagName.toLowerCase() !== 'li') continue;\n\n const id = extractFootnoteId(li);\n if (!id) continue;\n\n // Parse content via context.parseElement, then clean up backref artifacts\n let ops: Op[];\n if (context.parseElement) {\n ops = context.parseElement(li);\n\n // Clean up: remove backref arrow \"↩\" that the <a class=\"footnote-backref\"> produces\n ops = ops\n .map((op) => {\n if (isTextInsert(op) && op.insert.includes('\\u21a9')) {\n return { ...op, insert: op.insert.replace(/\\u21a9/g, '') };\n }\n return op;\n })\n .filter((op) => !isTextInsert(op) || op.insert !== '');\n\n if (ops.length === 0) {\n ops = [{ insert: '\\n' }];\n }\n } else {\n ops = [{ insert: '\\n' }];\n }\n\n notes[id] = { ops };\n }\n\n if (Object.keys(notes).length === 0) return null;\n\n return { type: 'footnotes', notes };\n },\n\n toMarkdown(data: FootnotesBlockData, context: BlockContext): string | null {\n const noteEntries = Object.entries(data.notes);\n if (noteEntries.length === 0) return null;\n\n const lines: string[] = [];\n for (const [id, note] of noteEntries) {\n // context.renderDelta produces Markdown when called from deltaToMarkdown,\n // or HTML when called from deltaToHtml — either way, use the output directly.\n // For multi-paragraph footnotes, continuation lines need 4-space indent (GFM convention).\n let content: string;\n if (context.renderDelta) {\n content = context.renderDelta(note.ops).trim();\n } else {\n content = '';\n }\n\n // First line: [^id]: content\n // Continuation: indented by 4 spaces\n const contentLines = content.split('\\n');\n const indented = contentLines\n .map((line, idx) => (idx === 0 ? `[^${id}]: ${line}` : ` ${line}`))\n .join('\\n');\n lines.push(indented);\n }\n\n return '\\n' + lines.join('\\n\\n');\n },\n\n // ── Normalize ─────────────────────────────────────────────\n\n normalize(data: FootnotesBlockData, registry: Registry): FootnotesBlockData {\n const newNotes: Record<string, { ops: Op[] }> = {};\n let changed = false;\n\n for (const [id, note] of Object.entries(data.notes)) {\n const normalized = normalizeDelta(new Delta(note.ops), registry);\n if (normalized.ops !== note.ops) {\n newNotes[id] = { ops: normalized.ops };\n changed = true;\n } else {\n newNotes[id] = note;\n }\n }\n\n return changed ? { ...data, notes: newNotes } : data;\n },\n\n // ── Nested Deltas ──────────────────────────────────────────\n\n getNestedDeltas(data: FootnotesBlockData): Op[][] {\n return Object.values(data.notes).map((note) => note.ops);\n },\n\n setNestedDeltas(data: FootnotesBlockData, deltas: Op[][]): FootnotesBlockData {\n const ids = Object.keys(data.notes);\n const newNotes: Record<string, { ops: Op[] }> = {};\n ids.forEach((id, i) => {\n newNotes[id] = { ops: deltas[i]! };\n });\n return { ...data, notes: newNotes };\n },\n};\n","import type { Op } from '@scrider/delta';\nimport { Delta } from '@scrider/delta';\nimport type { BlockContext, BlockHandler } from '../BlockHandler';\nimport type { Registry } from '../Registry';\nimport { normalizeDelta } from '../../conversion/sanitize';\nimport type { DOMElement } from '../../conversion/adapters/types';\nimport { isElement } from '../../conversion/adapters/types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** The 5 standard GitHub alert types */\nexport const ALERT_TYPES = ['note', 'tip', 'important', 'warning', 'caution'] as const;\n\n/** Union of valid alert types */\nexport type AlertType = (typeof ALERT_TYPES)[number];\n\n/**\n * Alert / Admonition block data.\n *\n * Stored in Delta as: `{ insert: { block: <AlertBlockData> } }`\n *\n * GitHub-style alerts:\n * ```markdown\n * > [!NOTE]\n * > Useful information.\n * ```\n *\n * HTML:\n * ```html\n * <div class=\"markdown-alert markdown-alert-note\">\n * <p class=\"markdown-alert-title\">Note</p>\n * <p>Useful information.</p>\n * </div>\n * ```\n */\nexport interface AlertBlockData {\n /** Block type discriminator */\n type: 'alert';\n /** Alert variant (note, tip, important, warning, caution) */\n alertType: AlertType;\n /** Nested Delta content (rich text) */\n content: { ops: Op[] };\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Check if a string is a valid alert type */\nfunction isAlertType(value: string): value is AlertType {\n return ALERT_TYPES.includes(value as AlertType);\n}\n\n/** Capitalize first letter: \"note\" → \"Note\" */\nfunction capitalize(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n// ============================================================================\n// AlertBlockHandler\n// ============================================================================\n\n/**\n * BlockHandler implementation for Alerts / Admonitions.\n *\n * Handles GitHub-style alerts (5 types: note, tip, important, warning, caution).\n * Each alert contains nested Delta content (rich text).\n *\n * HTML: `<div class=\"markdown-alert markdown-alert-{type}\"><p class=\"markdown-alert-title\">{Type}</p>...</div>`\n * Markdown: `> [!TYPE]\\n> content`\n */\nexport const alertBlockHandler: BlockHandler<AlertBlockData> = {\n type: 'alert',\n\n validate(data: AlertBlockData): boolean {\n if (!data || typeof data !== 'object' || data.type !== 'alert') {\n return false;\n }\n\n if (typeof data.alertType !== 'string' || !isAlertType(data.alertType)) {\n return false;\n }\n\n if (\n !data.content ||\n typeof data.content !== 'object' ||\n !Array.isArray(data.content.ops) ||\n data.content.ops.length === 0\n ) {\n return false;\n }\n\n return true;\n },\n\n // ── Conversion ──────────────────────────────────────────────\n\n toHtml(data: AlertBlockData, context: BlockContext): string {\n const pretty = context.options?.pretty ?? false;\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n const alertClass = `markdown-alert markdown-alert-${data.alertType}`;\n const title = capitalize(data.alertType);\n\n let html = `<div class=\"${alertClass}\">${nl}`;\n html += `${ind(1)}<p class=\"markdown-alert-title\">${title}</p>${nl}`;\n\n // Render nested Delta content\n if (context.renderDelta) {\n html += `${ind(1)}${context.renderDelta(data.content.ops)}${nl}`;\n }\n\n html += `</div>`;\n return html;\n },\n\n fromHtml(element: DOMElement, context: BlockContext): AlertBlockData | null {\n const tag = element.tagName.toLowerCase();\n if (tag !== 'div' && tag !== 'section') return null;\n\n const className = element.getAttribute('class') || '';\n if (!className.includes('markdown-alert')) return null;\n\n // Extract alert type from class: \"markdown-alert-note\" → \"note\"\n let alertType: AlertType = 'note';\n for (const t of ALERT_TYPES) {\n if (className.includes(`markdown-alert-${t}`)) {\n alertType = t;\n break;\n }\n }\n\n // Parse children, skipping the title <p class=\"markdown-alert-title\">\n let ops: Op[] = [];\n\n const children = element.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child)) continue;\n\n // Skip the title paragraph\n const childClass = child.getAttribute('class') || '';\n if (childClass.includes('markdown-alert-title')) continue;\n\n // Parse content elements\n if (context.parseElement) {\n const parsed = context.parseElement(child);\n ops = ops.concat(parsed);\n }\n }\n\n if (ops.length === 0) {\n ops = [{ insert: '\\n' }];\n }\n\n return {\n type: 'alert',\n alertType,\n content: { ops },\n };\n },\n\n toMarkdown(data: AlertBlockData, context: BlockContext): string | null {\n // > [!NOTE]\n // > content line 1\n // > content line 2\n const tag = `[!${data.alertType.toUpperCase()}]`;\n\n let contentMd = '';\n if (context.renderDelta) {\n // renderDelta produces Markdown when called from deltaToMarkdown\n contentMd = context.renderDelta(data.content.ops);\n }\n\n // Prefix each line with \"> \"\n const lines = contentMd.split('\\n');\n // Remove trailing empty line if present\n while (lines.length > 0 && (lines[lines.length - 1] ?? '').trim() === '') {\n lines.pop();\n }\n\n const prefixed = lines.map((line) => `> ${line}`).join('\\n');\n return `> ${tag}\\n${prefixed}`;\n },\n\n // ── Normalization ──────────────────────────────────────────\n\n normalize(data: AlertBlockData, registry: Registry): AlertBlockData {\n const normalized = normalizeDelta(new Delta(data.content.ops), registry);\n return {\n ...data,\n content: { ops: normalized.ops },\n };\n },\n\n // ── Nested Deltas ──────────────────────────────────────────\n\n getNestedDeltas(data: AlertBlockData): Op[][] {\n return [data.content.ops];\n },\n\n setNestedDeltas(data: AlertBlockData, deltas: Op[][]): AlertBlockData {\n const first = deltas[0];\n if (!first) return data;\n return {\n ...data,\n content: { ops: first },\n };\n },\n};\n","import type { Op } from '@scrider/delta';\nimport { Delta } from '@scrider/delta';\nimport type { BlockContext, BlockHandler } from '../BlockHandler';\nimport type { Registry } from '../Registry';\nimport { normalizeDelta } from '../../conversion/sanitize';\nimport type { DOMElement } from '../../conversion/adapters/types';\nimport { isElement } from '../../conversion/adapters/types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Columns Layout block data.\n *\n * Stored in Delta as: `{ insert: { block: <ColumnsBlockData> } }`\n *\n * Each column contains a full nested Delta (rich text, embeds, nested blocks).\n *\n * HTML:\n * ```html\n * <div class=\"columns columns-2\">\n * <div class=\"column\"><p>Column 1</p></div>\n * <div class=\"column\"><p>Column 2</p></div>\n * </div>\n * ```\n *\n * With custom widths:\n * ```html\n * <div class=\"columns columns-2\" style=\"grid-template-columns: 30% 70%\">\n * <div class=\"column\"><p>Sidebar</p></div>\n * <div class=\"column\"><p>Main content</p></div>\n * </div>\n * ```\n *\n * Markdown: no native equivalent → toMarkdown returns null → HTML fallback.\n *\n * Resize-ready: `widths` for per-column resize (future scrider-editor),\n * `width`/`height` in op attributes for overall dimensions.\n */\nexport interface ColumnsBlockData {\n /** Block type discriminator */\n type: 'columns';\n /** Column contents — array of nested Deltas */\n columns: { ops: Op[] }[];\n /** Optional: column widths in percent (sum ≈ 100). Default: equal (CSS 1fr each) */\n widths?: number[];\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Tolerance for widths sum validation (allows rounding: e.g. 33.33 + 33.33 + 33.34 = 100) */\nconst WIDTHS_SUM_TOLERANCE = 1;\n\n// ============================================================================\n// ColumnsBlockHandler\n// ============================================================================\n\n/**\n * BlockHandler implementation for Columns Layout.\n *\n * Multi-column layout with nested Delta content in each column.\n * Analogous to Alert (nested Delta) but with an array of columns.\n *\n * HTML: `<div class=\"columns columns-N\" [style=\"grid-template-columns: W1% W2%\"]>\n * <div class=\"column\">...</div>...\n * </div>`\n * Markdown: no equivalent → toMarkdown returns null → HTML fallback\n */\nexport const columnsBlockHandler: BlockHandler<ColumnsBlockData> = {\n type: 'columns',\n\n validate(data: ColumnsBlockData): boolean {\n if (!data || typeof data !== 'object' || data.type !== 'columns') {\n return false;\n }\n\n // columns must be an array with at least 2 elements\n // (1 column = Inline-Box pattern, use \"box\" block type instead)\n if (!Array.isArray(data.columns) || data.columns.length < 2) {\n return false;\n }\n\n // Each column must have non-empty ops\n for (const col of data.columns) {\n if (!col || typeof col !== 'object' || !Array.isArray(col.ops) || col.ops.length === 0) {\n return false;\n }\n }\n\n // widths validation (if provided)\n if (data.widths !== undefined) {\n if (!Array.isArray(data.widths)) {\n return false;\n }\n\n // Length must match columns\n if (data.widths.length !== data.columns.length) {\n return false;\n }\n\n // All values must be positive numbers\n for (const w of data.widths) {\n if (typeof w !== 'number' || w <= 0 || !isFinite(w)) {\n return false;\n }\n }\n\n // Sum must be approximately 100\n const sum = data.widths.reduce((a, b) => a + b, 0);\n if (Math.abs(sum - 100) > WIDTHS_SUM_TOLERANCE) {\n return false;\n }\n }\n\n return true;\n },\n\n // ── Conversion ──────────────────────────────────────────────\n\n toHtml(data: ColumnsBlockData, context: BlockContext): string {\n const n = data.columns.length;\n const pretty = context.options?.pretty ?? false;\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n // Class: \"columns columns-N\"\n const classAttr = `columns columns-${n}`;\n\n // Custom widths → inline style grid-template-columns\n let styleAttr = '';\n if (data.widths && data.widths.length === n) {\n const cols = data.widths.map((w) => `${w}%`).join(' ');\n styleAttr = ` style=\"grid-template-columns: ${cols}\"`;\n }\n\n let html = `<div class=\"${classAttr}\"${styleAttr}>${nl}`;\n\n for (const col of data.columns) {\n html += `${ind(1)}<div class=\"column\">${nl}`;\n if (context.renderDelta) {\n html += `${ind(2)}${context.renderDelta(col.ops)}${nl}`;\n }\n html += `${ind(1)}</div>${nl}`;\n }\n\n html += `</div>`;\n return html;\n },\n\n fromHtml(element: DOMElement, context: BlockContext): ColumnsBlockData | null {\n const tag = element.tagName.toLowerCase();\n if (tag !== 'div') return null;\n\n const className = element.getAttribute('class') || '';\n if (!className.includes('columns')) return null;\n\n // Don't match \"column\" (singular) without \"columns\" (plural)\n // \"columns\" class is required on the container\n if (!/\\bcolumns\\b/.test(className)) return null;\n\n const columns: { ops: Op[] }[] = [];\n const children = element.childNodes;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child)) continue;\n\n const childClass = child.getAttribute('class') || '';\n if (!/\\bcolumn\\b/.test(childClass)) continue;\n\n // Parse all children of the column div\n let ops: Op[] = [];\n if (context.parseElement) {\n const childChildren = child.childNodes;\n for (let j = 0; j < childChildren.length; j++) {\n const el = childChildren[j];\n if (el && isElement(el)) {\n const parsed = context.parseElement(el);\n ops = ops.concat(parsed);\n }\n }\n }\n\n if (ops.length === 0) {\n ops = [{ insert: '\\n' }];\n }\n\n columns.push({ ops });\n }\n\n if (columns.length === 0) return null;\n\n // Extract widths from inline style: grid-template-columns\n let widths: number[] | undefined;\n const style = element.getAttribute('style') || '';\n const match = style.match(/grid-template-columns:\\s*(.+?)(?:;|$)/);\n if (match && match[1]) {\n const parts = match[1].trim().split(/\\s+/);\n const parsed = parts.map((p) => parseFloat(p)).filter((n) => !isNaN(n) && n > 0);\n if (parsed.length === columns.length) {\n widths = parsed;\n }\n }\n\n const result: ColumnsBlockData = {\n type: 'columns',\n columns,\n };\n\n if (widths) {\n result.widths = widths;\n }\n\n return result;\n },\n\n toMarkdown(_data: ColumnsBlockData, _context: BlockContext): string | null {\n // No lossless Markdown representation for columns layout.\n // Returning null triggers fallback to toHtml() — HTML directly in Markdown\n // (valid per CommonMark/GFM spec).\n return null;\n },\n\n // ── Normalization ──────────────────────────────────────────\n\n normalize(data: ColumnsBlockData, registry: Registry): ColumnsBlockData {\n return {\n ...data,\n columns: data.columns.map((col) => ({\n ops: normalizeDelta(new Delta(col.ops), registry).ops,\n })),\n };\n },\n\n // ── Nested Deltas ──────────────────────────────────────────\n\n getNestedDeltas(data: ColumnsBlockData): Op[][] {\n return data.columns.map((col) => col.ops);\n },\n\n setNestedDeltas(data: ColumnsBlockData, deltas: Op[][]): ColumnsBlockData {\n return {\n ...data,\n columns: data.columns.map((col, i) => ({\n ...col,\n ops: deltas[i] ?? col.ops,\n })),\n };\n },\n};\n","import type { Op } from '@scrider/delta';\nimport { Delta } from '@scrider/delta';\nimport type { BlockContext, BlockHandler } from '../BlockHandler';\nimport type { Registry } from '../Registry';\nimport { normalizeDelta } from '../../conversion/sanitize';\nimport type { DOMElement } from '../../conversion/adapters/types';\nimport { isElement } from '../../conversion/adapters/types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Valid float positions for Inline-Box */\nexport const BOX_FLOAT_VALUES = ['left', 'right', 'center'] as const;\n\n/** Valid overflow modes for Inline-Box */\nexport const BOX_OVERFLOW_VALUES = ['auto', 'hidden', 'visible'] as const;\n\n/** Union of valid float positions */\nexport type BoxFloat = (typeof BOX_FLOAT_VALUES)[number];\n\n/** Union of valid overflow modes */\nexport type BoxOverflow = (typeof BOX_OVERFLOW_VALUES)[number];\n\n/**\n * Inline-Box block data.\n *\n * Stored in Delta as: `{ insert: { block: <BoxBlockData> }, attributes: { float, width, height, overflow } }`\n *\n * A float container with nested Delta content and text wrapping.\n * Visual properties (float, width, height, overflow) are stored in op attributes,\n * not in block data — clean separation of semantics vs presentation.\n *\n * HTML (float left/right):\n * ```html\n * <div class=\"inline-box\" data-float=\"left\" data-overflow=\"auto\"\n * style=\"width: 200px; height: 300px;\">\n * <p>Rich content</p>\n * </div>\n * ```\n *\n * HTML (center — no wrapping):\n * ```html\n * <div class=\"inline-box\" data-float=\"center\" data-overflow=\"auto\"\n * style=\"width: 200px; height: 300px;\">\n * <p>Content</p>\n * </div>\n * ```\n *\n * Markdown: no native equivalent → toMarkdown returns null → HTML fallback.\n */\nexport interface BoxBlockData {\n /** Block type discriminator */\n type: 'box';\n /** Nested Delta content (rich text) */\n content: { ops: Op[] };\n}\n\n/**\n * Op-level attributes for box block embed.\n * Stored in `op.attributes`, not in block data.\n */\nexport interface BoxOpAttributes {\n /** Float position: left/right = text wrapping, center = no wrapping */\n float?: BoxFloat;\n /** Container width (e.g. \"200px\", \"30%\") */\n width?: string;\n /** Container height (e.g. \"300px\", \"auto\") */\n height?: string;\n /** Overflow behavior when content exceeds dimensions */\n overflow?: BoxOverflow;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Check if a string is a valid box float value */\nfunction isBoxFloat(value: string): value is BoxFloat {\n return BOX_FLOAT_VALUES.includes(value as BoxFloat);\n}\n\n/** Check if a string is a valid box overflow value */\nfunction isBoxOverflow(value: string): value is BoxOverflow {\n return BOX_OVERFLOW_VALUES.includes(value as BoxOverflow);\n}\n\n// ============================================================================\n// BoxBlockHandler\n// ============================================================================\n\n/**\n * BlockHandler implementation for Inline-Box (Float Container).\n *\n * A container with nested Delta content that supports float positioning\n * and text wrapping. Like Alert (single nested Delta), but visual\n * properties are stored in op attributes, not in block data.\n *\n * HTML: `<div class=\"inline-box\" data-float=\"F\" data-overflow=\"O\" style=\"width: W; height: H\">...</div>`\n * Markdown: no equivalent → toMarkdown returns null → HTML fallback\n */\nexport const boxBlockHandler: BlockHandler<BoxBlockData> = {\n type: 'box',\n\n validate(data: BoxBlockData): boolean {\n if (!data || typeof data !== 'object' || data.type !== 'box') {\n return false;\n }\n\n if (\n !data.content ||\n typeof data.content !== 'object' ||\n !Array.isArray(data.content.ops) ||\n data.content.ops.length === 0\n ) {\n return false;\n }\n\n return true;\n },\n\n // ── Conversion ──────────────────────────────────────────────\n\n toHtml(data: BoxBlockData, context: BlockContext): string {\n const pretty = context.options?.pretty ?? false;\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n // Read visual properties from opAttributes (passed by converter)\n const opAttrs = context.opAttributes;\n const float = (opAttrs?.float as string) || 'left';\n const width = opAttrs?.width as string | undefined;\n const height = opAttrs?.height as string | undefined;\n const overflow = (opAttrs?.overflow as string) || 'auto';\n\n // Build data-* attributes for CSS-driven layout\n let attrs = `class=\"inline-box\" data-float=\"${float}\"`;\n if (overflow !== 'auto') {\n attrs += ` data-overflow=\"${overflow}\"`;\n }\n\n // Build inline style for dynamic values (width, height)\n const styles: string[] = [];\n if (width && width !== 'auto') styles.push(`width: ${width}`);\n if (height && height !== 'auto') styles.push(`height: ${height}`);\n if (styles.length > 0) {\n attrs += ` style=\"${styles.join('; ')}\"`;\n }\n\n let html = `<div ${attrs}>${nl}`;\n\n // Render nested Delta content\n if (context.renderDelta) {\n html += `${ind(1)}${context.renderDelta(data.content.ops)}${nl}`;\n }\n\n html += `</div>`;\n return html;\n },\n\n fromHtml(element: DOMElement, context: BlockContext): BoxBlockData | null {\n const tag = element.tagName.toLowerCase();\n if (tag !== 'div') return null;\n\n const className = element.getAttribute('class') || '';\n if (!className.includes('inline-box')) return null;\n\n // Parse children to get nested Delta content\n let ops: Op[] = [];\n\n const children = element.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child)) continue;\n\n if (context.parseElement) {\n const parsed = context.parseElement(child);\n ops = ops.concat(parsed);\n }\n }\n\n if (ops.length === 0) {\n ops = [{ insert: '\\n' }];\n }\n\n return {\n type: 'box',\n content: { ops },\n };\n },\n\n toMarkdown(_data: BoxBlockData, _context: BlockContext): string | null {\n // No lossless Markdown representation for float container.\n // Returning null triggers fallback to toHtml() — HTML directly in Markdown\n // (valid per CommonMark/GFM spec).\n return null;\n },\n\n // ── Normalization ──────────────────────────────────────────\n\n normalize(data: BoxBlockData, registry: Registry): BoxBlockData {\n const normalized = normalizeDelta(new Delta(data.content.ops), registry);\n return {\n ...data,\n content: { ops: normalized.ops },\n };\n },\n\n // ── Nested Deltas ──────────────────────────────────────────\n\n getNestedDeltas(data: BoxBlockData): Op[][] {\n return [data.content.ops];\n },\n\n setNestedDeltas(data: BoxBlockData, deltas: Op[][]): BoxBlockData {\n const first = deltas[0];\n if (!first) return data;\n return {\n ...data,\n content: { ops: first },\n };\n },\n};\n\n/**\n * Extract op attributes for box from an HTML element.\n *\n * Used by html-to-delta intercept to reconstruct op attributes\n * (float, width, height, overflow) from the HTML representation.\n */\nexport function extractBoxOpAttributes(element: DOMElement): BoxOpAttributes {\n const attrs: BoxOpAttributes = {};\n\n // float from data-float attribute\n const dataFloat = element.getAttribute('data-float');\n if (dataFloat && isBoxFloat(dataFloat)) {\n attrs.float = dataFloat;\n }\n\n // overflow from data-overflow attribute (default: auto)\n const dataOverflow = element.getAttribute('data-overflow');\n if (dataOverflow && isBoxOverflow(dataOverflow)) {\n attrs.overflow = dataOverflow;\n }\n\n // width and height from inline style\n const style = element.getAttribute('style') || '';\n\n const widthMatch = style.match(/(?:^|;\\s*)width:\\s*([^;]+)/);\n if (widthMatch?.[1]) {\n attrs.width = widthMatch[1].trim();\n }\n\n const heightMatch = style.match(/(?:^|;\\s*)height:\\s*([^;]+)/);\n if (heightMatch?.[1]) {\n attrs.height = heightMatch[1].trim();\n }\n\n return attrs;\n}\n","/**\n * CSS Named Colors (full list)\n * https://www.w3.org/TR/css-color-4/#named-colors\n */\nconst NAMED_COLORS: Record<string, string> = {\n // Basic colors\n black: '#000000',\n silver: '#c0c0c0',\n gray: '#808080',\n white: '#ffffff',\n maroon: '#800000',\n red: '#ff0000',\n purple: '#800080',\n fuchsia: '#ff00ff',\n green: '#008000',\n lime: '#00ff00',\n olive: '#808000',\n yellow: '#ffff00',\n navy: '#000080',\n blue: '#0000ff',\n teal: '#008080',\n aqua: '#00ffff',\n\n // Extended colors\n aliceblue: '#f0f8ff',\n antiquewhite: '#faebd7',\n aquamarine: '#7fffd4',\n azure: '#f0ffff',\n beige: '#f5f5dc',\n bisque: '#ffe4c4',\n blanchedalmond: '#ffebcd',\n blueviolet: '#8a2be2',\n brown: '#a52a2a',\n burlywood: '#deb887',\n cadetblue: '#5f9ea0',\n chartreuse: '#7fff00',\n chocolate: '#d2691e',\n coral: '#ff7f50',\n cornflowerblue: '#6495ed',\n cornsilk: '#fff8dc',\n crimson: '#dc143c',\n cyan: '#00ffff',\n darkblue: '#00008b',\n darkcyan: '#008b8b',\n darkgoldenrod: '#b8860b',\n darkgray: '#a9a9a9',\n darkgreen: '#006400',\n darkgrey: '#a9a9a9',\n darkkhaki: '#bdb76b',\n darkmagenta: '#8b008b',\n darkolivegreen: '#556b2f',\n darkorange: '#ff8c00',\n darkorchid: '#9932cc',\n darkred: '#8b0000',\n darksalmon: '#e9967a',\n darkseagreen: '#8fbc8f',\n darkslateblue: '#483d8b',\n darkslategray: '#2f4f4f',\n darkslategrey: '#2f4f4f',\n darkturquoise: '#00ced1',\n darkviolet: '#9400d3',\n deeppink: '#ff1493',\n deepskyblue: '#00bfff',\n dimgray: '#696969',\n dimgrey: '#696969',\n dodgerblue: '#1e90ff',\n firebrick: '#b22222',\n floralwhite: '#fffaf0',\n forestgreen: '#228b22',\n gainsboro: '#dcdcdc',\n ghostwhite: '#f8f8ff',\n gold: '#ffd700',\n goldenrod: '#daa520',\n greenyellow: '#adff2f',\n grey: '#808080',\n honeydew: '#f0fff0',\n hotpink: '#ff69b4',\n indianred: '#cd5c5c',\n indigo: '#4b0082',\n ivory: '#fffff0',\n khaki: '#f0e68c',\n lavender: '#e6e6fa',\n lavenderblush: '#fff0f5',\n lawngreen: '#7cfc00',\n lemonchiffon: '#fffacd',\n lightblue: '#add8e6',\n lightcoral: '#f08080',\n lightcyan: '#e0ffff',\n lightgoldenrodyellow: '#fafad2',\n lightgray: '#d3d3d3',\n lightgreen: '#90ee90',\n lightgrey: '#d3d3d3',\n lightpink: '#ffb6c1',\n lightsalmon: '#ffa07a',\n lightseagreen: '#20b2aa',\n lightskyblue: '#87cefa',\n lightslategray: '#778899',\n lightslategrey: '#778899',\n lightsteelblue: '#b0c4de',\n lightyellow: '#ffffe0',\n limegreen: '#32cd32',\n linen: '#faf0e6',\n magenta: '#ff00ff',\n mediumaquamarine: '#66cdaa',\n mediumblue: '#0000cd',\n mediumorchid: '#ba55d3',\n mediumpurple: '#9370db',\n mediumseagreen: '#3cb371',\n mediumslateblue: '#7b68ee',\n mediumspringgreen: '#00fa9a',\n mediumturquoise: '#48d1cc',\n mediumvioletred: '#c71585',\n midnightblue: '#191970',\n mintcream: '#f5fffa',\n mistyrose: '#ffe4e1',\n moccasin: '#ffe4b5',\n navajowhite: '#ffdead',\n oldlace: '#fdf5e6',\n olivedrab: '#6b8e23',\n orange: '#ffa500',\n orangered: '#ff4500',\n orchid: '#da70d6',\n palegoldenrod: '#eee8aa',\n palegreen: '#98fb98',\n paleturquoise: '#afeeee',\n palevioletred: '#db7093',\n papayawhip: '#ffefd5',\n peachpuff: '#ffdab9',\n peru: '#cd853f',\n pink: '#ffc0cb',\n plum: '#dda0dd',\n powderblue: '#b0e0e6',\n rosybrown: '#bc8f8f',\n royalblue: '#4169e1',\n saddlebrown: '#8b4513',\n salmon: '#fa8072',\n sandybrown: '#f4a460',\n seagreen: '#2e8b57',\n seashell: '#fff5ee',\n sienna: '#a0522d',\n skyblue: '#87ceeb',\n slateblue: '#6a5acd',\n slategray: '#708090',\n slategrey: '#708090',\n snow: '#fffafa',\n springgreen: '#00ff7f',\n steelblue: '#4682b4',\n tan: '#d2b48c',\n thistle: '#d8bfd8',\n tomato: '#ff6347',\n turquoise: '#40e0d0',\n violet: '#ee82ee',\n wheat: '#f5deb3',\n whitesmoke: '#f5f5f5',\n yellowgreen: '#9acd32',\n\n // CSS4 colors\n rebeccapurple: '#663399',\n};\n\n/**\n * Convert any color format to lowercase hex (#rrggbb)\n *\n * Supports:\n * - Hex: #rgb, #rrggbb, #rrggbbaa\n * - RGB: rgb(r, g, b), rgb(r g b)\n * - RGBA: rgba(r, g, b, a), rgba(r g b / a)\n * - Named colors: red, blue, etc.\n *\n * @param value - Color value to convert\n * @returns Lowercase hex color (#rrggbb) or original value if not recognized\n */\nexport function toHexColor(value: string): string {\n const trimmed = value.trim().toLowerCase();\n\n // Already hex\n if (trimmed.startsWith('#')) {\n return normalizeHex(trimmed);\n }\n\n // Named color\n if (NAMED_COLORS[trimmed]) {\n return NAMED_COLORS[trimmed];\n }\n\n // RGB/RGBA\n if (trimmed.startsWith('rgb')) {\n return parseRgb(trimmed);\n }\n\n // HSL (basic support - convert to RGB first would be complex)\n // For now, return as-is if not recognized\n return value;\n}\n\n/**\n * Normalize hex color to #rrggbb format\n */\nfunction normalizeHex(hex: string): string {\n // Remove # prefix\n let color = hex.slice(1);\n\n // Expand shorthand (#rgb → #rrggbb)\n if (color.length === 3) {\n color =\n color.charAt(0) +\n color.charAt(0) +\n color.charAt(1) +\n color.charAt(1) +\n color.charAt(2) +\n color.charAt(2);\n }\n\n // Handle #rgba shorthand\n if (color.length === 4) {\n color =\n color.charAt(0) +\n color.charAt(0) +\n color.charAt(1) +\n color.charAt(1) +\n color.charAt(2) +\n color.charAt(2);\n // Ignore alpha\n }\n\n // Handle #rrggbbaa (ignore alpha)\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n\n // Validate\n if (!/^[0-9a-f]{6}$/.test(color)) {\n return '#' + color; // Return as-is if invalid\n }\n\n return '#' + color;\n}\n\n/**\n * Parse rgb/rgba to hex\n */\nfunction parseRgb(value: string): string {\n // Match rgb(r, g, b) or rgba(r, g, b, a) or rgb(r g b) or rgb(r g b / a)\n // Supports negative numbers for clamping\n const match = value.match(\n /rgba?\\s*\\(\\s*(-?\\d+)\\s*[,\\s]\\s*(-?\\d+)\\s*[,\\s]\\s*(-?\\d+)(?:\\s*[,/]\\s*[\\d.]+)?\\s*\\)/,\n );\n\n if (!match) {\n return value; // Return as-is if not parseable\n }\n\n const [, rStr, gStr, bStr] = match;\n if (!rStr || !gStr || !bStr) return value;\n\n const r = Math.max(0, Math.min(255, parseInt(rStr, 10)));\n const g = Math.max(0, Math.min(255, parseInt(gStr, 10)));\n const b = Math.max(0, Math.min(255, parseInt(bStr, 10)));\n\n return '#' + toHex(r) + toHex(g) + toHex(b);\n}\n\n/**\n * Convert number to 2-digit hex\n */\nfunction toHex(n: number): string {\n const hex = n.toString(16);\n return hex.length === 1 ? '0' + hex : hex;\n}\n\n/**\n * Check if a value is a valid hex color\n *\n * @param value - Value to check\n * @returns true if valid hex color (#rrggbb or #rgb)\n */\nexport function isValidHexColor(value: string): boolean {\n return /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(value);\n}\n\n/**\n * Check if a value is a valid color (hex, rgb, rgba, or named)\n *\n * @param value - Value to check\n * @returns true if valid color\n */\nexport function isValidColor(value: string): boolean {\n const trimmed = value.trim().toLowerCase();\n\n // Hex\n if (/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(trimmed)) {\n return true;\n }\n\n // Named\n if (NAMED_COLORS[trimmed]) {\n return true;\n }\n\n // RGB/RGBA\n if (/^rgba?\\s*\\(\\s*\\d+\\s*[,\\s]\\s*\\d+\\s*[,\\s]\\s*\\d+(?:\\s*[,/]\\s*[\\d.]+)?\\s*\\)$/.test(trimmed)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Get list of all named colors\n */\nexport function getNamedColors(): string[] {\n return Object.keys(NAMED_COLORS);\n}\n","import type { Format } from '../../Format';\nimport { isValidColor, toHexColor } from '../../utils/color';\n\n/**\n * Background color format\n *\n * Delta: { insert: \"text\", attributes: { background: \"#ff0000\" } }\n *\n * Normalizes all color formats (rgb, named, etc.) to lowercase hex (#rrggbb)\n */\nexport const backgroundFormat: Format<string> = {\n name: 'background',\n scope: 'inline',\n\n normalize(value: string): string {\n return toHexColor(value);\n },\n\n validate(value: string): boolean {\n return typeof value === 'string' && isValidColor(value);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Bold format\n *\n * Delta: { insert: \"text\", attributes: { bold: true } }\n */\nexport const boldFormat: Format<boolean> = {\n name: 'bold',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Inline code format\n *\n * Delta: { insert: \"text\", attributes: { code: true } }\n */\nexport const codeFormat: Format<boolean> = {\n name: 'code',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\nimport { isValidColor, toHexColor } from '../../utils/color';\n\n/**\n * Text color format\n *\n * Delta: { insert: \"text\", attributes: { color: \"#ff0000\" } }\n *\n * Normalizes all color formats (rgb, named, etc.) to lowercase hex (#rrggbb)\n */\nexport const colorFormat: Format<string> = {\n name: 'color',\n scope: 'inline',\n\n normalize(value: string): string {\n return toHexColor(value);\n },\n\n validate(value: string): boolean {\n return typeof value === 'string' && isValidColor(value);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Font family format\n *\n * Delta: { insert: \"text\", attributes: { font: \"Times New Roman\" } }\n */\nexport const fontFormat: Format<string> = {\n name: 'font',\n scope: 'inline',\n\n validate(value: string): boolean {\n return typeof value === 'string' && value.length > 0;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Italic format\n *\n * Delta: { insert: \"text\", attributes: { italic: true } }\n */\nexport const italicFormat: Format<boolean> = {\n name: 'italic',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Keyboard input format\n *\n * Delta: { insert: \"text\", attributes: { kbd: true } }\n * HTML: <kbd>text</kbd>\n * Markdown: <kbd>text</kbd> (inline HTML)\n */\nexport const kbdFormat: Format<boolean> = {\n name: 'kbd',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Link format\n *\n * Delta: { insert: \"text\", attributes: { link: \"https://example.com\" } }\n *\n * Supports:\n * - Absolute URLs (http://, https://)\n * - Relative URLs (/path, ./path, ../path)\n * - Protocol-relative URLs (//example.com)\n * - mailto: and tel: links\n */\nexport const linkFormat: Format<string> = {\n name: 'link',\n scope: 'inline',\n\n normalize(value: string): string {\n return value.trim();\n },\n\n validate(value: string): boolean {\n if (typeof value !== 'string' || value.length === 0) {\n return false;\n }\n\n const trimmed = value.trim();\n\n // Relative URLs\n if (trimmed.startsWith('/') || trimmed.startsWith('./') || trimmed.startsWith('../')) {\n return true;\n }\n\n // Protocol-relative URLs\n if (trimmed.startsWith('//')) {\n return true;\n }\n\n // mailto: and tel:\n if (trimmed.startsWith('mailto:') || trimmed.startsWith('tel:')) {\n return true;\n }\n\n // Absolute URLs (http/https)\n try {\n const url = new URL(trimmed);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Mark (highlight) format\n *\n * Delta: { insert: \"text\", attributes: { mark: true } }\n * HTML: <mark>text</mark>\n */\nexport const markFormat: Format<boolean> = {\n name: 'mark',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Font size format\n *\n * Delta: { insert: \"text\", attributes: { size: \"14pt\" } }\n *\n * Value is a string with CSS unit (e.g. \"14pt\", \"16px\", \"1.2em\").\n */\nexport const sizeFormat: Format<string> = {\n name: 'size',\n scope: 'inline',\n\n validate(value: string): boolean {\n return typeof value === 'string' && value.length > 0;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Strikethrough format\n *\n * Delta: { insert: \"text\", attributes: { strike: true } }\n */\nexport const strikeFormat: Format<boolean> = {\n name: 'strike',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Subscript format\n *\n * Delta: { insert: \"text\", attributes: { subscript: true } }\n * HTML: <sub>text</sub>\n */\nexport const subscriptFormat: Format<boolean> = {\n name: 'subscript',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Superscript format\n *\n * Delta: { insert: \"text\", attributes: { superscript: true } }\n * HTML: <sup>text</sup>\n */\nexport const superscriptFormat: Format<boolean> = {\n name: 'superscript',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Underline format\n *\n * Delta: { insert: \"text\", attributes: { underline: true } }\n */\nexport const underlineFormat: Format<boolean> = {\n name: 'underline',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Valid alignment values\n */\nexport type AlignType = 'left' | 'center' | 'right' | 'justify';\n\nconst VALID_ALIGN_TYPES: AlignType[] = ['left', 'center', 'right', 'justify'];\n\n/**\n * Text alignment format\n *\n * Delta: { insert: \"\\n\", attributes: { align: \"center\" } }\n */\nexport const alignFormat: Format<AlignType> = {\n name: 'align',\n scope: 'block',\n\n normalize(value: AlignType): AlignType {\n return value.toLowerCase() as AlignType;\n },\n\n validate(value: AlignType): boolean {\n return VALID_ALIGN_TYPES.includes(value);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Blockquote format\n *\n * Delta: { insert: \"\\n\", attributes: { blockquote: true } }\n */\nexport const blockquoteFormat: Format<boolean> = {\n name: 'blockquote',\n scope: 'block',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Code block format\n *\n * Delta: { insert: \"\\n\", attributes: { \"code-block\": true } }\n * Delta: { insert: \"\\n\", attributes: { \"code-block\": \"javascript\" } }\n *\n * Value can be:\n * - true: generic code block\n * - string: language identifier for syntax highlighting\n */\nexport const codeBlockFormat: Format<boolean | string> = {\n name: 'code-block',\n scope: 'block',\n\n normalize(value: boolean | string): boolean | string {\n if (typeof value === 'string') {\n return value.toLowerCase().trim();\n }\n return value;\n },\n\n validate(value: boolean | string): boolean {\n if (value === true) {\n return true;\n }\n if (typeof value === 'string' && value.length > 0) {\n return true;\n }\n return false;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Header format (h1-h6)\n *\n * Delta: { insert: \"\\n\", attributes: { header: 1 } }\n *\n * Values: 1-6 (corresponding to h1-h6)\n */\nexport const headerFormat: Format<number> = {\n name: 'header',\n scope: 'block',\n\n normalize(value: number): number {\n // Clamp to valid range and ensure integer\n return Math.max(1, Math.min(6, Math.floor(value)));\n },\n\n validate(value: number): boolean {\n return Number.isInteger(value) && value >= 1 && value <= 6;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Header ID format — optional custom anchor id for headings\n *\n * Delta: { insert: \"\\n\", attributes: { header: 2, \"header-id\": \"getting-started\" } }\n *\n * When present, the heading gets this exact id in HTML output.\n * When absent, id is computed via slugify(text) at render time (if anchorLinks is enabled).\n *\n * Markdown: ## Title {#custom-id}\n */\nexport const headerIdFormat: Format<string> = {\n name: 'header-id',\n scope: 'block',\n\n normalize(value: string): string {\n return String(value).trim().toLowerCase();\n },\n\n validate(value: string): boolean {\n if (typeof value !== 'string') return false;\n const trimmed = value.trim();\n // Must be non-empty, valid HTML id: no whitespace, at least one char\n return trimmed.length > 0 && !/\\s/.test(trimmed);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Maximum indent level\n */\nconst MAX_INDENT = 8;\n\n/**\n * Indent format\n *\n * Delta: { insert: \"\\n\", attributes: { indent: 1 } }\n *\n * Values: 0-8 (0 = no indent)\n */\nexport const indentFormat: Format<number> = {\n name: 'indent',\n scope: 'block',\n\n normalize(value: number): number {\n // Clamp to valid range and ensure non-negative integer\n return Math.max(0, Math.min(MAX_INDENT, Math.floor(value)));\n },\n\n validate(value: number): boolean {\n return Number.isInteger(value) && value >= 0 && value <= MAX_INDENT;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Valid list types\n */\nexport type ListType = 'ordered' | 'bullet' | 'checked' | 'unchecked';\n\nconst VALID_LIST_TYPES: ListType[] = ['ordered', 'bullet', 'checked', 'unchecked'];\n\n/**\n * List format\n *\n * Delta: { insert: \"\\n\", attributes: { list: \"ordered\" } }\n * Delta: { insert: \"\\n\", attributes: { list: \"bullet\" } }\n * Delta: { insert: \"\\n\", attributes: { list: \"checked\" } }\n * Delta: { insert: \"\\n\", attributes: { list: \"unchecked\" } }\n */\nexport const listFormat: Format<ListType> = {\n name: 'list',\n scope: 'block',\n\n normalize(value: ListType): ListType {\n return value.toLowerCase() as ListType;\n },\n\n validate(value: ListType): boolean {\n return VALID_LIST_TYPES.includes(value);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Table row index format\n *\n * Delta: { insert: \"\\n\", attributes: { \"table-row\": 0 } }\n */\nexport const tableRowFormat: Format<number> = {\n name: 'table-row',\n scope: 'block',\n\n validate(value: number): boolean {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Table column index format\n *\n * Delta: { insert: \"\\n\", attributes: { \"table-col\": 0 } }\n */\nexport const tableColFormat: Format<number> = {\n name: 'table-col',\n scope: 'block',\n\n validate(value: number): boolean {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Table header cell format\n *\n * Delta: { insert: \"\\n\", attributes: { \"table-header\": true } }\n *\n * When true, the cell is rendered as <th> inside <thead>.\n */\nexport const tableHeaderFormat: Format<boolean> = {\n name: 'table-header',\n scope: 'block',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Valid table column alignment values\n */\nexport type TableColAlignType = 'left' | 'center' | 'right';\n\nconst VALID_ALIGNS: TableColAlignType[] = ['left', 'center', 'right'];\n\n/**\n * Table column alignment format\n *\n * Delta: { insert: \"\\n\", attributes: { \"table-col-align\": \"center\" } }\n *\n * Controls text-align of the column (rendered via style on <th>/<td>).\n * Compatible with GFM alignment syntax (:---|:---:|---:).\n */\nexport const tableColAlignFormat: Format<TableColAlignType> = {\n name: 'table-col-align',\n scope: 'block',\n\n normalize(value: TableColAlignType): TableColAlignType {\n return value.toLowerCase() as TableColAlignType;\n },\n\n validate(value: TableColAlignType): boolean {\n return VALID_ALIGNS.includes(value);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Block embed format — structural validation for complex block embeds.\n *\n * Delta: `{ insert: { block: { type: \"table\", ... } } }`\n *\n * This is the first level of two-level validation:\n * 1. blockFormat.validate() — structural: is it an object with `type`?\n * 2. BlockHandlerRegistry.get(type).validate() — semantic: is it a valid table?\n *\n * The `block` key is a **category**, not \"just another embed\".\n * It signals to converters and OT layer: \"nested structure, needs special handling\".\n */\nexport const blockFormat: Format<Record<string, unknown>> = {\n name: 'block',\n scope: 'embed',\n\n validate(value: Record<string, unknown>): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n typeof value.type === 'string' &&\n value.type.length > 0\n );\n },\n};\n","/**\n * HTML ↔ Delta Mapping Configuration\n *\n * Defines the mapping between HTML elements/attributes and Delta attributes.\n */\n\n/**\n * Inline format to HTML tag mapping\n *\n * Order matters for rendering: formats earlier in the list wrap formats later.\n * This creates a canonical nesting order for HTML output.\n */\nexport const INLINE_FORMAT_TAGS: Record<string, string> = {\n link: 'a',\n bold: 'strong',\n italic: 'em',\n underline: 'u',\n strike: 's',\n subscript: 'sub',\n superscript: 'sup',\n code: 'code',\n mark: 'mark',\n kbd: 'kbd',\n};\n\n/**\n * Order of inline formats for nesting (outer to inner)\n *\n * When rendering Delta to HTML, formats are nested in this order.\n * Example: bold + italic + code → <strong><em><code>text</code></em></strong>\n */\nexport const INLINE_FORMAT_ORDER: string[] = [\n 'link',\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'subscript',\n 'superscript',\n 'code',\n 'mark',\n 'kbd',\n];\n\n/**\n * Inline formats that use CSS styles instead of tags\n */\nexport const INLINE_STYLE_FORMATS: Record<string, string> = {\n color: 'color',\n background: 'background-color',\n font: 'font-family',\n size: 'font-size',\n};\n\n/**\n * Block format to HTML tag mapping\n */\nexport const BLOCK_FORMAT_TAGS: Record<string, string | ((value: unknown) => string)> = {\n header: (value: unknown) => `h${String(value)}`,\n blockquote: 'blockquote',\n 'code-block': 'pre',\n list: 'li', // Wrapped in ul/ol based on list type\n};\n\n/**\n * List type to wrapper tag mapping\n */\nexport const LIST_WRAPPER_TAGS: Record<string, string> = {\n ordered: 'ol',\n bullet: 'ul',\n checked: 'ul',\n unchecked: 'ul',\n};\n\n/**\n * Embed format to HTML renderer\n */\nexport type EmbedRenderer = (value: unknown, attributes?: Record<string, unknown>) => string;\n\nexport const EMBED_RENDERERS: Record<string, EmbedRenderer> = {\n image: (value, attrs) => {\n const src = typeof value === 'string' ? value : '';\n const altVal = attrs?.alt;\n const widthVal = attrs?.width;\n const heightVal = attrs?.height;\n const floatVal = attrs?.float;\n const alt =\n altVal != null && (typeof altVal === 'string' || typeof altVal === 'number')\n ? ` alt=\"${escapeHtml(String(altVal))}\"`\n : '';\n const width =\n widthVal != null && (typeof widthVal === 'string' || typeof widthVal === 'number')\n ? ` width=\"${String(widthVal)}\"`\n : '';\n const height =\n heightVal != null && (typeof heightVal === 'string' || typeof heightVal === 'number')\n ? ` height=\"${String(heightVal)}\"`\n : '';\n // Float: data-float attribute for CSS-driven text wrapping\n const float =\n floatVal != null && typeof floatVal === 'string' && floatVal !== 'none'\n ? ` data-float=\"${escapeHtml(floatVal)}\"`\n : '';\n return `<img src=\"${escapeHtml(src)}\"${alt}${width}${height}${float}>`;\n },\n\n video: (value, attrs) => {\n const src = typeof value === 'string' ? value : '';\n const floatVal = attrs?.float;\n const widthVal = attrs?.width;\n const heightVal = attrs?.height;\n // Float: data-float attribute for CSS-driven text wrapping\n const float =\n floatVal != null && typeof floatVal === 'string' && floatVal !== 'none'\n ? ` data-float=\"${escapeHtml(floatVal)}\"`\n : '';\n const styles: string[] = [];\n if (widthVal != null && (typeof widthVal === 'string' || typeof widthVal === 'number')) {\n const w = String(widthVal);\n if (w && w !== 'auto') styles.push(`width: ${/^\\d+$/.test(w) ? w + 'px' : w}`);\n }\n if (heightVal != null && (typeof heightVal === 'string' || typeof heightVal === 'number')) {\n const h = String(heightVal);\n if (h && h !== 'auto') styles.push(`height: ${/^\\d+$/.test(h) ? h + 'px' : h}`);\n }\n const style = styles.length > 0 ? ` style=\"${styles.join('; ')}\"` : '';\n const embedSrc = toVideoEmbedUrl(src);\n if (embedSrc) {\n return `<iframe src=\"${escapeHtml(embedSrc)}\" frameborder=\"0\" allowfullscreen${float}${style}></iframe>`;\n }\n return `<video src=\"${escapeHtml(src)}\" controls${float}${style}></video>`;\n },\n\n formula: (value) => {\n const latex = typeof value === 'string' ? value : '';\n return `<span class=\"formula\" data-formula=\"${escapeHtml(latex)}\">${escapeHtml(latex)}</span>`;\n },\n\n diagram: (value) => {\n const source = typeof value === 'string' ? value : '';\n return `<span class=\"diagram\" data-diagram=\"${escapeHtml(source)}\">${escapeHtml(source)}</span>`;\n },\n\n drawio: (value, attrs) => {\n const src = typeof value === 'string' ? value : '';\n const altVal = attrs?.alt;\n const alt =\n altVal != null && (typeof altVal === 'string' || typeof altVal === 'number')\n ? ` data-alt=\"${escapeHtml(String(altVal))}\"`\n : '';\n return `<span class=\"drawio\" data-drawio-src=\"${escapeHtml(src)}\"${alt}></span>`;\n },\n\n 'footnote-ref': (value) => {\n const id = typeof value === 'string' ? value : String(value);\n return `<sup class=\"footnote-ref\"><a href=\"#fn-${escapeHtml(id)}\" id=\"fnref-${escapeHtml(id)}\">[${escapeHtml(id)}]</a></sup>`;\n },\n\n divider: () => '<hr>',\n\n // Soft line break (Shift+Enter equivalent). Emitted with an explicit\n // `data-scrider-embed` marker so that html-to-delta can distinguish this\n // embed from the placeholder `<br>` that appears inside an empty\n // paragraph (`<p><br></p>`) without relying solely on positional\n // heuristics. See `soft-break.ts` for the format definition.\n softBreak: () => '<br data-scrider-embed>',\n};\n\n/**\n * HTML tag to inline format mapping (for parsing)\n */\nexport const TAG_TO_INLINE_FORMAT: Record<string, { format: string; value: unknown }> = {\n strong: { format: 'bold', value: true },\n b: { format: 'bold', value: true },\n em: { format: 'italic', value: true },\n i: { format: 'italic', value: true },\n u: { format: 'underline', value: true },\n ins: { format: 'underline', value: true },\n s: { format: 'strike', value: true },\n strike: { format: 'strike', value: true },\n del: { format: 'strike', value: true },\n sub: { format: 'subscript', value: true },\n sup: { format: 'superscript', value: true },\n code: { format: 'code', value: true },\n mark: { format: 'mark', value: true },\n kbd: { format: 'kbd', value: true },\n};\n\n/**\n * HTML tag to block format mapping (for parsing)\n */\nexport const TAG_TO_BLOCK_FORMAT: Record<string, { format: string; value: unknown }> = {\n h1: { format: 'header', value: 1 },\n h2: { format: 'header', value: 2 },\n h3: { format: 'header', value: 3 },\n h4: { format: 'header', value: 4 },\n h5: { format: 'header', value: 5 },\n h6: { format: 'header', value: 6 },\n blockquote: { format: 'blockquote', value: true },\n pre: { format: 'code-block', value: true },\n};\n\n/**\n * CSS text-align values to align format values\n */\nexport const CSS_ALIGN_TO_FORMAT: Record<string, string> = {\n left: 'left',\n center: 'center',\n right: 'right',\n justify: 'justify',\n};\n\n/**\n * Escape HTML special characters\n */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Unescape HTML entities\n */\nexport function unescapeHtml(text: string): string {\n return text\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/&/g, '&');\n}\n\n/**\n * Convert a video URL to an embeddable URL for rendering in <iframe>.\n * Returns null if the URL should be rendered as a <video> tag instead.\n *\n * Video rendering strategy:\n *\n * Service | Embed URL format | HTML tag\n * -------------|-------------------------------------------|----------\n * YouTube | youtube.com/embed/VIDEO_ID | <iframe>\n * VK Video | vkvideo.ru/video_ext.php?oid=&id=&hash= | <iframe>\n * Vimeo | player.vimeo.com/video/ID | <iframe>\n * Dailymotion | dailymotion.com/embed/video/ID | <iframe>\n * Direct file | example.com/video.mp4 | <video>\n *\n * Note: VK Video requires a `hash` parameter in the embed URL for security.\n * The hash can only be obtained from VK's \"Share → Embed\" dialog;\n * it cannot be computed from a regular vkvideo.ru/video-... page URL.\n *\n * Supported input URL conversions:\n * - youtube.com/embed/ID → pass through\n * - youtube.com/watch?v=ID → youtube.com/embed/ID\n * - youtu.be/ID → youtube.com/embed/ID\n * - player.vimeo.com/video/ID → pass through\n * - dailymotion.com/embed/... → pass through\n * - *://video_ext.php?... → pass through (VK Video embed)\n * - anything else → null (render as <video>)\n */\nexport function toVideoEmbedUrl(url: string): string | null {\n // Already an embed URL — pass through\n if (\n url.includes('youtube.com/embed') ||\n url.includes('player.vimeo.com') ||\n url.includes('dailymotion.com/embed') ||\n url.includes('video_ext.php') ||\n url.includes('rutube.ru/play/embed')\n ) {\n return url;\n }\n\n // YouTube watch URL: https://www.youtube.com/watch?v=VIDEO_ID\n const ytMatch = url.match(/youtube\\.com\\/watch\\?v=([\\w-]+)/);\n if (ytMatch) {\n return `https://www.youtube.com/embed/${ytMatch[1]}`;\n }\n\n // YouTube short URL: https://youtu.be/VIDEO_ID\n const ytShortMatch = url.match(/youtu\\.be\\/([\\w-]+)/);\n if (ytShortMatch) {\n return `https://www.youtube.com/embed/${ytShortMatch[1]}`;\n }\n\n // Rutube watch URL: https://rutube.ru/video/HASH/\n const rtMatch = url.match(/rutube\\.ru\\/video\\/([\\w]+)/);\n if (rtMatch) {\n return `https://rutube.ru/play/embed/${rtMatch[1]}`;\n }\n\n return null;\n}\n\n/**\n * Convert an embed URL back to a canonical video URL.\n * Used when parsing HTML (<iframe>) back to Delta.\n *\n * Conversions:\n * - YouTube embed → youtube.com/watch?v=ID (canonical)\n * - VK Video, Vimeo, Dailymotion, etc. → kept as-is\n * (VK Video hash cannot be reconstructed from canonical URL)\n */\nexport function fromVideoEmbedUrl(embedUrl: string): string {\n // YouTube embed → canonical watch URL\n const ytMatch = embedUrl.match(/youtube\\.com\\/embed\\/([\\w-]+)/);\n if (ytMatch) {\n return `https://www.youtube.com/watch?v=${ytMatch[1]}`;\n }\n\n // Rutube embed → canonical watch URL\n const rtMatch = embedUrl.match(/rutube\\.ru\\/play\\/embed\\/([\\w]+)/);\n if (rtMatch) {\n return `https://rutube.ru/video/${rtMatch[1]}/`;\n }\n\n // VK Video, Vimeo, Dailymotion, etc. — keep embed URL as-is\n // (VK Video requires hash parameter that can't be reconstructed)\n return embedUrl;\n}\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\n\n/**\n * Divider (Horizontal Rule) embed format\n *\n * Delta: { insert: { divider: true } }\n * HTML: <hr>\n * Markdown: ---\n *\n * Value is always `true` (no additional data needed)\n */\nexport const dividerFormat: Format<boolean> = {\n name: 'divider',\n scope: 'embed',\n\n normalize(value: boolean): boolean {\n return !!value;\n },\n\n validate(value: boolean): boolean {\n return value === true;\n },\n\n render(): string {\n return '<hr>';\n },\n\n match(element: DOMElement): FormatMatchResult<boolean> | null {\n if (element.tagName.toLowerCase() !== 'hr') return null;\n return { value: true };\n },\n};\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\nimport { isElement } from '../../../conversion/adapters/types';\nimport { escapeHtml } from '../../../conversion/html/config';\n\n/**\n * Footnote reference embed format\n *\n * Delta: { insert: { \"footnote-ref\": \"1\" } }\n *\n * Value is the footnote identifier string (e.g. \"1\", \"note\", \"my-ref\").\n * Rendered as superscript link in HTML: <sup class=\"footnote-ref\"><a href=\"#fn-1\">1</a></sup>\n * Markdown: [^1]\n */\nexport const footnoteRefFormat: Format<string> = {\n name: 'footnote-ref',\n scope: 'embed',\n\n validate(value: string): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n // Must be non-empty, no whitespace-only\n return value.trim().length > 0;\n },\n\n render(value: string): string {\n const id = typeof value === 'string' ? value : String(value);\n return `<sup class=\"footnote-ref\"><a href=\"#fn-${escapeHtml(id)}\" id=\"fnref-${escapeHtml(id)}\">[${escapeHtml(id)}]</a></sup>`;\n },\n\n match(element: DOMElement): FormatMatchResult<string> | null {\n if (element.tagName.toLowerCase() !== 'sup') return null;\n const className = element.getAttribute('class') || '';\n if (!className.includes('footnote-ref')) return null;\n\n // Extract id from nested <a href=\"#fn-{id}\">\n const children = element.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child && isElement(child)) {\n const href = child.getAttribute('href') || '';\n const hrefMatch = href.match(/#fn-(.+)/);\n if (hrefMatch?.[1]) {\n return { value: hrefMatch[1] };\n }\n }\n }\n\n // Fallback: try id attribute\n const id = element.getAttribute('id') || '';\n const refMatch = id.match(/^fnref-(.+)/);\n if (refMatch?.[1]) {\n return { value: refMatch[1] };\n }\n\n return null;\n },\n};\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\nimport { escapeHtml } from '../../../conversion/html/config';\n\n/**\n * Basic LaTeX validation patterns\n *\n * Checks for:\n * - Balanced braces\n * - Valid command structure\n */\nfunction isValidLatex(value: string): boolean {\n // Empty string is not valid\n if (!value || value.trim().length === 0) {\n return false;\n }\n\n // Check balanced braces\n let braceCount = 0;\n for (const char of value) {\n if (char === '{') braceCount++;\n if (char === '}') braceCount--;\n if (braceCount < 0) return false; // More closing than opening\n }\n if (braceCount !== 0) return false; // Unbalanced\n\n // Check balanced brackets\n let bracketCount = 0;\n for (const char of value) {\n if (char === '[') bracketCount++;\n if (char === ']') bracketCount--;\n if (bracketCount < 0) return false;\n }\n if (bracketCount !== 0) return false;\n\n // Check for invalid command patterns\n // Commands should be \\word not just backslash\n const invalidCommand = /\\\\(?![a-zA-Z]|\\\\|{|}|\\[|\\]|\\s|,|;|!|\\^|_)/;\n if (invalidCommand.test(value)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Formula (LaTeX) embed format\n *\n * Delta: { insert: { formula: \"E = mc^2\" } }\n *\n * Value is LaTeX string\n */\nexport const formulaFormat: Format<string> = {\n name: 'formula',\n scope: 'embed',\n\n normalize(value: string): string {\n // Trim whitespace but preserve internal formatting\n return value.trim();\n },\n\n validate(value: string): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n return isValidLatex(value);\n },\n\n render(value: string): string {\n const latex = typeof value === 'string' ? value : '';\n return `<span class=\"formula\" data-formula=\"${escapeHtml(latex)}\">${escapeHtml(latex)}</span>`;\n },\n\n match(element: DOMElement): FormatMatchResult<string> | null {\n if (element.tagName.toLowerCase() !== 'span') return null;\n const className = element.getAttribute('class') || '';\n if (!className.includes('formula')) return null;\n const formula = element.getAttribute('data-formula');\n if (!formula) return null;\n return { value: formula };\n },\n};\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\nimport type { AttributeMap } from '@scrider/delta';\nimport { escapeHtml } from '../../../conversion/html/config';\n\n/**\n * Image embed format\n *\n * Delta: { insert: { image: \"https://example.com/image.png\" } }\n *\n * Value is the image URL (http, https, data URI, or relative path)\n */\nexport const imageFormat: Format<string> = {\n name: 'image',\n scope: 'embed',\n\n normalize(value: string): string {\n return value.trim();\n },\n\n validate(value: string): boolean {\n if (typeof value !== 'string' || value.length === 0) {\n return false;\n }\n\n const trimmed = value.trim();\n\n // Data URI\n if (trimmed.startsWith('data:image/')) {\n return true;\n }\n\n // Relative paths\n if (trimmed.startsWith('/') || trimmed.startsWith('./') || trimmed.startsWith('../')) {\n return true;\n }\n\n // Protocol-relative\n if (trimmed.startsWith('//')) {\n return true;\n }\n\n // Absolute URLs\n try {\n const url = new URL(trimmed);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n },\n\n render(value: string, attributes?: AttributeMap): string {\n const src = typeof value === 'string' ? value : '';\n const altVal = attributes?.alt;\n const widthVal = attributes?.width;\n const heightVal = attributes?.height;\n const floatVal = attributes?.float;\n const alt =\n altVal != null && (typeof altVal === 'string' || typeof altVal === 'number')\n ? ` alt=\"${escapeHtml(String(altVal))}\"`\n : '';\n const width =\n widthVal != null && (typeof widthVal === 'string' || typeof widthVal === 'number')\n ? ` width=\"${String(widthVal)}\"`\n : '';\n const height =\n heightVal != null && (typeof heightVal === 'string' || typeof heightVal === 'number')\n ? ` height=\"${String(heightVal)}\"`\n : '';\n const float =\n floatVal != null && typeof floatVal === 'string' && floatVal !== 'none'\n ? ` data-float=\"${escapeHtml(floatVal)}\"`\n : '';\n return `<img src=\"${escapeHtml(src)}\"${alt}${width}${height}${float}>`;\n },\n\n match(element: DOMElement): FormatMatchResult<string> | null {\n if (element.tagName.toLowerCase() !== 'img') return null;\n const src = element.getAttribute('src');\n if (!src) return null;\n\n const attrs: AttributeMap = {};\n const alt = element.getAttribute('alt');\n const width = element.getAttribute('width');\n const height = element.getAttribute('height');\n const float = element.getAttribute('data-float');\n\n if (alt) attrs.alt = alt;\n if (width) attrs.width = parseInt(width, 10);\n if (height) attrs.height = parseInt(height, 10);\n if (float) attrs.float = float;\n\n if (Object.keys(attrs).length > 0) {\n return { value: src, attributes: attrs };\n }\n return { value: src };\n },\n};\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\n\n/**\n * Soft Line Break embed format\n *\n * Represents a \"Shift+Enter\" style line break that does NOT split the\n * containing block (paragraph, list item, table cell, etc.). This is the\n * Delta-level analogue of HTML `<br>` used as an inline line break and\n * of the GFM \"hard break\" Markdown construct (two trailing spaces + `\\n`).\n *\n * Delta: `{ insert: { softBreak: true } }`\n * HTML: `<br data-scrider-embed>` (with the explicit marker so that\n * round-trip parsing can distinguish a soft break from the\n * placeholder `<br>` that appears inside an empty paragraph)\n * Markdown: ` \\n` (default GFM hard break) or inline `<br>` (configurable\n * via `softBreakStyle` option on `deltaToMarkdown`)\n *\n * Value is always `true` — the embed has no additional data.\n *\n * @see {@link https://github.github.com/gfm/#hard-line-breaks GFM hard line break}\n */\nexport const softBreakFormat: Format<boolean> = {\n name: 'softBreak',\n scope: 'embed',\n\n normalize(value: boolean): boolean {\n return !!value;\n },\n\n validate(value: boolean): boolean {\n return value === true;\n },\n\n render(): string {\n return '<br data-scrider-embed>';\n },\n\n match(element: DOMElement): FormatMatchResult<boolean> | null {\n if (element.tagName.toLowerCase() !== 'br') return null;\n if (!element.hasAttribute('data-scrider-embed')) return null;\n return { value: true };\n },\n\n // NB: Markdown rendering is intentionally NOT implemented on the format\n // itself. The choice between `\" \\n\"` (GFM spaces) and inline `<br>`\n // depends on the caller-provided `softBreakStyle` option on\n // `deltaToMarkdown`, so the converter handles it as a built-in special\n // case instead of going through `Format.toMarkdown`. The Markdown side\n // of the round-trip is symmetric: `markdownToDelta` recognises both\n // `break` AST nodes and inline `<br>` HTML and emits this embed.\n};\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\nimport type { AttributeMap } from '@scrider/delta';\nimport { escapeHtml, toVideoEmbedUrl, fromVideoEmbedUrl } from '../../../conversion/html/config';\n\n/**\n * Video embed format\n *\n * Delta: { insert: { video: \"https://youtube.com/watch?v=...\" } }\n *\n * Value is the video URL\n */\nexport const videoFormat: Format<string> = {\n name: 'video',\n scope: 'embed',\n\n normalize(value: string): string {\n return value.trim();\n },\n\n validate(value: string): boolean {\n if (typeof value !== 'string' || value.length === 0) {\n return false;\n }\n\n const trimmed = value.trim();\n\n // Relative paths\n if (trimmed.startsWith('/') || trimmed.startsWith('./') || trimmed.startsWith('../')) {\n return true;\n }\n\n // Protocol-relative\n if (trimmed.startsWith('//')) {\n return true;\n }\n\n // Absolute URLs\n try {\n const url = new URL(trimmed);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n },\n\n render(value: string, attributes?: AttributeMap): string {\n const src = typeof value === 'string' ? value : '';\n const floatVal = attributes?.float;\n const widthVal = attributes?.width;\n const heightVal = attributes?.height;\n const float =\n floatVal != null && typeof floatVal === 'string' && floatVal !== 'none'\n ? ` data-float=\"${escapeHtml(floatVal)}\"`\n : '';\n const styles: string[] = [];\n if (widthVal != null && (typeof widthVal === 'string' || typeof widthVal === 'number')) {\n const w = String(widthVal);\n if (w && w !== 'auto') styles.push(`width: ${/^\\d+$/.test(w) ? w + 'px' : w}`);\n }\n if (heightVal != null && (typeof heightVal === 'string' || typeof heightVal === 'number')) {\n const h = String(heightVal);\n if (h && h !== 'auto') styles.push(`height: ${/^\\d+$/.test(h) ? h + 'px' : h}`);\n }\n const style = styles.length > 0 ? ` style=\"${styles.join('; ')}\"` : '';\n const embedSrc = toVideoEmbedUrl(src);\n if (embedSrc) {\n return `<iframe src=\"${escapeHtml(embedSrc)}\" frameborder=\"0\" allowfullscreen${float}${style}></iframe>`;\n }\n return `<video src=\"${escapeHtml(src)}\" controls${float}${style}></video>`;\n },\n\n match(element: DOMElement): FormatMatchResult<string> | null {\n const tagName = element.tagName.toLowerCase();\n if (tagName !== 'video' && tagName !== 'iframe') return null;\n\n const src = element.getAttribute('src');\n if (!src) return null;\n\n const attrs: AttributeMap = {};\n const float = element.getAttribute('data-float');\n const styleAttr = element.getAttribute('style') || '';\n\n if (float) attrs.float = float;\n\n // Extract width/height from inline style\n const widthMatch = styleAttr.match(/(?:^|;\\s*)width:\\s*([^;]+)/);\n if (widthMatch?.[1]) attrs.width = widthMatch[1].trim().replace(/px$/, '');\n const heightMatch = styleAttr.match(/(?:^|;\\s*)height:\\s*([^;]+)/);\n if (heightMatch?.[1]) attrs.height = heightMatch[1].trim().replace(/px$/, '');\n\n if (Object.keys(attrs).length > 0) {\n return { value: fromVideoEmbedUrl(src), attributes: attrs };\n }\n return { value: fromVideoEmbedUrl(src) };\n },\n};\n","import type { Format } from './Format';\nimport { Registry } from './Registry';\n\n// Inline formats\nimport {\n backgroundFormat,\n boldFormat,\n codeFormat,\n colorFormat,\n fontFormat,\n italicFormat,\n kbdFormat,\n linkFormat,\n markFormat,\n sizeFormat,\n strikeFormat,\n subscriptFormat,\n superscriptFormat,\n underlineFormat,\n} from './formats/inline';\n\n// Block formats\nimport {\n alignFormat,\n blockquoteFormat,\n codeBlockFormat,\n headerFormat,\n headerIdFormat,\n indentFormat,\n listFormat,\n tableRowFormat,\n tableColFormat,\n tableHeaderFormat,\n tableColAlignFormat,\n} from './formats/block';\n\n// Embed formats\nimport {\n blockFormat,\n dividerFormat,\n footnoteRefFormat,\n formulaFormat,\n imageFormat,\n softBreakFormat,\n videoFormat,\n} from './formats/embed';\n\n// Block handlers\nimport { BlockHandlerRegistry } from './BlockHandlerRegistry';\nimport { tableBlockHandler } from './blocks/table';\nimport { footnotesBlockHandler } from './blocks/footnotes';\nimport { alertBlockHandler } from './blocks/alert';\nimport { columnsBlockHandler } from './blocks/columns';\nimport { boxBlockHandler } from './blocks/box';\n\n/**\n * All default inline formats\n */\nexport const defaultInlineFormats: Format[] = [\n boldFormat,\n italicFormat,\n underlineFormat,\n strikeFormat,\n subscriptFormat,\n superscriptFormat,\n codeFormat,\n linkFormat,\n colorFormat,\n backgroundFormat,\n fontFormat,\n sizeFormat,\n markFormat,\n kbdFormat,\n];\n\n/**\n * All default block formats\n */\nexport const defaultBlockFormats: Format[] = [\n headerFormat,\n headerIdFormat,\n blockquoteFormat,\n codeBlockFormat,\n listFormat,\n alignFormat,\n indentFormat,\n tableRowFormat,\n tableColFormat,\n tableHeaderFormat,\n tableColAlignFormat,\n];\n\n/**\n * All default embed formats\n */\nexport const defaultEmbedFormats: Format[] = [\n imageFormat,\n videoFormat,\n formulaFormat,\n dividerFormat,\n softBreakFormat,\n blockFormat,\n footnoteRefFormat,\n];\n\n/**\n * All default formats combined\n */\nexport const defaultFormats: Format[] = [\n ...defaultInlineFormats,\n ...defaultBlockFormats,\n ...defaultEmbedFormats,\n];\n\n/**\n * Create a Registry with all default formats registered\n *\n * @returns Registry with standard formats\n *\n * @example\n * ```typescript\n * const registry = createDefaultRegistry();\n * registry.normalize({ color: 'red' }); // { color: '#ff0000' }\n * ```\n */\nexport function createDefaultRegistry(): Registry {\n return new Registry().register(defaultFormats);\n}\n\n/**\n * Create a BlockHandlerRegistry with default block handlers\n *\n * Includes:\n * - tableBlockHandler (Extended Table)\n * - footnotesBlockHandler (Footnotes)\n * - alertBlockHandler (Alerts/Admonitions)\n * - columnsBlockHandler (Columns Layout)\n * - boxBlockHandler (Inline-Box / Float Container)\n *\n * @returns BlockHandlerRegistry with default handlers\n *\n * @example\n * ```typescript\n * const blockHandlers = createDefaultBlockHandlers();\n * blockHandlers.has('table'); // true\n * blockHandlers.has('footnotes'); // true\n * blockHandlers.has('alert'); // true\n * blockHandlers.has('columns'); // true\n * blockHandlers.has('box'); // true\n * ```\n */\nexport function createDefaultBlockHandlers(): BlockHandlerRegistry {\n return new BlockHandlerRegistry()\n .register(tableBlockHandler)\n .register(footnotesBlockHandler)\n .register(alertBlockHandler)\n .register(columnsBlockHandler)\n .register(boxBlockHandler);\n}\n","/**\n * Browser DOM Adapter\n *\n * Uses native browser DOM APIs for HTML parsing and serialization.\n * Only available in browser environments.\n */\n\nimport type { DOMAdapter, DOMDocument, DOMDocumentFragment, DOMNode } from './types';\n\n/**\n * Browser DOM Adapter implementation\n *\n * Uses native browser APIs:\n * - DOMParser for parsing HTML\n * - Element.outerHTML for serialization\n */\nexport class BrowserDOMAdapter implements DOMAdapter {\n /**\n * Parse HTML string into a document fragment\n *\n * Uses a template element to parse arbitrary HTML safely.\n */\n parseHTML(html: string): DOMDocumentFragment {\n if (!this.isAvailable()) {\n throw new Error('BrowserDOMAdapter is not available in this environment');\n }\n\n const template = document.createElement('template');\n template.innerHTML = html;\n\n return template.content as unknown as DOMDocumentFragment;\n }\n\n /**\n * Serialize a node to HTML string\n */\n serializeHTML(node: DOMNode | DOMDocumentFragment): string {\n if (!this.isAvailable()) {\n throw new Error('BrowserDOMAdapter is not available in this environment');\n }\n\n // DocumentFragment - serialize all children\n if (node.nodeType === 11) {\n const container = document.createElement('div');\n const clone = (node as DocumentFragment).cloneNode(true);\n container.appendChild(clone);\n return container.innerHTML;\n }\n\n // Element - use outerHTML\n if (node.nodeType === 1) {\n return (node as unknown as Element).outerHTML;\n }\n\n // Text node - return text content\n if (node.nodeType === 3) {\n return String(node.textContent ?? '');\n }\n\n return '';\n }\n\n /**\n * Create a new document for building DOM structures\n */\n createDocument(): DOMDocument {\n if (!this.isAvailable()) {\n throw new Error('BrowserDOMAdapter is not available in this environment');\n }\n\n return document as unknown as DOMDocument;\n }\n\n /**\n * Check if browser DOM APIs are available\n */\n isAvailable(): boolean {\n return typeof document !== 'undefined' && typeof document.createElement === 'function';\n }\n}\n\n/**\n * Singleton instance of browser adapter\n */\nexport const browserAdapter = new BrowserDOMAdapter();\n","/**\n * Node.js DOM Adapter\n *\n * Uses jsdom for HTML parsing and serialization in Node.js environment.\n */\n\nimport type { DOMAdapter, DOMDocument, DOMDocumentFragment, DOMNode } from './types';\n\n// jsdom types - loaded dynamically\ninterface JsdomInstance {\n window: {\n document: Document;\n };\n}\n\ninterface JsdomConstructor {\n new (html: string): JsdomInstance;\n}\n\ninterface JsdomModuleType {\n JSDOM: JsdomConstructor;\n}\n\n/**\n * Cached jsdom module (lazy loaded)\n */\nlet jsdomModule: JsdomModuleType | null = null;\nlet jsdomLoadError: Error | null = null;\n\n/**\n * Attempt to load jsdom module\n */\nasync function loadJsdom(): Promise<JsdomModuleType> {\n if (jsdomLoadError) {\n throw jsdomLoadError;\n }\n\n if (jsdomModule) {\n return jsdomModule;\n }\n\n try {\n // Dynamic import for optional dependency\n const mod = await import('jsdom');\n jsdomModule = mod as unknown as JsdomModuleType;\n return jsdomModule;\n } catch {\n jsdomLoadError = new Error('jsdom is not installed. Install it with: pnpm add jsdom');\n throw jsdomLoadError;\n }\n}\n\n/**\n * Synchronously check if jsdom is available (without loading)\n */\nfunction isJsdomAvailable(): boolean {\n // In Node.js environment, we can check if the module exists\n if (typeof window !== 'undefined') {\n return false; // Browser environment\n }\n\n try {\n // Check if already loaded\n if (jsdomModule) return true;\n if (jsdomLoadError) return false;\n\n // Try to require jsdom (sync check)\n require.resolve('jsdom');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Node.js DOM Adapter implementation\n *\n * Uses jsdom for DOM operations in Node.js environment.\n * jsdom is loaded lazily to avoid issues in browser bundles.\n */\nexport class NodeDOMAdapter implements DOMAdapter {\n private jsdom: JsdomInstance | null = null;\n\n /**\n * Parse HTML string into a document fragment\n */\n parseHTML(html: string): DOMDocumentFragment {\n const dom = this.getOrCreateJsdom();\n const template = dom.window.document.createElement('template');\n template.innerHTML = html;\n\n return template.content as unknown as DOMDocumentFragment;\n }\n\n /**\n * Serialize a node to HTML string\n */\n serializeHTML(node: DOMNode | DOMDocumentFragment): string {\n const dom = this.getOrCreateJsdom();\n\n // DocumentFragment - serialize all children\n if (node.nodeType === 11) {\n const container = dom.window.document.createElement('div');\n const clone = (node as unknown as DocumentFragment).cloneNode(true);\n container.appendChild(clone);\n return container.innerHTML;\n }\n\n // Element - use outerHTML\n if (node.nodeType === 1) {\n return (node as unknown as Element).outerHTML;\n }\n\n // Text node - return text content\n if (node.nodeType === 3) {\n return String(node.textContent ?? '');\n }\n\n return '';\n }\n\n /**\n * Create a new document for building DOM structures\n */\n createDocument(): DOMDocument {\n const dom = this.getOrCreateJsdom();\n return dom.window.document as unknown as DOMDocument;\n }\n\n /**\n * Check if jsdom is available\n */\n isAvailable(): boolean {\n return isJsdomAvailable();\n }\n\n /**\n * Initialize the adapter with jsdom (async)\n *\n * Call this before using the adapter if you want to handle\n * loading errors gracefully.\n */\n async initialize(): Promise<void> {\n const mod = await loadJsdom();\n this.jsdom = new mod.JSDOM('<!DOCTYPE html><html><body></body></html>');\n }\n\n /**\n * Get or create jsdom instance (sync, throws if not available)\n */\n private getOrCreateJsdom(): JsdomInstance {\n if (this.jsdom) {\n return this.jsdom;\n }\n\n // Synchronous require for already-resolved module\n if (!isJsdomAvailable()) {\n throw new Error('jsdom is not available. Install it with: pnpm add jsdom');\n }\n\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mod = require('jsdom') as JsdomModuleType;\n this.jsdom = new mod.JSDOM('<!DOCTYPE html><html><body></body></html>');\n\n return this.jsdom;\n }\n}\n\n/**\n * Singleton instance of Node adapter\n */\nexport const nodeAdapter = new NodeDOMAdapter();\n","/**\n * DOM Adapters\n *\n * Platform-agnostic DOM manipulation for HTML ↔ Delta conversion.\n */\n\nexport * from './types';\nexport { BrowserDOMAdapter, browserAdapter } from './browser';\nexport { NodeDOMAdapter, nodeAdapter } from './node';\n\nimport type { DOMAdapter } from './types';\nimport { browserAdapter } from './browser';\nimport { nodeAdapter } from './node';\n\n/**\n * Get the appropriate DOM adapter for the current environment\n *\n * - In browser: returns BrowserDOMAdapter (native DOM)\n * - In Node.js: returns NodeDOMAdapter (jsdom)\n *\n * @returns The appropriate DOM adapter\n * @throws Error if no adapter is available\n */\nexport function getAdapter(): DOMAdapter {\n if (browserAdapter.isAvailable()) {\n return browserAdapter;\n }\n\n if (nodeAdapter.isAvailable()) {\n return nodeAdapter;\n }\n\n throw new Error('No DOM adapter available. In Node.js, install jsdom: pnpm add jsdom');\n}\n\n/**\n * Check if any DOM adapter is available\n */\nexport function isAdapterAvailable(): boolean {\n return browserAdapter.isAvailable() || nodeAdapter.isAvailable();\n}\n","/**\n * Delta → HTML Conversion\n *\n * Converts a Delta document to an HTML string.\n */\n\nimport { Delta, isInsert, isEmbedInsert } from '@scrider/delta';\nimport type { Op, AttributeMap } from '@scrider/delta';\nimport type { BlockHandlerRegistry } from '../../schema/BlockHandlerRegistry';\nimport type { BlockContext } from '../../schema/BlockHandler';\nimport type { Registry } from '../../schema/Registry';\nimport {\n INLINE_FORMAT_ORDER,\n INLINE_FORMAT_TAGS,\n INLINE_STYLE_FORMATS,\n BLOCK_FORMAT_TAGS,\n LIST_WRAPPER_TAGS,\n EMBED_RENDERERS,\n escapeHtml,\n} from './config';\nimport { slugifyWithDedup } from '../utils/slugify';\nimport {\n documentPresentationStyleParts,\n joinStyleParts,\n resolveDocumentPresentation,\n type DocumentPresentation,\n} from './document-presentation';\nimport {\n buildTableCellStyleAttr,\n resolveTablePresentation,\n tableOpenTag,\n type TableCellAlign,\n type TablePresentation,\n} from './table-presentation';\n\nexport type { TableCellAlign, TablePresentation, DocumentPresentation };\n\n/**\n * Options for Delta → HTML conversion\n */\nexport interface DeltaToHtmlOptions {\n /**\n * Pretty print output with indentation\n * @default false\n */\n pretty?: boolean;\n\n /**\n * Custom embed renderers (merged with defaults)\n */\n embedRenderers?: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>;\n\n /**\n * Wrap output in a container element\n * @default undefined (no wrapper)\n */\n wrapper?: string;\n\n /**\n * Use semantic HTML5 elements\n * @default true\n */\n semantic?: boolean;\n\n /**\n * Use hierarchical numbering for ordered lists (e.g., 1, 1.1, 1.1.1)\n * When enabled, list items get data-number attribute with calculated number\n * @default false\n */\n hierarchicalNumbers?: boolean;\n\n /**\n * Block handler registry for complex block embeds (Extended Table, etc.)\n * When provided, `{ insert: { block: { type, ... } } }` ops are dispatched\n * to the matching BlockHandler.toHtml() for rendering.\n */\n blockHandlers?: BlockHandlerRegistry;\n\n /**\n * Generate anchor link `id` attributes on heading elements (`<h1>`-`<h6>`).\n *\n * When enabled, headings get an `id` computed via slugify(text).\n * If a heading has an explicit `header-id` attribute in Delta, that id is used instead.\n * Duplicate slugs are deduplicated with `-1`, `-2` suffixes.\n *\n * @default false\n */\n anchorLinks?: boolean;\n\n /**\n * Format registry for custom embed rendering.\n *\n * When provided, embed formats with a `render()` method are used\n * before falling back to built-in EMBED_RENDERERS.\n * This enables extensibility without modifying converter internals.\n */\n registry?: Registry;\n\n /**\n * Simple Table presentation (borders, shades, header style) as inline CSS for\n * Office/HTML export and clipboard. Does not change Delta; omitted = legacy bare `<table>`.\n */\n tablePresentation?: TablePresentation;\n\n /**\n * Document-level paragraph styles (line spacing, first-line indent) as inline CSS for\n * Office/HTML export and clipboard. Does not change Delta.\n */\n documentPresentation?: DocumentPresentation;\n}\n\n/**\n * Line content with its formatting\n */\ninterface LineContent {\n ops: Op[];\n attributes: AttributeMap | undefined;\n}\n\n/**\n * Convert a Delta to an HTML string\n *\n * @param delta - The Delta to convert\n * @param options - Conversion options\n * @returns HTML string\n *\n * @example\n * ```typescript\n * const delta = new Delta()\n * .insert('Hello ', { bold: true })\n * .insert('World')\n * .insert('\\n', { header: 1 });\n *\n * const html = deltaToHtml(delta);\n * // '<h1><strong>Hello </strong>World</h1>'\n * ```\n */\nexport function deltaToHtml(delta: Delta, options: DeltaToHtmlOptions = {}): string {\n const lines = splitIntoLines(delta);\n const embedRenderers = { ...EMBED_RENDERERS, ...options.embedRenderers };\n const pretty = options.pretty ?? false;\n const hierarchicalNumbers = options.hierarchicalNumbers ?? false;\n const blockHandlers = options.blockHandlers;\n const anchorLinks = options.anchorLinks ?? false;\n const resolvedDocumentPresentation = resolveDocumentPresentation(options.documentPresentation);\n\n let html = '';\n let listStack: { type: string; indent: number }[] = [];\n\n // Hierarchical numbering counters: counters[0] = top level, counters[1] = first nested, etc.\n let counters: number[] = [];\n\n // Slug deduplication map for anchor links on headings\n const slugUsageMap = new Map<string, number>();\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (!line) continue;\n\n // Handle table grouping (adjacent lines with table-row attribute)\n if (isTableLine(line)) {\n html += closeAllLists(listStack, pretty);\n listStack = [];\n counters = [];\n\n const tableLines = collectTableLines(lines, i);\n html += renderTable(tableLines, embedRenderers, pretty, blockHandlers, options);\n i += tableLines.length - 1;\n continue;\n }\n\n const { tag, isList, listType, indent, isCodeBlock } = getBlockInfo(line.attributes);\n\n // Handle code block grouping (similar to lists)\n if (isCodeBlock) {\n // Close any open lists first\n html += closeAllLists(listStack, pretty);\n listStack = [];\n counters = [];\n\n // Collect all adjacent code-block lines\n const codeLines = collectCodeBlockLines(lines, i);\n const language = getCodeBlockLanguage(line.attributes);\n html += renderCodeBlock(codeLines, language, embedRenderers, pretty, blockHandlers, options);\n i += codeLines.length - 1; // Skip processed lines\n continue;\n }\n\n // Handle block-level embeds (e.g. <hr>) — render directly without <p> wrapper\n if (!isList && isBlockLevelEmbedLine(line)) {\n html += closeAllLists(listStack, pretty);\n listStack = [];\n counters = [];\n html += renderLineContent(line.ops, embedRenderers, blockHandlers, options);\n if (pretty) html += '\\n';\n continue;\n }\n\n // Handle list nesting\n if (isList) {\n html += handleListOpen(listStack, listType!, indent, pretty);\n\n // Update hierarchical counters for ordered lists\n if (hierarchicalNumbers && listType === 'ordered') {\n // Trim counters if we went back to a higher level\n if (counters.length > indent + 1) {\n counters = counters.slice(0, indent + 1);\n }\n // Extend counters if we went deeper\n // Use 1 for skipped parent levels (handles broken lists starting with nested items)\n while (counters.length < indent) {\n counters.push(1);\n }\n if (counters.length === indent) {\n counters.push(0); // Current level starts at 0, will be incremented below\n }\n // Increment counter at current level\n counters[indent] = (counters[indent] || 0) + 1;\n }\n } else {\n html += closeAllLists(listStack, pretty);\n listStack = [];\n // Reset counters when exiting list context\n counters = [];\n }\n\n // Render line content\n const content = renderLineContent(line.ops, embedRenderers, blockHandlers, options);\n\n // Wrap in block tag\n if (isList) {\n const listItemAttrs = getListItemAttributes(line.attributes);\n const indentLevel = listStack.length;\n\n // Calculate hierarchical number if enabled\n let hierarchicalNumber: string | undefined;\n if (hierarchicalNumbers && listType === 'ordered') {\n hierarchicalNumber = counters.slice(0, indent + 1).join('.');\n }\n\n html += renderListItem(\n content,\n listItemAttrs,\n pretty,\n indentLevel,\n hierarchicalNumber,\n resolvedDocumentPresentation,\n );\n } else {\n // Generate anchor id for headings\n let headingId: string | undefined;\n if (line.attributes?.header) {\n const customId = line.attributes['header-id'];\n if (typeof customId === 'string' && customId.length > 0) {\n headingId = customId;\n } else if (anchorLinks) {\n const plainText = extractPlainText(line.ops);\n headingId = slugifyWithDedup(plainText, slugUsageMap);\n }\n }\n html += renderBlock(\n content,\n tag,\n line.attributes,\n pretty,\n headingId,\n resolvedDocumentPresentation,\n );\n }\n }\n\n // Close any remaining lists\n html += closeAllLists(listStack, pretty);\n\n // Wrap in container if specified\n if (options.wrapper) {\n html = `<${options.wrapper}>${html}</${options.wrapper}>`;\n }\n\n return html;\n}\n\n/**\n * Get indentation string for pretty printing\n */\nfunction getIndent(level: number): string {\n return ' '.repeat(level);\n}\n\n/**\n * Split Delta into lines based on \\n characters\n */\nfunction splitIntoLines(delta: Delta): LineContent[] {\n const lines: LineContent[] = [];\n let currentOps: Op[] = [];\n\n for (const op of delta.ops) {\n if (!isInsert(op)) continue;\n\n if (isEmbedInsert(op)) {\n // Embeds are inline, add to current line\n currentOps.push(op);\n continue;\n }\n\n // Text insert - split by newlines\n const text = op.insert as string;\n const parts = text.split('\\n');\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n if (part === undefined) continue;\n\n // Add text content to current line\n if (part.length > 0) {\n currentOps.push({\n insert: part,\n ...(op.attributes && { attributes: op.attributes }),\n });\n }\n\n // If not the last part, this is a line break\n if (i < parts.length - 1) {\n lines.push({\n ops: currentOps,\n attributes: op.attributes, // Line attributes come from the \\n op\n });\n currentOps = [];\n }\n }\n }\n\n // Handle remaining content (no trailing \\n)\n if (currentOps.length > 0) {\n lines.push({\n ops: currentOps,\n attributes: undefined,\n });\n }\n\n return lines;\n}\n\n/**\n * Check if a line contains only a block-level embed (e.g. divider/hr).\n * These embeds should be rendered directly without a <p> wrapper,\n * since they are block-level void elements in HTML.\n *\n * Embeds with a `float` attribute are also treated as block-level,\n * because floated elements (images, videos) should not be wrapped in `<p>`.\n */\nconst BLOCK_LEVEL_EMBEDS = new Set(['divider', 'block']);\n\nfunction isBlockLevelEmbedLine(line: LineContent): boolean {\n if (line.ops.length !== 1) return false;\n const op = line.ops[0];\n if (!op || !isEmbedInsert(op)) return false;\n const embed = op.insert as Record<string, unknown>;\n const embedType = Object.keys(embed)[0];\n if (!!embedType && BLOCK_LEVEL_EMBEDS.has(embedType)) return true;\n // Embeds with float attribute are block-level (no <p> wrapper needed)\n const attrs = op.attributes as Record<string, unknown> | undefined;\n if (attrs && typeof attrs.float === 'string' && attrs.float !== 'none') return true;\n return false;\n}\n\n/**\n * Check if a line is a table cell\n */\nfunction isTableLine(line: LineContent): boolean {\n return (\n line.attributes != null &&\n typeof line.attributes['table-row'] === 'number' &&\n typeof line.attributes['table-col'] === 'number'\n );\n}\n\n/**\n * Collect all adjacent table lines starting from the given index\n */\nfunction collectTableLines(lines: LineContent[], startIndex: number): LineContent[] {\n const result: LineContent[] = [];\n for (let i = startIndex; i < lines.length; i++) {\n const line = lines[i];\n if (!line || !isTableLine(line)) break;\n result.push(line);\n }\n return result;\n}\n\n/**\n * Grouped cell data for rendering\n */\ninterface TableCell {\n ops: Op[];\n colAlign?: string | undefined;\n}\n\n/**\n * Render a group of table lines as an HTML <table>\n */\nfunction renderTable(\n tableLines: LineContent[],\n embedRenderers: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>,\n pretty: boolean,\n blockHandlers?: BlockHandlerRegistry,\n options?: DeltaToHtmlOptions,\n): string {\n // Group lines by row, preserving column order\n const rows = new Map<number, { isHeader: boolean; cells: Map<number, TableCell> }>();\n\n for (const line of tableLines) {\n const attrs = line.attributes!;\n const rowIdx = attrs['table-row'] as number;\n const colIdx = attrs['table-col'] as number;\n\n if (!rows.has(rowIdx)) {\n rows.set(rowIdx, { isHeader: !!attrs['table-header'], cells: new Map() });\n }\n\n const row = rows.get(rowIdx)!;\n if (attrs['table-header']) row.isHeader = true;\n row.cells.set(colIdx, {\n ops: line.ops,\n colAlign: typeof attrs['table-col-align'] === 'string' ? attrs['table-col-align'] : undefined,\n });\n }\n\n // Sort rows by index\n const sortedRows = [...rows.entries()].sort((a, b) => a[0] - b[0]);\n\n // Determine max columns\n let maxCol = 0;\n for (const [, row] of sortedRows) {\n for (const colIdx of row.cells.keys()) {\n if (colIdx > maxCol) maxCol = colIdx;\n }\n }\n\n // Separate header and body rows\n const headerRows = sortedRows.filter(([, r]) => r.isHeader);\n const bodyRows = sortedRows.filter(([, r]) => !r.isHeader);\n\n const indent = pretty ? ' ' : '';\n const nl = pretty ? '\\n' : '';\n const usePresentation = options?.tablePresentation !== undefined;\n const presentation = usePresentation ? resolveTablePresentation(options.tablePresentation) : null;\n const headerRowCount = headerRows.length;\n\n let html = usePresentation && presentation ? `${tableOpenTag(presentation)}${nl}` : `<table>${nl}`;\n\n // Render <thead>\n if (headerRows.length > 0) {\n html += `${indent}<thead>${nl}`;\n for (const [, row] of headerRows) {\n html += renderTableRow(\n row.cells,\n maxCol,\n 'th',\n embedRenderers,\n pretty,\n 2,\n blockHandlers,\n options,\n presentation,\n headerRowCount,\n );\n }\n html += `${indent}</thead>${nl}`;\n }\n\n // Render <tbody>\n if (bodyRows.length > 0) {\n html += `${indent}<tbody>${nl}`;\n let bodyRowIndex = 0;\n for (const [, row] of bodyRows) {\n html += renderTableRow(\n row.cells,\n maxCol,\n 'td',\n embedRenderers,\n pretty,\n 2,\n blockHandlers,\n options,\n presentation,\n headerRowCount,\n bodyRowIndex,\n );\n bodyRowIndex += 1;\n }\n html += `${indent}</tbody>${nl}`;\n }\n\n html += `</table>`;\n if (pretty) html += '\\n';\n return html;\n}\n\n/**\n * Render a single table row (<tr>)\n */\nfunction renderTableRow(\n cells: Map<number, TableCell>,\n maxCol: number,\n cellTag: 'th' | 'td',\n embedRenderers: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>,\n pretty: boolean,\n depth: number,\n blockHandlers?: BlockHandlerRegistry,\n options?: DeltaToHtmlOptions,\n presentation?: ReturnType<typeof resolveTablePresentation> | null,\n headerRowCount = 0,\n bodyRowIndex?: number,\n): string {\n const indent = pretty ? ' '.repeat(depth) : '';\n const cellIndent = pretty ? ' '.repeat(depth + 1) : '';\n const nl = pretty ? '\\n' : '';\n\n let html = `${indent}<tr>${nl}`;\n\n for (let col = 0; col <= maxCol; col++) {\n const cell = cells.get(col);\n const content = cell ? renderLineContent(cell.ops, embedRenderers, blockHandlers, options) : '';\n let styleAttr = '';\n if (presentation) {\n styleAttr = buildTableCellStyleAttr({\n presentation,\n cellTag,\n colAlign: cell?.colAlign,\n headerRowCount,\n bodyRowIndex: cellTag === 'td' ? bodyRowIndex : undefined,\n });\n } else {\n styleAttr =\n cell?.colAlign && cell.colAlign !== 'left' ? ` style=\"text-align: ${cell.colAlign}\"` : '';\n }\n html += `${cellIndent}<${cellTag}${styleAttr}>${content}</${cellTag}>${nl}`;\n }\n\n html += `${indent}</tr>${nl}`;\n return html;\n}\n\n/**\n * Get block element info from line attributes\n */\nfunction getBlockInfo(attributes: AttributeMap | undefined): {\n tag: string;\n isList: boolean;\n isCodeBlock: boolean;\n listType: string | undefined;\n indent: number;\n} {\n if (!attributes) {\n return { tag: 'p', isList: false, isCodeBlock: false, listType: undefined, indent: 0 };\n }\n\n const indent = typeof attributes.indent === 'number' ? attributes.indent : 0;\n\n // Check for code block (handled separately with grouping)\n if (attributes['code-block']) {\n return { tag: 'pre', isList: false, isCodeBlock: true, listType: undefined, indent };\n }\n\n // Check for list\n if (attributes.list) {\n const listVal = attributes.list;\n const listType = typeof listVal === 'string' ? listVal : 'bullet';\n return { tag: 'li', isList: true, isCodeBlock: false, listType, indent };\n }\n\n // Check for other block formats\n for (const [format, tagOrFn] of Object.entries(BLOCK_FORMAT_TAGS)) {\n if (format in attributes && format !== 'list' && format !== 'code-block') {\n const tag = typeof tagOrFn === 'function' ? tagOrFn(attributes[format]) : tagOrFn;\n return { tag, isList: false, isCodeBlock: false, listType: undefined, indent };\n }\n }\n\n return { tag: 'p', isList: false, isCodeBlock: false, listType: undefined, indent };\n}\n\n/**\n * Collect consecutive code block lines (same language)\n */\nfunction collectCodeBlockLines(lines: LineContent[], startIndex: number): LineContent[] {\n const codeLines: LineContent[] = [];\n const startLine = lines[startIndex];\n if (!startLine) return codeLines;\n\n const startLang = getCodeBlockLanguage(startLine.attributes);\n\n for (let i = startIndex; i < lines.length; i++) {\n const line = lines[i];\n if (!line || !line.attributes?.['code-block']) break;\n\n const lang = getCodeBlockLanguage(line.attributes);\n if (i > startIndex && lang !== startLang) break;\n\n codeLines.push(line);\n }\n\n return codeLines;\n}\n\n/**\n * Get language from code-block attribute\n */\nfunction getCodeBlockLanguage(attributes: AttributeMap | undefined): string | undefined {\n if (!attributes) return undefined;\n const codeBlock = attributes['code-block'];\n if (typeof codeBlock === 'string' && codeBlock !== 'true') {\n return codeBlock;\n }\n return undefined;\n}\n\n/**\n * Render a code block (grouped lines)\n */\nfunction renderCodeBlock(\n codeLines: LineContent[],\n language: string | undefined,\n embedRenderers: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>,\n pretty: boolean,\n blockHandlers?: BlockHandlerRegistry,\n options?: DeltaToHtmlOptions,\n): string {\n // Render each line's content (no HTML escaping of structure — just text)\n const lineContents = codeLines.map((line) =>\n renderLineContent(line.ops, embedRenderers, blockHandlers, options),\n );\n const code = lineContents.join('\\n');\n\n const langClass = language ? ` class=\"language-${escapeHtml(language)}\"` : '';\n const langAttr = language ? ` data-language=\"${escapeHtml(language)}\"` : '';\n const html = `<pre${langAttr}><code${langClass}>${code}\\n</code></pre>`;\n return pretty ? html + '\\n' : html;\n}\n\n/**\n * Handle opening list tags based on indent level\n */\nfunction handleListOpen(\n stack: { type: string; indent: number }[],\n listType: string,\n indent: number,\n pretty: boolean,\n): string {\n let html = '';\n const wrapperTag = LIST_WRAPPER_TAGS[listType] || 'ul';\n\n // Close lists that are at higher indent levels\n while (stack.length > 0) {\n const last = stack[stack.length - 1];\n if (!last || last.indent <= indent) break;\n const closed = stack.pop();\n if (closed) {\n const closeTag = LIST_WRAPPER_TAGS[closed.type] || 'ul';\n if (pretty) html += getIndent(stack.length);\n html += `</${closeTag}>`;\n if (pretty) html += '\\n';\n }\n }\n\n // Close and reopen if list type changed at same level\n const top = stack[stack.length - 1];\n if (top && top.indent === indent && top.type !== listType) {\n const closed = stack.pop();\n if (closed) {\n const closeTag = LIST_WRAPPER_TAGS[closed.type] || 'ul';\n if (pretty) html += getIndent(stack.length);\n html += `</${closeTag}>`;\n if (pretty) html += '\\n';\n }\n }\n\n // Open new lists as needed\n while (true) {\n const last = stack[stack.length - 1];\n const currentIndent = last ? last.indent + 1 : 0;\n\n if (currentIndent > indent) break;\n\n if (pretty) html += getIndent(stack.length);\n html += `<${wrapperTag}>`;\n if (pretty) html += '\\n';\n stack.push({ type: listType, indent: currentIndent });\n\n if (currentIndent >= indent) break;\n }\n\n // Ensure list is open at current level\n const current = stack[stack.length - 1];\n if (!current || current.indent < indent) {\n if (pretty) html += getIndent(stack.length);\n html += `<${wrapperTag}>`;\n if (pretty) html += '\\n';\n stack.push({ type: listType, indent });\n }\n\n return html;\n}\n\n/**\n * Close all open lists\n */\nfunction closeAllLists(stack: { type: string; indent: number }[], pretty: boolean): string {\n let html = '';\n while (stack.length > 0) {\n const closed = stack.pop()!;\n const closeTag = LIST_WRAPPER_TAGS[closed.type] || 'ul';\n if (pretty) html += getIndent(stack.length);\n html += `</${closeTag}>`;\n if (pretty) html += '\\n';\n }\n return html;\n}\n\n/**\n * Get list item specific attributes (checked/unchecked)\n */\nfunction getListItemAttributes(attributes: AttributeMap | undefined): string {\n if (!attributes) return '';\n\n const listType = attributes.list;\n if (listType === 'checked') {\n return ' data-checked=\"true\"';\n }\n if (listType === 'unchecked') {\n return ' data-checked=\"false\"';\n }\n\n return '';\n}\n\n/**\n * Render a list item\n */\nfunction renderListItem(\n content: string,\n attrs: string,\n pretty: boolean,\n indentLevel: number,\n hierarchicalNumber?: string,\n resolvedDocumentPresentation?: ReturnType<typeof resolveDocumentPresentation>,\n): string {\n const indent = pretty ? getIndent(indentLevel) : '';\n // Use <br> for empty list items so they have height in browser\n const innerContent = content || '<br>';\n\n // Add data-number attribute for hierarchical numbering\n let fullAttrs = attrs;\n if (hierarchicalNumber) {\n fullAttrs += ` data-number=\"${hierarchicalNumber}\"`;\n }\n\n const styleAttr = joinStyleParts(\n documentPresentationStyleParts('li', resolvedDocumentPresentation),\n );\n fullAttrs += styleAttr;\n\n const html = `${indent}<li${fullAttrs}>${innerContent}</li>`;\n return pretty ? html + '\\n' : html;\n}\n\n/**\n * Render a block element\n */\nfunction renderBlock(\n content: string,\n tag: string,\n attributes: AttributeMap | undefined,\n pretty?: boolean,\n id?: string,\n resolvedDocumentPresentation?: ReturnType<typeof resolveDocumentPresentation>,\n): string {\n const idAttr = id ? ` id=\"${escapeHtml(id)}\"` : '';\n const styleAttr = getBlockStyleAttribute(tag, attributes, resolvedDocumentPresentation);\n // Use <br> for empty paragraphs so they have height in browser\n const innerContent = content || '<br>';\n const html = `<${tag}${idAttr}${styleAttr}>${innerContent}</${tag}>`;\n return pretty ? html + '\\n' : html;\n}\n\n/**\n * Get style attribute for block element (alignment, document presentation, etc.)\n */\nfunction getBlockStyleAttribute(\n tag: string,\n attributes: AttributeMap | undefined,\n resolvedDocumentPresentation?: ReturnType<typeof resolveDocumentPresentation>,\n): string {\n const styles: string[] = documentPresentationStyleParts(tag, resolvedDocumentPresentation);\n\n if (attributes) {\n const alignVal = attributes.align;\n if (alignVal && typeof alignVal === 'string' && alignVal !== 'left') {\n styles.push(`text-align: ${alignVal}`);\n }\n\n if (attributes.indent && typeof attributes.indent === 'number') {\n // Skip indent for lists (handled by nesting)\n if (!attributes.list) {\n styles.push(`margin-left: ${attributes.indent * 2}em`);\n }\n }\n }\n\n return joinStyleParts(styles);\n}\n\n/**\n * Extract plain text from line ops (for slugify).\n * Walks insert ops, collecting text strings and ignoring embeds/formatting.\n */\nfunction extractPlainText(ops: Op[]): string {\n let text = '';\n for (const op of ops) {\n if (isInsert(op) && typeof op.insert === 'string') {\n text += op.insert;\n }\n }\n return text;\n}\n\n/**\n * Render line content (inline elements and embeds)\n */\nfunction renderLineContent(\n ops: Op[],\n embedRenderers: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>,\n blockHandlers?: BlockHandlerRegistry,\n options?: DeltaToHtmlOptions,\n): string {\n let html = '';\n\n for (const op of ops) {\n if (!isInsert(op)) continue;\n\n if (isEmbedInsert(op)) {\n html += renderEmbed(\n op.insert as Record<string, unknown>,\n op.attributes,\n embedRenderers,\n blockHandlers,\n options,\n );\n } else {\n html += renderInlineText(op.insert as string, op.attributes);\n }\n }\n\n return html;\n}\n\n/**\n * Render inline text with formatting\n */\nfunction renderInlineText(text: string, attributes: AttributeMap | undefined): string {\n if (!text) return '';\n\n let html = escapeHtml(text);\n\n if (!attributes) return html;\n\n // Apply style-based formats first (wrap in span if needed)\n const styles: string[] = [];\n for (const [format, cssProperty] of Object.entries(INLINE_STYLE_FORMATS)) {\n if (format in attributes) {\n styles.push(`${cssProperty}: ${String(attributes[format])}`);\n }\n }\n\n if (styles.length > 0) {\n html = `<span style=\"${styles.join('; ')}\">${html}</span>`;\n }\n\n // Apply tag-based formats (in reverse order for proper nesting)\n for (let i = INLINE_FORMAT_ORDER.length - 1; i >= 0; i--) {\n const format = INLINE_FORMAT_ORDER[i];\n if (!format) continue;\n if (!(format in attributes)) continue;\n\n const tag = INLINE_FORMAT_TAGS[format];\n if (!tag) continue;\n\n if (format === 'link') {\n const href = escapeHtml(String(attributes.link));\n html = `<a href=\"${href}\">${html}</a>`;\n } else {\n html = `<${tag}>${html}</${tag}>`;\n }\n }\n\n return html;\n}\n\n/**\n * Render an embed\n */\nfunction renderEmbed(\n value: Record<string, unknown>,\n attributes: AttributeMap | undefined,\n renderers: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>,\n blockHandlers?: BlockHandlerRegistry,\n options?: DeltaToHtmlOptions,\n): string {\n const embedType: string | undefined = Object.keys(value)[0];\n if (!embedType) return '';\n\n // Block embed dispatch: { block: { type: \"table\", ... } }\n if (embedType === 'block' && blockHandlers) {\n const blockData = value.block as Record<string, unknown>;\n if (blockData && typeof blockData.type === 'string') {\n const handler = blockHandlers.get(blockData.type);\n if (handler) {\n // Validate block data before rendering — skip invalid blocks gracefully\n if (handler.validate && !handler.validate(blockData)) {\n return ''; // invalid block data — skip\n }\n const context: BlockContext = {\n registry: null as unknown as Registry,\n options: { pretty: options?.pretty ?? false },\n renderDelta: (ops: Op[]) => deltaToHtml(new Delta(ops), options ?? {}),\n ...(attributes ? { opAttributes: attributes as Record<string, unknown> } : {}),\n };\n return handler.toHtml(blockData, context);\n }\n }\n return ''; // unknown block type — graceful fallback\n }\n\n const embedValue: unknown = value[embedType];\n\n // Check registry format render() first\n const registry = options?.registry;\n if (registry) {\n const format = registry.get(embedType);\n if (format?.render) {\n return format.render(embedValue, attributes);\n }\n }\n\n const renderer: ((value: unknown, attrs?: Record<string, unknown>) => string) | undefined =\n renderers[embedType];\n if (renderer) {\n return renderer(embedValue, attributes as Record<string, unknown> | undefined);\n }\n\n // Fallback: render as data attribute\n return `<span data-embed=\"${escapeHtml(embedType)}\" data-value=\"${escapeHtml(String(embedValue))}\"></span>`;\n}\n","/**\n * GitHub-compatible slugify for heading anchor links.\n *\n * Algorithm matches GitHub's heading-to-id conversion:\n * 1. Trim leading/trailing whitespace\n * 2. Convert to lowercase\n * 3. Remove everything except word characters (letters, digits, underscore),\n * spaces, hyphens (preserves Unicode letters via \\p{L})\n * 4. Replace spaces with hyphens\n * 5. Collapse consecutive hyphens\n * 6. Trim leading/trailing hyphens\n *\n * @param text - heading plain text content\n * @returns slugified string suitable for HTML id attribute\n *\n * @example\n * ```typescript\n * slugify('Getting Started'); // 'getting-started'\n * slugify('API Reference (v2)'); // 'api-reference-v2'\n * slugify('Что нового?'); // 'что-нового'\n * slugify(' Hello World '); // 'hello--world' → 'hello-world'\n * ```\n */\nexport function slugify(text: string): string {\n return (\n text\n .trim()\n .toLowerCase()\n // Remove everything except: letters (Unicode), digits, spaces, hyphens, underscores\n .replace(/[^\\p{L}\\p{N}\\s\\-_]/gu, '')\n // Replace whitespace with hyphens\n .replace(/\\s+/g, '-')\n // Collapse consecutive hyphens\n .replace(/-{2,}/g, '-')\n // Trim leading/trailing hyphens\n .replace(/^-+|-+$/g, '')\n );\n}\n\n/**\n * Slugify with deduplication: appends `-1`, `-2`, etc. on collision.\n *\n * Tracks used slugs via a Map. Call this for each heading in order during\n * a single document render pass.\n *\n * @param text - heading plain text content\n * @param usedSlugs - mutable map tracking slug usage counts\n * @returns unique slugified string\n *\n * @example\n * ```typescript\n * const used = new Map<string, number>();\n * slugifyWithDedup('FAQ', used); // 'faq'\n * slugifyWithDedup('FAQ', used); // 'faq-1'\n * slugifyWithDedup('FAQ', used); // 'faq-2'\n * ```\n */\nexport function slugifyWithDedup(text: string, usedSlugs: Map<string, number>): string {\n const base = slugify(text);\n const count = usedSlugs.get(base) ?? 0;\n usedSlugs.set(base, count + 1);\n\n if (count === 0) {\n return base;\n }\n return `${base}-${count}`;\n}\n","/**\n * Document-level HTML presentation for deltaToHtml (clipboard, export).\n * Not stored in Delta — mirrors editor Settings (line spacing, first-line indent).\n */\n\nexport interface DocumentPresentation {\n /** Line spacing multiplier, e.g. 1.5 */\n lineSpacing?: number;\n /** First-line indent in centimeters, e.g. 1.25 */\n textIndentCm?: number;\n}\n\nexport interface ResolvedDocumentPresentation {\n lineSpacing: number | undefined;\n textIndentCm: number | undefined;\n}\n\nexport function resolveDocumentPresentation(\n presentation?: DocumentPresentation,\n): ResolvedDocumentPresentation | undefined {\n if (!presentation) return undefined;\n\n const lineSpacing =\n typeof presentation.lineSpacing === 'number' && presentation.lineSpacing > 0\n ? presentation.lineSpacing\n : undefined;\n const textIndentCm =\n typeof presentation.textIndentCm === 'number' && presentation.textIndentCm > 0\n ? presentation.textIndentCm\n : undefined;\n\n if (lineSpacing === undefined && textIndentCm === undefined) return undefined;\n\n return { lineSpacing, textIndentCm };\n}\n\n/** Block tags that receive document line spacing (not headings). */\nconst LINE_HEIGHT_TAGS = new Set(['p', 'li', 'blockquote']);\n\nexport function documentPresentationStyleParts(\n tag: string,\n resolved: ResolvedDocumentPresentation | undefined,\n): string[] {\n if (!resolved) return [];\n\n const parts: string[] = [];\n\n if (resolved.lineSpacing !== undefined && LINE_HEIGHT_TAGS.has(tag)) {\n const pct = Math.round(resolved.lineSpacing * 100);\n parts.push(`line-height:${resolved.lineSpacing}`);\n parts.push(`mso-line-height-alt:${pct}%`);\n }\n\n if (resolved.textIndentCm !== undefined && tag === 'p') {\n parts.push(`text-indent:${resolved.textIndentCm}cm`);\n }\n\n return parts;\n}\n\nexport function joinStyleParts(parts: string[]): string {\n return parts.length > 0 ? ` style=\"${parts.join('; ')}\"` : '';\n}\n","/**\n * Simple Table HTML presentation options for deltaToHtml (clipboard, export).\n * Structural data stays in Delta (table-row, table-col-align); this only affects inline styles.\n */\n\n/** Column/cell horizontal alignment (GFM subset). */\nexport type TableCellAlign = 'left' | 'center' | 'right';\n\n/** Optional styling when serializing Simple Tables to HTML. */\nexport interface TablePresentation {\n /** Full 1px border on all cell sides. When true, `line` is ignored. */\n grid?: boolean;\n /** Bottom border only (DeepSeek / ChatGPT). Used when `grid` is not true. */\n line?: boolean;\n /** Border color as explicit hex (e.g. `#e7e7e7`). */\n borderColor?: string;\n /** Background on header cells (`th`). */\n headerShade?: boolean;\n /** Background on even table rows in the body (see `isZebraBodyRow`). */\n zebraRows?: boolean;\n /** `font-weight: bold` on `th`. */\n headerBold?: boolean;\n /** `text-align: center` on `th` (GitHub-style header). */\n headerCenter?: boolean;\n /**\n * Alignment for cells without `table-col-align` in Delta. Never overrides GFM column align.\n * @default 'left'\n */\n defaultCellAlign?: TableCellAlign;\n}\n\nconst DEFAULT_BORDER_COLOR = '#e7e7e7';\nconst DEFAULT_HEADER_BG = '#f5f5f5';\nconst DEFAULT_ZEBRA_BG = '#fafafa';\nconst CELL_PADDING = '6px 13px';\n\nexport interface ResolvedTablePresentation {\n grid: boolean;\n line: boolean;\n borderColor: string;\n headerShade: boolean;\n zebraRows: boolean;\n headerBold: boolean;\n headerCenter: boolean;\n defaultCellAlign: TableCellAlign;\n}\n\nexport function resolveTablePresentation(\n presentation?: TablePresentation,\n): ResolvedTablePresentation {\n return {\n grid: presentation?.grid === true,\n line: presentation?.line === true && presentation?.grid !== true,\n borderColor: presentation?.borderColor ?? DEFAULT_BORDER_COLOR,\n headerShade: presentation?.headerShade === true,\n zebraRows: presentation?.zebraRows === true,\n headerBold: presentation?.headerBold === true,\n headerCenter: presentation?.headerCenter === true,\n defaultCellAlign: presentation?.defaultCellAlign ?? 'left',\n };\n}\n\n/** Match CSS `tr:nth-child(even) td` when header rows precede body in `<table>`. */\nexport function isZebraBodyRow(headerRowCount: number, bodyRowIndex: number): boolean {\n return (headerRowCount + bodyRowIndex + 1) % 2 === 0;\n}\n\nfunction isTableCellAlign(value: string | undefined): value is TableCellAlign {\n return value === 'left' || value === 'center' || value === 'right';\n}\n\nexport function tableOpenTag(presentation: ResolvedTablePresentation): string {\n if (!presentation.grid && !presentation.line) {\n return '<table>';\n }\n return `<table style=\"border-collapse: collapse\">`;\n}\n\nexport interface TableCellStyleParams {\n presentation: ResolvedTablePresentation;\n cellTag: 'th' | 'td';\n colAlign?: string | undefined;\n headerRowCount: number;\n /** Index among body rows only (0 = first `<tr>` in `<tbody>`). */\n bodyRowIndex?: number | undefined;\n}\n\nexport function buildTableCellStyleAttr(params: TableCellStyleParams): string {\n const { presentation, cellTag, colAlign, headerRowCount, bodyRowIndex } = params;\n const parts: string[] = [];\n\n parts.push(`padding: ${CELL_PADDING}`);\n\n const color = presentation.borderColor;\n if (presentation.grid) {\n parts.push(`border: 1px solid ${color}`);\n } else if (presentation.line) {\n const width = cellTag === 'th' ? '1px' : '0.5px';\n parts.push(`border-bottom: ${width} solid ${color}`);\n }\n\n let textAlign: TableCellAlign | undefined;\n if (cellTag === 'th' && presentation.headerCenter) {\n textAlign = 'center';\n } else if (isTableCellAlign(colAlign)) {\n textAlign = colAlign;\n } else if (colAlign == null || colAlign === 'left') {\n textAlign = presentation.defaultCellAlign;\n }\n\n if (textAlign && textAlign !== 'left') {\n parts.push(`text-align: ${textAlign}`);\n }\n\n if (cellTag === 'th' && presentation.headerBold) {\n parts.push('font-weight: bold');\n }\n\n if (cellTag === 'th' && presentation.headerShade) {\n parts.push(`background-color: ${DEFAULT_HEADER_BG}`);\n } else if (\n cellTag === 'td' &&\n presentation.zebraRows &&\n bodyRowIndex !== undefined &&\n isZebraBodyRow(headerRowCount, bodyRowIndex)\n ) {\n parts.push(`background-color: ${DEFAULT_ZEBRA_BG}`);\n }\n\n return ` style=\"${parts.join('; ')}\"`;\n}\n","/**\n * HTML → Delta Conversion\n *\n * Converts HTML string to a Delta document.\n */\n\nimport { Delta } from '@scrider/delta';\nimport type { AttributeMap, Op } from '@scrider/delta';\nimport type { DOMAdapter, DOMNode, DOMElement } from '../adapters/types';\nimport { NODE_TYPE, isElement } from '../adapters/types';\nimport { getAdapter } from '../adapters';\nimport type { BlockHandlerRegistry } from '../../schema/BlockHandlerRegistry';\nimport type { BlockContext } from '../../schema/BlockHandler';\nimport type { Registry } from '../../schema/Registry';\nimport {\n TAG_TO_INLINE_FORMAT,\n TAG_TO_BLOCK_FORMAT,\n CSS_ALIGN_TO_FORMAT,\n fromVideoEmbedUrl,\n} from './config';\nimport { slugify } from '../utils/slugify';\n\n/**\n * Options for HTML → Delta conversion\n */\nexport interface HtmlToDeltaOptions {\n /**\n * DOM adapter to use (defaults to auto-detected)\n */\n adapter?: DOMAdapter;\n\n /**\n * Normalize whitespace (collapse multiple spaces, trim)\n * @default true\n */\n normalizeWhitespace?: boolean;\n\n /**\n * Custom tag handlers for special elements\n */\n tagHandlers?: Record<string, TagHandler>;\n\n /**\n * Block handler registry for Extended Table and other block embeds.\n * When provided and a handler for 'table' is registered,\n * `<table>` elements will be parsed as block embeds instead of Simple Table.\n */\n blockHandlers?: BlockHandlerRegistry;\n\n /**\n * Format registry for custom embed matching.\n *\n * When provided, embed formats with a `match()` method are tried\n * before falling back to built-in tag handlers (img, video, iframe, etc.).\n * This enables extensibility without modifying converter internals.\n */\n registry?: Registry;\n}\n\n/**\n * Custom tag handler function\n */\nexport type TagHandler = (element: DOMElement, context: ParserContext) => void;\n\n/**\n * Parser context passed to tag handlers\n */\nexport interface ParserContext {\n delta: Delta;\n attributes: AttributeMap;\n blockAttributes: AttributeMap;\n pushText(text: string): void;\n pushEmbed(embed: Record<string, unknown>, attrs?: AttributeMap): void;\n pushNewline(): void;\n}\n\n/**\n * Convert HTML string to Delta\n *\n * @param html - The HTML string to convert\n * @param options - Conversion options\n * @returns Delta document\n *\n * @example\n * ```typescript\n * const html = '<p><strong>Hello</strong> World</p>';\n * const delta = htmlToDelta(html);\n * // { ops: [\n * // { insert: 'Hello', attributes: { bold: true } },\n * // { insert: ' World\\n' }\n * // ]}\n * ```\n */\nexport function htmlToDelta(html: string, options: HtmlToDeltaOptions = {}): Delta {\n const adapter = options.adapter ?? getAdapter();\n const normalizeWhitespace = options.normalizeWhitespace ?? true;\n const tagHandlers = { ...DEFAULT_TAG_HANDLERS, ...options.tagHandlers };\n\n // Parse HTML\n const fragment = adapter.parseHTML(html);\n\n // Initialize delta and state\n const delta = new Delta();\n let currentAttributes: AttributeMap = {};\n let currentBlockAttributes: AttributeMap = {};\n let pendingText = '';\n let atLineStart = true; // Track if we're at the start of a line\n\n // Context for tag handlers\n const context: ParserContext = {\n delta,\n get attributes() {\n return { ...currentAttributes };\n },\n get blockAttributes() {\n return { ...currentBlockAttributes };\n },\n pushText(text: string) {\n if (normalizeWhitespace) {\n text = normalizeText(text, pendingText, atLineStart);\n }\n if (text) {\n pendingText += text;\n atLineStart = false;\n }\n },\n pushEmbed(embed: Record<string, unknown>, attrs?: AttributeMap) {\n // Flush pending text first\n flushText();\n const finalAttrs = { ...currentAttributes, ...attrs };\n if (Object.keys(finalAttrs).length > 0) {\n delta.insert(embed, finalAttrs);\n } else {\n delta.insert(embed);\n }\n atLineStart = false;\n },\n pushNewline() {\n flushText();\n const attrs = { ...currentBlockAttributes };\n if (Object.keys(attrs).length > 0) {\n delta.insert('\\n', attrs);\n } else {\n delta.insert('\\n');\n }\n currentBlockAttributes = {};\n atLineStart = true;\n },\n };\n\n /**\n * Flush pending text to delta\n */\n function flushText(): void {\n if (pendingText) {\n const attrs = { ...currentAttributes };\n if (Object.keys(attrs).length > 0) {\n delta.insert(pendingText, attrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n // Note: atLineStart is NOT reset here - we're still on the same line\n }\n }\n\n /**\n * Process a node recursively\n */\n function processNode(node: DOMNode): void {\n // Text node\n if (node.nodeType === NODE_TYPE.TEXT_NODE) {\n const text = node.textContent ?? '';\n context.pushText(text);\n return;\n }\n\n // Element node\n if (!isElement(node)) return;\n\n const tagName = node.tagName.toLowerCase();\n\n // Check for custom handler (supports \"tag\" and \"tag.class\" keys)\n const handler = findTagHandler(tagHandlers, node, tagName);\n if (handler) {\n handler(node, context);\n return;\n }\n\n // Check for block element\n const blockFormat = TAG_TO_BLOCK_FORMAT[tagName];\n if (blockFormat) {\n processBlockElement(node, blockFormat);\n return;\n }\n\n // Check for list element\n if (tagName === 'ul' || tagName === 'ol') {\n processListElement(node, tagName);\n return;\n }\n\n // Check for inline element\n const inlineFormat = TAG_TO_INLINE_FORMAT[tagName];\n if (inlineFormat) {\n processInlineElement(node, inlineFormat);\n return;\n }\n\n // Check for link\n if (tagName === 'a') {\n processLinkElement(node);\n return;\n }\n\n // Check for span with styles\n if (tagName === 'span') {\n processSpanElement(node);\n return;\n }\n\n // Check for table\n if (tagName === 'table') {\n processTableElement(node);\n return;\n }\n\n // Check registry embed formats (custom match before hardcoded handlers)\n if (options.registry) {\n const embedFormats = options.registry.getByScope('embed');\n for (const format of embedFormats) {\n if (format.match) {\n const result = format.match(node);\n if (result != null) {\n context.pushEmbed({ [format.name]: result.value }, result.attributes);\n return;\n }\n }\n }\n }\n\n // Check for embeds\n if (tagName === 'img') {\n processImageElement(node);\n return;\n }\n\n if (tagName === 'video' || tagName === 'iframe') {\n processVideoElement(node);\n return;\n }\n\n if (tagName === 'hr') {\n context.pushEmbed({ divider: true });\n context.pushNewline();\n return;\n }\n\n // Check for footnotes section: <section class=\"footnotes\">\n if (tagName === 'section' || tagName === 'div') {\n const className = node.getAttribute('class') || '';\n if (className.includes('footnotes')) {\n processFootnotesSection(node);\n return;\n }\n if (className.includes('markdown-alert')) {\n processAlertElement(node);\n return;\n }\n if (/\\bcolumns\\b/.test(className)) {\n processColumnsElement(node);\n return;\n }\n if (className.includes('inline-box')) {\n processBoxElement(node);\n return;\n }\n }\n\n // Check for paragraph/div (default block)\n if (tagName === 'p' || tagName === 'div') {\n processDefaultBlock(node);\n return;\n }\n\n // Check for br\n if (tagName === 'br') {\n // Soft line break disambiguation (Phase 7 Part 0):\n // 1. `<br data-scrider-embed>` — explicit marker emitted by our own\n // `deltaToHtml` for a `{ softBreak: true }` embed. Always treated\n // as an embed, regardless of position.\n // 2. `<br>` between content (sibling-aware heuristic) — typical for\n // browser-inserted Shift+Enter (`<p>foo<br>bar</p>`) or copy-paste\n // from rich-text sources. Treated as a softBreak embed.\n // 3. `<br>` at the start of a block / placeholder — treated as a\n // regular newline to preserve historical behaviour for the\n // `<p><br>text</p>` shape. The `<p><br></p>` (br-only) shape is\n // already short-circuited earlier by `processDefaultBlock`.\n // 4. Browser-added trailing line-box filler `<br>` (Phase 7 Part 0,\n // v1.3.3): a plain `<br>` whose immediately-preceding element is\n // ALSO a `<br>` and that has no semantic content after it inside\n // its parent block. contenteditable browsers append this marker\n // to give a trailing empty line a visual line-box; admitting it\n // as a softBreak embed corrupts the Delta (extra soft break that\n // survives subsequent edits and de-styles the parent block when\n // the user presses Enter/Backspace nearby).\n const hasMarker = node.hasAttribute('data-scrider-embed');\n if (hasMarker) {\n context.pushEmbed({ softBreak: true });\n return;\n }\n if (isBrowserEmptyLineFiller(node)) {\n // silently drop — it has no semantic meaning\n return;\n }\n if (hasMeaningfulPrevSibling(node)) {\n context.pushEmbed({ softBreak: true });\n } else {\n context.pushNewline();\n }\n return;\n }\n\n // Unknown element - process children\n processChildren(node);\n }\n\n /**\n * Process children of a node\n */\n function processChildren(node: DOMNode): void {\n const children = node.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child) processNode(child);\n }\n }\n\n /**\n * Process a block element (h1, blockquote, pre, etc.)\n */\n function processBlockElement(\n element: DOMElement,\n format: { format: string; value: unknown },\n ): void {\n // Special handling for <pre> — code blocks\n if (format.format === 'code-block') {\n processCodeBlockElement(element);\n return;\n }\n\n const prevBlockAttrs = { ...currentBlockAttributes };\n currentBlockAttributes[format.format] = format.value;\n\n // Add alignment if present\n const align = getAlignment(element);\n if (align) {\n currentBlockAttributes.align = align;\n }\n\n // Extract custom header id (only if different from computed slug)\n if (format.format === 'header') {\n const id = element.getAttribute('id');\n if (id) {\n const text = element.textContent || '';\n const computedSlug = slugify(text);\n if (id !== computedSlug) {\n currentBlockAttributes['header-id'] = id;\n }\n }\n }\n\n processChildren(element);\n context.pushNewline();\n\n currentBlockAttributes = prevBlockAttrs;\n }\n\n /**\n * Process a code block element (<pre>, possibly with <code> child)\n */\n function processCodeBlockElement(element: DOMElement): void {\n const prevBlockAttrs = { ...currentBlockAttributes };\n\n // Extract language from <code class=\"language-xxx\"> or <pre data-language=\"xxx\">\n let language: string | undefined;\n\n // Check <pre data-language=\"xxx\">\n const dataLang = element.getAttribute('data-language');\n if (dataLang) {\n language = dataLang;\n }\n\n // Check for <code class=\"language-xxx\"> child\n const children = element.childNodes;\n let codeElement: DOMElement | null = null;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child && isElement(child) && child.tagName.toLowerCase() === 'code') {\n codeElement = child;\n break;\n }\n }\n\n if (codeElement && !language) {\n const className = codeElement.getAttribute('class') || '';\n const match = className.match(/language-(\\S+)/);\n if (match?.[1]) {\n language = match[1];\n }\n }\n\n // Set code-block attribute with language or true\n const codeBlockValue: unknown = language || true;\n currentBlockAttributes['code-block'] = codeBlockValue;\n\n // Get text content from the code element or pre directly\n const sourceElement = codeElement || element;\n const rawText = sourceElement.textContent ?? '';\n\n // Remove trailing newline (code blocks always end with \\n in the HTML)\n const text = rawText.endsWith('\\n') ? rawText.slice(0, -1) : rawText;\n\n // Split by lines — each line gets its own code-block attribute\n const codeLines = text.split('\\n');\n for (let i = 0; i < codeLines.length; i++) {\n const line = codeLines[i];\n if (line !== undefined && line.length > 0) {\n flushText();\n pendingText = line;\n }\n flushText();\n const attrs = { ...currentBlockAttributes };\n if (Object.keys(attrs).length > 0) {\n delta.insert('\\n', attrs);\n } else {\n delta.insert('\\n');\n }\n atLineStart = true;\n }\n\n currentBlockAttributes = prevBlockAttrs;\n }\n\n /**\n * Process a list element (ul/ol)\n */\n function processListElement(element: DOMElement, listTag: string, indent: number = 0): void {\n const children = element.childNodes;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child)) continue;\n\n const childTag = child.tagName.toLowerCase();\n if (childTag === 'li') {\n processListItem(child, listTag, indent);\n } else if (childTag === 'ul' || childTag === 'ol') {\n // Nested list without li wrapper - increment indent\n processListElement(child, childTag, indent + 1);\n }\n }\n }\n\n /**\n * Process a list item\n */\n function processListItem(element: DOMElement, listTag: string, indent: number): void {\n const prevBlockAttrs = { ...currentBlockAttributes };\n\n // Determine list type\n let listType = listTag === 'ol' ? 'ordered' : 'bullet';\n\n // Check for checkbox (task list)\n const dataChecked = element.getAttribute('data-checked');\n if (dataChecked === 'true') {\n listType = 'checked';\n } else if (dataChecked === 'false') {\n listType = 'unchecked';\n }\n\n currentBlockAttributes.list = listType;\n if (indent > 0) {\n currentBlockAttributes.indent = indent;\n }\n\n // Process content, but handle nested lists specially\n const children = element.childNodes;\n let hasNestedList = false;\n\n // Check if this is an empty list item with only <br> for visibility\n // (generated by deltaToHtml for empty lines, or by browser on Enter)\n const firstChild = children[0];\n const isBrOnlyListItem =\n children.length === 1 &&\n firstChild !== undefined &&\n isElement(firstChild) &&\n firstChild.tagName.toLowerCase() === 'br';\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child) continue;\n\n if (isElement(child)) {\n const childTag = child.tagName.toLowerCase();\n if (childTag === 'ul' || childTag === 'ol') {\n // Flush current content before nested list\n if (!hasNestedList) {\n context.pushNewline();\n hasNestedList = true;\n }\n // Process nested list with increased indent\n processNestedList(child, childTag, indent + 1);\n continue;\n }\n }\n\n // Skip processing <br> in empty list items\n if (!hasNestedList && !isBrOnlyListItem) {\n processNode(child);\n }\n }\n\n if (!hasNestedList) {\n context.pushNewline();\n }\n\n currentBlockAttributes = prevBlockAttrs;\n }\n\n /**\n * Process a nested list\n */\n function processNestedList(element: DOMElement, listTag: string, indent: number): void {\n const children = element.childNodes;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child)) continue;\n\n const childTag = child.tagName.toLowerCase();\n if (childTag === 'li') {\n processListItem(child, listTag, indent);\n }\n }\n }\n\n /**\n * Process an inline element (strong, em, etc.)\n */\n function processInlineElement(\n element: DOMElement,\n format: { format: string; value: unknown },\n ): void {\n // Flush before changing attributes\n flushText();\n\n const prevAttrs = { ...currentAttributes };\n currentAttributes[format.format] = format.value;\n\n processChildren(element);\n\n // Flush before restoring attributes\n flushText();\n currentAttributes = prevAttrs;\n }\n\n /**\n * Process a link element\n */\n function processLinkElement(element: DOMElement): void {\n const href = element.getAttribute('href');\n if (!href) {\n processChildren(element);\n return;\n }\n\n // Flush before changing attributes\n flushText();\n\n const prevAttrs = { ...currentAttributes };\n currentAttributes.link = href;\n\n processChildren(element);\n\n // Flush before restoring attributes\n flushText();\n currentAttributes = prevAttrs;\n }\n\n /**\n * Process a span element (for styles)\n */\n function processSpanElement(element: DOMElement): void {\n // Flush before changing attributes\n flushText();\n\n const prevAttrs = { ...currentAttributes };\n\n // Extract color\n const color = element.style?.color || element.style?.getPropertyValue?.('color');\n if (color) {\n currentAttributes.color = color;\n }\n\n // Extract background\n const bg =\n element.style?.backgroundColor || element.style?.getPropertyValue?.('background-color');\n if (bg) {\n currentAttributes.background = bg;\n }\n\n // Extract font-family\n const fontFamily =\n element.style?.fontFamily || element.style?.getPropertyValue?.('font-family');\n if (fontFamily) {\n currentAttributes.font = fontFamily.replace(/^[\"']|[\"']$/g, '');\n }\n\n // Extract font-size\n const fontSize = element.style?.fontSize || element.style?.getPropertyValue?.('font-size');\n if (fontSize) {\n currentAttributes.size = fontSize;\n }\n\n processChildren(element);\n\n // Flush before restoring attributes\n flushText();\n currentAttributes = prevAttrs;\n }\n\n /**\n * Process an image element\n */\n function processImageElement(element: DOMElement): void {\n const src = element.getAttribute('src');\n if (!src) return;\n\n const attrs: AttributeMap = {};\n const alt = element.getAttribute('alt');\n const width = element.getAttribute('width');\n const height = element.getAttribute('height');\n const float = element.getAttribute('data-float');\n\n if (alt) attrs.alt = alt;\n if (width) attrs.width = parseInt(width, 10);\n if (height) attrs.height = parseInt(height, 10);\n if (float) attrs.float = float;\n\n context.pushEmbed({ image: src }, attrs);\n }\n\n /**\n * Process a video/iframe element.\n * Converts embed URLs back to canonical form (e.g. youtube.com/embed/X → youtube.com/watch?v=X).\n */\n function processVideoElement(element: DOMElement): void {\n const src = element.getAttribute('src');\n if (!src) return;\n\n const attrs: AttributeMap = {};\n const float = element.getAttribute('data-float');\n const style = element.getAttribute('style') || '';\n\n if (float) attrs.float = float;\n\n // Extract width/height from inline style (used for floated videos)\n // Strip 'px' suffix to store clean numeric strings for roundtrip consistency\n const widthMatch = style.match(/(?:^|;\\s*)width:\\s*([^;]+)/);\n if (widthMatch?.[1]) attrs.width = widthMatch[1].trim().replace(/px$/, '');\n const heightMatch = style.match(/(?:^|;\\s*)height:\\s*([^;]+)/);\n if (heightMatch?.[1]) attrs.height = heightMatch[1].trim().replace(/px$/, '');\n\n const embedAttrs = Object.keys(attrs).length > 0 ? attrs : undefined;\n context.pushEmbed({ video: fromVideoEmbedUrl(src) }, embedAttrs);\n }\n\n /**\n * Process a <section class=\"footnotes\"> element.\n * If blockHandlers has a 'footnotes' handler registered, parse as block embed.\n * Otherwise, process children normally (graceful fallback).\n */\n function processFootnotesSection(section: DOMElement): void {\n const footnotesHandler = options.blockHandlers?.get('footnotes');\n if (footnotesHandler) {\n const blockContext: BlockContext = {\n registry: undefined as never, // Registry not needed for fromHtml parsing\n parseElement: (el: DOMElement): Op[] => {\n // Recursive: parse element's inner HTML → Delta ops\n const innerHtml = el.innerHTML ?? '';\n if (!innerHtml) return [{ insert: '\\n' }];\n return htmlToDelta(innerHtml, options).ops;\n },\n };\n const data = footnotesHandler.fromHtml(section, blockContext);\n if (data) {\n flushText();\n delta.insert({ block: data });\n delta.insert('\\n');\n atLineStart = true;\n return;\n }\n }\n\n // Fallback: process children normally\n processChildren(section);\n }\n\n /**\n * Process a <div class=\"markdown-alert markdown-alert-{type}\"> element.\n * If blockHandlers has an 'alert' handler registered, parse as block embed.\n * Otherwise, process children normally (graceful fallback).\n */\n function processAlertElement(element: DOMElement): void {\n const alertHandler = options.blockHandlers?.get('alert');\n if (alertHandler) {\n const blockContext: BlockContext = {\n registry: undefined as never,\n parseElement: (el: DOMElement): Op[] => {\n const innerHtml = el.innerHTML ?? '';\n if (!innerHtml) return [{ insert: '\\n' }];\n return htmlToDelta(innerHtml, options).ops;\n },\n };\n const data = alertHandler.fromHtml(element, blockContext);\n if (data) {\n flushText();\n delta.insert({ block: data });\n delta.insert('\\n');\n atLineStart = true;\n return;\n }\n }\n\n // Fallback: process children normally\n processChildren(element);\n }\n\n /**\n * Process a <div class=\"columns\"> element.\n * If blockHandlers has a 'columns' handler registered, parse as block embed.\n * Otherwise, process children normally (graceful fallback).\n */\n function processColumnsElement(element: DOMElement): void {\n const columnsHandler = options.blockHandlers?.get('columns');\n if (columnsHandler) {\n const blockContext: BlockContext = {\n registry: undefined as never,\n parseElement: (el: DOMElement): Op[] => {\n const innerHtml = el.innerHTML ?? '';\n if (!innerHtml) return [{ insert: '\\n' }];\n return htmlToDelta(innerHtml, options).ops;\n },\n };\n const data = columnsHandler.fromHtml(element, blockContext);\n if (data) {\n flushText();\n delta.insert({ block: data });\n delta.insert('\\n');\n atLineStart = true;\n return;\n }\n }\n\n // Fallback: process children normally\n processChildren(element);\n }\n\n /**\n * Process a <div class=\"inline-box\"> element.\n * If blockHandlers has a 'box' handler registered, parse as block embed.\n * Extracts op attributes (float, width, height, overflow) from HTML data-attrs and style.\n * Otherwise, process children normally (graceful fallback).\n */\n function processBoxElement(element: DOMElement): void {\n const boxHandler = options.blockHandlers?.get('box');\n if (boxHandler) {\n const blockContext: BlockContext = {\n registry: undefined as never,\n parseElement: (el: DOMElement): Op[] => {\n const innerHtml = el.innerHTML ?? '';\n if (!innerHtml) return [{ insert: '\\n' }];\n return htmlToDelta(innerHtml, options).ops;\n },\n };\n const data = boxHandler.fromHtml(element, blockContext);\n if (data) {\n flushText();\n\n // Extract op attributes from HTML element\n const opAttrs: Record<string, string> = {};\n\n const dataFloat = element.getAttribute('data-float');\n if (dataFloat) opAttrs.float = dataFloat;\n\n const dataOverflow = element.getAttribute('data-overflow');\n if (dataOverflow) opAttrs.overflow = dataOverflow;\n\n // Extract width/height from inline style\n const style = element.getAttribute('style') || '';\n const widthMatch = style.match(/(?:^|;\\s*)width:\\s*([^;]+)/);\n if (widthMatch?.[1]) opAttrs.width = widthMatch[1].trim();\n\n const heightMatch = style.match(/(?:^|;\\s*)height:\\s*([^;]+)/);\n if (heightMatch?.[1]) opAttrs.height = heightMatch[1].trim();\n\n const hasAttrs = Object.keys(opAttrs).length > 0;\n delta.insert({ block: data }, hasAttrs ? opAttrs : undefined);\n delta.insert('\\n');\n atLineStart = true;\n return;\n }\n }\n\n // Fallback: process children normally\n processChildren(element);\n }\n\n /**\n * Process a <table> element.\n * If blockHandlers has a 'table' handler registered, parse as Extended Table (block embed).\n * Otherwise, fall back to Simple Table (linear block attributes).\n */\n function processTableElement(table: DOMElement): void {\n // Opt-in: Extended Table via BlockHandler\n const tableHandler = options.blockHandlers?.get('table');\n if (tableHandler) {\n const blockContext: BlockContext = {\n registry: undefined as never, // Registry not needed for fromHtml parsing\n parseElement: (el: DOMElement): Op[] => {\n // Recursive: parse element's inner HTML → Delta ops\n const innerHtml = el.innerHTML ?? '';\n if (!innerHtml) return [{ insert: '\\n' }];\n return htmlToDelta(innerHtml, options).ops;\n },\n };\n const data = tableHandler.fromHtml(table, blockContext);\n if (data) {\n flushText();\n delta.insert({ block: data });\n delta.insert('\\n');\n atLineStart = true;\n return;\n }\n // If fromHtml returns null, fall through to Simple Table\n }\n\n // Simple Table: linear block attributes\n let rowIdx = 0;\n\n // Iterate over direct children: <thead>, <tbody>, or direct <tr>\n const tableChildren = table.childNodes;\n for (let i = 0; i < tableChildren.length; i++) {\n const section = tableChildren[i];\n if (!section || !isElement(section)) continue;\n\n const sectionTag = section.tagName.toLowerCase();\n\n if (sectionTag === 'thead' || sectionTag === 'tbody' || sectionTag === 'tfoot') {\n const isHeader = sectionTag === 'thead';\n const sectionChildren = section.childNodes;\n for (let j = 0; j < sectionChildren.length; j++) {\n const row = sectionChildren[j];\n if (!row || !isElement(row) || row.tagName.toLowerCase() !== 'tr') continue;\n processTableRow(row, rowIdx, isHeader);\n rowIdx++;\n }\n } else if (sectionTag === 'tr') {\n // Direct <tr> without <thead>/<tbody> wrapper\n processTableRow(section, rowIdx, false);\n rowIdx++;\n }\n }\n }\n\n /**\n * Process a single <tr> element\n */\n function processTableRow(tr: DOMElement, rowIdx: number, isHeader: boolean): void {\n let colIdx = 0;\n\n const cells = tr.childNodes;\n for (let i = 0; i < cells.length; i++) {\n const cell = cells[i];\n if (!cell || !isElement(cell)) continue;\n\n const cellTag = cell.tagName.toLowerCase();\n if (cellTag !== 'td' && cellTag !== 'th') continue;\n\n const cellIsHeader = isHeader || cellTag === 'th';\n\n // Extract column alignment from style\n const textAlign = cell.style?.textAlign || cell.style?.getPropertyValue?.('text-align');\n const colAlign =\n textAlign && (textAlign === 'left' || textAlign === 'center' || textAlign === 'right')\n ? textAlign\n : undefined;\n\n // Save and set block attributes for this cell\n const prevBlockAttrs = { ...currentBlockAttributes };\n currentBlockAttributes['table-row'] = rowIdx;\n currentBlockAttributes['table-col'] = colIdx;\n if (cellIsHeader) {\n currentBlockAttributes['table-header'] = true;\n }\n if (colAlign) {\n currentBlockAttributes['table-col-align'] = colAlign;\n }\n\n // Process cell content (inline elements)\n processChildren(cell);\n context.pushNewline();\n\n currentBlockAttributes = prevBlockAttrs;\n colIdx++;\n }\n }\n\n /**\n * Process a default block element (p, div)\n */\n function processDefaultBlock(element: DOMElement): void {\n const prevBlockAttrs = { ...currentBlockAttributes };\n\n // Check for alignment\n const align = getAlignment(element);\n if (align) {\n currentBlockAttributes.align = align;\n }\n\n // Check if this is an empty paragraph with only <br> for visibility\n // (generated by deltaToHtml for empty lines).\n //\n // Exception (Phase 7 Part 0 — softBreak): a lone `<br data-scrider-embed>`\n // inside `<p>` is NOT a placeholder. It encodes a `{ softBreak: true }`\n // embed that happens to occupy an otherwise empty paragraph (e.g. the\n // output of `softBreakFormat.render()` followed by the block `\\n`, or a\n // copy-paste of a structurally-isolated soft line break). The short-\n // circuit below would otherwise skip `processChildren`, the `br` branch\n // in `processNode` would never run, and the embed would silently\n // degrade to a plain block newline. Keep `processChildren` for that\n // case so the marker is honoured.\n const children = element.childNodes;\n const firstChild = children[0];\n const isBrOnlyParagraph =\n children.length === 1 &&\n firstChild !== undefined &&\n isElement(firstChild) &&\n firstChild.tagName.toLowerCase() === 'br' &&\n !firstChild.hasAttribute('data-scrider-embed');\n\n if (!isBrOnlyParagraph) {\n processChildren(element);\n }\n context.pushNewline();\n\n currentBlockAttributes = prevBlockAttrs;\n }\n\n /**\n * Get alignment from element style\n */\n function getAlignment(element: DOMElement): string | null {\n const textAlign = element.style?.textAlign || element.style?.getPropertyValue?.('text-align');\n\n if (textAlign && CSS_ALIGN_TO_FORMAT[textAlign]) {\n return CSS_ALIGN_TO_FORMAT[textAlign];\n }\n\n return null;\n }\n\n // Process all nodes in fragment\n const children = fragment.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child) processNode(child);\n }\n\n // Flush any remaining text\n flushText();\n\n // Ensure document ends with newline if not empty\n if (delta.ops.length > 0) {\n const lastOp = delta.ops[delta.ops.length - 1];\n if (lastOp && 'insert' in lastOp) {\n const lastInsert = lastOp.insert as string | Record<string, unknown>;\n if (typeof lastInsert === 'string' && !lastInsert.endsWith('\\n')) {\n delta.insert('\\n');\n }\n }\n }\n\n return delta;\n}\n\n/**\n * Normalize whitespace in text\n */\nfunction normalizeText(text: string, pendingText: string, atLineStart: boolean): string {\n // Replace multiple whitespace with single space\n text = text.replace(/[\\t\\n\\r]+/g, ' ');\n\n // Collapse multiple spaces\n text = text.replace(/ +/g, ' ');\n\n // Trim leading space only if at start of line AND no pending text\n if (atLineStart && pendingText === '' && text.startsWith(' ')) {\n text = text.slice(1);\n }\n\n return text;\n}\n\n/**\n * Sibling-aware heuristic for `<br>` disambiguation.\n *\n * Returns `true` when the given `<br>` node has at least one previous\n * sibling that contributes content (non-whitespace text or any element).\n * Such a `<br>` is treated as a soft line break embed; otherwise it is\n * treated as a regular newline (preserving historical behaviour for\n * placeholder shapes like `<p><br>text</p>`).\n *\n * The DOMAdapter interface does not expose `previousSibling`, so we walk\n * the parent's `childNodes` list up to the current node.\n */\nfunction hasMeaningfulPrevSibling(brNode: DOMElement): boolean {\n const parent = brNode.parentNode;\n if (!parent) return false;\n const children = parent.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child) continue;\n if (child === brNode) return false; // reached <br> with no prior content\n if (child.nodeType === NODE_TYPE.TEXT_NODE) {\n const text = child.textContent ?? '';\n if (text.trim().length > 0) return true;\n } else if (isElement(child)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Phase 7 Part 0 (v1.3.3) — detect a browser-added trailing line-box\n * filler `<br>`.\n *\n * contenteditable engines (Chrome especially) append a plain `<br>` after\n * a \"real\" `<br>` to give the trailing empty line a visual line-box. This\n * filler carries no user intent — keeping it as a `softBreak` embed in the\n * Delta corrupts subsequent edits (extra embed shifts caret positions and\n * makes `splitBlock` / `deleteBackward` operate on the wrong newline).\n *\n * A `<br>` qualifies as a filler when ALL of:\n * - it has NO `data-scrider-embed` attribute (caller checks first);\n * - its immediately-preceding sibling element is also a `<br>` (with or\n * without the marker — either kind of \"real\" line break is OK);\n * - any sibling that comes AFTER it is whitespace-only text, a ZWSP\n * (`\\u200B`, our own caret slot), or another filler `<br>` — i.e. no\n * semantic content follows it inside the parent block.\n *\n * The check ignores ZWSP/whitespace so the renderToDOM caret-slot ZWSP\n * appended by ScriderEditor does not defeat the heuristic.\n */\nfunction isBrowserEmptyLineFiller(brNode: DOMElement): boolean {\n const parent = brNode.parentNode;\n if (!parent) return false;\n const children = parent.childNodes;\n\n let prevElement: DOMElement | null = null;\n let foundCurrent = false;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child) continue;\n if (child === brNode) {\n foundCurrent = true;\n continue;\n }\n if (!foundCurrent) {\n // BEFORE current: track the immediate preceding element. Skip pure\n // whitespace text. Any non-whitespace text RESETS the element chain\n // (the preceding <br> would no longer be \"immediate\" if real text\n // sits between them).\n if (child.nodeType === NODE_TYPE.TEXT_NODE) {\n const text = (child.textContent ?? '').replace(/[\\s\\u200B]/g, '');\n if (text.length > 0) prevElement = null;\n } else if (isElement(child)) {\n prevElement = child;\n }\n } else {\n // AFTER current: any semantic content disqualifies the filler.\n if (child.nodeType === NODE_TYPE.TEXT_NODE) {\n const text = (child.textContent ?? '').replace(/[\\s\\u200B]/g, '');\n if (text.length > 0) return false;\n } else if (isElement(child)) {\n const tag = child.tagName?.toLowerCase();\n // Another <br> after us is also filler-shaped (browsers sometimes\n // emit a chain), so don't disqualify on that alone.\n if (tag !== 'br') return false;\n }\n }\n }\n\n if (!prevElement) return false;\n return prevElement.tagName?.toLowerCase() === 'br';\n}\n\n/**\n * Find a matching tag handler for an element.\n * Supports keys in formats:\n * - \"tag\" — matches by tag name only\n * - \"tag.class\" — matches by tag name AND CSS class\n * Class-specific handlers take priority over tag-only handlers.\n */\nfunction findTagHandler(\n handlers: Record<string, TagHandler>,\n element: DOMElement,\n tagName: string,\n): TagHandler | null {\n // First try class-specific handlers (tag.class)\n const className = element.getAttribute('class');\n if (className) {\n const classes = className.split(/\\s+/);\n for (const cls of classes) {\n const key = `${tagName}.${cls}`;\n if (handlers[key]) {\n return handlers[key];\n }\n }\n }\n\n // Then try tag-only handler\n if (handlers[tagName]) {\n return handlers[tagName];\n }\n\n return null;\n}\n\n/**\n * Default tag handlers\n */\nconst DEFAULT_TAG_HANDLERS: Record<string, TagHandler> = {\n // Formula span\n 'span.formula': (element, context) => {\n const formula = element.getAttribute('data-formula');\n if (formula) {\n context.pushEmbed({ formula });\n }\n },\n\n // Diagram (Mermaid) span — inline mode\n 'span.diagram': (element, context) => {\n const diagram = element.getAttribute('data-diagram');\n if (diagram) {\n context.pushEmbed({ diagram });\n }\n },\n\n // Draw.io diagram span — file reference\n 'span.drawio': (element, context) => {\n const src = element.getAttribute('data-drawio-src');\n if (src) {\n const attrs: Record<string, unknown> = {};\n const alt = element.getAttribute('data-alt');\n if (alt) attrs.alt = alt;\n context.pushEmbed({ drawio: src }, Object.keys(attrs).length > 0 ? attrs : undefined);\n }\n },\n\n // Footnote reference: <sup class=\"footnote-ref\"><a href=\"#fn-{id}\">{label}</a></sup>\n 'sup.footnote-ref': (element, context) => {\n // Extract id from the nested <a> href=\"#fn-{id}\"\n const children = element.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child && isElement(child) && child.tagName.toLowerCase() === 'a') {\n const href = child.getAttribute('href') || '';\n const match = href.match(/#fn-(.+)/);\n if (match?.[1]) {\n context.pushEmbed({ 'footnote-ref': match[1] });\n return;\n }\n }\n }\n // Fallback: try id attribute on <sup> itself\n const id = element.getAttribute('id') || '';\n const refMatch = id.match(/^fnref-(.+)/);\n if (refMatch?.[1]) {\n context.pushEmbed({ 'footnote-ref': refMatch[1] });\n }\n },\n};\n","/**\n * Delta → Markdown Conversion\n *\n * Converts a Delta document to Markdown string.\n */\n\nimport { Delta, isInsert, isTextInsert, isEmbedInsert } from '@scrider/delta';\nimport type { Op, AttributeMap, InsertOp } from '@scrider/delta';\nimport type { BlockHandlerRegistry } from '../../schema/BlockHandlerRegistry';\nimport type { BlockContext } from '../../schema/BlockHandler';\nimport type { Registry } from '../../schema/Registry';\nimport {\n escapeMarkdown,\n INLINE_FORMAT_SYNTAX,\n MD_INLINE_FORMAT_ORDER,\n BLOCK_FORMAT_PREFIX,\n LIST_TYPE_PREFIX,\n getIndentPrefix,\n renderImage,\n renderLink,\n renderCodeBlock,\n} from './config';\nimport { escapeHtml, toVideoEmbedUrl } from '../html/config';\nimport { deltaToHtml } from '../html/delta-to-html';\n\n/**\n * Options for Delta → Markdown conversion\n */\nexport interface DeltaToMarkdownOptions {\n /**\n * Use strict Markdown (no GFM extensions)\n * @default false\n */\n strict?: boolean;\n\n /**\n * Preserve empty lines using <br> tags\n * When false, multiple empty lines collapse to one paragraph break\n * @default false\n */\n preserveEmptyLines?: boolean;\n\n /**\n * Math syntax for formula output\n * - 'dollar': $...$ for inline, $$...$$ for block (default, GFM-compatible)\n * - 'latex': \\(...\\) for inline, \\[...\\] for block (used by LLMs: DeepSeek, ChatGPT, Claude)\n * @default 'dollar'\n */\n mathSyntax?: 'dollar' | 'latex';\n\n /**\n * Display math rendering mode\n * - true (default): code-block \"math\" → ```math ``` (GFM code block)\n * - false: code-block \"math\" → $...$ on its own line (inline syntax)\n *\n * Does NOT affect inline formulas ({ formula }) — they always render as $...$\n * @default true\n */\n mathBlock?: boolean;\n\n /**\n * Mermaid diagram rendering mode\n * - true (default): code-block \"mermaid\" → ```mermaid ``` (fenced block)\n * - false: code-block \"mermaid\" → ```mermaid ``` (same output, but { diagram } embeds also → ```mermaid)\n *\n * Does NOT affect the Markdown output for code-block \"mermaid\" (always fenced).\n * Controls how { diagram } embeds are rendered.\n * @default true\n */\n mermaidBlock?: boolean;\n\n /**\n * PlantUML diagram rendering mode\n * - true (default): code-block \"plantuml\" → ```plantuml ``` (fenced block)\n * - false: code-block \"plantuml\" → ```plantuml ``` (same output, but { diagram } embeds with @startuml → ```plantuml)\n *\n * Does NOT affect the Markdown output for code-block \"plantuml\" (always fenced).\n * Controls how { diagram } embeds containing PlantUML are rendered.\n * @default true\n */\n plantumlBlock?: boolean;\n\n /**\n * Custom embed renderers\n */\n embedRenderers?: Record<string, (value: unknown, attrs?: AttributeMap) => string>;\n\n /**\n * Block handler registry for Extended Table and other block embeds.\n * When provided, block embeds will be rendered via handler.toMarkdown() → fallback to handler.toHtml().\n */\n blockHandlers?: BlockHandlerRegistry;\n\n /**\n * Pretty-print HTML output for block embeds (Extended Table, Columns, etc.)\n * When true, HTML fallback in Markdown is indented and line-broken for readability.\n * When false (default), HTML is compact single-line — safer for CommonMark.\n * @default false\n */\n prettyHtml?: boolean;\n\n /**\n * Format registry for custom embed Markdown rendering.\n *\n * When provided, embed formats with a `toMarkdown()` method are used\n * before falling back to built-in handlers. If `toMarkdown()` returns null,\n * `render()` is used as HTML fallback in Markdown.\n */\n registry?: Registry;\n\n /**\n * Rendering style for `{ softBreak: true }` embeds (Phase 7 Part 0).\n *\n * - `'spaces'` (default): GFM-canonical hard break — two trailing spaces\n * followed by `\\n` (`\" \\n\"`). Round-trips losslessly through remark.\n * - `'html'`: inline `<br>` tag. Slightly more visible in source view\n * and immune to editor whitespace trimming. Recommended for the\n * LFM (LLM-Flavored Markdown) flavour exposed by the editor's\n * \"source\" toggle.\n *\n * Does not affect how soft breaks are rendered inside table cells —\n * those always use inline `<br>` because GFM tables forbid raw `\\n`.\n *\n * @default 'spaces'\n */\n softBreakStyle?: 'spaces' | 'html';\n\n /**\n * Strip trailing newlines from the final output.\n *\n * Useful when serialising a single block (e.g. one table for inline\n * editing) where the GFM padding (blank line after a table, trailing\n * paragraph newline, etc.) is not wanted. The internal structure of the\n * markdown is unaffected — only trailing `\\n+` at the very end of the\n * returned string is removed.\n *\n * @default false\n */\n trimTrailingNewlines?: boolean;\n}\n\n/**\n * Line data for processing\n */\ninterface Line {\n ops: InsertOp[];\n attributes: AttributeMap;\n}\n\n/**\n * Convert Delta to Markdown\n *\n * @param delta - The Delta document to convert\n * @param options - Conversion options\n * @returns Markdown string\n *\n * @example\n * ```typescript\n * const delta = new Delta()\n * .insert('Hello', { bold: true })\n * .insert(' World\\n');\n *\n * const md = deltaToMarkdown(delta);\n * // '**Hello** World\\n'\n * ```\n */\nexport function deltaToMarkdown(delta: Delta, options: DeltaToMarkdownOptions = {}): string {\n const {\n strict = false,\n preserveEmptyLines = false,\n mathSyntax = 'dollar',\n mathBlock = true,\n embedRenderers = {},\n blockHandlers,\n prettyHtml = false,\n registry,\n softBreakStyle = 'spaces',\n trimTrailingNewlines = false,\n } = options;\n const useLatexDelimiters = mathSyntax === 'latex';\n\n // Split ops into lines\n const lines = splitIntoLines(delta.ops);\n\n // Track list state for proper numbering\n let orderedListIndex = 0;\n let lastListType: string | null = null;\n let lastIndent = 0;\n let lastWasBlockquote = false;\n\n const result: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (!line) continue;\n const attrs = line.attributes;\n const isBlockquote = !!attrs.blockquote;\n\n // Check for table - needs special handling (group adjacent table lines)\n if (typeof attrs['table-row'] === 'number' && typeof attrs['table-col'] === 'number') {\n const tableLines = collectTableLines(lines, i);\n result.push(\n renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters, registry, softBreakStyle),\n );\n result.push(''); // Blank line after table — GFM requires it to end the table block\n i += tableLines.length - 1;\n lastListType = null;\n orderedListIndex = 0;\n lastWasBlockquote = false;\n continue;\n }\n\n // Check for code block - needs special handling\n if (attrs['code-block']) {\n if (lastWasBlockquote) {\n result.push('');\n lastWasBlockquote = false;\n }\n const codeLines = collectCodeBlock(lines, i);\n const language = getCodeBlockLanguage(attrs);\n const code = codeLines\n .map((l) =>\n renderLineContent(\n l.ops,\n embedRenderers,\n true,\n false,\n blockHandlers,\n false,\n registry,\n softBreakStyle,\n ),\n )\n .join('\\n');\n\n if (language === 'math') {\n if (mathBlock === false) {\n // Render display math as inline $...$ on its own line\n // Blank lines around ensure it's not absorbed by adjacent lists/paragraphs\n result.push('');\n result.push(`$${code}$`);\n result.push('');\n } else if (useLatexDelimiters) {\n // Use \\[...\\] for display math in LaTeX mode\n result.push(`\\\\[\\n${code}\\n\\\\]`);\n } else {\n // Default: GFM code block ```math\n result.push(renderCodeBlock(code, language));\n }\n } else {\n result.push(renderCodeBlock(code, language));\n }\n\n i += codeLines.length - 1; // Skip processed lines\n lastListType = null;\n orderedListIndex = 0;\n continue;\n }\n\n // Insert blank line at blockquote boundary to prevent lazy continuation\n if (lastWasBlockquote && !isBlockquote) {\n result.push('');\n } else if (!lastWasBlockquote && isBlockquote && result.length > 0) {\n // Also add blank line before blockquote if preceded by content\n const lastLine = result[result.length - 1];\n if (lastLine !== undefined && lastLine !== '') {\n result.push('');\n }\n }\n\n // Handle list numbering reset\n const listType = typeof attrs.list === 'string' ? attrs.list : undefined;\n const indent = typeof attrs.indent === 'number' ? attrs.indent : 0;\n\n if (listType) {\n if (listType !== lastListType || indent !== lastIndent) {\n orderedListIndex = 0;\n }\n if (listType === 'ordered') {\n orderedListIndex++;\n }\n } else {\n lastListType = null;\n orderedListIndex = 0;\n }\n\n // Render line content\n const content = renderLineContent(\n line.ops,\n embedRenderers,\n false,\n useLatexDelimiters,\n blockHandlers,\n prettyHtml,\n registry,\n softBreakStyle,\n );\n\n // Handle empty lines\n if (!content && !hasBlockFormat(attrs)) {\n // Empty line with no block formatting\n result.push(preserveEmptyLines ? '<br>' : '');\n lastWasBlockquote = false;\n continue;\n }\n\n // Apply block formatting\n const markdown = renderBlockFormat(content, attrs, orderedListIndex, strict);\n result.push(markdown);\n\n // After a standalone <img> tag (floated/sized image), add a blank line so\n // CommonMark type-7 HTML block terminates before the next paragraph.\n if (/^<img\\s/.test(content) && !hasBlockFormat(attrs)) {\n result.push('');\n }\n\n lastListType = listType ?? null;\n lastIndent = indent;\n lastWasBlockquote = isBlockquote;\n }\n\n const md = result.join('\\n');\n return trimTrailingNewlines ? md.replace(/\\n+$/, '') : md;\n}\n\n/**\n * Check if attributes contain any block formatting\n */\nfunction hasBlockFormat(attrs: AttributeMap): boolean {\n return !!(\n attrs.header ||\n attrs.list ||\n attrs.blockquote ||\n attrs['code-block'] ||\n attrs.align ||\n attrs.indent\n );\n}\n\n/**\n * Split ops into lines based on newline characters\n */\nfunction splitIntoLines(ops: Op[]): Line[] {\n const lines: Line[] = [];\n let currentOps: InsertOp[] = [];\n\n for (const op of ops) {\n if (!isInsert(op)) continue;\n\n const opAttrs: AttributeMap = op.attributes ?? {};\n\n if (isTextInsert(op)) {\n const text: string = op.insert;\n const parts: string[] = text.split('\\n');\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n if (part === undefined) continue;\n\n // Add text content to current line (with inline attributes only)\n if (part.length > 0) {\n const newOp: InsertOp = { insert: part };\n // Only copy inline attributes, not block attributes\n const inlineAttrs: AttributeMap = {};\n for (const [key, value] of Object.entries(opAttrs)) {\n // Skip block attributes\n if (\n ![\n 'header',\n 'blockquote',\n 'code-block',\n 'list',\n 'indent',\n 'align',\n 'direction',\n 'table-row',\n 'table-col',\n 'table-header',\n 'table-col-align',\n ].includes(key)\n ) {\n inlineAttrs[key] = value;\n }\n }\n if (Object.keys(inlineAttrs).length > 0) {\n newOp.attributes = inlineAttrs;\n }\n currentOps.push(newOp);\n }\n\n // If not the last part, this is a line break\n if (i < parts.length - 1) {\n lines.push({\n ops: currentOps,\n attributes: opAttrs, // Line attributes come from the \\n op\n });\n currentOps = [];\n }\n }\n } else {\n // Embed\n currentOps.push(op);\n }\n }\n\n // Don't forget the last line if there's content\n if (currentOps.length > 0) {\n lines.push({ ops: currentOps, attributes: {} });\n }\n\n return lines;\n}\n\n/**\n * Collect consecutive code block lines\n */\nfunction collectCodeBlock(lines: Line[], startIndex: number): Line[] {\n const codeLines: Line[] = [];\n const startLine = lines[startIndex];\n if (!startLine) return codeLines;\n\n const startLang = getCodeBlockLanguage(startLine.attributes);\n\n for (let i = startIndex; i < lines.length; i++) {\n const line = lines[i];\n if (!line || !line.attributes['code-block']) break;\n\n const lang = getCodeBlockLanguage(line.attributes);\n if (i > startIndex && lang !== startLang) break;\n\n codeLines.push(line);\n }\n\n return codeLines;\n}\n\n/**\n * Collect consecutive table lines\n */\nfunction collectTableLines(lines: Line[], startIndex: number): Line[] {\n const result: Line[] = [];\n for (let i = startIndex; i < lines.length; i++) {\n const line = lines[i];\n if (\n !line ||\n typeof line.attributes['table-row'] !== 'number' ||\n typeof line.attributes['table-col'] !== 'number'\n ) {\n break;\n }\n result.push(line);\n }\n return result;\n}\n\n/**\n * Table cell data for Markdown rendering\n */\ninterface MdTableCell {\n ops: InsertOp[];\n colAlign?: string | undefined;\n}\n\n/**\n * Render a group of table lines as a GFM Markdown table\n */\nfunction renderMarkdownTable(\n tableLines: Line[],\n embedRenderers: Record<string, (value: unknown, attrs?: AttributeMap) => string>,\n useLatexDelimiters: boolean = false,\n registry?: Registry,\n softBreakStyle: 'spaces' | 'html' = 'spaces',\n): string {\n // Group by row\n const rows = new Map<number, { isHeader: boolean; cells: Map<number, MdTableCell> }>();\n\n for (const line of tableLines) {\n const attrs = line.attributes;\n const rowIdx = attrs['table-row'] as number;\n const colIdx = attrs['table-col'] as number;\n\n if (!rows.has(rowIdx)) {\n rows.set(rowIdx, { isHeader: !!attrs['table-header'], cells: new Map() });\n }\n\n const row = rows.get(rowIdx)!;\n if (attrs['table-header']) row.isHeader = true;\n row.cells.set(colIdx, {\n ops: line.ops,\n colAlign: typeof attrs['table-col-align'] === 'string' ? attrs['table-col-align'] : undefined,\n });\n }\n\n // Sort rows by index\n const sortedRows = [...rows.entries()].sort((a, b) => a[0] - b[0]);\n\n // Determine max columns\n let maxCol = 0;\n for (const [, row] of sortedRows) {\n for (const colIdx of row.cells.keys()) {\n if (colIdx > maxCol) maxCol = colIdx;\n }\n }\n\n // Separate header and body rows\n const headerRows = sortedRows.filter(([, r]) => r.isHeader);\n const bodyRows = sortedRows.filter(([, r]) => !r.isHeader);\n\n // Collect column alignments from header row (or first row)\n const colAligns: (string | undefined)[] = [];\n const alignSource = headerRows.length > 0 ? headerRows : bodyRows;\n if (alignSource.length > 0) {\n const firstRow = alignSource[0]!;\n for (let col = 0; col <= maxCol; col++) {\n const cell = firstRow[1].cells.get(col);\n colAligns.push(cell?.colAlign);\n }\n }\n\n const mdLines: string[] = [];\n\n // If there's a header, render it + separator\n if (headerRows.length > 0) {\n for (const [, row] of headerRows) {\n mdLines.push(\n renderMdRow(row.cells, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle),\n );\n }\n mdLines.push(renderMdSeparator(maxCol, colAligns));\n } else {\n // No header: render a synthetic empty header + separator (GFM requires header)\n const emptyRow = new Map<number, MdTableCell>();\n for (let col = 0; col <= maxCol; col++) {\n emptyRow.set(col, { ops: [] });\n }\n mdLines.push(\n renderMdRow(emptyRow, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle),\n );\n mdLines.push(renderMdSeparator(maxCol, colAligns));\n }\n\n // Render body rows\n for (const [, row] of bodyRows) {\n mdLines.push(\n renderMdRow(row.cells, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle),\n );\n }\n\n return mdLines.join('\\n');\n}\n\n/**\n * Render a single GFM table row\n */\nfunction renderMdRow(\n cells: Map<number, MdTableCell>,\n maxCol: number,\n embedRenderers: Record<string, (value: unknown, attrs?: AttributeMap) => string>,\n useLatexDelimiters: boolean = false,\n registry?: Registry,\n softBreakStyle: 'spaces' | 'html' = 'spaces',\n): string {\n const parts: string[] = [];\n for (let col = 0; col <= maxCol; col++) {\n const cell = cells.get(col);\n const content = cell\n ? renderLineContent(\n cell.ops,\n embedRenderers,\n false,\n useLatexDelimiters,\n undefined,\n false,\n registry,\n softBreakStyle,\n true, // inTableCell — softBreak must use <br>, never \" \\n\"\n )\n : '';\n // Escape pipe characters in cell content\n parts.push(content.replace(/\\|/g, '\\\\|'));\n }\n return '| ' + parts.join(' | ') + ' |';\n}\n\n/**\n * Render the GFM separator row (with alignment)\n */\nfunction renderMdSeparator(maxCol: number, colAligns: (string | undefined)[]): string {\n const parts: string[] = [];\n for (let col = 0; col <= maxCol; col++) {\n const align = colAligns[col];\n if (align === 'center') {\n parts.push(':---:');\n } else if (align === 'right') {\n parts.push('---:');\n } else if (align === 'left') {\n parts.push(':---');\n } else {\n parts.push('---');\n }\n }\n return '| ' + parts.join(' | ') + ' |';\n}\n\n/**\n * Get code block language from attributes\n */\nfunction getCodeBlockLanguage(attributes: AttributeMap): string | undefined {\n const codeBlock = attributes['code-block'];\n if (typeof codeBlock === 'string' && codeBlock !== 'true') {\n return codeBlock;\n }\n return undefined;\n}\n\n/**\n * Render inline content of a line\n */\nfunction renderLineContent(\n ops: InsertOp[],\n embedRenderers: Record<string, (value: unknown, attrs?: AttributeMap) => string>,\n inCodeBlock: boolean,\n useLatexDelimiters: boolean = false,\n blockHandlers?: BlockHandlerRegistry,\n prettyHtml: boolean = false,\n registry?: Registry,\n softBreakStyle: 'spaces' | 'html' = 'spaces',\n inTableCell: boolean = false,\n): string {\n let result = '';\n\n for (const op of ops) {\n const attrs: AttributeMap | undefined = op.attributes;\n\n if (isTextInsert(op)) {\n const text: string = op.insert;\n if (inCodeBlock) {\n // Don't escape or format in code blocks\n result += text;\n } else {\n result += renderInlineText(text, attrs);\n }\n } else if (isEmbedInsert(op)) {\n const embed: Record<string, unknown> = op.insert;\n result += renderEmbed(\n embed,\n attrs,\n embedRenderers,\n useLatexDelimiters,\n blockHandlers,\n prettyHtml,\n registry,\n softBreakStyle,\n inTableCell,\n );\n }\n }\n\n return result;\n}\n\n/**\n * Render inline text with formatting\n */\nfunction renderInlineText(text: string, attributes?: AttributeMap): string {\n if (!attributes || Object.keys(attributes).length === 0) {\n return escapeMarkdown(text);\n }\n\n // Handle link specially (wraps everything)\n const link = typeof attributes.link === 'string' ? attributes.link : undefined;\n\n // Escape text first (skip for inline code — backtick content is literal)\n let result = attributes.code ? text : escapeMarkdown(text);\n\n // Apply inline formats in order (inner to outer for wrapping)\n // We iterate in reverse so outer formats wrap inner ones\n for (let i = MD_INLINE_FORMAT_ORDER.length - 1; i >= 0; i--) {\n const format = MD_INLINE_FORMAT_ORDER[i];\n if (!format || !attributes[format]) continue;\n\n const syntax = INLINE_FORMAT_SYNTAX[format];\n if (syntax) {\n result = `${syntax.prefix}${result}${syntax.suffix}`;\n }\n }\n\n // Apply link last (outermost, before style spans)\n if (link) {\n result = renderLink(result, link);\n }\n\n // Apply style-based formats as <span style=\"...\"> (outermost wrapping)\n const styleProps: string[] = [];\n if (typeof attributes.color === 'string') styleProps.push(`color: ${attributes.color}`);\n if (typeof attributes.background === 'string')\n styleProps.push(`background-color: ${attributes.background}`);\n if (typeof attributes.font === 'string') styleProps.push(`font-family: ${attributes.font}`);\n if (typeof attributes.size === 'string') styleProps.push(`font-size: ${attributes.size}`);\n if (styleProps.length > 0) {\n result = `<span style=\"${styleProps.join('; ')}\">${result}</span>`;\n }\n\n return result;\n}\n\n/**\n * Render an embed to Markdown\n */\nfunction renderEmbed(\n embed: Record<string, unknown>,\n attributes: AttributeMap | undefined,\n customRenderers: Record<string, (value: unknown, attrs?: AttributeMap) => string>,\n useLatexDelimiters: boolean = false,\n blockHandlers?: BlockHandlerRegistry,\n prettyHtml: boolean = false,\n registry?: Registry,\n softBreakStyle: 'spaces' | 'html' = 'spaces',\n inTableCell: boolean = false,\n): string {\n const entries = Object.entries(embed);\n if (entries.length === 0) return '';\n\n const firstEntry = entries[0];\n if (!firstEntry) return '';\n\n const embedType: string = firstEntry[0];\n const embedValue: unknown = firstEntry[1];\n\n // Soft line break (Phase 7 Part 0) — handled here (before registry\n // / custom-renderer lookup) so the caller-controlled `softBreakStyle`\n // option always wins over any registered `Format.toMarkdown`.\n // Inside table cells, GFM forbids raw `\\n`, so the embed is always\n // rendered as inline `<br>` regardless of the style preference.\n if (embedType === 'softBreak') {\n if (inTableCell) return '<br>';\n return softBreakStyle === 'html' ? '<br>' : ' \\n';\n }\n\n // Handle block embeds via BlockHandler\n if (embedType === 'block' && blockHandlers) {\n const blockData = embedValue as Record<string, unknown>;\n if (blockData && typeof blockData.type === 'string') {\n const handler = blockHandlers.get(blockData.type);\n if (handler) {\n const opAttrs = attributes ? { opAttributes: attributes as Record<string, unknown> } : {};\n\n // Try toMarkdown first — renderDelta produces Markdown\n if (handler.toMarkdown) {\n const mdContext: BlockContext = {\n registry: undefined as never,\n renderDelta: (ops: Op[]): string => deltaToMarkdown(new Delta(ops), { blockHandlers }),\n ...opAttrs,\n };\n const md = handler.toMarkdown(blockData, mdContext);\n if (md !== null) return md;\n }\n\n // Fallback: render as HTML directly in Markdown (valid per CommonMark).\n // renderDelta must produce HTML so cell content is proper HTML, not\n // Markdown syntax that would be lost during htmlToDelta roundtrip.\n const htmlContext: BlockContext = {\n registry: undefined as never,\n ...(prettyHtml ? { options: { pretty: true } } : {}),\n renderDelta: (ops: Op[]): string =>\n deltaToHtml(new Delta(ops), { blockHandlers, pretty: prettyHtml }),\n ...opAttrs,\n };\n return '\\n' + handler.toHtml(blockData, htmlContext) + '\\n';\n }\n }\n return '';\n }\n\n // Check for custom renderer\n const customRenderer = customRenderers[embedType];\n if (customRenderer) {\n return customRenderer(embedValue, attributes);\n }\n\n // Check registry format toMarkdown() / render() fallback\n if (registry) {\n const format = registry.get(embedType);\n if (format) {\n // Try toMarkdown first\n if (format.toMarkdown) {\n const md = format.toMarkdown(embedValue, attributes);\n if (md !== null) return md;\n }\n // Fallback to render() as HTML-in-Markdown\n if (format.render) {\n return format.render(embedValue, attributes);\n }\n }\n }\n\n // Built-in embed handling\n if (embedType === 'image') {\n const src = typeof embedValue === 'string' ? embedValue : '';\n const alt = typeof attributes?.alt === 'string' ? attributes.alt : undefined;\n\n // When float/width/height are present, use HTML <img> to preserve attributes\n const hasFloat =\n attributes?.float != null &&\n typeof attributes.float === 'string' &&\n attributes.float !== 'none';\n const hasWidth = attributes?.width != null;\n const hasHeight = attributes?.height != null;\n\n if (hasFloat || hasWidth || hasHeight) {\n const altAttr = alt ? ` alt=\"${escapeHtml(alt)}\"` : '';\n const floatAttr = hasFloat ? ` data-float=\"${escapeHtml(String(attributes.float))}\"` : '';\n const widthAttr = hasWidth ? ` width=\"${escapeHtml(String(attributes.width))}\"` : '';\n const heightAttr = hasHeight ? ` height=\"${escapeHtml(String(attributes.height))}\"` : '';\n return `<img src=\"${escapeHtml(src)}\"${altAttr}${floatAttr}${widthAttr}${heightAttr}>`;\n }\n\n return renderImage(src, alt);\n }\n\n if (embedType === 'video') {\n const src = typeof embedValue === 'string' ? embedValue : '';\n\n // When float/width/height are present, use HTML to preserve attributes\n const hasFloat =\n attributes?.float != null &&\n typeof attributes.float === 'string' &&\n attributes.float !== 'none';\n const hasWidth = attributes?.width != null;\n const hasHeight = attributes?.height != null;\n\n if (hasFloat || hasWidth || hasHeight) {\n const floatAttr = hasFloat ? ` data-float=\"${escapeHtml(String(attributes.float))}\"` : '';\n const styles: string[] = [];\n if (hasWidth) {\n const w =\n typeof attributes.width === 'string' || typeof attributes.width === 'number'\n ? String(attributes.width)\n : '';\n if (w && w !== 'auto') styles.push(`width: ${/^\\d+$/.test(w) ? w + 'px' : w}`);\n }\n if (hasHeight) {\n const h =\n typeof attributes.height === 'string' || typeof attributes.height === 'number'\n ? String(attributes.height)\n : '';\n if (h && h !== 'auto') styles.push(`height: ${/^\\d+$/.test(h) ? h + 'px' : h}`);\n }\n const styleAttr = styles.length > 0 ? ` style=\"${styles.join('; ')}\"` : '';\n const embedSrc = toVideoEmbedUrl(src);\n if (embedSrc) {\n return `<iframe src=\"${escapeHtml(embedSrc)}\" frameborder=\"0\" allowfullscreen${floatAttr}${styleAttr}></iframe>`;\n }\n return `<video src=\"${escapeHtml(src)}\" controls${floatAttr}${styleAttr}></video>`;\n }\n\n // Simple video without attributes → readable Markdown (like images)\n return ``;\n }\n\n if (embedType === 'formula') {\n const latex = typeof embedValue === 'string' ? embedValue : '';\n return useLatexDelimiters ? `\\\\(${latex}\\\\)` : `$${latex}$`;\n }\n\n if (embedType === 'diagram') {\n // Diagram embed → render as fenced code block with appropriate language\n const source = typeof embedValue === 'string' ? embedValue : '';\n const lang = source.trimStart().startsWith('@startuml') ? 'plantuml' : 'mermaid';\n return `\\n\\`\\`\\`${lang}\\n${source}\\n\\`\\`\\`\\n`;\n }\n\n if (embedType === 'drawio') {\n // Draw.io embeds use image-like syntax in Markdown (file reference)\n const src = typeof embedValue === 'string' ? embedValue : '';\n const alt = typeof attributes?.alt === 'string' ? attributes.alt : undefined;\n return renderImage(src, alt);\n }\n\n if (embedType === 'footnote-ref') {\n // Footnote reference: [^id]\n const id = typeof embedValue === 'string' ? embedValue : String(embedValue);\n return `[^${id}]`;\n }\n\n if (embedType === 'divider') {\n return '\\n---\\n';\n }\n\n // Unknown embed - skip\n return '';\n}\n\n/**\n * Render block formatting (headers, lists, etc.)\n */\nfunction renderBlockFormat(\n content: string,\n attributes: AttributeMap,\n orderedIndex: number,\n _strict: boolean,\n): string {\n const indent = typeof attributes.indent === 'number' ? attributes.indent : 0;\n const indentPrefix = getIndentPrefix(indent);\n\n // Header\n const header = typeof attributes.header === 'number' ? attributes.header : undefined;\n if (header) {\n const prefixFn = BLOCK_FORMAT_PREFIX.header;\n if (typeof prefixFn === 'function') {\n let line = prefixFn(header) + content;\n // Append custom header-id if present\n const headerId = attributes['header-id'];\n if (typeof headerId === 'string' && headerId.length > 0) {\n line += ` {#${headerId}}`;\n }\n return line;\n }\n }\n\n // Blockquote\n if (attributes.blockquote) {\n return '> ' + content;\n }\n\n // List\n const listType = typeof attributes.list === 'string' ? attributes.list : undefined;\n if (listType) {\n const prefixDef = LIST_TYPE_PREFIX[listType];\n let prefix: string;\n\n if (typeof prefixDef === 'function') {\n prefix = prefixDef(orderedIndex - 1);\n } else if (prefixDef) {\n prefix = prefixDef;\n } else {\n prefix = '- ';\n }\n\n return indentPrefix + prefix + content;\n }\n\n // Align - not supported in basic Markdown, skip\n // content remains unchanged\n\n // Regular paragraph\n return content;\n}\n","/**\n * Markdown ↔ Delta Mapping Configuration\n *\n * Defines the mapping between Markdown syntax and Delta attributes.\n */\n\n/**\n * Characters that need escaping in Markdown text\n *\n * Note: `.` is only special at line start after a number (ordered lists)\n * We escape only the most impactful chars: \\ ` * _ [ ] < > #\n * Chars like `.` `!` `|` are context-dependent and rarely need escaping inline.\n */\nexport const MARKDOWN_ESCAPE_CHARS = /[\\\\`*_[\\]<>#]/g;\n\n/**\n * Escape special Markdown characters\n */\nexport function escapeMarkdown(text: string): string {\n return text.replace(MARKDOWN_ESCAPE_CHARS, '\\\\$&');\n}\n\n/**\n * Inline format to Markdown syntax mapping\n *\n * Note: underline, subscript, superscript, mark use HTML tags\n * since Markdown has no native syntax for them\n */\nexport const INLINE_FORMAT_SYNTAX: Record<string, { prefix: string; suffix: string }> = {\n bold: { prefix: '**', suffix: '**' },\n italic: { prefix: '_', suffix: '_' },\n underline: { prefix: '<u>', suffix: '</u>' },\n strike: { prefix: '~~', suffix: '~~' },\n subscript: { prefix: '<sub>', suffix: '</sub>' },\n superscript: { prefix: '<sup>', suffix: '</sup>' },\n code: { prefix: '`', suffix: '`' },\n mark: { prefix: '<mark>', suffix: '</mark>' },\n kbd: { prefix: '<kbd>', suffix: '</kbd>' },\n};\n\n/**\n * Order of inline formats for nesting (outer to inner)\n *\n * Bold + Italic → ***text***\n * Bold + Strike → **~~text~~**\n * Underline, subscript, superscript, mark → HTML tags in Markdown\n */\nexport const MD_INLINE_FORMAT_ORDER: string[] = [\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'subscript',\n 'superscript',\n 'code',\n 'mark',\n 'kbd',\n];\n\n/**\n * Block format to Markdown prefix mapping\n */\nexport const BLOCK_FORMAT_PREFIX: Record<string, string | ((value: unknown) => string)> = {\n header: (value: unknown) => {\n const level = typeof value === 'number' ? value : 1;\n return '#'.repeat(Math.min(Math.max(level, 1), 6)) + ' ';\n },\n blockquote: '> ',\n 'code-block': '', // Handled separately with fences\n};\n\n/**\n * List type to Markdown prefix\n */\nexport const LIST_TYPE_PREFIX: Record<string, string | ((index: number) => string)> = {\n bullet: '- ',\n ordered: (index: number) => `${index + 1}. `,\n checked: '- [x] ',\n unchecked: '- [ ] ',\n};\n\n/**\n * Generate indent prefix for nested lists\n */\nexport function getIndentPrefix(level: number): string {\n // Use 4 spaces for indentation (works for both bullet and ordered lists)\n return ' '.repeat(level);\n}\n\n/**\n * Render an image embed to Markdown\n */\nexport function renderImage(src: string, alt?: string, _title?: string): string {\n const altText = alt ?? '';\n return ``;\n}\n\n/**\n * Render a link to Markdown\n */\nexport function renderLink(text: string, href: string, _title?: string): string {\n return `[${text}](${href})`;\n}\n\n/**\n * Render a code block with optional language\n */\nexport function renderCodeBlock(code: string, language?: string): string {\n const lang = language ?? '';\n return `\\`\\`\\`${lang}\\n${code}\\n\\`\\`\\``;\n}\n","/**\n * Markdown → Delta Conversion\n *\n * Converts Markdown string to a Delta document using remark (unified).\n */\n\nimport { Delta } from '@scrider/delta';\nimport type { AttributeMap } from '@scrider/delta';\nimport type { BlockHandlerRegistry } from '../../schema/BlockHandlerRegistry';\nimport { htmlToDelta } from '../html/html-to-delta';\n\n/**\n * Options for Markdown → Delta conversion\n */\nexport interface MarkdownToDeltaOptions {\n /**\n * Enable GFM (GitHub Flavored Markdown) extensions\n * Includes: tables, strikethrough, task lists, autolinks\n * @default true\n */\n gfm?: boolean;\n\n /**\n * Display math rendering mode\n * - true (default): $$...$$ / ```math → code-block \"math\" in Delta\n * - false: $$...$$ / ```math → inline { formula } embed in Delta\n *\n * Does NOT affect inline math ($...$) — always becomes { formula } embed\n * @default true\n */\n mathBlock?: boolean;\n\n /**\n * Mermaid diagram rendering mode\n * - true (default): ```mermaid → code-block \"mermaid\" in Delta\n * - false: ```mermaid → inline { diagram } embed in Delta\n * @default true\n */\n mermaidBlock?: boolean;\n\n /**\n * PlantUML diagram rendering mode\n * - true (default): ```plantuml → code-block \"plantuml\" in Delta\n * - false: ```plantuml → inline { diagram } embed in Delta\n * @default true\n */\n plantumlBlock?: boolean;\n\n /**\n * Custom node handlers for special elements\n */\n nodeHandlers?: Record<string, NodeHandler>;\n\n /**\n * Block handler registry for Extended Table and other block embeds.\n * Reserved for future use — GFM tables don't support Extended Table features.\n * HTML tables in Markdown are parsed via htmlToDelta when blockHandlers is provided.\n */\n blockHandlers?: BlockHandlerRegistry;\n}\n\n/**\n * MDAST node type (simplified)\n */\ninterface MdastNode {\n type: string;\n children?: MdastNode[];\n value?: string;\n url?: string;\n alt?: string;\n title?: string;\n lang?: string;\n meta?: string;\n depth?: number;\n ordered?: boolean;\n checked?: boolean | null;\n spread?: boolean;\n /** Footnote identifier (for footnoteReference / footnoteDefinition) */\n identifier?: string;\n /** Footnote label (for footnoteReference / footnoteDefinition) */\n label?: string;\n}\n\n/**\n * Custom node handler function\n */\nexport type NodeHandler = (node: MdastNode, context: ParserContext) => void;\n\n/**\n * Parser context for building Delta\n */\nexport interface ParserContext {\n delta: Delta;\n pushText(text: string, attrs?: AttributeMap): void;\n pushEmbed(embed: Record<string, unknown>, attrs?: AttributeMap): void;\n pushNewline(attrs?: AttributeMap): void;\n}\n\n// Lazy-loaded remark modules\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet remarkParse: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet remarkGfm: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet remarkMath: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet unified: any = null;\n\n/**\n * Check if remark is available for synchronous use.\n *\n * Returns true if either:\n * - remark modules have been preloaded (via {@link preloadRemark} or a prior\n * `markdownToDelta` / `markdownToDeltaSync` call), OR\n * - CommonJS `require()` is available and can resolve `unified` and\n * `remark-parse` (Node.js without ESM-only mode).\n *\n * In browser ESM environments where `require` is undefined, this returns\n * `false` until {@link preloadRemark} has been awaited at least once.\n */\nexport function isRemarkAvailable(): boolean {\n if (unified && remarkParse) return true;\n if (typeof require === 'undefined') return false;\n try {\n require.resolve('unified');\n require.resolve('remark-parse');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Preload remark modules (`unified`, `remark-parse`, `remark-gfm`, optionally\n * `remark-math`) asynchronously. After this resolves successfully, the\n * synchronous {@link markdownToDeltaSync} is usable in environments where\n * `require()` is not available (e.g. browser ESM).\n *\n * Safe to call multiple times: subsequent calls short-circuit if modules are\n * already loaded.\n *\n * @returns `true` if mandatory modules (`unified`, `remark-parse`,\n * `remark-gfm`) are now loaded; `false` if any required module is missing.\n * The function never throws — callers can branch on the boolean for\n * graceful degradation.\n *\n * @example\n * // On editor mount:\n * useEffect(() => {\n * preloadRemark();\n * }, []);\n */\nexport async function preloadRemark(): Promise<boolean> {\n if (unified && remarkParse && remarkGfm) return true;\n\n try {\n const [unifiedMod, remarkParseMod, remarkGfmMod] = await Promise.all([\n import('unified'),\n import('remark-parse'),\n import('remark-gfm'),\n ]);\n unified = unifiedMod.unified;\n remarkParse = remarkParseMod.default;\n remarkGfm = remarkGfmMod.default;\n } catch {\n return false;\n }\n\n // remark-math is optional — enables $...$ and $$...$$ syntax\n if (!remarkMath) {\n try {\n const remarkMathMod = await import('remark-math');\n remarkMath = remarkMathMod.default;\n } catch {\n // remark-math not installed — $...$ will be treated as plain text\n }\n }\n\n return true;\n}\n\n/**\n * Preprocess markdown before parsing:\n * - Convert LaTeX math delimiters \\(...\\) → $...$ and \\[...\\] → $$...$$\n * - When mathBlock=true, promote standalone $...$ (entire line) to $$...$$ display math\n *\n * LaTeX delimiters are widely used by LLMs (DeepSeek, ChatGPT, Claude)\n * and are safe to convert since \\( \\) in plain Markdown is just escaped parens.\n *\n * Note: standalone <br> tags are replaced with <!--empty-line--> HTML comment sentinels\n * surrounded by blank lines. This makes remark parse them as block-level HTML nodes\n * (not inline HTML within a paragraph), avoiding newline duplication during roundtrip.\n * The sentinel is detected in processInlineHtml() which calls pushNewline().\n */\nfunction preprocessMarkdown(markdown: string, mathBlock: boolean): string {\n // Convert \\(...\\) → $...$ (inline math, single line)\n markdown = markdown.replace(/\\\\\\((.+?)\\\\\\)/g, (_match, content: string) => `$${content}$`);\n\n // Convert \\[...\\] → $$...$$ (display math, may span multiple lines)\n markdown = markdown.replace(/\\\\\\[([\\s\\S]+?)\\\\\\]/g, (_match, content: string) => `$$${content}$$`);\n\n // When mathBlock=true, promote standalone $...$ to $$\\n...\\n$$ (display math)\n // A line containing ONLY a single $...$ formula → display math block\n // remark-math requires $$ on separate lines for display math recognition\n // This handles DeepSeek/LLM output where $...$ is used on its own line for display formulas\n if (mathBlock) {\n markdown = markdown.replace(\n /^\\$([^$\\n]+)\\$\\s*$/gm,\n (_match, content: string) => `$$\\n${content}\\n$$`,\n );\n }\n\n // Replace standalone <br> with <!--empty-line--> sentinel surrounded by blank lines.\n // <br> tags are emitted by deltaToMarkdown(preserveEmptyLines: true) to represent\n // empty lines in the Delta. We convert them to block-level HTML comments so remark\n // creates a separate 'html' AST node (not inline HTML merged with paragraph text).\n // The sentinel is detected in processInlineHtml() which calls pushNewline(),\n // producing exactly one \\n per <br> — preserving empty lines through roundtrip.\n return markdown.replace(/^<br\\s*\\/?>$/gim, '\\n<!--empty-line-->\\n');\n}\n\n/**\n * Convert Markdown to Delta (async)\n */\nexport async function markdownToDelta(\n markdown: string,\n options: MarkdownToDeltaOptions = {},\n): Promise<Delta> {\n const {\n gfm = true,\n mathBlock = true,\n mermaidBlock = true,\n plantumlBlock = true,\n nodeHandlers = {},\n } = options;\n\n markdown = preprocessMarkdown(markdown, mathBlock);\n\n const loaded = await preloadRemark();\n if (!loaded || !unified || !remarkParse) {\n throw new Error(\n 'remark is not installed. Install with: pnpm add unified remark-parse remark-gfm',\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n let processor = unified().use(remarkParse);\n\n if (gfm && remarkGfm) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n processor = processor.use(remarkGfm);\n }\n\n if (remarkMath) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n processor = processor.use(remarkMath);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n const tree = processor.parse(markdown) as MdastNode;\n\n return astToDelta(\n tree,\n nodeHandlers,\n mathBlock,\n mermaidBlock,\n plantumlBlock,\n options.blockHandlers,\n );\n}\n\n/**\n * Synchronous version (requires remark to be pre-loaded or uses require)\n */\nexport function markdownToDeltaSync(markdown: string, options: MarkdownToDeltaOptions = {}): Delta {\n const {\n gfm = true,\n mathBlock = true,\n mermaidBlock = true,\n plantumlBlock = true,\n nodeHandlers = {},\n } = options;\n\n markdown = preprocessMarkdown(markdown, mathBlock);\n\n if (!unified || !remarkParse) {\n if (typeof require === 'undefined') {\n throw new Error(\n 'markdownToDeltaSync requires remark to be preloaded in this environment. ' +\n '`require()` is not available (likely browser ESM). ' +\n 'Call `await preloadRemark()` once on application startup before using the sync API, ' +\n 'or use the async `markdownToDelta()` instead.',\n );\n }\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment\n const unifiedMod = require('unified');\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment\n const remarkParseMod = require('remark-parse');\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment\n const remarkGfmMod = require('remark-gfm');\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n unified = unifiedMod.unified;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n remarkParse = remarkParseMod.default;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n remarkGfm = remarkGfmMod.default;\n } catch {\n throw new Error(\n 'remark is not installed. Install with: pnpm add unified remark-parse remark-gfm',\n );\n }\n\n // remark-math is optional\n if (!remarkMath) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment\n const remarkMathMod = require('remark-math');\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n remarkMath = remarkMathMod.default;\n } catch {\n // remark-math not installed\n }\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n let processor = unified().use(remarkParse);\n\n if (gfm && remarkGfm) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n processor = processor.use(remarkGfm);\n }\n\n if (remarkMath) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n processor = processor.use(remarkMath);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n const tree = processor.parse(markdown) as MdastNode;\n\n return astToDelta(\n tree,\n nodeHandlers,\n mathBlock,\n mermaidBlock,\n plantumlBlock,\n options.blockHandlers,\n );\n}\n\n/**\n * Convert MDAST to Delta\n */\nfunction astToDelta(\n tree: MdastNode,\n customHandlers: Record<string, NodeHandler>,\n mathBlock: boolean,\n mermaidBlock: boolean,\n plantumlBlock: boolean,\n blockHandlers?: BlockHandlerRegistry,\n): Delta {\n const delta = new Delta();\n let currentInlineAttrs: AttributeMap = {};\n let pendingText = '';\n // Stack for tracking which attributes each <span style> added (for correct nested span handling)\n const spanAttrStack: string[][] = [];\n\n // Footnote definitions collected during AST traversal (for finalization)\n const footnoteDefinitions = new Map<string, MdastNode>();\n\n const context: ParserContext = {\n delta,\n pushText(text: string, attrs?: AttributeMap) {\n if (attrs && Object.keys(attrs).length > 0) {\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n delta.insert(text, { ...currentInlineAttrs, ...attrs });\n } else {\n pendingText += text;\n }\n },\n pushEmbed(embed: Record<string, unknown>, attrs?: AttributeMap) {\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n if (attrs && Object.keys(attrs).length > 0) {\n delta.insert(embed, attrs);\n } else {\n delta.insert(embed);\n }\n },\n pushNewline(attrs?: AttributeMap) {\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n if (attrs && Object.keys(attrs).length > 0) {\n delta.insert('\\n', attrs);\n } else {\n delta.insert('\\n');\n }\n },\n };\n\n // Heading ID extraction: parse {#custom-id} from heading text\n const HEADING_ID_RE = /\\s*\\{#([\\w-]+)\\}\\s*$/;\n\n /**\n * Extract custom heading id from `{#id}` suffix in heading text.\n * Mutates the last text child to strip the `{#id}` part.\n * Returns the extracted id, or null if none found.\n */\n function extractHeadingId(heading: MdastNode): string | null {\n const children = heading.children;\n if (!children || children.length === 0) return null;\n\n // Find the last text node\n const lastChild = children[children.length - 1];\n if (!lastChild || lastChild.type !== 'text' || !lastChild.value) return null;\n\n const match = lastChild.value.match(HEADING_ID_RE);\n if (!match) return null;\n\n // Strip {#id} from the text node\n lastChild.value = lastChild.value.replace(HEADING_ID_RE, '');\n\n return match[1]!;\n }\n\n // Alert type detection: check if blockquote starts with [!TYPE]\n const ALERT_TYPE_RE = /^\\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\]\\s*$/i;\n\n function extractAlertType(blockquote: MdastNode): string | null {\n const bqChildren = blockquote.children;\n if (!bqChildren || bqChildren.length === 0) return null;\n\n const firstChild = bqChildren[0];\n if (!firstChild || firstChild.type !== 'paragraph') return null;\n\n const paraChildren = firstChild.children;\n if (!paraChildren || paraChildren.length === 0) return null;\n\n const firstInline = paraChildren[0];\n if (!firstInline || firstInline.type !== 'text' || !firstInline.value) return null;\n\n const firstLine = firstInline.value.split('\\n')[0] ?? '';\n const match = ALERT_TYPE_RE.exec(firstLine.trim());\n if (!match || !match[1]) return null;\n\n return match[1].toLowerCase();\n }\n\n function processAlertBlockquote(blockquote: MdastNode, alertType: string): void {\n // Build a synthetic root with the blockquote's content, minus the [!TYPE] tag\n const children: MdastNode[] = [...(blockquote.children || [])];\n\n const first = children[0];\n if (first && first.type === 'paragraph' && first.children) {\n const firstPara: MdastNode = { ...first, children: [...first.children] };\n const firstInline = firstPara.children![0];\n\n if (firstInline && firstInline.type === 'text' && firstInline.value) {\n // Remove the [!TYPE] line from the text\n const lines = firstInline.value.split('\\n');\n lines.shift(); // remove \"[!TYPE]\" line\n const remaining = lines.join('\\n');\n\n if (remaining.trim().length > 0) {\n firstPara.children![0] = { ...firstInline, value: remaining };\n } else {\n firstPara.children!.shift();\n }\n\n if (firstPara.children!.length === 0) {\n children.shift();\n } else {\n children[0] = firstPara;\n }\n }\n }\n\n // Convert remaining content to nested Delta\n const syntheticRoot: MdastNode = {\n type: 'root',\n children,\n };\n const contentDelta = astToDelta(\n syntheticRoot,\n customHandlers,\n mathBlock,\n mermaidBlock,\n plantumlBlock,\n blockHandlers,\n );\n\n context.pushEmbed({\n block: {\n type: 'alert',\n alertType,\n content: { ops: contentDelta.ops },\n },\n });\n context.pushNewline();\n }\n\n function processNode(node: MdastNode, blockAttrs: AttributeMap = {}): void {\n const customHandler = customHandlers[node.type];\n if (customHandler) {\n customHandler(node, context);\n return;\n }\n\n switch (node.type) {\n case 'root':\n processChildren(node, blockAttrs);\n break;\n\n case 'paragraph':\n processChildren(node, blockAttrs);\n context.pushNewline(blockAttrs);\n break;\n\n case 'heading': {\n const headerId = extractHeadingId(node);\n processChildren(node, {});\n const headerAttrs: Record<string, unknown> = { header: node.depth ?? 1 };\n if (headerId) {\n headerAttrs['header-id'] = headerId;\n }\n context.pushNewline(headerAttrs);\n break;\n }\n\n case 'blockquote': {\n // Check for GitHub-style alert: > [!NOTE] / > [!TIP] / etc.\n const alertType = extractAlertType(node);\n if (alertType) {\n processAlertBlockquote(node, alertType);\n } else {\n processChildren(node, { blockquote: true });\n }\n break;\n }\n\n case 'list':\n processList(node);\n break;\n\n case 'listItem':\n break;\n\n case 'code':\n processCodeBlock(node);\n break;\n\n case 'table':\n processTable(node);\n break;\n\n case 'tableRow':\n case 'tableCell':\n // Handled inside processTable\n break;\n\n case 'thematicBreak':\n context.pushEmbed({ divider: true });\n context.pushNewline();\n break;\n\n case 'text':\n context.pushText(node.value ?? '');\n break;\n\n case 'strong':\n processInline(node, { bold: true });\n break;\n\n case 'emphasis':\n processInline(node, { italic: true });\n break;\n\n case 'delete':\n processInline(node, { strike: true });\n break;\n\n case 'inlineCode':\n context.pushText(node.value ?? '', { code: true });\n break;\n\n case 'link':\n processLink(node);\n break;\n\n case 'image':\n processImage(node);\n break;\n\n case 'inlineMath':\n // $...$ inline LaTeX formula → formula embed\n context.pushEmbed({ formula: node.value ?? '' });\n break;\n\n case 'math':\n // $$...$$ display math block → code-block with lang \"math\"\n processMathBlock(node);\n break;\n\n case 'footnoteReference':\n context.pushEmbed({ 'footnote-ref': node.identifier ?? '' });\n break;\n\n case 'footnoteDefinition':\n // Collect for post-processing — skip inline output\n footnoteDefinitions.set(node.identifier ?? '', node);\n break;\n\n case 'break':\n // GFM hard break (` \\n` or `\\\\\\n`) — soft line break inside the\n // current block, NOT a paragraph split. Emitted as a `softBreak`\n // embed so that round-trip with HTML `<br>` and editor-driven\n // Shift+Enter is consistent.\n context.pushEmbed({ softBreak: true });\n break;\n\n case 'html': {\n const htmlContent = node.value ?? '';\n if (isBlockLevelHtml(htmlContent)) {\n processBlockHtml(htmlContent);\n } else {\n processInlineHtml(node);\n }\n break;\n }\n\n default:\n if (node.children) {\n processChildren(node, blockAttrs);\n }\n }\n }\n\n function processChildren(node: MdastNode, blockAttrs: AttributeMap): void {\n if (!node.children) return;\n for (const child of node.children) {\n processNode(child, blockAttrs);\n }\n }\n\n function processInline(node: MdastNode, attrs: AttributeMap): void {\n const prevAttrs = { ...currentInlineAttrs };\n\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n\n currentInlineAttrs = { ...currentInlineAttrs, ...attrs };\n\n if (node.children) {\n for (const child of node.children) {\n processNode(child);\n }\n }\n\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n\n currentInlineAttrs = prevAttrs;\n }\n\n function processLink(node: MdastNode): void {\n processInline(node, { link: node.url ?? '' });\n }\n\n function processImage(node: MdastNode): void {\n const url = node.url ?? '';\n const alt = node.alt ?? '';\n\n //  → video embed (case-insensitive: ![video], ![VIDEO])\n if (alt.toLowerCase() === 'video') {\n context.pushEmbed({ video: url });\n return;\n }\n\n const attrs: AttributeMap = {};\n if (node.alt) attrs.alt = node.alt;\n\n // Detect .drawio files by extension — render as drawio embed instead of image\n if (url.toLowerCase().endsWith('.drawio')) {\n context.pushEmbed({ drawio: url }, Object.keys(attrs).length > 0 ? attrs : undefined);\n } else {\n context.pushEmbed({ image: url }, Object.keys(attrs).length > 0 ? attrs : undefined);\n }\n }\n\n function processList(node: MdastNode, indent = 0): void {\n if (!node.children) return;\n\n const ordered = node.ordered ?? false;\n\n for (const item of node.children) {\n if (item.type !== 'listItem') continue;\n\n let listType: string;\n if (item.checked === true) {\n listType = 'checked';\n } else if (item.checked === false) {\n listType = 'unchecked';\n } else {\n listType = ordered ? 'ordered' : 'bullet';\n }\n\n const blockAttrs: AttributeMap = { list: listType };\n if (indent > 0) {\n blockAttrs.indent = indent;\n }\n\n if (item.children) {\n for (const child of item.children) {\n if (child.type === 'list') {\n processList(child, indent + 1);\n } else if (child.type === 'paragraph') {\n processChildren(child, {});\n context.pushNewline(blockAttrs);\n } else {\n processNode(child, blockAttrs);\n }\n }\n }\n }\n }\n\n function processCodeBlock(node: MdastNode): void {\n const code = node.value ?? '';\n const lang = node.lang;\n\n // Mermaid: when mermaidBlock=false, flatten to inline { diagram } embed\n if (lang === 'mermaid' && mermaidBlock === false) {\n context.pushEmbed({ diagram: code });\n context.pushNewline();\n return;\n }\n\n // PlantUML: when plantumlBlock=false, flatten to inline { diagram } embed\n if (lang === 'plantuml' && plantumlBlock === false) {\n context.pushEmbed({ diagram: code });\n context.pushNewline();\n return;\n }\n\n const lines = code.split('\\n');\n const codeBlockAttr: AttributeMap = {\n 'code-block': lang ?? true,\n };\n\n for (const line of lines) {\n context.pushText(line);\n context.pushNewline(codeBlockAttr);\n }\n }\n\n /**\n * Process $$...$$ display math block.\n * mathBlock=true → code-block with lang \"math\"\n * mathBlock=false → inline { formula } embed\n */\n function processMathBlock(node: MdastNode): void {\n const value = node.value ?? '';\n\n if (mathBlock === false) {\n // Flatten display math to inline formula embed\n context.pushEmbed({ formula: value });\n context.pushNewline();\n } else {\n // Default: render as code-block \"math\"\n const lines = value.split('\\n');\n const mathBlockAttr: AttributeMap = { 'code-block': 'math' };\n\n for (const line of lines) {\n context.pushText(line);\n context.pushNewline(mathBlockAttr);\n }\n }\n }\n\n /**\n * Process GFM table node.\n * In MDAST, `table.align` is Array<'left'|'center'|'right'|null>.\n * First `tableRow` child is the header row.\n */\n function processTable(node: MdastNode): void {\n if (!node.children) return;\n\n // Table-level alignment array from remark-gfm\n const aligns: (string | null)[] = (node as unknown as { align: (string | null)[] }).align || [];\n\n for (let rowIdx = 0; rowIdx < node.children.length; rowIdx++) {\n const rowNode = node.children[rowIdx];\n if (!rowNode || rowNode.type !== 'tableRow') continue;\n\n const isHeader = rowIdx === 0; // GFM: first row is always header\n\n if (!rowNode.children) continue;\n\n for (let colIdx = 0; colIdx < rowNode.children.length; colIdx++) {\n const cellNode = rowNode.children[colIdx];\n if (!cellNode || cellNode.type !== 'tableCell') continue;\n\n // Build block attributes for this cell\n const cellBlockAttrs: AttributeMap = {\n 'table-row': rowIdx,\n 'table-col': colIdx,\n };\n if (isHeader) {\n cellBlockAttrs['table-header'] = true;\n }\n const colAlign = aligns[colIdx];\n if (colAlign) {\n cellBlockAttrs['table-col-align'] = colAlign;\n }\n\n // Process inline content of the cell\n if (cellNode.children) {\n for (const child of cellNode.children) {\n processNode(child);\n }\n }\n\n context.pushNewline(cellBlockAttrs);\n }\n }\n }\n\n /**\n * Check if HTML content starts with a block-level element tag.\n * Block-level HTML in Markdown is dispatched to htmlToDelta() for full parsing.\n */\n function isBlockLevelHtml(html: string): boolean {\n return /^\\s*<(div|table|section|article|aside|nav|header|footer|figure|pre|hr|ol|ul|dl|details|iframe|video)\\b/i.test(\n html,\n );\n }\n\n /**\n * Process block-level HTML by delegating to the existing htmlToDelta() converter.\n * This enables Markdown roundtrip for block embeds (Extended Table, Columns, Inline-Box, etc.)\n * that output HTML fallback in deltaToMarkdown.\n */\n function processBlockHtml(html: string): void {\n // Flush pending inline content\n flushInlineText();\n\n // Delegate to existing htmlToDelta with all registered block handlers\n const blockDelta = htmlToDelta(html, blockHandlers ? { blockHandlers } : {});\n\n // Merge ops from block conversion into current delta\n for (const op of blockDelta.ops) {\n delta.push(op);\n }\n }\n\n /**\n * Flush pending text into delta with current inline attributes.\n */\n function flushInlineText(): void {\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n }\n\n /**\n * Map an HTML tag name to the corresponding Delta inline attribute.\n * Returns [attrName, attrValue] or null if not recognized.\n */\n function tagToInlineAttr(tag: string): [string, unknown] | null {\n switch (tag) {\n case 'u':\n case 'ins':\n return ['underline', true];\n case 'sub':\n return ['subscript', true];\n case 'sup':\n return ['superscript', true];\n case 'mark':\n return ['mark', true];\n case 'kbd':\n return ['kbd', true];\n case 'b':\n case 'strong':\n return ['bold', true];\n case 'i':\n case 'em':\n return ['italic', true];\n case 's':\n case 'del':\n case 'strike':\n return ['strike', true];\n default:\n return null;\n }\n }\n\n /**\n * Process inline HTML tags: <u>, <ins>, <sub>, <sup>, <mark>, <kbd>,\n * <b>, <strong>, <i>, <em>, <s>, <del>, <strike>, <span style=\"color/background\">.\n */\n function processInlineHtml(node: MdastNode): void {\n // Trim whitespace: remark HTML-block nodes may carry trailing newlines\n // that would prevent our ^…$ regex anchors from matching.\n const html = (node.value ?? '').trim();\n\n // Match opening tags: simple inline format tags\n const openTagMatch = html.match(/^<(u|ins|sub|sup|mark|kbd|b|strong|i|em|s|del|strike)>$/i);\n if (openTagMatch) {\n const tag = openTagMatch[1]?.toLowerCase() ?? '';\n flushInlineText();\n const attr = tagToInlineAttr(tag);\n if (attr) {\n currentInlineAttrs = { ...currentInlineAttrs, [attr[0]]: attr[1] };\n }\n return;\n }\n\n // Match closing tags: simple inline format tags\n const closeTagMatch = html.match(/^<\\/(u|ins|sub|sup|mark|kbd|b|strong|i|em|s|del|strike)>$/i);\n if (closeTagMatch) {\n const tag = closeTagMatch[1]?.toLowerCase() ?? '';\n flushInlineText();\n const attr = tagToInlineAttr(tag);\n if (attr) {\n const newAttrs = { ...currentInlineAttrs };\n delete newAttrs[attr[0]];\n currentInlineAttrs = newAttrs;\n }\n return;\n }\n\n // Opening <span style=\"...\"> — extract color and/or background-color\n const spanMatch = html.match(/^<span\\s+style=\"([^\"]*)\">/i);\n if (spanMatch) {\n flushInlineText();\n const style = spanMatch[1] ?? '';\n const addedKeys: string[] = [];\n\n const colorMatch = style.match(/(?:^|;)\\s*color\\s*:\\s*([^;]+)/i);\n if (colorMatch) {\n currentInlineAttrs = { ...currentInlineAttrs, color: colorMatch[1]!.trim() };\n addedKeys.push('color');\n }\n\n const bgMatch = style.match(/(?:^|;)\\s*background(?:-color)?\\s*:\\s*([^;]+)/i);\n if (bgMatch) {\n currentInlineAttrs = { ...currentInlineAttrs, background: bgMatch[1]!.trim() };\n addedKeys.push('background');\n }\n\n const fontMatch = style.match(/(?:^|;)\\s*font-family\\s*:\\s*([^;]+)/i);\n if (fontMatch) {\n currentInlineAttrs = {\n ...currentInlineAttrs,\n font: fontMatch[1]!.trim().replace(/^[\"']|[\"']$/g, ''),\n };\n addedKeys.push('font');\n }\n\n const sizeMatch = style.match(/(?:^|;)\\s*font-size\\s*:\\s*([^;]+)/i);\n if (sizeMatch) {\n currentInlineAttrs = { ...currentInlineAttrs, size: sizeMatch[1]!.trim() };\n addedKeys.push('size');\n }\n\n spanAttrStack.push(addedKeys);\n return;\n }\n\n // Closing </span> — pop attributes added by the matching opening <span>\n if (/^<\\/span>$/i.test(html)) {\n flushInlineText();\n const keys = spanAttrStack.pop();\n if (keys) {\n const newAttrs = { ...currentInlineAttrs };\n for (const key of keys) delete newAttrs[key];\n currentInlineAttrs = newAttrs;\n }\n return;\n }\n\n // Handle <img> void element with attributes (float, width, height)\n // This enables roundtrip for floated images: Delta→MD outputs <img data-float=\"...\">,\n // remark-parse sees it as inline HTML, and we reconstruct the image embed here.\n const imgMatch = html.match(/^<img\\s+([^>]*)\\/?>$/i);\n if (imgMatch) {\n const attrStr = imgMatch[1] ?? '';\n const srcMatch = attrStr.match(/src=\"([^\"]*)\"/);\n if (srcMatch) {\n flushInlineText();\n const attrs: AttributeMap = {};\n const altMatch = attrStr.match(/alt=\"([^\"]*)\"/);\n const floatMatch = attrStr.match(/data-float=\"([^\"]*)\"/);\n const widthMatch = attrStr.match(/width=\"([^\"]*)\"/);\n const heightMatch = attrStr.match(/height=\"([^\"]*)\"/);\n if (altMatch?.[1]) attrs.alt = altMatch[1];\n if (floatMatch?.[1]) attrs.float = floatMatch[1];\n if (widthMatch?.[1]) attrs.width = parseInt(widthMatch[1], 10) || widthMatch[1];\n if (heightMatch?.[1]) attrs.height = parseInt(heightMatch[1], 10) || heightMatch[1];\n context.pushEmbed(\n { image: srcMatch[1]! },\n Object.keys(attrs).length > 0 ? attrs : undefined,\n );\n // When <img> appears as a standalone HTML block (type-7), it needs a\n // trailing newline to close the Delta \"line\" — just like the original\n // Delta structure {insert:{image:…}} + {insert:\"\\n\"}.\n context.pushNewline();\n }\n return;\n }\n\n // Handle <!--empty-line--> sentinel (from preprocessMarkdown <br> replacement)\n if (html.trim() === '<!--empty-line-->') {\n context.pushNewline();\n return;\n }\n\n // Handle <br> / <br/> / <br data-scrider-embed> — inline line break\n // (e.g. `text1<br>text2`). Always becomes a softBreak embed so that\n // the construct survives round-trip through HTML, Delta and Markdown.\n if (/^<br\\b[^>]*\\/?>$/i.test(html)) {\n context.pushEmbed({ softBreak: true });\n return;\n }\n\n // For other HTML, just output as text (or skip)\n }\n\n processNode(tree);\n\n // Finalization: create footnotes block embed from collected definitions\n if (footnoteDefinitions.size > 0) {\n const notes: Record<string, { ops: unknown[] }> = {};\n for (const [id, defNode] of footnoteDefinitions) {\n // Convert each definition's children to a separate Delta\n const syntheticRoot: MdastNode = {\n type: 'root',\n children: defNode.children || [],\n };\n const defDelta = astToDelta(\n syntheticRoot,\n customHandlers,\n mathBlock,\n mermaidBlock,\n plantumlBlock,\n blockHandlers,\n );\n notes[id] = { ops: defDelta.ops };\n }\n context.pushEmbed({ block: { type: 'footnotes', notes } });\n context.pushNewline();\n }\n\n if (delta.ops.length > 0) {\n const lastOp = delta.ops[delta.ops.length - 1];\n if (lastOp && 'insert' in lastOp) {\n const lastInsert = lastOp.insert;\n // Add trailing \\n if the document doesn't end with one.\n // Covers both text not ending with \\n and embed objects (which have no \\n).\n if (typeof lastInsert !== 'string' || !lastInsert.endsWith('\\n')) {\n delta.insert('\\n');\n }\n }\n }\n\n return delta;\n}\n","/**\n * Simple-table region detection in flat Delta.\n *\n * Helpers for callers (e.g. editors that need to find the boundaries of a\n * markdown-style table within a Delta op stream — for example to enter\n * \"edit as markdown source\" mode on double-click of a rendered table cell).\n *\n * A simple-table region is a contiguous run of ops that ends, for each cell,\n * with a `\\n`-op carrying the `table-row` attribute (the standard format\n * produced by {@link markdownToDelta} for GFM tables and consumed by\n * {@link deltaToMarkdown}).\n */\n\nimport type { InsertOp, Op } from '@scrider/delta';\nimport { isInsert, isTextInsert } from '@scrider/delta';\n\n/**\n * Detected boundaries of a simple-table region.\n */\nexport interface TableRegion {\n /** Inclusive start index in the original ops array. */\n startOpIdx: number;\n /**\n * Inclusive end index — always points at the last `\\n`-op of the table\n * (the terminator of the last cell of the last row).\n */\n endOpIdx: number;\n /** Slice of the original ops array covering the region. */\n ops: InsertOp[];\n}\n\n/**\n * Predicate: this op is a `\\n`-op that terminates a simple-table cell\n * (i.e. it carries a `table-row` attribute).\n */\nexport function isTableNewlineOp(op: Op | undefined): boolean {\n if (!op || !isInsert(op) || !isTextInsert(op)) return false;\n if (!op.insert.includes('\\n')) return false;\n return !!op.attributes && 'table-row' in op.attributes;\n}\n\n/**\n * Find the boundaries of the simple-table region containing the given hint\n * op index. The hint may be:\n * - an inline op inside a cell,\n * - the cell-terminating `\\n`-op itself,\n * - any op between two table newlines.\n *\n * The function walks **forward** from the hint to find the nearest `\\n`-op:\n * if it does not carry a `table-row` attribute, the hint is not inside a\n * table and `null` is returned. Otherwise the algorithm extends the region\n * forward through contiguous table newlines and backward to the op just\n * after the previous non-table `\\n`-op (or the start of the array).\n *\n * @param ops - The full ops array (e.g. `delta.ops`).\n * @param hintOpIdx - Any op index known or guessed to be within a table.\n * @returns The detected region, or `null` if `hintOpIdx` is out of range or\n * not within any simple-table region.\n *\n * @example\n * // After hit-testing a `<td>` element to a Delta op index:\n * const region = extractTableRegion(state.delta.ops, hitOpIdx);\n * if (region) {\n * const md = deltaToMarkdown(new Delta(region.ops), {\n * trimTrailingNewlines: true,\n * });\n * // replace ops in [region.startOpIdx, region.endOpIdx] with a single\n * // { insert: md + '\\n' } op to enter source-edit mode\n * }\n */\nexport function extractTableRegion(\n ops: readonly Op[],\n hintOpIdx: number,\n): TableRegion | null {\n if (hintOpIdx < 0 || hintOpIdx >= ops.length) return null;\n\n // Step 1: find the first \\n-op at or after the hint. If it is not a\n // table-newline, the hint is not inside a table cell.\n let probeIdx = -1;\n for (let i = hintOpIdx; i < ops.length; i++) {\n const op = ops[i];\n if (!op || !isInsert(op)) continue;\n if (isTextInsert(op) && op.insert.includes('\\n')) {\n probeIdx = i;\n break;\n }\n }\n if (probeIdx < 0) return null;\n if (!isTableNewlineOp(ops[probeIdx])) return null;\n\n // Step 2: extend forward. The last contiguous table-newline is the end.\n let endOpIdx = probeIdx;\n for (let i = probeIdx + 1; i < ops.length; i++) {\n const op = ops[i];\n if (!op || !isInsert(op)) break;\n if (isTextInsert(op) && op.insert.includes('\\n')) {\n if (isTableNewlineOp(op)) {\n endOpIdx = i;\n } else {\n break;\n }\n }\n }\n\n // Step 3: extend backward. The table starts right after the previous\n // non-table \\n-op (or at index 0 if none).\n let startOpIdx = 0;\n for (let i = probeIdx - 1; i >= 0; i--) {\n const op = ops[i];\n if (!op || !isInsert(op)) {\n startOpIdx = i + 1;\n break;\n }\n if (isTextInsert(op) && op.insert.includes('\\n') && !isTableNewlineOp(op)) {\n startOpIdx = i + 1;\n break;\n }\n }\n\n const regionOps = ops.slice(startOpIdx, endOpIdx + 1) as InsertOp[];\n return { startOpIdx, endOpIdx, ops: regionOps };\n}\n"],"mappings":"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","names":["import_delta","import_delta","import_delta","import_delta","import_delta","import_delta","import_delta","blockFormat","children","import_delta","renderCodeBlock","splitIntoLines","collectTableLines","getCodeBlockLanguage","renderLineContent","renderCodeBlock","renderInlineText","renderEmbed","import_delta","import_delta"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/schema/Registry.ts","../src/schema/BlockHandlerRegistry.ts","../src/schema/blocks/table.ts","../src/conversion/sanitize.ts","../src/conversion/adapters/types.ts","../src/schema/blocks/footnotes.ts","../src/schema/blocks/alert.ts","../src/schema/blocks/columns.ts","../src/schema/blocks/box.ts","../src/schema/utils/color.ts","../src/schema/formats/inline/background.ts","../src/schema/formats/inline/bold.ts","../src/schema/formats/inline/code.ts","../src/schema/formats/inline/color.ts","../src/schema/formats/inline/font.ts","../src/schema/formats/inline/italic.ts","../src/schema/formats/inline/kbd.ts","../src/schema/formats/inline/link.ts","../src/schema/formats/inline/mark.ts","../src/schema/formats/inline/size.ts","../src/schema/formats/inline/strike.ts","../src/schema/formats/inline/subscript.ts","../src/schema/formats/inline/superscript.ts","../src/schema/formats/inline/underline.ts","../src/schema/formats/block/align.ts","../src/schema/formats/block/blockquote.ts","../src/schema/formats/block/code-block.ts","../src/schema/formats/block/header.ts","../src/schema/formats/block/header-id.ts","../src/schema/formats/block/indent.ts","../src/schema/formats/block/list.ts","../src/schema/formats/block/table-row.ts","../src/schema/formats/block/table-col.ts","../src/schema/formats/block/table-header.ts","../src/schema/formats/block/table-col-align.ts","../src/schema/formats/embed/block.ts","../src/conversion/html/config.ts","../src/schema/formats/embed/divider.ts","../src/schema/formats/embed/footnote-ref.ts","../src/schema/formats/embed/formula.ts","../src/schema/formats/embed/image.ts","../src/schema/formats/embed/soft-break.ts","../src/schema/formats/embed/video.ts","../src/schema/defaults.ts","../src/conversion/adapters/browser.ts","../src/conversion/adapters/node.ts","../src/conversion/adapters/index.ts","../src/conversion/html/delta-to-html.ts","../src/conversion/utils/slugify.ts","../src/conversion/html/document-presentation.ts","../src/conversion/html/table-presentation.ts","../src/conversion/html/html-to-delta.ts","../src/conversion/markdown/delta-to-markdown.ts","../src/conversion/markdown/config.ts","../src/conversion/markdown/markdown-to-delta.ts","../src/conversion/markdown/table-region.ts"],"sourcesContent":["/**\n * @scrider/formatter\n * Schema, conversion and block handlers for @scrider/delta\n */\n\n// Re-export Core (convenience — use one import for everything)\nexport * from '@scrider/delta';\n\n// Schema (Registry & Formats)\nexport type { Format, FormatDefinition, FormatMatchResult, FormatScope } from './schema';\nexport type { BlockHandler, BlockContext, BlockRenderOptions } from './schema';\nexport type { TableBlockData, CellData, CellAlign } from './schema';\nexport type { FootnotesBlockData } from './schema';\nexport type { AlertBlockData, AlertType } from './schema';\nexport type { ColumnsBlockData } from './schema';\nexport type { BoxBlockData, BoxFloat, BoxOverflow, BoxOpAttributes } from './schema';\nexport {\n ALERT_TYPES,\n BOX_FLOAT_VALUES,\n BOX_OVERFLOW_VALUES,\n BlockHandlerRegistry,\n createDefaultBlockHandlers,\n createDefaultRegistry,\n defaultBlockFormats,\n defaultEmbedFormats,\n defaultFormats,\n defaultInlineFormats,\n Registry,\n tableBlockHandler,\n footnotesBlockHandler,\n alertBlockHandler,\n columnsBlockHandler,\n boxBlockHandler,\n extractBoxOpAttributes,\n} from './schema';\n\n// Individual formats (for custom registries)\nexport {\n // Inline\n backgroundFormat,\n boldFormat,\n codeFormat,\n colorFormat,\n fontFormat,\n italicFormat,\n kbdFormat,\n linkFormat,\n markFormat,\n sizeFormat,\n strikeFormat,\n subscriptFormat,\n superscriptFormat,\n underlineFormat,\n // Block\n alignFormat,\n blockquoteFormat,\n codeBlockFormat,\n headerFormat,\n headerIdFormat,\n indentFormat,\n listFormat,\n tableRowFormat,\n tableColFormat,\n tableHeaderFormat,\n tableColAlignFormat,\n // Embed\n blockFormat,\n dividerFormat,\n footnoteRefFormat,\n formulaFormat,\n imageFormat,\n softBreakFormat,\n videoFormat,\n} from './schema';\nexport type { AlignType, ListType, TableColAlignType } from './schema';\n\n// Color utilities\nexport { getNamedColors, isValidColor, isValidHexColor, toHexColor } from './schema';\n\n// Conversion (DOM adapters)\nexport type {\n DeltaToHtmlOptions,\n TableCellAlign,\n TablePresentation,\n DocumentPresentation,\n ResolvedTablePresentation,\n ResolvedDocumentPresentation,\n DOMAdapter,\n DOMDocument,\n DOMDocumentFragment,\n DOMElement,\n DOMNode,\n DOMNodeList,\n HtmlToDeltaOptions,\n SanitizeOptions,\n DeltaToMarkdownOptions,\n MarkdownToDeltaOptions,\n} from './conversion';\nexport {\n BrowserDOMAdapter,\n browserAdapter,\n cloneDelta,\n deltaToHtml,\n resolveTablePresentation,\n resolveDocumentPresentation,\n documentPresentationStyleParts,\n isZebraBodyRow,\n escapeHtml,\n getAdapter,\n htmlToDelta,\n isAdapterAvailable,\n isElement,\n isTextNode,\n NODE_TYPE,\n NodeDOMAdapter,\n nodeAdapter,\n normalizeDelta,\n sanitizeDelta,\n unescapeHtml,\n validateDelta,\n // Markdown conversion\n deltaToMarkdown,\n markdownToDelta,\n markdownToDeltaSync,\n isRemarkAvailable,\n preloadRemark,\n // Simple-table region detection\n extractTableRegion,\n isTableNewlineOp,\n // Slugify utility\n slugify,\n slugifyWithDedup,\n} from './conversion';\nexport type { TableRegion } from './conversion';\n\n/**\n * Convenience alias for ops in a \"content\" Delta (a snapshot, not a change).\n *\n * `Op` is a discriminated union of `InsertOp | RetainOp | DeleteOp` — useful\n * when describing changes that the OT layer can apply or invert. However,\n * a Delta that represents document content (e.g. `state.delta` in an editor)\n * only ever contains insert ops. Use `ContentOp` to express that intent in\n * APIs and avoid repetitive narrowing via `isInsert()` / `'insert' in op`.\n */\nexport type { InsertOp as ContentOp } from '@scrider/delta';\n","import type { AttributeMap } from '@scrider/delta';\nimport type { Format, FormatScope } from './Format';\n\n/**\n * Registry of formats\n *\n * Manages a collection of Format definitions for validation,\n * normalization, and sanitization of Delta attributes.\n *\n * @example\n * ```typescript\n * const registry = new Registry()\n * .register(boldFormat)\n * .register(italicFormat)\n * .register(colorFormat);\n *\n * // Normalize attributes\n * registry.normalize({ color: 'red' });\n * // { color: '#ff0000' }\n *\n * // Validate attributes\n * registry.validate({ header: 3 }); // true\n * registry.validate({ header: 10 }); // false\n * ```\n */\nexport class Registry {\n private formats: Map<string, Format> = new Map();\n\n /**\n * Register a format or array of formats\n *\n * @param format - Format or array of formats to register\n * @returns this for chaining\n */\n register(format: Format): this;\n register(formats: Format[]): this;\n register(formatOrFormats: Format | Format[]): this {\n const formats = Array.isArray(formatOrFormats) ? formatOrFormats : [formatOrFormats];\n\n for (const format of formats) {\n if (this.formats.has(format.name)) {\n throw new Error(`Format \"${format.name}\" is already registered`);\n }\n this.formats.set(format.name, format);\n }\n\n return this;\n }\n\n /**\n * Get a format by name\n *\n * @param name - Format name\n * @returns Format or undefined if not found\n */\n get(name: string): Format | undefined {\n return this.formats.get(name);\n }\n\n /**\n * Check if a format is registered\n *\n * @param name - Format name\n * @returns true if format exists\n */\n has(name: string): boolean {\n return this.formats.has(name);\n }\n\n /**\n * Get all formats with a specific scope\n *\n * @param scope - Format scope to filter by\n * @returns Array of formats with the given scope\n */\n getByScope(scope: FormatScope): Format[] {\n const result: Format[] = [];\n for (const format of this.formats.values()) {\n if (format.scope === scope) {\n result.push(format);\n }\n }\n return result;\n }\n\n /**\n * Get all registered format names\n *\n * @returns Array of format names\n */\n getNames(): string[] {\n return Array.from(this.formats.keys());\n }\n\n /**\n * Normalize all attributes using registered formats\n *\n * Applies normalize() for each attribute that has a registered format.\n * Unknown attributes are passed through unchanged.\n *\n * @param attributes - Attributes to normalize\n * @returns New object with normalized attributes\n */\n normalize(attributes: AttributeMap | undefined): AttributeMap | undefined {\n if (!attributes) return undefined;\n\n const result: AttributeMap = {};\n let hasChanges = false;\n\n for (const [key, value] of Object.entries(attributes)) {\n const format = this.formats.get(key);\n\n if (format?.normalize) {\n const normalized = format.normalize(value);\n result[key] = normalized;\n if (normalized !== value) {\n hasChanges = true;\n }\n } else {\n result[key] = value;\n }\n }\n\n // Return original if no changes (optimization)\n return hasChanges ? result : attributes;\n }\n\n /**\n * Validate all attributes\n *\n * @param attributes - Attributes to validate\n * @returns true if all known attributes are valid\n */\n validate(attributes: AttributeMap | undefined): boolean {\n if (!attributes) return true;\n\n for (const [key, value] of Object.entries(attributes)) {\n const format = this.formats.get(key);\n\n if (format?.validate && !format.validate(value)) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Sanitize attributes by removing invalid values\n *\n * Removes attributes that:\n * - Are not registered (unknown formats)\n * - Fail validation\n *\n * @param attributes - Attributes to sanitize\n * @param removeUnknown - If true, remove unregistered attributes (default: true)\n * @returns New object with only valid attributes\n */\n sanitize(\n attributes: AttributeMap | undefined,\n removeUnknown: boolean = true,\n ): AttributeMap | undefined {\n if (!attributes) return undefined;\n\n const result: AttributeMap = {};\n let hasKeys = false;\n\n for (const [key, value] of Object.entries(attributes)) {\n const format = this.formats.get(key);\n\n // Skip unknown formats if removeUnknown is true\n if (!format && removeUnknown) {\n continue;\n }\n\n // Skip invalid values\n if (format?.validate && !format.validate(value)) {\n continue;\n }\n\n // Normalize if possible\n if (format?.normalize) {\n result[key] = format.normalize(value);\n } else {\n result[key] = value;\n }\n hasKeys = true;\n }\n\n return hasKeys ? result : undefined;\n }\n\n /**\n * Get the number of registered formats\n */\n get size(): number {\n return this.formats.size;\n }\n}\n","import type { BlockHandler } from './BlockHandler';\n\n/**\n * Registry for BlockHandler implementations.\n *\n * Separate from Registry (FormatRegistry) — different responsibilities:\n * - Registry: attribute validation/normalization (key-value pairs, primitives)\n * - BlockHandlerRegistry: block rendering/parsing (complex structures with nested Delta)\n *\n * Connected to converters via options:\n * ```typescript\n * deltaToHtml(delta, { registry, blockHandlers });\n * htmlToDelta(html, { registry, blockHandlers });\n * ```\n *\n * @example\n * ```typescript\n * const blockHandlers = new BlockHandlerRegistry()\n * .register(tableBlockHandler);\n *\n * deltaToHtml(delta, { registry, blockHandlers });\n * ```\n */\nexport class BlockHandlerRegistry {\n private handlers = new Map<string, BlockHandler>();\n\n /**\n * Register a block handler\n *\n * @param handler - BlockHandler to register\n * @returns this for chaining\n * @throws Error if handler with same type is already registered\n */\n register(handler: BlockHandler): this {\n if (this.handlers.has(handler.type)) {\n throw new Error(`BlockHandler \"${handler.type}\" is already registered`);\n }\n this.handlers.set(handler.type, handler);\n return this;\n }\n\n /**\n * Get a handler by block type\n *\n * @param type - Block type (e.g. \"table\")\n * @returns BlockHandler or undefined if not found\n */\n get(type: string): BlockHandler | undefined {\n return this.handlers.get(type);\n }\n\n /**\n * Check if a handler is registered for a block type\n *\n * @param type - Block type\n * @returns true if handler exists\n */\n has(type: string): boolean {\n return this.handlers.has(type);\n }\n\n /**\n * Get the number of registered handlers\n */\n get size(): number {\n return this.handlers.size;\n }\n\n /**\n * Get all registered block type names\n */\n getTypes(): string[] {\n return Array.from(this.handlers.keys());\n }\n}\n","import type { Op } from '@scrider/delta';\nimport { Delta } from '@scrider/delta';\nimport type { BlockContext, BlockHandler } from '../BlockHandler';\nimport type { Registry } from '../Registry';\nimport { normalizeDelta } from '../../conversion/sanitize';\nimport type { DOMElement } from '../../conversion/adapters/types';\nimport { isElement } from '../../conversion/adapters/types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Cell alignment options\n */\nexport type CellAlign = 'left' | 'center' | 'right';\n\n/**\n * Data for a single cell in an Extended Table.\n *\n * Every non-merged cell must have `ops` — a nested Delta (Op[]).\n * Empty cells use `{ ops: [{ insert: \"\\n\" }] }`.\n */\nexport interface CellData {\n /** Nested Delta content (full rich-text) */\n ops: Op[];\n /** Number of columns this cell spans (default: 1) */\n colspan?: number;\n /** Number of rows this cell spans (default: 1) */\n rowspan?: number;\n}\n\n/**\n * Extended Table block data.\n *\n * Stored in Delta as: `{ insert: { block: <TableBlockData> } }`\n *\n * All coordinates \"r:c\" within the grid MUST be present in `cells`.\n * - `CellData` — cell with content\n * - `null` — cell absorbed by neighbor's colspan/rowspan\n * - Missing key — INVALID (validate() rejects)\n */\nexport interface TableBlockData {\n /** Block type discriminator */\n type: 'table';\n /** Number of header rows (default: 0) */\n headerRows?: number;\n /** Column widths (percentages by default) */\n colWidths?: number[];\n /** Column alignments */\n colAligns?: (CellAlign | null)[];\n /** Cells indexed by \"row:col\" */\n cells: Record<string, CellData | null>;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\n/** Pattern for cell key: \"row:col\" where row and col are non-negative integers */\nconst CELL_KEY_RE = /^(\\d+):(\\d+)$/;\n\n/**\n * Parse cell key \"r:c\" into [row, col] or null if invalid.\n */\nfunction parseCellKey(key: string): [number, number] | null {\n const match = CELL_KEY_RE.exec(key);\n if (!match) return null;\n return [parseInt(match[1]!, 10), parseInt(match[2]!, 10)];\n}\n\n/**\n * Determine grid dimensions from cell keys.\n * Returns [rows, cols] or null if no valid keys.\n */\nfunction getGridDimensions(cells: Record<string, CellData | null>): [number, number] | null {\n let maxRow = -1;\n let maxCol = -1;\n\n for (const key of Object.keys(cells)) {\n const parsed = parseCellKey(key);\n if (!parsed) return null; // invalid key format\n const [r, c] = parsed;\n if (r > maxRow) maxRow = r;\n if (c > maxCol) maxCol = c;\n }\n\n if (maxRow < 0 || maxCol < 0) return null;\n return [maxRow + 1, maxCol + 1];\n}\n\n/**\n * Validate that a CellData has valid ops (non-empty array).\n */\nfunction isValidCellData(cell: CellData): boolean {\n return (\n typeof cell === 'object' &&\n cell !== null &&\n Array.isArray(cell.ops) &&\n cell.ops.length > 0 &&\n (cell.colspan === undefined || (Number.isInteger(cell.colspan) && cell.colspan >= 1)) &&\n (cell.rowspan === undefined || (Number.isInteger(cell.rowspan) && cell.rowspan >= 1))\n );\n}\n\n/**\n * Validate that merged (null) cells correspond to cells with colspan/rowspan.\n *\n * For each cell with colspan > 1 or rowspan > 1, all covered cells must be null.\n * Conversely, every null cell must be covered by exactly one spanning cell.\n */\nfunction validateMergedCells(\n cells: Record<string, CellData | null>,\n rows: number,\n cols: number,\n): boolean {\n // Track which cells are covered by a span\n const covered = new Set<string>();\n\n // First pass: collect all cells that should be covered by spans\n for (const [key, cell] of Object.entries(cells)) {\n if (cell === null) continue;\n\n const parsed = parseCellKey(key);\n if (!parsed) return false;\n const [r, c] = parsed;\n\n const cs = cell.colspan ?? 1;\n const rs = cell.rowspan ?? 1;\n\n // Check that span doesn't exceed grid\n if (r + rs > rows || c + cs > cols) return false;\n\n // Mark covered cells (excluding the source cell itself)\n for (let dr = 0; dr < rs; dr++) {\n for (let dc = 0; dc < cs; dc++) {\n if (dr === 0 && dc === 0) continue; // skip source\n const coveredKey = `${r + dr}:${c + dc}`;\n if (covered.has(coveredKey)) return false; // double coverage\n covered.add(coveredKey);\n }\n }\n }\n\n // Second pass: verify every null cell is covered, and no non-null cell is covered\n for (const [key, cell] of Object.entries(cells)) {\n if (cell === null) {\n if (!covered.has(key)) return false; // null but not covered\n } else {\n if (covered.has(key)) return false; // non-null but covered\n }\n }\n\n return true;\n}\n\n// ============================================================================\n// Rendering Helpers\n// ============================================================================\n\n/**\n * Render a single row of an Extended Table.\n */\nfunction renderExtendedRow(\n data: TableBlockData,\n row: number,\n cols: number,\n defaultCellTag: 'th' | 'td',\n context: BlockContext,\n pretty: boolean,\n): string {\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n let html = `${ind(2)}<tr>${nl}`;\n\n for (let c = 0; c < cols; c++) {\n const key = `${row}:${c}`;\n const cell = data.cells[key];\n\n // Skip null cells (covered by colspan/rowspan)\n if (cell === null) continue;\n\n // Skip if cell is undefined (shouldn't happen in valid data)\n if (cell === undefined) continue;\n\n const cellTag = row < (data.headerRows ?? 0) ? 'th' : defaultCellTag;\n const attrs: string[] = [];\n\n // colspan/rowspan attributes\n if (cell.colspan && cell.colspan > 1) {\n attrs.push(`colspan=\"${cell.colspan}\"`);\n }\n if (cell.rowspan && cell.rowspan > 1) {\n attrs.push(`rowspan=\"${cell.rowspan}\"`);\n }\n\n // Column alignment\n if (data.colAligns) {\n const align = data.colAligns[c];\n if (align && align !== 'left') {\n attrs.push(`style=\"text-align: ${align}\"`);\n }\n }\n\n const attrStr = attrs.length > 0 ? ' ' + attrs.join(' ') : '';\n\n // Render cell content via context.renderDelta (recursive)\n let content = '';\n if (context.renderDelta) {\n content = context.renderDelta(cell.ops);\n }\n\n html += `${ind(3)}<${cellTag}${attrStr}>${content}</${cellTag}>${nl}`;\n }\n\n html += `${ind(2)}</tr>${nl}`;\n return html;\n}\n\n// ============================================================================\n// GFM Markdown Helpers\n// ============================================================================\n\n/**\n * Check whether an Extended Table can be losslessly represented as\n * a GFM Markdown table (no colspan, rowspan, colWidths).\n */\nfunction isGfmCompatible(data: TableBlockData): boolean {\n // colWidths → not representable in GFM\n if (data.colWidths && data.colWidths.some((w) => w > 0)) {\n return false;\n }\n\n // Check cells for colspan/rowspan\n for (const cell of Object.values(data.cells)) {\n if (cell === null) return false; // null means merged — not GFM\n if (cell.colspan && cell.colspan > 1) return false;\n if (cell.rowspan && cell.rowspan > 1) return false;\n }\n\n return true;\n}\n\n/**\n * Strip trailing newlines from rendered Markdown cell content.\n * Cell ops always end with `\\n`, but we don't want that inside a table cell.\n */\nfunction stripCellContent(rendered: string): string {\n return rendered.replace(/\\n+$/, '').replace(/\\n/g, ' ');\n}\n\n/**\n * Render a GFM-compatible Extended Table as a Markdown table string.\n */\nfunction renderGfmTable(data: TableBlockData, context: BlockContext): string {\n const dims = getGridDimensions(data.cells);\n if (!dims) return '';\n const [rows, cols] = dims;\n\n const headerRows = data.headerRows ?? 0;\n const lines: string[] = [];\n\n // GFM requires a header row. If headerRows === 0, synthesize an empty one.\n if (headerRows === 0) {\n const emptyParts: string[] = [];\n for (let c = 0; c < cols; c++) {\n emptyParts.push(' ');\n }\n lines.push('| ' + emptyParts.join(' | ') + ' |');\n lines.push(renderGfmSeparator(cols, data.colAligns));\n }\n\n for (let r = 0; r < rows; r++) {\n const parts: string[] = [];\n for (let c = 0; c < cols; c++) {\n const cell = data.cells[`${r}:${c}`];\n let text = '';\n if (cell && context.renderDelta) {\n text = stripCellContent(context.renderDelta(cell.ops));\n }\n // Escape pipe characters inside cell content\n parts.push(text.replace(/\\|/g, '\\\\|'));\n }\n lines.push('| ' + parts.join(' | ') + ' |');\n\n // After header row(s), insert GFM separator\n if (headerRows > 0 && r === headerRows - 1) {\n lines.push(renderGfmSeparator(cols, data.colAligns));\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Render the GFM separator row: | --- | :---: | ---: |\n */\nfunction renderGfmSeparator(cols: number, colAligns?: (CellAlign | null)[]): string {\n const sepParts: string[] = [];\n for (let c = 0; c < cols; c++) {\n const align = colAligns?.[c];\n if (align === 'center') {\n sepParts.push(':---:');\n } else if (align === 'right') {\n sepParts.push('---:');\n } else if (align === 'left') {\n sepParts.push(':---');\n } else {\n sepParts.push('---');\n }\n }\n return '| ' + sepParts.join(' | ') + ' |';\n}\n\n// ============================================================================\n// Parsing Helpers (HTML → TableBlockData)\n// ============================================================================\n\n/**\n * Collect `<tr>` rows from a `<table>` element,\n * tracking which belong to `<thead>` (header rows).\n */\nfunction collectTableRows(table: DOMElement): { rows: DOMElement[]; headerRowCount: number } {\n const rows: DOMElement[] = [];\n let headerRowCount = 0;\n\n const children = table.childNodes;\n for (let i = 0; i < children.length; i++) {\n const section = children[i];\n if (!section || !isElement(section)) continue;\n\n const sectionTag = section.tagName.toLowerCase();\n\n if (sectionTag === 'thead' || sectionTag === 'tbody' || sectionTag === 'tfoot') {\n const isHeader = sectionTag === 'thead';\n const sectionChildren = section.childNodes;\n for (let j = 0; j < sectionChildren.length; j++) {\n const row = sectionChildren[j];\n if (!row || !isElement(row) || row.tagName.toLowerCase() !== 'tr') continue;\n rows.push(row);\n if (isHeader) headerRowCount++;\n }\n } else if (sectionTag === 'tr') {\n rows.push(section);\n }\n }\n\n return { rows, headerRowCount };\n}\n\n/**\n * Extract colWidths from `<colgroup>` → `<col>` elements.\n * Returns an array of widths or undefined if no `<colgroup>`.\n */\nfunction extractColWidths(table: DOMElement): number[] | undefined {\n const children = table.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child) || child.tagName.toLowerCase() !== 'colgroup') continue;\n\n const widths: number[] = [];\n const cols = child.childNodes;\n for (let j = 0; j < cols.length; j++) {\n const col = cols[j];\n if (!col || !isElement(col) || col.tagName.toLowerCase() !== 'col') continue;\n\n let width = 0;\n const style = col.getAttribute('style') || '';\n const widthMatch = style.match(/width:\\s*([\\d.]+)(%|px)/);\n if (widthMatch?.[1]) {\n width = parseFloat(widthMatch[1]);\n } else {\n const widthAttr = col.getAttribute('width');\n if (widthAttr) {\n width = parseFloat(widthAttr) || 0;\n }\n }\n widths.push(width);\n }\n\n if (widths.length > 0) return widths;\n }\n\n return undefined;\n}\n\n/**\n * Extract text-align from a cell element's style attribute.\n */\nfunction extractCellAlign(cell: DOMElement): CellAlign | null {\n const textAlign = cell.style?.textAlign || cell.style?.getPropertyValue?.('text-align');\n if (textAlign === 'left' || textAlign === 'center' || textAlign === 'right') {\n return textAlign;\n }\n\n // Fallback: parse style string directly\n const style = cell.getAttribute('style') || '';\n const match = style.match(/text-align:\\s*(left|center|right)/);\n if (match?.[1]) {\n return match[1] as CellAlign;\n }\n\n return null;\n}\n\n/**\n * Parse a `<table>` element into TableBlockData.\n *\n * Steps:\n * 1. Iterate `<thead>` → count headerRows\n * 2. Iterate `<tbody>` / direct `<tr>` → data rows\n * 3. For each `<td>`/`<th>`:\n * - Read colspan/rowspan from attributes\n * - `context.parseElement!(td)` → ops\n * - Fill null for merged cells\n * 4. Extract colWidths from `<col>` / style\n * 5. Extract colAligns from `style=\"text-align: ...\"` on first row cells\n * 6. Return `{ type: 'table', headerRows, colWidths, colAligns, cells }`\n */\nfunction parseTableElement(table: DOMElement, context: BlockContext): TableBlockData | null {\n const { rows, headerRowCount } = collectTableRows(table);\n if (rows.length === 0) return null;\n\n const cells: Record<string, CellData | null> = {};\n const colAligns: (CellAlign | null)[] = [];\n let maxCol = 0;\n let firstRowProcessed = false;\n\n // Track which grid positions are occupied by spanning cells\n const occupied = new Set<string>();\n\n for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {\n const row = rows[rowIdx]!;\n let colIdx = 0;\n const cellChildren = row.childNodes;\n\n for (let ci = 0; ci < cellChildren.length; ci++) {\n const cell = cellChildren[ci];\n if (!cell || !isElement(cell)) continue;\n const cellTag = cell.tagName.toLowerCase();\n if (cellTag !== 'td' && cellTag !== 'th') continue;\n\n // Skip occupied positions (from previous row/col spans)\n while (occupied.has(`${rowIdx}:${colIdx}`)) {\n colIdx++;\n }\n\n // Read colspan/rowspan\n const colspanAttr = cell.getAttribute('colspan');\n const rowspanAttr = cell.getAttribute('rowspan');\n const colspan = colspanAttr ? parseInt(colspanAttr, 10) || 1 : 1;\n const rowspan = rowspanAttr ? parseInt(rowspanAttr, 10) || 1 : 1;\n\n // Parse cell content via context.parseElement\n let ops: Op[];\n if (context.parseElement) {\n ops = context.parseElement(cell);\n if (ops.length === 0) {\n ops = [{ insert: '\\n' }];\n }\n } else {\n ops = [{ insert: '\\n' }];\n }\n\n // Build CellData\n const cellData: CellData = { ops };\n if (colspan > 1) cellData.colspan = colspan;\n if (rowspan > 1) cellData.rowspan = rowspan;\n\n cells[`${rowIdx}:${colIdx}`] = cellData;\n\n // Mark spanned positions as occupied + fill null\n for (let dr = 0; dr < rowspan; dr++) {\n for (let dc = 0; dc < colspan; dc++) {\n if (dr === 0 && dc === 0) continue;\n const coveredKey = `${rowIdx + dr}:${colIdx + dc}`;\n occupied.add(coveredKey);\n cells[coveredKey] = null;\n }\n }\n\n // Also mark positions in current row for multi-column\n for (let dc = 1; dc < colspan; dc++) {\n occupied.add(`${rowIdx}:${colIdx + dc}`);\n }\n\n // Collect column alignments from first data row\n if (!firstRowProcessed) {\n const align = extractCellAlign(cell);\n // Fill for colspan\n for (let dc = 0; dc < colspan; dc++) {\n colAligns.push(align);\n }\n }\n\n const cellEndCol = colIdx + colspan - 1;\n if (cellEndCol > maxCol) maxCol = cellEndCol;\n\n colIdx += colspan;\n }\n\n // Update maxCol for any remaining occupied positions\n while (occupied.has(`${rowIdx}:${colIdx}`)) {\n colIdx++;\n }\n if (colIdx - 1 > maxCol) maxCol = colIdx - 1;\n\n if (!firstRowProcessed) firstRowProcessed = true;\n }\n\n const totalCols = maxCol + 1;\n const totalRows = rows.length;\n\n // Ensure all grid positions are present (fill missing as empty cells)\n for (let r = 0; r < totalRows; r++) {\n for (let c = 0; c < totalCols; c++) {\n const key = `${r}:${c}`;\n if (!(key in cells)) {\n cells[key] = { ops: [{ insert: '\\n' }] };\n }\n }\n }\n\n // Build result\n const result: TableBlockData = {\n type: 'table',\n cells,\n };\n\n if (headerRowCount > 0) {\n result.headerRows = headerRowCount;\n }\n\n // Extract colWidths from <colgroup>\n const colWidths = extractColWidths(table);\n if (colWidths) {\n // Ensure colWidths has correct length\n while (colWidths.length < totalCols) colWidths.push(0);\n if (colWidths.length > totalCols) colWidths.length = totalCols;\n result.colWidths = colWidths;\n }\n\n // Add colAligns if any non-null\n if (colAligns.length > 0 && colAligns.some((a) => a !== null)) {\n // Ensure correct length\n while (colAligns.length < totalCols) colAligns.push(null);\n if (colAligns.length > totalCols) colAligns.length = totalCols;\n result.colAligns = colAligns;\n }\n\n return result;\n}\n\n// ============================================================================\n// TableBlockHandler\n// ============================================================================\n\n/**\n * BlockHandler implementation for Extended Table.\n *\n * Handles validation, HTML conversion, and nested Delta access.\n * toHtml/fromHtml are implemented in E.3/E.4 stages.\n */\nexport const tableBlockHandler: BlockHandler<TableBlockData> = {\n type: 'table',\n\n validate(data: TableBlockData): boolean {\n // 1. Type check\n if (!data || typeof data !== 'object' || data.type !== 'table') {\n return false;\n }\n\n // 2. Cells must be a non-empty object\n if (!data.cells || typeof data.cells !== 'object' || Array.isArray(data.cells)) {\n return false;\n }\n\n const cellKeys = Object.keys(data.cells);\n if (cellKeys.length === 0) return false;\n\n // 3. All keys must be valid \"r:c\" format\n for (const key of cellKeys) {\n if (!CELL_KEY_RE.test(key)) return false;\n }\n\n // 4. Determine grid dimensions\n const dims = getGridDimensions(data.cells);\n if (!dims) return false;\n const [rows, cols] = dims;\n\n // 5. All coordinates within grid must be present (no holes)\n if (cellKeys.length !== rows * cols) return false;\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n if (!(`${r}:${c}` in data.cells)) return false;\n }\n }\n\n // 6. Each non-null cell must have valid CellData\n for (const [, cell] of Object.entries(data.cells)) {\n if (cell !== null && !isValidCellData(cell)) return false;\n }\n\n // 7. Validate merged cells consistency\n if (!validateMergedCells(data.cells, rows, cols)) return false;\n\n // 8. headerRows validation\n if (data.headerRows !== undefined) {\n if (!Number.isInteger(data.headerRows) || data.headerRows < 0 || data.headerRows > rows) {\n return false;\n }\n }\n\n // 9. colWidths validation\n if (data.colWidths !== undefined) {\n if (!Array.isArray(data.colWidths) || data.colWidths.length !== cols) {\n return false;\n }\n for (const w of data.colWidths) {\n if (typeof w !== 'number' || w < 0) return false;\n }\n }\n\n // 10. colAligns validation\n if (data.colAligns !== undefined) {\n if (!Array.isArray(data.colAligns) || data.colAligns.length !== cols) {\n return false;\n }\n const validAligns: (string | null)[] = ['left', 'center', 'right', null];\n for (const a of data.colAligns) {\n if (!validAligns.includes(a)) return false;\n }\n }\n\n return true;\n },\n\n // ── Conversion ──────────────────────────────────────────────\n\n toHtml(data: TableBlockData, context: BlockContext): string {\n const pretty = context.options?.pretty ?? false;\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n // Determine grid dimensions from cells\n const dims = getGridDimensions(data.cells);\n if (!dims) return '';\n const [rows, cols] = dims;\n const headerRows = data.headerRows ?? 0;\n\n let html = `<table>${nl}`;\n\n // Render <colgroup> if colWidths specified\n if (data.colWidths && data.colWidths.length > 0) {\n const widthMode = context.options?.tableWidthMode ?? 'percent';\n html += `${ind(1)}<colgroup>${nl}`;\n for (let c = 0; c < cols; c++) {\n const w = data.colWidths[c];\n if (w !== undefined && w > 0) {\n const unit = widthMode === 'pixel' ? 'px' : '%';\n html += `${ind(2)}<col style=\"width: ${w}${unit}\">${nl}`;\n } else {\n html += `${ind(2)}<col>${nl}`;\n }\n }\n html += `${ind(1)}</colgroup>${nl}`;\n }\n\n // Render <thead> if headerRows > 0\n if (headerRows > 0) {\n html += `${ind(1)}<thead>${nl}`;\n for (let r = 0; r < headerRows; r++) {\n html += renderExtendedRow(data, r, cols, 'th', context, pretty);\n }\n html += `${ind(1)}</thead>${nl}`;\n }\n\n // Render <tbody>\n const bodyStart = headerRows;\n if (bodyStart < rows) {\n html += `${ind(1)}<tbody>${nl}`;\n for (let r = bodyStart; r < rows; r++) {\n html += renderExtendedRow(data, r, cols, 'td', context, pretty);\n }\n html += `${ind(1)}</tbody>${nl}`;\n }\n\n html += `</table>`;\n return html;\n },\n\n fromHtml(element: DOMElement, context: BlockContext): TableBlockData | null {\n return parseTableElement(element, context);\n },\n\n toMarkdown(data: TableBlockData, context: BlockContext): string | null {\n // If the table is GFM-compatible (no colspan/rowspan/colWidths),\n // render as native GFM Markdown table instead of HTML\n if (isGfmCompatible(data)) {\n return renderGfmTable(data, context);\n }\n // Extended Table features → null → fallback to HTML in Markdown\n return null;\n },\n\n // ── Normalize ─────────────────────────────────────────────\n\n normalize(data: TableBlockData, registry: Registry): TableBlockData {\n const newCells: Record<string, CellData | null> = {};\n let changed = false;\n\n for (const [key, cell] of Object.entries(data.cells)) {\n if (cell !== null) {\n const normalized = normalizeDelta(new Delta(cell.ops), registry);\n if (normalized.ops !== cell.ops) {\n newCells[key] = { ...cell, ops: normalized.ops };\n changed = true;\n } else {\n newCells[key] = cell;\n }\n } else {\n newCells[key] = null;\n }\n }\n\n return changed ? { ...data, cells: newCells } : data;\n },\n\n // ── Nested Deltas ──────────────────────────────────────────\n\n getNestedDeltas(data: TableBlockData): Op[][] {\n const deltas: Op[][] = [];\n for (const cell of Object.values(data.cells)) {\n if (cell !== null) {\n deltas.push(cell.ops);\n }\n }\n return deltas;\n },\n\n setNestedDeltas(data: TableBlockData, deltas: Op[][]): TableBlockData {\n const newCells: Record<string, CellData | null> = {};\n let idx = 0;\n for (const [key, cell] of Object.entries(data.cells)) {\n if (cell !== null) {\n newCells[key] = { ...cell, ops: deltas[idx++]! };\n } else {\n newCells[key] = null;\n }\n }\n return { ...data, cells: newCells };\n },\n};\n","/**\n * Delta Sanitization\n *\n * Cleans Delta by removing unknown attributes, validating values,\n * and normalizing through Registry.\n */\n\nimport { Delta, isInsert, isRetain, isEmbedInsert, deepClone } from '@scrider/delta';\nimport type { Op, AttributeMap } from '@scrider/delta';\nimport type { Registry } from '../schema/Registry';\n\n/**\n * Options for sanitizeDelta\n */\nexport interface SanitizeOptions {\n /**\n * Remove attributes not registered in the registry\n * @default true\n */\n removeUnknown?: boolean;\n\n /**\n * Normalize attribute values (e.g., color: 'red' → '#ff0000')\n * @default true\n */\n normalize?: boolean;\n\n /**\n * Remove operations with invalid embed values\n * @default false\n */\n removeInvalidEmbeds?: boolean;\n\n /**\n * List of embed types that are allowed (if not set, all registered are allowed)\n */\n allowedEmbeds?: string[];\n}\n\nconst DEFAULT_OPTIONS: Required<SanitizeOptions> = {\n removeUnknown: true,\n normalize: true,\n removeInvalidEmbeds: false,\n allowedEmbeds: [],\n};\n\n/**\n * Sanitize a Delta using a Registry\n *\n * Performs the following operations:\n * 1. Removes attributes not registered in the registry (if removeUnknown=true)\n * 2. Removes attributes with invalid values\n * 3. Normalizes attribute values (if normalize=true)\n * 4. Optionally removes invalid embed operations\n *\n * @param delta - The Delta to sanitize\n * @param registry - The Registry to use for validation/normalization\n * @param options - Sanitization options\n * @returns A new sanitized Delta\n *\n * @example\n * ```typescript\n * const registry = createDefaultRegistry();\n * const dirty = new Delta()\n * .insert('Hello', { bold: true, unknown: 'value', color: 'red' })\n * .insert('\\n');\n *\n * const clean = sanitizeDelta(dirty, registry);\n * // { bold: true, color: '#ff0000' } - unknown removed, color normalized\n * ```\n */\nexport function sanitizeDelta(\n delta: Delta,\n registry: Registry,\n options: SanitizeOptions = {},\n): Delta {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const result = new Delta();\n\n for (const op of delta.ops) {\n const sanitizedOp = sanitizeOp(op, registry, opts);\n\n if (sanitizedOp !== null) {\n result.push(sanitizedOp);\n }\n }\n\n return result;\n}\n\n/**\n * Sanitize a single operation\n *\n * @returns Sanitized op, or null if the op should be removed\n */\nfunction sanitizeOp(op: Op, registry: Registry, options: Required<SanitizeOptions>): Op | null {\n // Handle insert operations\n if (isInsert(op)) {\n // Check embed validity\n if (isEmbedInsert(op)) {\n const embedValue = op.insert as Record<string, unknown>;\n const embedType = Object.keys(embedValue)[0];\n\n // Check if embed has a valid type\n if (!embedType) {\n return options.removeInvalidEmbeds ? null : op;\n }\n\n // Check if embed type is allowed\n if (options.allowedEmbeds.length > 0) {\n if (!options.allowedEmbeds.includes(embedType)) {\n return options.removeInvalidEmbeds ? null : op;\n }\n }\n\n // Check if embed type is registered\n if (!registry.has(embedType)) {\n return options.removeInvalidEmbeds ? null : op;\n }\n\n // Validate embed value\n const format = registry.get(embedType);\n if (format?.validate && !format.validate(embedValue[embedType])) {\n return options.removeInvalidEmbeds ? null : op;\n }\n }\n\n // Sanitize attributes\n const sanitizedAttrs = sanitizeAttributes(op.attributes, registry, options);\n\n // Return new op with sanitized attributes\n if (sanitizedAttrs === op.attributes) {\n return op; // No changes\n }\n\n const newOp: Op = { insert: op.insert };\n if (sanitizedAttrs !== undefined) {\n newOp.attributes = sanitizedAttrs;\n }\n\n return newOp;\n }\n\n // Handle retain operations\n if (isRetain(op)) {\n const sanitizedAttrs = sanitizeAttributes(op.attributes, registry, options);\n\n if (sanitizedAttrs === op.attributes) {\n return op; // No changes\n }\n\n const newOp: Op = { retain: op.retain };\n if (sanitizedAttrs !== undefined) {\n newOp.attributes = sanitizedAttrs;\n }\n\n return newOp;\n }\n\n // Delete operations pass through unchanged\n return op;\n}\n\n/**\n * Sanitize attributes using registry\n */\nfunction sanitizeAttributes(\n attributes: AttributeMap | undefined,\n registry: Registry,\n options: Required<SanitizeOptions>,\n): AttributeMap | undefined {\n if (!attributes) {\n return undefined;\n }\n\n let result: AttributeMap | undefined;\n let hasChanges = false;\n\n for (const [key, value] of Object.entries(attributes)) {\n const format = registry.get(key);\n\n // Remove unknown attributes\n if (!format && options.removeUnknown) {\n hasChanges = true;\n continue;\n }\n\n // Skip invalid values\n if (format?.validate && !format.validate(value)) {\n hasChanges = true;\n continue;\n }\n\n // Initialize result if we're keeping this attribute\n if (!result) {\n result = {};\n }\n\n // Normalize or keep as-is\n if (format?.normalize && options.normalize) {\n const normalized = format.normalize(value);\n result[key] = normalized;\n if (normalized !== value) {\n hasChanges = true;\n }\n } else {\n result[key] = value;\n }\n }\n\n // Return original if no changes (optimization)\n if (!hasChanges) {\n return attributes;\n }\n\n // Return undefined if all attributes were removed\n return result && Object.keys(result).length > 0 ? result : undefined;\n}\n\n/**\n * Normalize a Delta's attributes without removing anything\n *\n * This is a lighter operation that only normalizes values,\n * without removing unknown or invalid attributes.\n *\n * @param delta - The Delta to normalize\n * @param registry - The Registry to use for normalization\n * @returns A new Delta with normalized attributes\n */\nexport function normalizeDelta(delta: Delta, registry: Registry): Delta {\n return sanitizeDelta(delta, registry, {\n removeUnknown: false,\n normalize: true,\n removeInvalidEmbeds: false,\n });\n}\n\n/**\n * Validate a Delta against a Registry\n *\n * @param delta - The Delta to validate\n * @param registry - The Registry to use for validation\n * @returns true if all attributes in the Delta are valid\n */\nexport function validateDelta(delta: Delta, registry: Registry): boolean {\n for (const op of delta.ops) {\n // Check embeds\n if (isInsert(op) && isEmbedInsert(op)) {\n const embedValue = op.insert as Record<string, unknown>;\n const embedType = Object.keys(embedValue)[0];\n\n // Check if embed has a valid type\n if (!embedType) {\n return false;\n }\n\n // Check if embed type is registered\n if (!registry.has(embedType)) {\n return false;\n }\n\n // Validate embed value\n const format = registry.get(embedType);\n if (format?.validate && !format.validate(embedValue[embedType])) {\n return false;\n }\n }\n\n // Validate attributes (only InsertOp and RetainOp have attributes)\n if ('attributes' in op && op.attributes) {\n if (!registry.validate(op.attributes)) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * Deep clone a Delta\n *\n * @param delta - The Delta to clone\n * @returns A new Delta with cloned ops\n */\nexport function cloneDelta(delta: Delta): Delta {\n return new Delta(deepClone(delta.ops));\n}\n","/**\n * DOM Adapter Interface\n *\n * Provides a unified interface for DOM operations across different environments:\n * - Browser: uses native DOM APIs\n * - Node.js: uses jsdom\n *\n * This abstraction allows the same conversion code to work in both environments.\n */\n\n/**\n * Minimal Document interface required for HTML parsing/rendering\n */\nexport interface DOMDocument {\n createElement(tagName: string): DOMElement;\n createTextNode(text: string): DOMNode;\n createDocumentFragment(): DOMDocumentFragment;\n readonly body: DOMElement;\n}\n\n/**\n * Minimal DocumentFragment interface\n */\nexport interface DOMDocumentFragment {\n appendChild(node: DOMNode): DOMNode;\n readonly childNodes: DOMNodeList;\n readonly firstChild: DOMNode | null;\n readonly nodeType: number;\n readonly textContent: string | null;\n}\n\n/**\n * Minimal Node interface\n */\nexport interface DOMNode {\n readonly nodeType: number;\n readonly nodeName: string;\n readonly parentNode: DOMNode | null;\n readonly childNodes: DOMNodeList;\n readonly firstChild: DOMNode | null;\n readonly nextSibling: DOMNode | null;\n textContent: string | null;\n appendChild(node: DOMNode): DOMNode;\n cloneNode(deep?: boolean): DOMNode;\n}\n\n/**\n * Minimal Element interface\n */\nexport interface DOMElement extends DOMNode {\n readonly tagName: string;\n innerHTML: string;\n outerHTML: string;\n getAttribute(name: string): string | null;\n setAttribute(name: string, value: string): void;\n hasAttribute(name: string): boolean;\n removeAttribute(name: string): void;\n readonly style: DOMCSSStyleDeclaration;\n readonly classList: DOMTokenList;\n querySelector(selector: string): DOMElement | null;\n querySelectorAll(selector: string): DOMNodeList;\n}\n\n/**\n * Minimal CSSStyleDeclaration interface\n */\nexport interface DOMCSSStyleDeclaration {\n getPropertyValue(property: string): string;\n setProperty(property: string, value: string): void;\n // Common CSS properties\n color?: string;\n backgroundColor?: string;\n fontFamily?: string;\n fontSize?: string;\n fontWeight?: string;\n fontStyle?: string;\n textDecoration?: string;\n textAlign?: string;\n}\n\n/**\n * Minimal DOMTokenList interface (for classList)\n */\nexport interface DOMTokenList {\n add(...tokens: string[]): void;\n remove(...tokens: string[]): void;\n contains(token: string): boolean;\n readonly length: number;\n}\n\n/**\n * Minimal NodeList interface\n */\nexport interface DOMNodeList {\n readonly length: number;\n item(index: number): DOMNode | null;\n [index: number]: DOMNode;\n forEach(callback: (node: DOMNode, index: number) => void): void;\n}\n\n/**\n * Node type constants\n */\nexport const NODE_TYPE = {\n ELEMENT_NODE: 1,\n TEXT_NODE: 3,\n DOCUMENT_NODE: 9,\n DOCUMENT_FRAGMENT_NODE: 11,\n} as const;\n\n/**\n * DOM Adapter interface\n *\n * Provides methods for creating and manipulating DOM structures\n * in a platform-agnostic way.\n */\nexport interface DOMAdapter {\n /**\n * Parse HTML string into a document fragment\n */\n parseHTML(html: string): DOMDocumentFragment;\n\n /**\n * Serialize a node to HTML string\n */\n serializeHTML(node: DOMNode | DOMDocumentFragment): string;\n\n /**\n * Create a new document for building DOM structures\n */\n createDocument(): DOMDocument;\n\n /**\n * Check if this adapter is available in the current environment\n */\n isAvailable(): boolean;\n}\n\n/**\n * Type guard: check if node is an Element\n */\nexport function isElement(node: DOMNode): node is DOMElement {\n return node.nodeType === NODE_TYPE.ELEMENT_NODE;\n}\n\n/**\n * Type guard: check if node is a Text node\n */\nexport function isTextNode(node: DOMNode): boolean {\n return node.nodeType === NODE_TYPE.TEXT_NODE;\n}\n","import type { Op } from '@scrider/delta';\nimport { isTextInsert, Delta } from '@scrider/delta';\nimport type { BlockContext, BlockHandler } from '../BlockHandler';\nimport type { Registry } from '../Registry';\nimport { normalizeDelta } from '../../conversion/sanitize';\nimport type { DOMElement } from '../../conversion/adapters/types';\nimport { isElement } from '../../conversion/adapters/types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Footnotes block data — a collection of footnote definitions.\n *\n * Stored in Delta as: `{ insert: { block: <FootnotesBlockData> } }`\n *\n * Each note is keyed by its string identifier (e.g. \"1\", \"note\", \"my-ref\").\n * Values contain nested Delta content (rich-text).\n *\n * Placed at the end of the document, after all content.\n */\nexport interface FootnotesBlockData {\n /** Block type discriminator */\n type: 'footnotes';\n /** Map of footnote id → content (nested Delta ops) */\n notes: Record<string, { ops: Op[] }>;\n}\n\n// ============================================================================\n// Validation Helpers\n// ============================================================================\n\n/**\n * Validate that a note entry has valid ops (non-empty array).\n */\nfunction isValidNoteData(note: { ops: Op[] }): boolean {\n return (\n typeof note === 'object' && note !== null && Array.isArray(note.ops) && note.ops.length > 0\n );\n}\n\n// ============================================================================\n// Rendering Helpers\n// ============================================================================\n\n// ============================================================================\n// Parsing Helpers (HTML → FootnotesBlockData)\n// ============================================================================\n\n/**\n * Extract footnote id from an element's `id` attribute.\n * Expects format: \"fn-{id}\" → returns \"{id}\"\n */\nfunction extractFootnoteId(element: DOMElement): string | null {\n const id = element.getAttribute('id') || '';\n if (id.startsWith('fn-')) {\n return id.slice(3);\n }\n return null;\n}\n\n// ============================================================================\n// FootnotesBlockHandler\n// ============================================================================\n\n/**\n * BlockHandler implementation for Footnotes.\n *\n * Handles a single block embed containing all footnote definitions.\n * Each footnote has an id and nested Delta content.\n *\n * HTML: <section class=\"footnotes\"><ol><li id=\"fn-{id}\">...</li></ol></section>\n * Markdown: [^id]: content\n */\nexport const footnotesBlockHandler: BlockHandler<FootnotesBlockData> = {\n type: 'footnotes',\n\n validate(data: FootnotesBlockData): boolean {\n // 1. Type check\n if (!data || typeof data !== 'object' || data.type !== 'footnotes') {\n return false;\n }\n\n // 2. Notes must be a non-empty object\n if (!data.notes || typeof data.notes !== 'object' || Array.isArray(data.notes)) {\n return false;\n }\n\n const noteIds = Object.keys(data.notes);\n if (noteIds.length === 0) return false;\n\n // 3. All keys must be non-empty strings\n for (const id of noteIds) {\n if (typeof id !== 'string' || id.trim().length === 0) return false;\n }\n\n // 4. All values must have valid ops\n for (const note of Object.values(data.notes)) {\n if (!isValidNoteData(note)) return false;\n }\n\n return true;\n },\n\n // ── Conversion ──────────────────────────────────────────────\n\n toHtml(data: FootnotesBlockData, context: BlockContext): string {\n const pretty = context.options?.pretty ?? false;\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n const noteEntries = Object.entries(data.notes);\n if (noteEntries.length === 0) return '';\n\n let html = `<section class=\"footnotes\">${nl}`;\n html += `${ind(1)}<ol>${nl}`;\n\n for (const [id, note] of noteEntries) {\n html += `${ind(2)}<li id=\"fn-${id}\">${nl}`;\n\n // Render nested Delta content\n let content = '';\n if (context.renderDelta) {\n content = context.renderDelta(note.ops);\n }\n\n // Insert backref link inline at the end of the last <p> (before </p>)\n const backref = ` <a href=\"#fnref-${id}\" class=\"footnote-backref\">\\u21a9</a>`;\n const lastPClose = content.lastIndexOf('</p>');\n if (lastPClose !== -1) {\n content = content.slice(0, lastPClose) + backref + content.slice(lastPClose);\n } else {\n content += backref;\n }\n\n html += `${ind(3)}${content}${nl}`;\n\n html += `${ind(2)}</li>${nl}`;\n }\n\n html += `${ind(1)}</ol>${nl}`;\n html += `</section>`;\n return html;\n },\n\n fromHtml(element: DOMElement, context: BlockContext): FootnotesBlockData | null {\n // Expect <section class=\"footnotes\"> or <div class=\"footnotes\">\n const tag = element.tagName.toLowerCase();\n if (tag !== 'section' && tag !== 'div') return null;\n\n const className = element.getAttribute('class') || '';\n if (!className.includes('footnotes')) return null;\n\n // Find <ol> inside\n let ol: DOMElement | null = null;\n const children = element.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child && isElement(child) && child.tagName.toLowerCase() === 'ol') {\n ol = child;\n break;\n }\n }\n\n if (!ol) return null;\n\n const notes: Record<string, { ops: Op[] }> = {};\n\n // Parse each <li>\n const liChildren = ol.childNodes;\n for (let i = 0; i < liChildren.length; i++) {\n const li = liChildren[i];\n if (!li || !isElement(li) || li.tagName.toLowerCase() !== 'li') continue;\n\n const id = extractFootnoteId(li);\n if (!id) continue;\n\n // Parse content via context.parseElement, then clean up backref artifacts\n let ops: Op[];\n if (context.parseElement) {\n ops = context.parseElement(li);\n\n // Clean up: remove backref arrow \"↩\" that the <a class=\"footnote-backref\"> produces\n ops = ops\n .map((op) => {\n if (isTextInsert(op) && op.insert.includes('\\u21a9')) {\n return { ...op, insert: op.insert.replace(/\\u21a9/g, '') };\n }\n return op;\n })\n .filter((op) => !isTextInsert(op) || op.insert !== '');\n\n if (ops.length === 0) {\n ops = [{ insert: '\\n' }];\n }\n } else {\n ops = [{ insert: '\\n' }];\n }\n\n notes[id] = { ops };\n }\n\n if (Object.keys(notes).length === 0) return null;\n\n return { type: 'footnotes', notes };\n },\n\n toMarkdown(data: FootnotesBlockData, context: BlockContext): string | null {\n const noteEntries = Object.entries(data.notes);\n if (noteEntries.length === 0) return null;\n\n const lines: string[] = [];\n for (const [id, note] of noteEntries) {\n // context.renderDelta produces Markdown when called from deltaToMarkdown,\n // or HTML when called from deltaToHtml — either way, use the output directly.\n // For multi-paragraph footnotes, continuation lines need 4-space indent (GFM convention).\n let content: string;\n if (context.renderDelta) {\n content = context.renderDelta(note.ops).trim();\n } else {\n content = '';\n }\n\n // First line: [^id]: content\n // Continuation: indented by 4 spaces\n const contentLines = content.split('\\n');\n const indented = contentLines\n .map((line, idx) => (idx === 0 ? `[^${id}]: ${line}` : ` ${line}`))\n .join('\\n');\n lines.push(indented);\n }\n\n return '\\n' + lines.join('\\n\\n');\n },\n\n // ── Normalize ─────────────────────────────────────────────\n\n normalize(data: FootnotesBlockData, registry: Registry): FootnotesBlockData {\n const newNotes: Record<string, { ops: Op[] }> = {};\n let changed = false;\n\n for (const [id, note] of Object.entries(data.notes)) {\n const normalized = normalizeDelta(new Delta(note.ops), registry);\n if (normalized.ops !== note.ops) {\n newNotes[id] = { ops: normalized.ops };\n changed = true;\n } else {\n newNotes[id] = note;\n }\n }\n\n return changed ? { ...data, notes: newNotes } : data;\n },\n\n // ── Nested Deltas ──────────────────────────────────────────\n\n getNestedDeltas(data: FootnotesBlockData): Op[][] {\n return Object.values(data.notes).map((note) => note.ops);\n },\n\n setNestedDeltas(data: FootnotesBlockData, deltas: Op[][]): FootnotesBlockData {\n const ids = Object.keys(data.notes);\n const newNotes: Record<string, { ops: Op[] }> = {};\n ids.forEach((id, i) => {\n newNotes[id] = { ops: deltas[i]! };\n });\n return { ...data, notes: newNotes };\n },\n};\n","import type { Op } from '@scrider/delta';\nimport { Delta } from '@scrider/delta';\nimport type { BlockContext, BlockHandler } from '../BlockHandler';\nimport type { Registry } from '../Registry';\nimport { normalizeDelta } from '../../conversion/sanitize';\nimport type { DOMElement } from '../../conversion/adapters/types';\nimport { isElement } from '../../conversion/adapters/types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** The 5 standard GitHub alert types */\nexport const ALERT_TYPES = ['note', 'tip', 'important', 'warning', 'caution'] as const;\n\n/** Union of valid alert types */\nexport type AlertType = (typeof ALERT_TYPES)[number];\n\n/**\n * Alert / Admonition block data.\n *\n * Stored in Delta as: `{ insert: { block: <AlertBlockData> } }`\n *\n * GitHub-style alerts:\n * ```markdown\n * > [!NOTE]\n * > Useful information.\n * ```\n *\n * HTML:\n * ```html\n * <div class=\"markdown-alert markdown-alert-note\">\n * <p class=\"markdown-alert-title\">Note</p>\n * <p>Useful information.</p>\n * </div>\n * ```\n */\nexport interface AlertBlockData {\n /** Block type discriminator */\n type: 'alert';\n /** Alert variant (note, tip, important, warning, caution) */\n alertType: AlertType;\n /** Nested Delta content (rich text) */\n content: { ops: Op[] };\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Check if a string is a valid alert type */\nfunction isAlertType(value: string): value is AlertType {\n return ALERT_TYPES.includes(value as AlertType);\n}\n\n/** Capitalize first letter: \"note\" → \"Note\" */\nfunction capitalize(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n// ============================================================================\n// AlertBlockHandler\n// ============================================================================\n\n/**\n * BlockHandler implementation for Alerts / Admonitions.\n *\n * Handles GitHub-style alerts (5 types: note, tip, important, warning, caution).\n * Each alert contains nested Delta content (rich text).\n *\n * HTML: `<div class=\"markdown-alert markdown-alert-{type}\"><p class=\"markdown-alert-title\">{Type}</p>...</div>`\n * Markdown: `> [!TYPE]\\n> content`\n */\nexport const alertBlockHandler: BlockHandler<AlertBlockData> = {\n type: 'alert',\n\n validate(data: AlertBlockData): boolean {\n if (!data || typeof data !== 'object' || data.type !== 'alert') {\n return false;\n }\n\n if (typeof data.alertType !== 'string' || !isAlertType(data.alertType)) {\n return false;\n }\n\n if (\n !data.content ||\n typeof data.content !== 'object' ||\n !Array.isArray(data.content.ops) ||\n data.content.ops.length === 0\n ) {\n return false;\n }\n\n return true;\n },\n\n // ── Conversion ──────────────────────────────────────────────\n\n toHtml(data: AlertBlockData, context: BlockContext): string {\n const pretty = context.options?.pretty ?? false;\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n const alertClass = `markdown-alert markdown-alert-${data.alertType}`;\n const title = capitalize(data.alertType);\n\n let html = `<div class=\"${alertClass}\">${nl}`;\n html += `${ind(1)}<p class=\"markdown-alert-title\">${title}</p>${nl}`;\n\n // Render nested Delta content\n if (context.renderDelta) {\n html += `${ind(1)}${context.renderDelta(data.content.ops)}${nl}`;\n }\n\n html += `</div>`;\n return html;\n },\n\n fromHtml(element: DOMElement, context: BlockContext): AlertBlockData | null {\n const tag = element.tagName.toLowerCase();\n if (tag !== 'div' && tag !== 'section') return null;\n\n const className = element.getAttribute('class') || '';\n if (!className.includes('markdown-alert')) return null;\n\n // Extract alert type from class: \"markdown-alert-note\" → \"note\"\n let alertType: AlertType = 'note';\n for (const t of ALERT_TYPES) {\n if (className.includes(`markdown-alert-${t}`)) {\n alertType = t;\n break;\n }\n }\n\n // Parse children, skipping the title <p class=\"markdown-alert-title\">\n let ops: Op[] = [];\n\n const children = element.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child)) continue;\n\n // Skip the title paragraph\n const childClass = child.getAttribute('class') || '';\n if (childClass.includes('markdown-alert-title')) continue;\n\n // Parse content elements\n if (context.parseElement) {\n const parsed = context.parseElement(child);\n ops = ops.concat(parsed);\n }\n }\n\n if (ops.length === 0) {\n ops = [{ insert: '\\n' }];\n }\n\n return {\n type: 'alert',\n alertType,\n content: { ops },\n };\n },\n\n toMarkdown(data: AlertBlockData, context: BlockContext): string | null {\n // > [!NOTE]\n // > content line 1\n // > content line 2\n const tag = `[!${data.alertType.toUpperCase()}]`;\n\n let contentMd = '';\n if (context.renderDelta) {\n // renderDelta produces Markdown when called from deltaToMarkdown\n contentMd = context.renderDelta(data.content.ops);\n }\n\n // Prefix each line with \"> \"\n const lines = contentMd.split('\\n');\n // Remove trailing empty line if present\n while (lines.length > 0 && (lines[lines.length - 1] ?? '').trim() === '') {\n lines.pop();\n }\n\n const prefixed = lines.map((line) => `> ${line}`).join('\\n');\n return `> ${tag}\\n${prefixed}`;\n },\n\n // ── Normalization ──────────────────────────────────────────\n\n normalize(data: AlertBlockData, registry: Registry): AlertBlockData {\n const normalized = normalizeDelta(new Delta(data.content.ops), registry);\n return {\n ...data,\n content: { ops: normalized.ops },\n };\n },\n\n // ── Nested Deltas ──────────────────────────────────────────\n\n getNestedDeltas(data: AlertBlockData): Op[][] {\n return [data.content.ops];\n },\n\n setNestedDeltas(data: AlertBlockData, deltas: Op[][]): AlertBlockData {\n const first = deltas[0];\n if (!first) return data;\n return {\n ...data,\n content: { ops: first },\n };\n },\n};\n","import type { Op } from '@scrider/delta';\nimport { Delta } from '@scrider/delta';\nimport type { BlockContext, BlockHandler } from '../BlockHandler';\nimport type { Registry } from '../Registry';\nimport { normalizeDelta } from '../../conversion/sanitize';\nimport type { DOMElement } from '../../conversion/adapters/types';\nimport { isElement } from '../../conversion/adapters/types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Columns Layout block data.\n *\n * Stored in Delta as: `{ insert: { block: <ColumnsBlockData> } }`\n *\n * Each column contains a full nested Delta (rich text, embeds, nested blocks).\n *\n * HTML:\n * ```html\n * <div class=\"columns columns-2\">\n * <div class=\"column\"><p>Column 1</p></div>\n * <div class=\"column\"><p>Column 2</p></div>\n * </div>\n * ```\n *\n * With custom widths:\n * ```html\n * <div class=\"columns columns-2\" style=\"grid-template-columns: 30% 70%\">\n * <div class=\"column\"><p>Sidebar</p></div>\n * <div class=\"column\"><p>Main content</p></div>\n * </div>\n * ```\n *\n * Markdown: no native equivalent → toMarkdown returns null → HTML fallback.\n *\n * Resize-ready: `widths` for per-column resize (future scrider-editor),\n * `width`/`height` in op attributes for overall dimensions.\n */\nexport interface ColumnsBlockData {\n /** Block type discriminator */\n type: 'columns';\n /** Column contents — array of nested Deltas */\n columns: { ops: Op[] }[];\n /** Optional: column widths in percent (sum ≈ 100). Default: equal (CSS 1fr each) */\n widths?: number[];\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Tolerance for widths sum validation (allows rounding: e.g. 33.33 + 33.33 + 33.34 = 100) */\nconst WIDTHS_SUM_TOLERANCE = 1;\n\n// ============================================================================\n// ColumnsBlockHandler\n// ============================================================================\n\n/**\n * BlockHandler implementation for Columns Layout.\n *\n * Multi-column layout with nested Delta content in each column.\n * Analogous to Alert (nested Delta) but with an array of columns.\n *\n * HTML: `<div class=\"columns columns-N\" [style=\"grid-template-columns: W1% W2%\"]>\n * <div class=\"column\">...</div>...\n * </div>`\n * Markdown: no equivalent → toMarkdown returns null → HTML fallback\n */\nexport const columnsBlockHandler: BlockHandler<ColumnsBlockData> = {\n type: 'columns',\n\n validate(data: ColumnsBlockData): boolean {\n if (!data || typeof data !== 'object' || data.type !== 'columns') {\n return false;\n }\n\n // columns must be an array with at least 2 elements\n // (1 column = Inline-Box pattern, use \"box\" block type instead)\n if (!Array.isArray(data.columns) || data.columns.length < 2) {\n return false;\n }\n\n // Each column must have non-empty ops\n for (const col of data.columns) {\n if (!col || typeof col !== 'object' || !Array.isArray(col.ops) || col.ops.length === 0) {\n return false;\n }\n }\n\n // widths validation (if provided)\n if (data.widths !== undefined) {\n if (!Array.isArray(data.widths)) {\n return false;\n }\n\n // Length must match columns\n if (data.widths.length !== data.columns.length) {\n return false;\n }\n\n // All values must be positive numbers\n for (const w of data.widths) {\n if (typeof w !== 'number' || w <= 0 || !isFinite(w)) {\n return false;\n }\n }\n\n // Sum must be approximately 100\n const sum = data.widths.reduce((a, b) => a + b, 0);\n if (Math.abs(sum - 100) > WIDTHS_SUM_TOLERANCE) {\n return false;\n }\n }\n\n return true;\n },\n\n // ── Conversion ──────────────────────────────────────────────\n\n toHtml(data: ColumnsBlockData, context: BlockContext): string {\n const n = data.columns.length;\n const pretty = context.options?.pretty ?? false;\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n // Class: \"columns columns-N\"\n const classAttr = `columns columns-${n}`;\n\n // Custom widths → inline style grid-template-columns\n let styleAttr = '';\n if (data.widths && data.widths.length === n) {\n const cols = data.widths.map((w) => `${w}%`).join(' ');\n styleAttr = ` style=\"grid-template-columns: ${cols}\"`;\n }\n\n let html = `<div class=\"${classAttr}\"${styleAttr}>${nl}`;\n\n for (const col of data.columns) {\n html += `${ind(1)}<div class=\"column\">${nl}`;\n if (context.renderDelta) {\n html += `${ind(2)}${context.renderDelta(col.ops)}${nl}`;\n }\n html += `${ind(1)}</div>${nl}`;\n }\n\n html += `</div>`;\n return html;\n },\n\n fromHtml(element: DOMElement, context: BlockContext): ColumnsBlockData | null {\n const tag = element.tagName.toLowerCase();\n if (tag !== 'div') return null;\n\n const className = element.getAttribute('class') || '';\n if (!className.includes('columns')) return null;\n\n // Don't match \"column\" (singular) without \"columns\" (plural)\n // \"columns\" class is required on the container\n if (!/\\bcolumns\\b/.test(className)) return null;\n\n const columns: { ops: Op[] }[] = [];\n const children = element.childNodes;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child)) continue;\n\n const childClass = child.getAttribute('class') || '';\n if (!/\\bcolumn\\b/.test(childClass)) continue;\n\n // Parse all children of the column div\n let ops: Op[] = [];\n if (context.parseElement) {\n const childChildren = child.childNodes;\n for (let j = 0; j < childChildren.length; j++) {\n const el = childChildren[j];\n if (el && isElement(el)) {\n const parsed = context.parseElement(el);\n ops = ops.concat(parsed);\n }\n }\n }\n\n if (ops.length === 0) {\n ops = [{ insert: '\\n' }];\n }\n\n columns.push({ ops });\n }\n\n if (columns.length === 0) return null;\n\n // Extract widths from inline style: grid-template-columns\n let widths: number[] | undefined;\n const style = element.getAttribute('style') || '';\n const match = style.match(/grid-template-columns:\\s*(.+?)(?:;|$)/);\n if (match && match[1]) {\n const parts = match[1].trim().split(/\\s+/);\n const parsed = parts.map((p) => parseFloat(p)).filter((n) => !isNaN(n) && n > 0);\n if (parsed.length === columns.length) {\n widths = parsed;\n }\n }\n\n const result: ColumnsBlockData = {\n type: 'columns',\n columns,\n };\n\n if (widths) {\n result.widths = widths;\n }\n\n return result;\n },\n\n toMarkdown(_data: ColumnsBlockData, _context: BlockContext): string | null {\n // No lossless Markdown representation for columns layout.\n // Returning null triggers fallback to toHtml() — HTML directly in Markdown\n // (valid per CommonMark/GFM spec).\n return null;\n },\n\n // ── Normalization ──────────────────────────────────────────\n\n normalize(data: ColumnsBlockData, registry: Registry): ColumnsBlockData {\n return {\n ...data,\n columns: data.columns.map((col) => ({\n ops: normalizeDelta(new Delta(col.ops), registry).ops,\n })),\n };\n },\n\n // ── Nested Deltas ──────────────────────────────────────────\n\n getNestedDeltas(data: ColumnsBlockData): Op[][] {\n return data.columns.map((col) => col.ops);\n },\n\n setNestedDeltas(data: ColumnsBlockData, deltas: Op[][]): ColumnsBlockData {\n return {\n ...data,\n columns: data.columns.map((col, i) => ({\n ...col,\n ops: deltas[i] ?? col.ops,\n })),\n };\n },\n};\n","import type { Op } from '@scrider/delta';\nimport { Delta } from '@scrider/delta';\nimport type { BlockContext, BlockHandler } from '../BlockHandler';\nimport type { Registry } from '../Registry';\nimport { normalizeDelta } from '../../conversion/sanitize';\nimport type { DOMElement } from '../../conversion/adapters/types';\nimport { isElement } from '../../conversion/adapters/types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Valid float positions for Inline-Box */\nexport const BOX_FLOAT_VALUES = ['left', 'right', 'center'] as const;\n\n/** Valid overflow modes for Inline-Box */\nexport const BOX_OVERFLOW_VALUES = ['auto', 'hidden', 'visible'] as const;\n\n/** Union of valid float positions */\nexport type BoxFloat = (typeof BOX_FLOAT_VALUES)[number];\n\n/** Union of valid overflow modes */\nexport type BoxOverflow = (typeof BOX_OVERFLOW_VALUES)[number];\n\n/**\n * Inline-Box block data.\n *\n * Stored in Delta as: `{ insert: { block: <BoxBlockData> }, attributes: { float, width, height, overflow } }`\n *\n * A float container with nested Delta content and text wrapping.\n * Visual properties (float, width, height, overflow) are stored in op attributes,\n * not in block data — clean separation of semantics vs presentation.\n *\n * HTML (float left/right):\n * ```html\n * <div class=\"inline-box\" data-float=\"left\" data-overflow=\"auto\"\n * style=\"width: 200px; height: 300px;\">\n * <p>Rich content</p>\n * </div>\n * ```\n *\n * HTML (center — no wrapping):\n * ```html\n * <div class=\"inline-box\" data-float=\"center\" data-overflow=\"auto\"\n * style=\"width: 200px; height: 300px;\">\n * <p>Content</p>\n * </div>\n * ```\n *\n * Markdown: no native equivalent → toMarkdown returns null → HTML fallback.\n */\nexport interface BoxBlockData {\n /** Block type discriminator */\n type: 'box';\n /** Nested Delta content (rich text) */\n content: { ops: Op[] };\n}\n\n/**\n * Op-level attributes for box block embed.\n * Stored in `op.attributes`, not in block data.\n */\nexport interface BoxOpAttributes {\n /** Float position: left/right = text wrapping, center = no wrapping */\n float?: BoxFloat;\n /** Container width (e.g. \"200px\", \"30%\") */\n width?: string;\n /** Container height (e.g. \"300px\", \"auto\") */\n height?: string;\n /** Overflow behavior when content exceeds dimensions */\n overflow?: BoxOverflow;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Check if a string is a valid box float value */\nfunction isBoxFloat(value: string): value is BoxFloat {\n return BOX_FLOAT_VALUES.includes(value as BoxFloat);\n}\n\n/** Check if a string is a valid box overflow value */\nfunction isBoxOverflow(value: string): value is BoxOverflow {\n return BOX_OVERFLOW_VALUES.includes(value as BoxOverflow);\n}\n\n// ============================================================================\n// BoxBlockHandler\n// ============================================================================\n\n/**\n * BlockHandler implementation for Inline-Box (Float Container).\n *\n * A container with nested Delta content that supports float positioning\n * and text wrapping. Like Alert (single nested Delta), but visual\n * properties are stored in op attributes, not in block data.\n *\n * HTML: `<div class=\"inline-box\" data-float=\"F\" data-overflow=\"O\" style=\"width: W; height: H\">...</div>`\n * Markdown: no equivalent → toMarkdown returns null → HTML fallback\n */\nexport const boxBlockHandler: BlockHandler<BoxBlockData> = {\n type: 'box',\n\n validate(data: BoxBlockData): boolean {\n if (!data || typeof data !== 'object' || data.type !== 'box') {\n return false;\n }\n\n if (\n !data.content ||\n typeof data.content !== 'object' ||\n !Array.isArray(data.content.ops) ||\n data.content.ops.length === 0\n ) {\n return false;\n }\n\n return true;\n },\n\n // ── Conversion ──────────────────────────────────────────────\n\n toHtml(data: BoxBlockData, context: BlockContext): string {\n const pretty = context.options?.pretty ?? false;\n const nl = pretty ? '\\n' : '';\n const ind = (level: number): string => (pretty ? ' '.repeat(level) : '');\n\n // Read visual properties from opAttributes (passed by converter)\n const opAttrs = context.opAttributes;\n const float = (opAttrs?.float as string) || 'left';\n const width = opAttrs?.width as string | undefined;\n const height = opAttrs?.height as string | undefined;\n const overflow = (opAttrs?.overflow as string) || 'auto';\n\n // Build data-* attributes for CSS-driven layout\n let attrs = `class=\"inline-box\" data-float=\"${float}\"`;\n if (overflow !== 'auto') {\n attrs += ` data-overflow=\"${overflow}\"`;\n }\n\n // Build inline style for dynamic values (width, height)\n const styles: string[] = [];\n if (width && width !== 'auto') styles.push(`width: ${width}`);\n if (height && height !== 'auto') styles.push(`height: ${height}`);\n if (styles.length > 0) {\n attrs += ` style=\"${styles.join('; ')}\"`;\n }\n\n let html = `<div ${attrs}>${nl}`;\n\n // Render nested Delta content\n if (context.renderDelta) {\n html += `${ind(1)}${context.renderDelta(data.content.ops)}${nl}`;\n }\n\n html += `</div>`;\n return html;\n },\n\n fromHtml(element: DOMElement, context: BlockContext): BoxBlockData | null {\n const tag = element.tagName.toLowerCase();\n if (tag !== 'div') return null;\n\n const className = element.getAttribute('class') || '';\n if (!className.includes('inline-box')) return null;\n\n // Parse children to get nested Delta content\n let ops: Op[] = [];\n\n const children = element.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child)) continue;\n\n if (context.parseElement) {\n const parsed = context.parseElement(child);\n ops = ops.concat(parsed);\n }\n }\n\n if (ops.length === 0) {\n ops = [{ insert: '\\n' }];\n }\n\n return {\n type: 'box',\n content: { ops },\n };\n },\n\n toMarkdown(_data: BoxBlockData, _context: BlockContext): string | null {\n // No lossless Markdown representation for float container.\n // Returning null triggers fallback to toHtml() — HTML directly in Markdown\n // (valid per CommonMark/GFM spec).\n return null;\n },\n\n // ── Normalization ──────────────────────────────────────────\n\n normalize(data: BoxBlockData, registry: Registry): BoxBlockData {\n const normalized = normalizeDelta(new Delta(data.content.ops), registry);\n return {\n ...data,\n content: { ops: normalized.ops },\n };\n },\n\n // ── Nested Deltas ──────────────────────────────────────────\n\n getNestedDeltas(data: BoxBlockData): Op[][] {\n return [data.content.ops];\n },\n\n setNestedDeltas(data: BoxBlockData, deltas: Op[][]): BoxBlockData {\n const first = deltas[0];\n if (!first) return data;\n return {\n ...data,\n content: { ops: first },\n };\n },\n};\n\n/**\n * Extract op attributes for box from an HTML element.\n *\n * Used by html-to-delta intercept to reconstruct op attributes\n * (float, width, height, overflow) from the HTML representation.\n */\nexport function extractBoxOpAttributes(element: DOMElement): BoxOpAttributes {\n const attrs: BoxOpAttributes = {};\n\n // float from data-float attribute\n const dataFloat = element.getAttribute('data-float');\n if (dataFloat && isBoxFloat(dataFloat)) {\n attrs.float = dataFloat;\n }\n\n // overflow from data-overflow attribute (default: auto)\n const dataOverflow = element.getAttribute('data-overflow');\n if (dataOverflow && isBoxOverflow(dataOverflow)) {\n attrs.overflow = dataOverflow;\n }\n\n // width and height from inline style\n const style = element.getAttribute('style') || '';\n\n const widthMatch = style.match(/(?:^|;\\s*)width:\\s*([^;]+)/);\n if (widthMatch?.[1]) {\n attrs.width = widthMatch[1].trim();\n }\n\n const heightMatch = style.match(/(?:^|;\\s*)height:\\s*([^;]+)/);\n if (heightMatch?.[1]) {\n attrs.height = heightMatch[1].trim();\n }\n\n return attrs;\n}\n","/**\n * CSS Named Colors (full list)\n * https://www.w3.org/TR/css-color-4/#named-colors\n */\nconst NAMED_COLORS: Record<string, string> = {\n // Basic colors\n black: '#000000',\n silver: '#c0c0c0',\n gray: '#808080',\n white: '#ffffff',\n maroon: '#800000',\n red: '#ff0000',\n purple: '#800080',\n fuchsia: '#ff00ff',\n green: '#008000',\n lime: '#00ff00',\n olive: '#808000',\n yellow: '#ffff00',\n navy: '#000080',\n blue: '#0000ff',\n teal: '#008080',\n aqua: '#00ffff',\n\n // Extended colors\n aliceblue: '#f0f8ff',\n antiquewhite: '#faebd7',\n aquamarine: '#7fffd4',\n azure: '#f0ffff',\n beige: '#f5f5dc',\n bisque: '#ffe4c4',\n blanchedalmond: '#ffebcd',\n blueviolet: '#8a2be2',\n brown: '#a52a2a',\n burlywood: '#deb887',\n cadetblue: '#5f9ea0',\n chartreuse: '#7fff00',\n chocolate: '#d2691e',\n coral: '#ff7f50',\n cornflowerblue: '#6495ed',\n cornsilk: '#fff8dc',\n crimson: '#dc143c',\n cyan: '#00ffff',\n darkblue: '#00008b',\n darkcyan: '#008b8b',\n darkgoldenrod: '#b8860b',\n darkgray: '#a9a9a9',\n darkgreen: '#006400',\n darkgrey: '#a9a9a9',\n darkkhaki: '#bdb76b',\n darkmagenta: '#8b008b',\n darkolivegreen: '#556b2f',\n darkorange: '#ff8c00',\n darkorchid: '#9932cc',\n darkred: '#8b0000',\n darksalmon: '#e9967a',\n darkseagreen: '#8fbc8f',\n darkslateblue: '#483d8b',\n darkslategray: '#2f4f4f',\n darkslategrey: '#2f4f4f',\n darkturquoise: '#00ced1',\n darkviolet: '#9400d3',\n deeppink: '#ff1493',\n deepskyblue: '#00bfff',\n dimgray: '#696969',\n dimgrey: '#696969',\n dodgerblue: '#1e90ff',\n firebrick: '#b22222',\n floralwhite: '#fffaf0',\n forestgreen: '#228b22',\n gainsboro: '#dcdcdc',\n ghostwhite: '#f8f8ff',\n gold: '#ffd700',\n goldenrod: '#daa520',\n greenyellow: '#adff2f',\n grey: '#808080',\n honeydew: '#f0fff0',\n hotpink: '#ff69b4',\n indianred: '#cd5c5c',\n indigo: '#4b0082',\n ivory: '#fffff0',\n khaki: '#f0e68c',\n lavender: '#e6e6fa',\n lavenderblush: '#fff0f5',\n lawngreen: '#7cfc00',\n lemonchiffon: '#fffacd',\n lightblue: '#add8e6',\n lightcoral: '#f08080',\n lightcyan: '#e0ffff',\n lightgoldenrodyellow: '#fafad2',\n lightgray: '#d3d3d3',\n lightgreen: '#90ee90',\n lightgrey: '#d3d3d3',\n lightpink: '#ffb6c1',\n lightsalmon: '#ffa07a',\n lightseagreen: '#20b2aa',\n lightskyblue: '#87cefa',\n lightslategray: '#778899',\n lightslategrey: '#778899',\n lightsteelblue: '#b0c4de',\n lightyellow: '#ffffe0',\n limegreen: '#32cd32',\n linen: '#faf0e6',\n magenta: '#ff00ff',\n mediumaquamarine: '#66cdaa',\n mediumblue: '#0000cd',\n mediumorchid: '#ba55d3',\n mediumpurple: '#9370db',\n mediumseagreen: '#3cb371',\n mediumslateblue: '#7b68ee',\n mediumspringgreen: '#00fa9a',\n mediumturquoise: '#48d1cc',\n mediumvioletred: '#c71585',\n midnightblue: '#191970',\n mintcream: '#f5fffa',\n mistyrose: '#ffe4e1',\n moccasin: '#ffe4b5',\n navajowhite: '#ffdead',\n oldlace: '#fdf5e6',\n olivedrab: '#6b8e23',\n orange: '#ffa500',\n orangered: '#ff4500',\n orchid: '#da70d6',\n palegoldenrod: '#eee8aa',\n palegreen: '#98fb98',\n paleturquoise: '#afeeee',\n palevioletred: '#db7093',\n papayawhip: '#ffefd5',\n peachpuff: '#ffdab9',\n peru: '#cd853f',\n pink: '#ffc0cb',\n plum: '#dda0dd',\n powderblue: '#b0e0e6',\n rosybrown: '#bc8f8f',\n royalblue: '#4169e1',\n saddlebrown: '#8b4513',\n salmon: '#fa8072',\n sandybrown: '#f4a460',\n seagreen: '#2e8b57',\n seashell: '#fff5ee',\n sienna: '#a0522d',\n skyblue: '#87ceeb',\n slateblue: '#6a5acd',\n slategray: '#708090',\n slategrey: '#708090',\n snow: '#fffafa',\n springgreen: '#00ff7f',\n steelblue: '#4682b4',\n tan: '#d2b48c',\n thistle: '#d8bfd8',\n tomato: '#ff6347',\n turquoise: '#40e0d0',\n violet: '#ee82ee',\n wheat: '#f5deb3',\n whitesmoke: '#f5f5f5',\n yellowgreen: '#9acd32',\n\n // CSS4 colors\n rebeccapurple: '#663399',\n};\n\n/**\n * Convert any color format to lowercase hex (#rrggbb)\n *\n * Supports:\n * - Hex: #rgb, #rrggbb, #rrggbbaa\n * - RGB: rgb(r, g, b), rgb(r g b)\n * - RGBA: rgba(r, g, b, a), rgba(r g b / a)\n * - Named colors: red, blue, etc.\n *\n * @param value - Color value to convert\n * @returns Lowercase hex color (#rrggbb) or original value if not recognized\n */\nexport function toHexColor(value: string): string {\n const trimmed = value.trim().toLowerCase();\n\n // Already hex\n if (trimmed.startsWith('#')) {\n return normalizeHex(trimmed);\n }\n\n // Named color\n if (NAMED_COLORS[trimmed]) {\n return NAMED_COLORS[trimmed];\n }\n\n // RGB/RGBA\n if (trimmed.startsWith('rgb')) {\n return parseRgb(trimmed);\n }\n\n // HSL (basic support - convert to RGB first would be complex)\n // For now, return as-is if not recognized\n return value;\n}\n\n/**\n * Normalize hex color to #rrggbb format\n */\nfunction normalizeHex(hex: string): string {\n // Remove # prefix\n let color = hex.slice(1);\n\n // Expand shorthand (#rgb → #rrggbb)\n if (color.length === 3) {\n color =\n color.charAt(0) +\n color.charAt(0) +\n color.charAt(1) +\n color.charAt(1) +\n color.charAt(2) +\n color.charAt(2);\n }\n\n // Handle #rgba shorthand\n if (color.length === 4) {\n color =\n color.charAt(0) +\n color.charAt(0) +\n color.charAt(1) +\n color.charAt(1) +\n color.charAt(2) +\n color.charAt(2);\n // Ignore alpha\n }\n\n // Handle #rrggbbaa (ignore alpha)\n if (color.length === 8) {\n color = color.slice(0, 6);\n }\n\n // Validate\n if (!/^[0-9a-f]{6}$/.test(color)) {\n return '#' + color; // Return as-is if invalid\n }\n\n return '#' + color;\n}\n\n/**\n * Parse rgb/rgba to hex\n */\nfunction parseRgb(value: string): string {\n // Match rgb(r, g, b) or rgba(r, g, b, a) or rgb(r g b) or rgb(r g b / a)\n // Supports negative numbers for clamping\n const match = value.match(\n /rgba?\\s*\\(\\s*(-?\\d+)\\s*[,\\s]\\s*(-?\\d+)\\s*[,\\s]\\s*(-?\\d+)(?:\\s*[,/]\\s*[\\d.]+)?\\s*\\)/,\n );\n\n if (!match) {\n return value; // Return as-is if not parseable\n }\n\n const [, rStr, gStr, bStr] = match;\n if (!rStr || !gStr || !bStr) return value;\n\n const r = Math.max(0, Math.min(255, parseInt(rStr, 10)));\n const g = Math.max(0, Math.min(255, parseInt(gStr, 10)));\n const b = Math.max(0, Math.min(255, parseInt(bStr, 10)));\n\n return '#' + toHex(r) + toHex(g) + toHex(b);\n}\n\n/**\n * Convert number to 2-digit hex\n */\nfunction toHex(n: number): string {\n const hex = n.toString(16);\n return hex.length === 1 ? '0' + hex : hex;\n}\n\n/**\n * Check if a value is a valid hex color\n *\n * @param value - Value to check\n * @returns true if valid hex color (#rrggbb or #rgb)\n */\nexport function isValidHexColor(value: string): boolean {\n return /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(value);\n}\n\n/**\n * Check if a value is a valid color (hex, rgb, rgba, or named)\n *\n * @param value - Value to check\n * @returns true if valid color\n */\nexport function isValidColor(value: string): boolean {\n const trimmed = value.trim().toLowerCase();\n\n // Hex\n if (/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(trimmed)) {\n return true;\n }\n\n // Named\n if (NAMED_COLORS[trimmed]) {\n return true;\n }\n\n // RGB/RGBA\n if (/^rgba?\\s*\\(\\s*\\d+\\s*[,\\s]\\s*\\d+\\s*[,\\s]\\s*\\d+(?:\\s*[,/]\\s*[\\d.]+)?\\s*\\)$/.test(trimmed)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Get list of all named colors\n */\nexport function getNamedColors(): string[] {\n return Object.keys(NAMED_COLORS);\n}\n","import type { Format } from '../../Format';\nimport { isValidColor, toHexColor } from '../../utils/color';\n\n/**\n * Background color format\n *\n * Delta: { insert: \"text\", attributes: { background: \"#ff0000\" } }\n *\n * Normalizes all color formats (rgb, named, etc.) to lowercase hex (#rrggbb)\n */\nexport const backgroundFormat: Format<string> = {\n name: 'background',\n scope: 'inline',\n\n normalize(value: string): string {\n return toHexColor(value);\n },\n\n validate(value: string): boolean {\n return typeof value === 'string' && isValidColor(value);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Bold format\n *\n * Delta: { insert: \"text\", attributes: { bold: true } }\n */\nexport const boldFormat: Format<boolean> = {\n name: 'bold',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Inline code format\n *\n * Delta: { insert: \"text\", attributes: { code: true } }\n */\nexport const codeFormat: Format<boolean> = {\n name: 'code',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\nimport { isValidColor, toHexColor } from '../../utils/color';\n\n/**\n * Text color format\n *\n * Delta: { insert: \"text\", attributes: { color: \"#ff0000\" } }\n *\n * Normalizes all color formats (rgb, named, etc.) to lowercase hex (#rrggbb)\n */\nexport const colorFormat: Format<string> = {\n name: 'color',\n scope: 'inline',\n\n normalize(value: string): string {\n return toHexColor(value);\n },\n\n validate(value: string): boolean {\n return typeof value === 'string' && isValidColor(value);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Font family format\n *\n * Delta: { insert: \"text\", attributes: { font: \"Times New Roman\" } }\n */\nexport const fontFormat: Format<string> = {\n name: 'font',\n scope: 'inline',\n\n validate(value: string): boolean {\n return typeof value === 'string' && value.length > 0;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Italic format\n *\n * Delta: { insert: \"text\", attributes: { italic: true } }\n */\nexport const italicFormat: Format<boolean> = {\n name: 'italic',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Keyboard input format\n *\n * Delta: { insert: \"text\", attributes: { kbd: true } }\n * HTML: <kbd>text</kbd>\n * Markdown: <kbd>text</kbd> (inline HTML)\n */\nexport const kbdFormat: Format<boolean> = {\n name: 'kbd',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Link format\n *\n * Delta: { insert: \"text\", attributes: { link: \"https://example.com\" } }\n *\n * Supports:\n * - Absolute URLs (http://, https://)\n * - Relative URLs (/path, ./path, ../path)\n * - Protocol-relative URLs (//example.com)\n * - mailto: and tel: links\n */\nexport const linkFormat: Format<string> = {\n name: 'link',\n scope: 'inline',\n\n normalize(value: string): string {\n return value.trim();\n },\n\n validate(value: string): boolean {\n if (typeof value !== 'string' || value.length === 0) {\n return false;\n }\n\n const trimmed = value.trim();\n\n // Relative URLs\n if (trimmed.startsWith('/') || trimmed.startsWith('./') || trimmed.startsWith('../')) {\n return true;\n }\n\n // Protocol-relative URLs\n if (trimmed.startsWith('//')) {\n return true;\n }\n\n // mailto: and tel:\n if (trimmed.startsWith('mailto:') || trimmed.startsWith('tel:')) {\n return true;\n }\n\n // Absolute URLs (http/https)\n try {\n const url = new URL(trimmed);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Mark (highlight) format\n *\n * Delta: { insert: \"text\", attributes: { mark: true } }\n * HTML: <mark>text</mark>\n */\nexport const markFormat: Format<boolean> = {\n name: 'mark',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Font size format\n *\n * Delta: { insert: \"text\", attributes: { size: \"14pt\" } }\n *\n * Value is a string with CSS unit (e.g. \"14pt\", \"16px\", \"1.2em\").\n */\nexport const sizeFormat: Format<string> = {\n name: 'size',\n scope: 'inline',\n\n validate(value: string): boolean {\n return typeof value === 'string' && value.length > 0;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Strikethrough format\n *\n * Delta: { insert: \"text\", attributes: { strike: true } }\n */\nexport const strikeFormat: Format<boolean> = {\n name: 'strike',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Subscript format\n *\n * Delta: { insert: \"text\", attributes: { subscript: true } }\n * HTML: <sub>text</sub>\n */\nexport const subscriptFormat: Format<boolean> = {\n name: 'subscript',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Superscript format\n *\n * Delta: { insert: \"text\", attributes: { superscript: true } }\n * HTML: <sup>text</sup>\n */\nexport const superscriptFormat: Format<boolean> = {\n name: 'superscript',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Underline format\n *\n * Delta: { insert: \"text\", attributes: { underline: true } }\n */\nexport const underlineFormat: Format<boolean> = {\n name: 'underline',\n scope: 'inline',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Valid alignment values\n */\nexport type AlignType = 'left' | 'center' | 'right' | 'justify';\n\nconst VALID_ALIGN_TYPES: AlignType[] = ['left', 'center', 'right', 'justify'];\n\n/**\n * Text alignment format\n *\n * Delta: { insert: \"\\n\", attributes: { align: \"center\" } }\n */\nexport const alignFormat: Format<AlignType> = {\n name: 'align',\n scope: 'block',\n\n normalize(value: AlignType): AlignType {\n return value.toLowerCase() as AlignType;\n },\n\n validate(value: AlignType): boolean {\n return VALID_ALIGN_TYPES.includes(value);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Blockquote format\n *\n * Delta: { insert: \"\\n\", attributes: { blockquote: true } }\n */\nexport const blockquoteFormat: Format<boolean> = {\n name: 'blockquote',\n scope: 'block',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Code block format\n *\n * Delta: { insert: \"\\n\", attributes: { \"code-block\": true } }\n * Delta: { insert: \"\\n\", attributes: { \"code-block\": \"javascript\" } }\n *\n * Value can be:\n * - true: generic code block\n * - string: language identifier for syntax highlighting\n */\nexport const codeBlockFormat: Format<boolean | string> = {\n name: 'code-block',\n scope: 'block',\n\n normalize(value: boolean | string): boolean | string {\n if (typeof value === 'string') {\n return value.toLowerCase().trim();\n }\n return value;\n },\n\n validate(value: boolean | string): boolean {\n if (value === true) {\n return true;\n }\n if (typeof value === 'string' && value.length > 0) {\n return true;\n }\n return false;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Header format (h1-h6)\n *\n * Delta: { insert: \"\\n\", attributes: { header: 1 } }\n *\n * Values: 1-6 (corresponding to h1-h6)\n */\nexport const headerFormat: Format<number> = {\n name: 'header',\n scope: 'block',\n\n normalize(value: number): number {\n // Clamp to valid range and ensure integer\n return Math.max(1, Math.min(6, Math.floor(value)));\n },\n\n validate(value: number): boolean {\n return Number.isInteger(value) && value >= 1 && value <= 6;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Header ID format — optional custom anchor id for headings\n *\n * Delta: { insert: \"\\n\", attributes: { header: 2, \"header-id\": \"getting-started\" } }\n *\n * When present, the heading gets this exact id in HTML output.\n * When absent, id is computed via slugify(text) at render time (if anchorLinks is enabled).\n *\n * Markdown: ## Title {#custom-id}\n */\nexport const headerIdFormat: Format<string> = {\n name: 'header-id',\n scope: 'block',\n\n normalize(value: string): string {\n return String(value).trim().toLowerCase();\n },\n\n validate(value: string): boolean {\n if (typeof value !== 'string') return false;\n const trimmed = value.trim();\n // Must be non-empty, valid HTML id: no whitespace, at least one char\n return trimmed.length > 0 && !/\\s/.test(trimmed);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Maximum indent level\n */\nconst MAX_INDENT = 8;\n\n/**\n * Indent format\n *\n * Delta: { insert: \"\\n\", attributes: { indent: 1 } }\n *\n * Values: 0-8 (0 = no indent)\n */\nexport const indentFormat: Format<number> = {\n name: 'indent',\n scope: 'block',\n\n normalize(value: number): number {\n // Clamp to valid range and ensure non-negative integer\n return Math.max(0, Math.min(MAX_INDENT, Math.floor(value)));\n },\n\n validate(value: number): boolean {\n return Number.isInteger(value) && value >= 0 && value <= MAX_INDENT;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Valid list types\n */\nexport type ListType = 'ordered' | 'bullet' | 'checked' | 'unchecked';\n\nconst VALID_LIST_TYPES: ListType[] = ['ordered', 'bullet', 'checked', 'unchecked'];\n\n/**\n * List format\n *\n * Delta: { insert: \"\\n\", attributes: { list: \"ordered\" } }\n * Delta: { insert: \"\\n\", attributes: { list: \"bullet\" } }\n * Delta: { insert: \"\\n\", attributes: { list: \"checked\" } }\n * Delta: { insert: \"\\n\", attributes: { list: \"unchecked\" } }\n */\nexport const listFormat: Format<ListType> = {\n name: 'list',\n scope: 'block',\n\n normalize(value: ListType): ListType {\n return value.toLowerCase() as ListType;\n },\n\n validate(value: ListType): boolean {\n return VALID_LIST_TYPES.includes(value);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Table row index format\n *\n * Delta: { insert: \"\\n\", attributes: { \"table-row\": 0 } }\n */\nexport const tableRowFormat: Format<number> = {\n name: 'table-row',\n scope: 'block',\n\n validate(value: number): boolean {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Table column index format\n *\n * Delta: { insert: \"\\n\", attributes: { \"table-col\": 0 } }\n */\nexport const tableColFormat: Format<number> = {\n name: 'table-col',\n scope: 'block',\n\n validate(value: number): boolean {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Table header cell format\n *\n * Delta: { insert: \"\\n\", attributes: { \"table-header\": true } }\n *\n * When true, the cell is rendered as <th> inside <thead>.\n */\nexport const tableHeaderFormat: Format<boolean> = {\n name: 'table-header',\n scope: 'block',\n\n validate(value: boolean): boolean {\n return value === true;\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Valid table column alignment values\n */\nexport type TableColAlignType = 'left' | 'center' | 'right';\n\nconst VALID_ALIGNS: TableColAlignType[] = ['left', 'center', 'right'];\n\n/**\n * Table column alignment format\n *\n * Delta: { insert: \"\\n\", attributes: { \"table-col-align\": \"center\" } }\n *\n * Controls text-align of the column (rendered via style on <th>/<td>).\n * Compatible with GFM alignment syntax (:---|:---:|---:).\n */\nexport const tableColAlignFormat: Format<TableColAlignType> = {\n name: 'table-col-align',\n scope: 'block',\n\n normalize(value: TableColAlignType): TableColAlignType {\n return value.toLowerCase() as TableColAlignType;\n },\n\n validate(value: TableColAlignType): boolean {\n return VALID_ALIGNS.includes(value);\n },\n};\n","import type { Format } from '../../Format';\n\n/**\n * Block embed format — structural validation for complex block embeds.\n *\n * Delta: `{ insert: { block: { type: \"table\", ... } } }`\n *\n * This is the first level of two-level validation:\n * 1. blockFormat.validate() — structural: is it an object with `type`?\n * 2. BlockHandlerRegistry.get(type).validate() — semantic: is it a valid table?\n *\n * The `block` key is a **category**, not \"just another embed\".\n * It signals to converters and OT layer: \"nested structure, needs special handling\".\n */\nexport const blockFormat: Format<Record<string, unknown>> = {\n name: 'block',\n scope: 'embed',\n\n validate(value: Record<string, unknown>): boolean {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n typeof value.type === 'string' &&\n value.type.length > 0\n );\n },\n};\n","/**\n * HTML ↔ Delta Mapping Configuration\n *\n * Defines the mapping between HTML elements/attributes and Delta attributes.\n */\n\n/**\n * Inline format to HTML tag mapping\n *\n * Order matters for rendering: formats earlier in the list wrap formats later.\n * This creates a canonical nesting order for HTML output.\n */\nexport const INLINE_FORMAT_TAGS: Record<string, string> = {\n link: 'a',\n bold: 'strong',\n italic: 'em',\n underline: 'u',\n strike: 's',\n subscript: 'sub',\n superscript: 'sup',\n code: 'code',\n mark: 'mark',\n kbd: 'kbd',\n};\n\n/**\n * Order of inline formats for nesting (outer to inner)\n *\n * When rendering Delta to HTML, formats are nested in this order.\n * Example: bold + italic + code → <strong><em><code>text</code></em></strong>\n */\nexport const INLINE_FORMAT_ORDER: string[] = [\n 'link',\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'subscript',\n 'superscript',\n 'code',\n 'mark',\n 'kbd',\n];\n\n/**\n * Inline formats that use CSS styles instead of tags\n */\nexport const INLINE_STYLE_FORMATS: Record<string, string> = {\n color: 'color',\n background: 'background-color',\n font: 'font-family',\n size: 'font-size',\n};\n\n/**\n * Block format to HTML tag mapping\n */\nexport const BLOCK_FORMAT_TAGS: Record<string, string | ((value: unknown) => string)> = {\n header: (value: unknown) => `h${String(value)}`,\n blockquote: 'blockquote',\n 'code-block': 'pre',\n list: 'li', // Wrapped in ul/ol based on list type\n};\n\n/**\n * List type to wrapper tag mapping\n */\nexport const LIST_WRAPPER_TAGS: Record<string, string> = {\n ordered: 'ol',\n bullet: 'ul',\n checked: 'ul',\n unchecked: 'ul',\n};\n\n/**\n * Embed format to HTML renderer\n */\nexport type EmbedRenderer = (value: unknown, attributes?: Record<string, unknown>) => string;\n\nexport const EMBED_RENDERERS: Record<string, EmbedRenderer> = {\n image: (value, attrs) => {\n const src = typeof value === 'string' ? value : '';\n const altVal = attrs?.alt;\n const widthVal = attrs?.width;\n const heightVal = attrs?.height;\n const floatVal = attrs?.float;\n const alt =\n altVal != null && (typeof altVal === 'string' || typeof altVal === 'number')\n ? ` alt=\"${escapeHtml(String(altVal))}\"`\n : '';\n const width =\n widthVal != null && (typeof widthVal === 'string' || typeof widthVal === 'number')\n ? ` width=\"${String(widthVal)}\"`\n : '';\n const height =\n heightVal != null && (typeof heightVal === 'string' || typeof heightVal === 'number')\n ? ` height=\"${String(heightVal)}\"`\n : '';\n // Float: data-float attribute for CSS-driven text wrapping\n const float =\n floatVal != null && typeof floatVal === 'string' && floatVal !== 'none'\n ? ` data-float=\"${escapeHtml(floatVal)}\"`\n : '';\n return `<img src=\"${escapeHtml(src)}\"${alt}${width}${height}${float}>`;\n },\n\n video: (value, attrs) => {\n const src = typeof value === 'string' ? value : '';\n const floatVal = attrs?.float;\n const widthVal = attrs?.width;\n const heightVal = attrs?.height;\n // Float: data-float attribute for CSS-driven text wrapping\n const float =\n floatVal != null && typeof floatVal === 'string' && floatVal !== 'none'\n ? ` data-float=\"${escapeHtml(floatVal)}\"`\n : '';\n const styles: string[] = [];\n if (widthVal != null && (typeof widthVal === 'string' || typeof widthVal === 'number')) {\n const w = String(widthVal);\n if (w && w !== 'auto') styles.push(`width: ${/^\\d+$/.test(w) ? w + 'px' : w}`);\n }\n if (heightVal != null && (typeof heightVal === 'string' || typeof heightVal === 'number')) {\n const h = String(heightVal);\n if (h && h !== 'auto') styles.push(`height: ${/^\\d+$/.test(h) ? h + 'px' : h}`);\n }\n const style = styles.length > 0 ? ` style=\"${styles.join('; ')}\"` : '';\n const embedSrc = toVideoEmbedUrl(src);\n if (embedSrc) {\n return `<iframe src=\"${escapeHtml(embedSrc)}\" frameborder=\"0\" allowfullscreen${float}${style}></iframe>`;\n }\n return `<video src=\"${escapeHtml(src)}\" controls${float}${style}></video>`;\n },\n\n formula: (value) => {\n const latex = typeof value === 'string' ? value : '';\n return `<span class=\"formula\" data-formula=\"${escapeHtml(latex)}\">${escapeHtml(latex)}</span>`;\n },\n\n diagram: (value) => {\n const source = typeof value === 'string' ? value : '';\n return `<span class=\"diagram\" data-diagram=\"${escapeHtml(source)}\">${escapeHtml(source)}</span>`;\n },\n\n drawio: (value, attrs) => {\n const src = typeof value === 'string' ? value : '';\n const altVal = attrs?.alt;\n const alt =\n altVal != null && (typeof altVal === 'string' || typeof altVal === 'number')\n ? ` data-alt=\"${escapeHtml(String(altVal))}\"`\n : '';\n return `<span class=\"drawio\" data-drawio-src=\"${escapeHtml(src)}\"${alt}></span>`;\n },\n\n 'footnote-ref': (value) => {\n const id = typeof value === 'string' ? value : String(value);\n return `<sup class=\"footnote-ref\"><a href=\"#fn-${escapeHtml(id)}\" id=\"fnref-${escapeHtml(id)}\">[${escapeHtml(id)}]</a></sup>`;\n },\n\n divider: () => '<hr>',\n\n // Soft line break (Shift+Enter equivalent). Emitted with an explicit\n // `data-scrider-embed` marker so that html-to-delta can distinguish this\n // embed from the placeholder `<br>` that appears inside an empty\n // paragraph (`<p><br></p>`) without relying solely on positional\n // heuristics. See `soft-break.ts` for the format definition.\n softBreak: () => '<br data-scrider-embed>',\n};\n\n/**\n * HTML tag to inline format mapping (for parsing)\n */\nexport const TAG_TO_INLINE_FORMAT: Record<string, { format: string; value: unknown }> = {\n strong: { format: 'bold', value: true },\n b: { format: 'bold', value: true },\n em: { format: 'italic', value: true },\n i: { format: 'italic', value: true },\n u: { format: 'underline', value: true },\n ins: { format: 'underline', value: true },\n s: { format: 'strike', value: true },\n strike: { format: 'strike', value: true },\n del: { format: 'strike', value: true },\n sub: { format: 'subscript', value: true },\n sup: { format: 'superscript', value: true },\n code: { format: 'code', value: true },\n mark: { format: 'mark', value: true },\n kbd: { format: 'kbd', value: true },\n};\n\n/**\n * HTML tag to block format mapping (for parsing)\n */\nexport const TAG_TO_BLOCK_FORMAT: Record<string, { format: string; value: unknown }> = {\n h1: { format: 'header', value: 1 },\n h2: { format: 'header', value: 2 },\n h3: { format: 'header', value: 3 },\n h4: { format: 'header', value: 4 },\n h5: { format: 'header', value: 5 },\n h6: { format: 'header', value: 6 },\n blockquote: { format: 'blockquote', value: true },\n pre: { format: 'code-block', value: true },\n};\n\n/**\n * CSS text-align values to align format values\n */\nexport const CSS_ALIGN_TO_FORMAT: Record<string, string> = {\n left: 'left',\n center: 'center',\n right: 'right',\n justify: 'justify',\n};\n\n/**\n * Escape HTML special characters\n */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Unescape HTML entities\n */\nexport function unescapeHtml(text: string): string {\n return text\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/&/g, '&');\n}\n\n/**\n * Convert a video URL to an embeddable URL for rendering in <iframe>.\n * Returns null if the URL should be rendered as a <video> tag instead.\n *\n * Video rendering strategy:\n *\n * Service | Embed URL format | HTML tag\n * -------------|-------------------------------------------|----------\n * YouTube | youtube.com/embed/VIDEO_ID | <iframe>\n * VK Video | vkvideo.ru/video_ext.php?oid=&id=&hash= | <iframe>\n * Vimeo | player.vimeo.com/video/ID | <iframe>\n * Dailymotion | dailymotion.com/embed/video/ID | <iframe>\n * Direct file | example.com/video.mp4 | <video>\n *\n * Note: VK Video requires a `hash` parameter in the embed URL for security.\n * The hash can only be obtained from VK's \"Share → Embed\" dialog;\n * it cannot be computed from a regular vkvideo.ru/video-... page URL.\n *\n * Supported input URL conversions:\n * - youtube.com/embed/ID → pass through\n * - youtube.com/watch?v=ID → youtube.com/embed/ID\n * - youtu.be/ID → youtube.com/embed/ID\n * - player.vimeo.com/video/ID → pass through\n * - dailymotion.com/embed/... → pass through\n * - *://video_ext.php?... → pass through (VK Video embed)\n * - anything else → null (render as <video>)\n */\nexport function toVideoEmbedUrl(url: string): string | null {\n // Already an embed URL — pass through\n if (\n url.includes('youtube.com/embed') ||\n url.includes('player.vimeo.com') ||\n url.includes('dailymotion.com/embed') ||\n url.includes('video_ext.php') ||\n url.includes('rutube.ru/play/embed')\n ) {\n return url;\n }\n\n // YouTube watch URL: https://www.youtube.com/watch?v=VIDEO_ID\n const ytMatch = url.match(/youtube\\.com\\/watch\\?v=([\\w-]+)/);\n if (ytMatch) {\n return `https://www.youtube.com/embed/${ytMatch[1]}`;\n }\n\n // YouTube short URL: https://youtu.be/VIDEO_ID\n const ytShortMatch = url.match(/youtu\\.be\\/([\\w-]+)/);\n if (ytShortMatch) {\n return `https://www.youtube.com/embed/${ytShortMatch[1]}`;\n }\n\n // Rutube watch URL: https://rutube.ru/video/HASH/\n const rtMatch = url.match(/rutube\\.ru\\/video\\/([\\w]+)/);\n if (rtMatch) {\n return `https://rutube.ru/play/embed/${rtMatch[1]}`;\n }\n\n return null;\n}\n\n/**\n * Convert an embed URL back to a canonical video URL.\n * Used when parsing HTML (<iframe>) back to Delta.\n *\n * Conversions:\n * - YouTube embed → youtube.com/watch?v=ID (canonical)\n * - VK Video, Vimeo, Dailymotion, etc. → kept as-is\n * (VK Video hash cannot be reconstructed from canonical URL)\n */\nexport function fromVideoEmbedUrl(embedUrl: string): string {\n // YouTube embed → canonical watch URL\n const ytMatch = embedUrl.match(/youtube\\.com\\/embed\\/([\\w-]+)/);\n if (ytMatch) {\n return `https://www.youtube.com/watch?v=${ytMatch[1]}`;\n }\n\n // Rutube embed → canonical watch URL\n const rtMatch = embedUrl.match(/rutube\\.ru\\/play\\/embed\\/([\\w]+)/);\n if (rtMatch) {\n return `https://rutube.ru/video/${rtMatch[1]}/`;\n }\n\n // VK Video, Vimeo, Dailymotion, etc. — keep embed URL as-is\n // (VK Video requires hash parameter that can't be reconstructed)\n return embedUrl;\n}\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\n\n/**\n * Divider (Horizontal Rule) embed format\n *\n * Delta: { insert: { divider: true } }\n * HTML: <hr>\n * Markdown: ---\n *\n * Value is always `true` (no additional data needed)\n */\nexport const dividerFormat: Format<boolean> = {\n name: 'divider',\n scope: 'embed',\n\n normalize(value: boolean): boolean {\n return !!value;\n },\n\n validate(value: boolean): boolean {\n return value === true;\n },\n\n render(): string {\n return '<hr>';\n },\n\n match(element: DOMElement): FormatMatchResult<boolean> | null {\n if (element.tagName.toLowerCase() !== 'hr') return null;\n return { value: true };\n },\n};\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\nimport { isElement } from '../../../conversion/adapters/types';\nimport { escapeHtml } from '../../../conversion/html/config';\n\n/**\n * Footnote reference embed format\n *\n * Delta: { insert: { \"footnote-ref\": \"1\" } }\n *\n * Value is the footnote identifier string (e.g. \"1\", \"note\", \"my-ref\").\n * Rendered as superscript link in HTML: <sup class=\"footnote-ref\"><a href=\"#fn-1\">1</a></sup>\n * Markdown: [^1]\n */\nexport const footnoteRefFormat: Format<string> = {\n name: 'footnote-ref',\n scope: 'embed',\n\n validate(value: string): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n // Must be non-empty, no whitespace-only\n return value.trim().length > 0;\n },\n\n render(value: string): string {\n const id = typeof value === 'string' ? value : String(value);\n return `<sup class=\"footnote-ref\"><a href=\"#fn-${escapeHtml(id)}\" id=\"fnref-${escapeHtml(id)}\">[${escapeHtml(id)}]</a></sup>`;\n },\n\n match(element: DOMElement): FormatMatchResult<string> | null {\n if (element.tagName.toLowerCase() !== 'sup') return null;\n const className = element.getAttribute('class') || '';\n if (!className.includes('footnote-ref')) return null;\n\n // Extract id from nested <a href=\"#fn-{id}\">\n const children = element.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child && isElement(child)) {\n const href = child.getAttribute('href') || '';\n const hrefMatch = href.match(/#fn-(.+)/);\n if (hrefMatch?.[1]) {\n return { value: hrefMatch[1] };\n }\n }\n }\n\n // Fallback: try id attribute\n const id = element.getAttribute('id') || '';\n const refMatch = id.match(/^fnref-(.+)/);\n if (refMatch?.[1]) {\n return { value: refMatch[1] };\n }\n\n return null;\n },\n};\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\nimport { escapeHtml } from '../../../conversion/html/config';\n\n/**\n * Basic LaTeX validation patterns\n *\n * Checks for:\n * - Balanced braces\n * - Valid command structure\n */\nfunction isValidLatex(value: string): boolean {\n // Empty string is not valid\n if (!value || value.trim().length === 0) {\n return false;\n }\n\n // Check balanced braces\n let braceCount = 0;\n for (const char of value) {\n if (char === '{') braceCount++;\n if (char === '}') braceCount--;\n if (braceCount < 0) return false; // More closing than opening\n }\n if (braceCount !== 0) return false; // Unbalanced\n\n // Check balanced brackets\n let bracketCount = 0;\n for (const char of value) {\n if (char === '[') bracketCount++;\n if (char === ']') bracketCount--;\n if (bracketCount < 0) return false;\n }\n if (bracketCount !== 0) return false;\n\n // Check for invalid command patterns\n // Commands should be \\word not just backslash\n const invalidCommand = /\\\\(?![a-zA-Z]|\\\\|{|}|\\[|\\]|\\s|,|;|!|\\^|_)/;\n if (invalidCommand.test(value)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Formula (LaTeX) embed format\n *\n * Delta: { insert: { formula: \"E = mc^2\" } }\n *\n * Value is LaTeX string\n */\nexport const formulaFormat: Format<string> = {\n name: 'formula',\n scope: 'embed',\n\n normalize(value: string): string {\n // Trim whitespace but preserve internal formatting\n return value.trim();\n },\n\n validate(value: string): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n return isValidLatex(value);\n },\n\n render(value: string): string {\n const latex = typeof value === 'string' ? value : '';\n return `<span class=\"formula\" data-formula=\"${escapeHtml(latex)}\">${escapeHtml(latex)}</span>`;\n },\n\n match(element: DOMElement): FormatMatchResult<string> | null {\n if (element.tagName.toLowerCase() !== 'span') return null;\n const className = element.getAttribute('class') || '';\n if (!className.includes('formula')) return null;\n const formula = element.getAttribute('data-formula');\n if (!formula) return null;\n return { value: formula };\n },\n};\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\nimport type { AttributeMap } from '@scrider/delta';\nimport { escapeHtml } from '../../../conversion/html/config';\n\n/**\n * Image embed format\n *\n * Delta: { insert: { image: \"https://example.com/image.png\" } }\n *\n * Value is the image URL (http, https, data URI, or relative path)\n */\nexport const imageFormat: Format<string> = {\n name: 'image',\n scope: 'embed',\n\n normalize(value: string): string {\n return value.trim();\n },\n\n validate(value: string): boolean {\n if (typeof value !== 'string' || value.length === 0) {\n return false;\n }\n\n const trimmed = value.trim();\n\n // Data URI\n if (trimmed.startsWith('data:image/')) {\n return true;\n }\n\n // Relative paths\n if (trimmed.startsWith('/') || trimmed.startsWith('./') || trimmed.startsWith('../')) {\n return true;\n }\n\n // Protocol-relative\n if (trimmed.startsWith('//')) {\n return true;\n }\n\n // Absolute URLs\n try {\n const url = new URL(trimmed);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n },\n\n render(value: string, attributes?: AttributeMap): string {\n const src = typeof value === 'string' ? value : '';\n const altVal = attributes?.alt;\n const widthVal = attributes?.width;\n const heightVal = attributes?.height;\n const floatVal = attributes?.float;\n const alt =\n altVal != null && (typeof altVal === 'string' || typeof altVal === 'number')\n ? ` alt=\"${escapeHtml(String(altVal))}\"`\n : '';\n const width =\n widthVal != null && (typeof widthVal === 'string' || typeof widthVal === 'number')\n ? ` width=\"${String(widthVal)}\"`\n : '';\n const height =\n heightVal != null && (typeof heightVal === 'string' || typeof heightVal === 'number')\n ? ` height=\"${String(heightVal)}\"`\n : '';\n const float =\n floatVal != null && typeof floatVal === 'string' && floatVal !== 'none'\n ? ` data-float=\"${escapeHtml(floatVal)}\"`\n : '';\n return `<img src=\"${escapeHtml(src)}\"${alt}${width}${height}${float}>`;\n },\n\n match(element: DOMElement): FormatMatchResult<string> | null {\n if (element.tagName.toLowerCase() !== 'img') return null;\n const src = element.getAttribute('src');\n if (!src) return null;\n\n const attrs: AttributeMap = {};\n const alt = element.getAttribute('alt');\n const width = element.getAttribute('width');\n const height = element.getAttribute('height');\n const float = element.getAttribute('data-float');\n\n if (alt) attrs.alt = alt;\n if (width) attrs.width = parseInt(width, 10);\n if (height) attrs.height = parseInt(height, 10);\n if (float) attrs.float = float;\n\n if (Object.keys(attrs).length > 0) {\n return { value: src, attributes: attrs };\n }\n return { value: src };\n },\n};\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\n\n/**\n * Soft Line Break embed format\n *\n * Represents a \"Shift+Enter\" style line break that does NOT split the\n * containing block (paragraph, list item, table cell, etc.). This is the\n * Delta-level analogue of HTML `<br>` used as an inline line break and\n * of the GFM \"hard break\" Markdown construct (two trailing spaces + `\\n`).\n *\n * Delta: `{ insert: { softBreak: true } }`\n * HTML: `<br data-scrider-embed>` (with the explicit marker so that\n * round-trip parsing can distinguish a soft break from the\n * placeholder `<br>` that appears inside an empty paragraph)\n * Markdown: ` \\n` (default GFM hard break) or inline `<br>` (configurable\n * via `softBreakStyle` option on `deltaToMarkdown`)\n *\n * Value is always `true` — the embed has no additional data.\n *\n * @see {@link https://github.github.com/gfm/#hard-line-breaks GFM hard line break}\n */\nexport const softBreakFormat: Format<boolean> = {\n name: 'softBreak',\n scope: 'embed',\n\n normalize(value: boolean): boolean {\n return !!value;\n },\n\n validate(value: boolean): boolean {\n return value === true;\n },\n\n render(): string {\n return '<br data-scrider-embed>';\n },\n\n match(element: DOMElement): FormatMatchResult<boolean> | null {\n if (element.tagName.toLowerCase() !== 'br') return null;\n if (!element.hasAttribute('data-scrider-embed')) return null;\n return { value: true };\n },\n\n // NB: Markdown rendering is intentionally NOT implemented on the format\n // itself. The choice between `\" \\n\"` (GFM spaces) and inline `<br>`\n // depends on the caller-provided `softBreakStyle` option on\n // `deltaToMarkdown`, so the converter handles it as a built-in special\n // case instead of going through `Format.toMarkdown`. The Markdown side\n // of the round-trip is symmetric: `markdownToDelta` recognises both\n // `break` AST nodes and inline `<br>` HTML and emits this embed.\n};\n","import type { Format, FormatMatchResult } from '../../Format';\nimport type { DOMElement } from '../../../conversion/adapters/types';\nimport type { AttributeMap } from '@scrider/delta';\nimport { escapeHtml, toVideoEmbedUrl, fromVideoEmbedUrl } from '../../../conversion/html/config';\n\n/**\n * Video embed format\n *\n * Delta: { insert: { video: \"https://youtube.com/watch?v=...\" } }\n *\n * Value is the video URL\n */\nexport const videoFormat: Format<string> = {\n name: 'video',\n scope: 'embed',\n\n normalize(value: string): string {\n return value.trim();\n },\n\n validate(value: string): boolean {\n if (typeof value !== 'string' || value.length === 0) {\n return false;\n }\n\n const trimmed = value.trim();\n\n // Relative paths\n if (trimmed.startsWith('/') || trimmed.startsWith('./') || trimmed.startsWith('../')) {\n return true;\n }\n\n // Protocol-relative\n if (trimmed.startsWith('//')) {\n return true;\n }\n\n // Absolute URLs\n try {\n const url = new URL(trimmed);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n },\n\n render(value: string, attributes?: AttributeMap): string {\n const src = typeof value === 'string' ? value : '';\n const floatVal = attributes?.float;\n const widthVal = attributes?.width;\n const heightVal = attributes?.height;\n const float =\n floatVal != null && typeof floatVal === 'string' && floatVal !== 'none'\n ? ` data-float=\"${escapeHtml(floatVal)}\"`\n : '';\n const styles: string[] = [];\n if (widthVal != null && (typeof widthVal === 'string' || typeof widthVal === 'number')) {\n const w = String(widthVal);\n if (w && w !== 'auto') styles.push(`width: ${/^\\d+$/.test(w) ? w + 'px' : w}`);\n }\n if (heightVal != null && (typeof heightVal === 'string' || typeof heightVal === 'number')) {\n const h = String(heightVal);\n if (h && h !== 'auto') styles.push(`height: ${/^\\d+$/.test(h) ? h + 'px' : h}`);\n }\n const style = styles.length > 0 ? ` style=\"${styles.join('; ')}\"` : '';\n const embedSrc = toVideoEmbedUrl(src);\n if (embedSrc) {\n return `<iframe src=\"${escapeHtml(embedSrc)}\" frameborder=\"0\" allowfullscreen${float}${style}></iframe>`;\n }\n return `<video src=\"${escapeHtml(src)}\" controls${float}${style}></video>`;\n },\n\n match(element: DOMElement): FormatMatchResult<string> | null {\n const tagName = element.tagName.toLowerCase();\n if (tagName !== 'video' && tagName !== 'iframe') return null;\n\n const src = element.getAttribute('src');\n if (!src) return null;\n\n const attrs: AttributeMap = {};\n const float = element.getAttribute('data-float');\n const styleAttr = element.getAttribute('style') || '';\n\n if (float) attrs.float = float;\n\n // Extract width/height from inline style\n const widthMatch = styleAttr.match(/(?:^|;\\s*)width:\\s*([^;]+)/);\n if (widthMatch?.[1]) attrs.width = widthMatch[1].trim().replace(/px$/, '');\n const heightMatch = styleAttr.match(/(?:^|;\\s*)height:\\s*([^;]+)/);\n if (heightMatch?.[1]) attrs.height = heightMatch[1].trim().replace(/px$/, '');\n\n if (Object.keys(attrs).length > 0) {\n return { value: fromVideoEmbedUrl(src), attributes: attrs };\n }\n return { value: fromVideoEmbedUrl(src) };\n },\n};\n","import type { Format } from './Format';\nimport { Registry } from './Registry';\n\n// Inline formats\nimport {\n backgroundFormat,\n boldFormat,\n codeFormat,\n colorFormat,\n fontFormat,\n italicFormat,\n kbdFormat,\n linkFormat,\n markFormat,\n sizeFormat,\n strikeFormat,\n subscriptFormat,\n superscriptFormat,\n underlineFormat,\n} from './formats/inline';\n\n// Block formats\nimport {\n alignFormat,\n blockquoteFormat,\n codeBlockFormat,\n headerFormat,\n headerIdFormat,\n indentFormat,\n listFormat,\n tableRowFormat,\n tableColFormat,\n tableHeaderFormat,\n tableColAlignFormat,\n} from './formats/block';\n\n// Embed formats\nimport {\n blockFormat,\n dividerFormat,\n footnoteRefFormat,\n formulaFormat,\n imageFormat,\n softBreakFormat,\n videoFormat,\n} from './formats/embed';\n\n// Block handlers\nimport { BlockHandlerRegistry } from './BlockHandlerRegistry';\nimport { tableBlockHandler } from './blocks/table';\nimport { footnotesBlockHandler } from './blocks/footnotes';\nimport { alertBlockHandler } from './blocks/alert';\nimport { columnsBlockHandler } from './blocks/columns';\nimport { boxBlockHandler } from './blocks/box';\n\n/**\n * All default inline formats\n */\nexport const defaultInlineFormats: Format[] = [\n boldFormat,\n italicFormat,\n underlineFormat,\n strikeFormat,\n subscriptFormat,\n superscriptFormat,\n codeFormat,\n linkFormat,\n colorFormat,\n backgroundFormat,\n fontFormat,\n sizeFormat,\n markFormat,\n kbdFormat,\n];\n\n/**\n * All default block formats\n */\nexport const defaultBlockFormats: Format[] = [\n headerFormat,\n headerIdFormat,\n blockquoteFormat,\n codeBlockFormat,\n listFormat,\n alignFormat,\n indentFormat,\n tableRowFormat,\n tableColFormat,\n tableHeaderFormat,\n tableColAlignFormat,\n];\n\n/**\n * All default embed formats\n */\nexport const defaultEmbedFormats: Format[] = [\n imageFormat,\n videoFormat,\n formulaFormat,\n dividerFormat,\n softBreakFormat,\n blockFormat,\n footnoteRefFormat,\n];\n\n/**\n * All default formats combined\n */\nexport const defaultFormats: Format[] = [\n ...defaultInlineFormats,\n ...defaultBlockFormats,\n ...defaultEmbedFormats,\n];\n\n/**\n * Create a Registry with all default formats registered\n *\n * @returns Registry with standard formats\n *\n * @example\n * ```typescript\n * const registry = createDefaultRegistry();\n * registry.normalize({ color: 'red' }); // { color: '#ff0000' }\n * ```\n */\nexport function createDefaultRegistry(): Registry {\n return new Registry().register(defaultFormats);\n}\n\n/**\n * Create a BlockHandlerRegistry with default block handlers\n *\n * Includes:\n * - tableBlockHandler (Extended Table)\n * - footnotesBlockHandler (Footnotes)\n * - alertBlockHandler (Alerts/Admonitions)\n * - columnsBlockHandler (Columns Layout)\n * - boxBlockHandler (Inline-Box / Float Container)\n *\n * @returns BlockHandlerRegistry with default handlers\n *\n * @example\n * ```typescript\n * const blockHandlers = createDefaultBlockHandlers();\n * blockHandlers.has('table'); // true\n * blockHandlers.has('footnotes'); // true\n * blockHandlers.has('alert'); // true\n * blockHandlers.has('columns'); // true\n * blockHandlers.has('box'); // true\n * ```\n */\nexport function createDefaultBlockHandlers(): BlockHandlerRegistry {\n return new BlockHandlerRegistry()\n .register(tableBlockHandler)\n .register(footnotesBlockHandler)\n .register(alertBlockHandler)\n .register(columnsBlockHandler)\n .register(boxBlockHandler);\n}\n","/**\n * Browser DOM Adapter\n *\n * Uses native browser DOM APIs for HTML parsing and serialization.\n * Only available in browser environments.\n */\n\nimport type { DOMAdapter, DOMDocument, DOMDocumentFragment, DOMNode } from './types';\n\n/**\n * Browser DOM Adapter implementation\n *\n * Uses native browser APIs:\n * - DOMParser for parsing HTML\n * - Element.outerHTML for serialization\n */\nexport class BrowserDOMAdapter implements DOMAdapter {\n /**\n * Parse HTML string into a document fragment\n *\n * Uses a template element to parse arbitrary HTML safely.\n */\n parseHTML(html: string): DOMDocumentFragment {\n if (!this.isAvailable()) {\n throw new Error('BrowserDOMAdapter is not available in this environment');\n }\n\n const template = document.createElement('template');\n template.innerHTML = html;\n\n return template.content as unknown as DOMDocumentFragment;\n }\n\n /**\n * Serialize a node to HTML string\n */\n serializeHTML(node: DOMNode | DOMDocumentFragment): string {\n if (!this.isAvailable()) {\n throw new Error('BrowserDOMAdapter is not available in this environment');\n }\n\n // DocumentFragment - serialize all children\n if (node.nodeType === 11) {\n const container = document.createElement('div');\n const clone = (node as DocumentFragment).cloneNode(true);\n container.appendChild(clone);\n return container.innerHTML;\n }\n\n // Element - use outerHTML\n if (node.nodeType === 1) {\n return (node as unknown as Element).outerHTML;\n }\n\n // Text node - return text content\n if (node.nodeType === 3) {\n return String(node.textContent ?? '');\n }\n\n return '';\n }\n\n /**\n * Create a new document for building DOM structures\n */\n createDocument(): DOMDocument {\n if (!this.isAvailable()) {\n throw new Error('BrowserDOMAdapter is not available in this environment');\n }\n\n return document as unknown as DOMDocument;\n }\n\n /**\n * Check if browser DOM APIs are available\n */\n isAvailable(): boolean {\n return typeof document !== 'undefined' && typeof document.createElement === 'function';\n }\n}\n\n/**\n * Singleton instance of browser adapter\n */\nexport const browserAdapter = new BrowserDOMAdapter();\n","/**\n * Node.js DOM Adapter\n *\n * Uses jsdom for HTML parsing and serialization in Node.js environment.\n */\n\nimport type { DOMAdapter, DOMDocument, DOMDocumentFragment, DOMNode } from './types';\n\n// jsdom types - loaded dynamically\ninterface JsdomInstance {\n window: {\n document: Document;\n };\n}\n\ninterface JsdomConstructor {\n new (html: string): JsdomInstance;\n}\n\ninterface JsdomModuleType {\n JSDOM: JsdomConstructor;\n}\n\n/**\n * Cached jsdom module (lazy loaded)\n */\nlet jsdomModule: JsdomModuleType | null = null;\nlet jsdomLoadError: Error | null = null;\n\n/**\n * Attempt to load jsdom module\n */\nasync function loadJsdom(): Promise<JsdomModuleType> {\n if (jsdomLoadError) {\n throw jsdomLoadError;\n }\n\n if (jsdomModule) {\n return jsdomModule;\n }\n\n try {\n // Dynamic import for optional dependency\n const mod = await import('jsdom');\n jsdomModule = mod as unknown as JsdomModuleType;\n return jsdomModule;\n } catch {\n jsdomLoadError = new Error('jsdom is not installed. Install it with: pnpm add jsdom');\n throw jsdomLoadError;\n }\n}\n\n/**\n * Synchronously check if jsdom is available (without loading)\n */\nfunction isJsdomAvailable(): boolean {\n // In Node.js environment, we can check if the module exists\n if (typeof window !== 'undefined') {\n return false; // Browser environment\n }\n\n try {\n // Check if already loaded\n if (jsdomModule) return true;\n if (jsdomLoadError) return false;\n\n // Try to require jsdom (sync check)\n require.resolve('jsdom');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Node.js DOM Adapter implementation\n *\n * Uses jsdom for DOM operations in Node.js environment.\n * jsdom is loaded lazily to avoid issues in browser bundles.\n */\nexport class NodeDOMAdapter implements DOMAdapter {\n private jsdom: JsdomInstance | null = null;\n\n /**\n * Parse HTML string into a document fragment\n */\n parseHTML(html: string): DOMDocumentFragment {\n const dom = this.getOrCreateJsdom();\n const template = dom.window.document.createElement('template');\n template.innerHTML = html;\n\n return template.content as unknown as DOMDocumentFragment;\n }\n\n /**\n * Serialize a node to HTML string\n */\n serializeHTML(node: DOMNode | DOMDocumentFragment): string {\n const dom = this.getOrCreateJsdom();\n\n // DocumentFragment - serialize all children\n if (node.nodeType === 11) {\n const container = dom.window.document.createElement('div');\n const clone = (node as unknown as DocumentFragment).cloneNode(true);\n container.appendChild(clone);\n return container.innerHTML;\n }\n\n // Element - use outerHTML\n if (node.nodeType === 1) {\n return (node as unknown as Element).outerHTML;\n }\n\n // Text node - return text content\n if (node.nodeType === 3) {\n return String(node.textContent ?? '');\n }\n\n return '';\n }\n\n /**\n * Create a new document for building DOM structures\n */\n createDocument(): DOMDocument {\n const dom = this.getOrCreateJsdom();\n return dom.window.document as unknown as DOMDocument;\n }\n\n /**\n * Check if jsdom is available\n */\n isAvailable(): boolean {\n return isJsdomAvailable();\n }\n\n /**\n * Initialize the adapter with jsdom (async)\n *\n * Call this before using the adapter if you want to handle\n * loading errors gracefully.\n */\n async initialize(): Promise<void> {\n const mod = await loadJsdom();\n this.jsdom = new mod.JSDOM('<!DOCTYPE html><html><body></body></html>');\n }\n\n /**\n * Get or create jsdom instance (sync, throws if not available)\n */\n private getOrCreateJsdom(): JsdomInstance {\n if (this.jsdom) {\n return this.jsdom;\n }\n\n // Synchronous require for already-resolved module\n if (!isJsdomAvailable()) {\n throw new Error('jsdom is not available. Install it with: pnpm add jsdom');\n }\n\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mod = require('jsdom') as JsdomModuleType;\n this.jsdom = new mod.JSDOM('<!DOCTYPE html><html><body></body></html>');\n\n return this.jsdom;\n }\n}\n\n/**\n * Singleton instance of Node adapter\n */\nexport const nodeAdapter = new NodeDOMAdapter();\n","/**\n * DOM Adapters\n *\n * Platform-agnostic DOM manipulation for HTML ↔ Delta conversion.\n */\n\nexport * from './types';\nexport { BrowserDOMAdapter, browserAdapter } from './browser';\nexport { NodeDOMAdapter, nodeAdapter } from './node';\n\nimport type { DOMAdapter } from './types';\nimport { browserAdapter } from './browser';\nimport { nodeAdapter } from './node';\n\n/**\n * Get the appropriate DOM adapter for the current environment\n *\n * - In browser: returns BrowserDOMAdapter (native DOM)\n * - In Node.js: returns NodeDOMAdapter (jsdom)\n *\n * @returns The appropriate DOM adapter\n * @throws Error if no adapter is available\n */\nexport function getAdapter(): DOMAdapter {\n if (browserAdapter.isAvailable()) {\n return browserAdapter;\n }\n\n if (nodeAdapter.isAvailable()) {\n return nodeAdapter;\n }\n\n throw new Error('No DOM adapter available. In Node.js, install jsdom: pnpm add jsdom');\n}\n\n/**\n * Check if any DOM adapter is available\n */\nexport function isAdapterAvailable(): boolean {\n return browserAdapter.isAvailable() || nodeAdapter.isAvailable();\n}\n","/**\n * Delta → HTML Conversion\n *\n * Converts a Delta document to an HTML string.\n */\n\nimport { Delta, isInsert, isEmbedInsert } from '@scrider/delta';\nimport type { Op, AttributeMap } from '@scrider/delta';\nimport type { BlockHandlerRegistry } from '../../schema/BlockHandlerRegistry';\nimport type { BlockContext } from '../../schema/BlockHandler';\nimport type { Registry } from '../../schema/Registry';\nimport {\n INLINE_FORMAT_ORDER,\n INLINE_FORMAT_TAGS,\n INLINE_STYLE_FORMATS,\n BLOCK_FORMAT_TAGS,\n LIST_WRAPPER_TAGS,\n EMBED_RENDERERS,\n escapeHtml,\n} from './config';\nimport { slugifyWithDedup } from '../utils/slugify';\nimport {\n documentPresentationStyleParts,\n joinStyleParts,\n resolveDocumentPresentation,\n type DocumentPresentation,\n} from './document-presentation';\nimport {\n buildTableCellStyleAttr,\n resolveTablePresentation,\n tableOpenTag,\n type TableCellAlign,\n type TablePresentation,\n} from './table-presentation';\n\nexport type { TableCellAlign, TablePresentation, DocumentPresentation };\n\n/**\n * Options for Delta → HTML conversion\n */\nexport interface DeltaToHtmlOptions {\n /**\n * Pretty print output with indentation\n * @default false\n */\n pretty?: boolean;\n\n /**\n * Custom embed renderers (merged with defaults)\n */\n embedRenderers?: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>;\n\n /**\n * Wrap output in a container element\n * @default undefined (no wrapper)\n */\n wrapper?: string;\n\n /**\n * Use semantic HTML5 elements\n * @default true\n */\n semantic?: boolean;\n\n /**\n * Use hierarchical numbering for ordered lists (e.g., 1, 1.1, 1.1.1)\n * When enabled, list items get data-number attribute with calculated number\n * @default false\n */\n hierarchicalNumbers?: boolean;\n\n /**\n * Block handler registry for complex block embeds (Extended Table, etc.)\n * When provided, `{ insert: { block: { type, ... } } }` ops are dispatched\n * to the matching BlockHandler.toHtml() for rendering.\n */\n blockHandlers?: BlockHandlerRegistry;\n\n /**\n * Generate anchor link `id` attributes on heading elements (`<h1>`-`<h6>`).\n *\n * When enabled, headings get an `id` computed via slugify(text).\n * If a heading has an explicit `header-id` attribute in Delta, that id is used instead.\n * Duplicate slugs are deduplicated with `-1`, `-2` suffixes.\n *\n * @default false\n */\n anchorLinks?: boolean;\n\n /**\n * Format registry for custom embed rendering.\n *\n * When provided, embed formats with a `render()` method are used\n * before falling back to built-in EMBED_RENDERERS.\n * This enables extensibility without modifying converter internals.\n */\n registry?: Registry;\n\n /**\n * Simple Table presentation (borders, shades, header style) as inline CSS for\n * Office/HTML export and clipboard. Does not change Delta; omitted = legacy bare `<table>`.\n */\n tablePresentation?: TablePresentation;\n\n /**\n * Document-level paragraph styles (line spacing, first-line indent) as inline CSS for\n * Office/HTML export and clipboard. Does not change Delta.\n */\n documentPresentation?: DocumentPresentation;\n}\n\n/**\n * Line content with its formatting\n */\ninterface LineContent {\n ops: Op[];\n attributes: AttributeMap | undefined;\n}\n\n/**\n * Convert a Delta to an HTML string\n *\n * @param delta - The Delta to convert\n * @param options - Conversion options\n * @returns HTML string\n *\n * @example\n * ```typescript\n * const delta = new Delta()\n * .insert('Hello ', { bold: true })\n * .insert('World')\n * .insert('\\n', { header: 1 });\n *\n * const html = deltaToHtml(delta);\n * // '<h1><strong>Hello </strong>World</h1>'\n * ```\n */\nexport function deltaToHtml(delta: Delta, options: DeltaToHtmlOptions = {}): string {\n const lines = splitIntoLines(delta);\n const embedRenderers = { ...EMBED_RENDERERS, ...options.embedRenderers };\n const pretty = options.pretty ?? false;\n const hierarchicalNumbers = options.hierarchicalNumbers ?? false;\n const blockHandlers = options.blockHandlers;\n const anchorLinks = options.anchorLinks ?? false;\n const resolvedDocumentPresentation = resolveDocumentPresentation(options.documentPresentation);\n\n let html = '';\n let listStack: { type: string; indent: number }[] = [];\n\n // Hierarchical numbering counters: counters[0] = top level, counters[1] = first nested, etc.\n let counters: number[] = [];\n\n // Slug deduplication map for anchor links on headings\n const slugUsageMap = new Map<string, number>();\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (!line) continue;\n\n // Handle table grouping (adjacent lines with table-row attribute)\n if (isTableLine(line)) {\n html += closeAllLists(listStack, pretty);\n listStack = [];\n counters = [];\n\n const tableLines = collectTableLines(lines, i);\n html += renderTable(tableLines, embedRenderers, pretty, blockHandlers, options);\n i += tableLines.length - 1;\n continue;\n }\n\n const { tag, isList, listType, indent, isCodeBlock } = getBlockInfo(line.attributes);\n\n // Handle code block grouping (similar to lists)\n if (isCodeBlock) {\n // Close any open lists first\n html += closeAllLists(listStack, pretty);\n listStack = [];\n counters = [];\n\n // Collect all adjacent code-block lines\n const codeLines = collectCodeBlockLines(lines, i);\n const language = getCodeBlockLanguage(line.attributes);\n html += renderCodeBlock(codeLines, language, embedRenderers, pretty, blockHandlers, options);\n i += codeLines.length - 1; // Skip processed lines\n continue;\n }\n\n // Handle block-level embeds (e.g. <hr>) — render directly without <p> wrapper\n if (!isList && isBlockLevelEmbedLine(line)) {\n html += closeAllLists(listStack, pretty);\n listStack = [];\n counters = [];\n html += renderLineContent(line.ops, embedRenderers, blockHandlers, options);\n if (pretty) html += '\\n';\n continue;\n }\n\n // Handle list nesting\n if (isList) {\n html += handleListOpen(listStack, listType!, indent, pretty);\n\n // Update hierarchical counters for ordered lists\n if (hierarchicalNumbers && listType === 'ordered') {\n // Trim counters if we went back to a higher level\n if (counters.length > indent + 1) {\n counters = counters.slice(0, indent + 1);\n }\n // Extend counters if we went deeper\n // Use 1 for skipped parent levels (handles broken lists starting with nested items)\n while (counters.length < indent) {\n counters.push(1);\n }\n if (counters.length === indent) {\n counters.push(0); // Current level starts at 0, will be incremented below\n }\n // Increment counter at current level\n counters[indent] = (counters[indent] || 0) + 1;\n }\n } else {\n html += closeAllLists(listStack, pretty);\n listStack = [];\n // Reset counters when exiting list context\n counters = [];\n }\n\n // Render line content\n const content = renderLineContent(line.ops, embedRenderers, blockHandlers, options);\n\n // Wrap in block tag\n if (isList) {\n const listItemAttrs = getListItemAttributes(line.attributes);\n const indentLevel = listStack.length;\n\n // Calculate hierarchical number if enabled\n let hierarchicalNumber: string | undefined;\n if (hierarchicalNumbers && listType === 'ordered') {\n hierarchicalNumber = counters.slice(0, indent + 1).join('.');\n }\n\n html += renderListItem(\n content,\n listItemAttrs,\n pretty,\n indentLevel,\n hierarchicalNumber,\n resolvedDocumentPresentation,\n );\n } else {\n // Generate anchor id for headings\n let headingId: string | undefined;\n if (line.attributes?.header) {\n const customId = line.attributes['header-id'];\n if (typeof customId === 'string' && customId.length > 0) {\n headingId = customId;\n } else if (anchorLinks) {\n const plainText = extractPlainText(line.ops);\n headingId = slugifyWithDedup(plainText, slugUsageMap);\n }\n }\n html += renderBlock(\n content,\n tag,\n line.attributes,\n pretty,\n headingId,\n resolvedDocumentPresentation,\n );\n }\n }\n\n // Close any remaining lists\n html += closeAllLists(listStack, pretty);\n\n // Wrap in container if specified\n if (options.wrapper) {\n html = `<${options.wrapper}>${html}</${options.wrapper}>`;\n }\n\n return html;\n}\n\n/**\n * Get indentation string for pretty printing\n */\nfunction getIndent(level: number): string {\n return ' '.repeat(level);\n}\n\n/**\n * Split Delta into lines based on \\n characters\n */\nfunction splitIntoLines(delta: Delta): LineContent[] {\n const lines: LineContent[] = [];\n let currentOps: Op[] = [];\n\n for (const op of delta.ops) {\n if (!isInsert(op)) continue;\n\n if (isEmbedInsert(op)) {\n // Embeds are inline, add to current line\n currentOps.push(op);\n continue;\n }\n\n // Text insert - split by newlines\n const text = op.insert as string;\n const parts = text.split('\\n');\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n if (part === undefined) continue;\n\n // Add text content to current line\n if (part.length > 0) {\n currentOps.push({\n insert: part,\n ...(op.attributes && { attributes: op.attributes }),\n });\n }\n\n // If not the last part, this is a line break\n if (i < parts.length - 1) {\n lines.push({\n ops: currentOps,\n attributes: op.attributes, // Line attributes come from the \\n op\n });\n currentOps = [];\n }\n }\n }\n\n // Handle remaining content (no trailing \\n)\n if (currentOps.length > 0) {\n lines.push({\n ops: currentOps,\n attributes: undefined,\n });\n }\n\n return lines;\n}\n\n/**\n * Check if a line contains only a block-level embed (e.g. divider/hr).\n * These embeds should be rendered directly without a <p> wrapper,\n * since they are block-level void elements in HTML.\n *\n * Embeds with a `float` attribute are also treated as block-level,\n * because floated elements (images, videos) should not be wrapped in `<p>`.\n */\nconst BLOCK_LEVEL_EMBEDS = new Set(['divider', 'block']);\n\nfunction isBlockLevelEmbedLine(line: LineContent): boolean {\n if (line.ops.length !== 1) return false;\n const op = line.ops[0];\n if (!op || !isEmbedInsert(op)) return false;\n const embed = op.insert as Record<string, unknown>;\n const embedType = Object.keys(embed)[0];\n if (!!embedType && BLOCK_LEVEL_EMBEDS.has(embedType)) return true;\n // Embeds with float attribute are block-level (no <p> wrapper needed)\n const attrs = op.attributes as Record<string, unknown> | undefined;\n if (attrs && typeof attrs.float === 'string' && attrs.float !== 'none') return true;\n return false;\n}\n\n/**\n * Check if a line is a table cell\n */\nfunction isTableLine(line: LineContent): boolean {\n return (\n line.attributes != null &&\n typeof line.attributes['table-row'] === 'number' &&\n typeof line.attributes['table-col'] === 'number'\n );\n}\n\n/**\n * Collect all adjacent table lines starting from the given index\n */\nfunction collectTableLines(lines: LineContent[], startIndex: number): LineContent[] {\n const result: LineContent[] = [];\n for (let i = startIndex; i < lines.length; i++) {\n const line = lines[i];\n if (!line || !isTableLine(line)) break;\n result.push(line);\n }\n return result;\n}\n\n/**\n * Grouped cell data for rendering\n */\ninterface TableCell {\n ops: Op[];\n colAlign?: string | undefined;\n}\n\n/**\n * Render a group of table lines as an HTML <table>\n */\nfunction renderTable(\n tableLines: LineContent[],\n embedRenderers: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>,\n pretty: boolean,\n blockHandlers?: BlockHandlerRegistry,\n options?: DeltaToHtmlOptions,\n): string {\n // Group lines by row, preserving column order\n const rows = new Map<number, { isHeader: boolean; cells: Map<number, TableCell> }>();\n\n for (const line of tableLines) {\n const attrs = line.attributes!;\n const rowIdx = attrs['table-row'] as number;\n const colIdx = attrs['table-col'] as number;\n\n if (!rows.has(rowIdx)) {\n rows.set(rowIdx, { isHeader: !!attrs['table-header'], cells: new Map() });\n }\n\n const row = rows.get(rowIdx)!;\n if (attrs['table-header']) row.isHeader = true;\n row.cells.set(colIdx, {\n ops: line.ops,\n colAlign: typeof attrs['table-col-align'] === 'string' ? attrs['table-col-align'] : undefined,\n });\n }\n\n // Sort rows by index\n const sortedRows = [...rows.entries()].sort((a, b) => a[0] - b[0]);\n\n // Determine max columns\n let maxCol = 0;\n for (const [, row] of sortedRows) {\n for (const colIdx of row.cells.keys()) {\n if (colIdx > maxCol) maxCol = colIdx;\n }\n }\n\n // Separate header and body rows\n const headerRows = sortedRows.filter(([, r]) => r.isHeader);\n const bodyRows = sortedRows.filter(([, r]) => !r.isHeader);\n\n const indent = pretty ? ' ' : '';\n const nl = pretty ? '\\n' : '';\n const usePresentation = options?.tablePresentation !== undefined;\n const presentation = usePresentation ? resolveTablePresentation(options.tablePresentation) : null;\n const headerRowCount = headerRows.length;\n\n let html = usePresentation && presentation ? `${tableOpenTag(presentation)}${nl}` : `<table>${nl}`;\n\n // Render <thead>\n if (headerRows.length > 0) {\n html += `${indent}<thead>${nl}`;\n for (const [, row] of headerRows) {\n html += renderTableRow(\n row.cells,\n maxCol,\n 'th',\n embedRenderers,\n pretty,\n 2,\n blockHandlers,\n options,\n presentation,\n headerRowCount,\n );\n }\n html += `${indent}</thead>${nl}`;\n }\n\n // Render <tbody>\n if (bodyRows.length > 0) {\n html += `${indent}<tbody>${nl}`;\n let bodyRowIndex = 0;\n for (const [, row] of bodyRows) {\n html += renderTableRow(\n row.cells,\n maxCol,\n 'td',\n embedRenderers,\n pretty,\n 2,\n blockHandlers,\n options,\n presentation,\n headerRowCount,\n bodyRowIndex,\n );\n bodyRowIndex += 1;\n }\n html += `${indent}</tbody>${nl}`;\n }\n\n html += `</table>`;\n if (pretty) html += '\\n';\n return html;\n}\n\n/**\n * Render a single table row (<tr>)\n */\nfunction renderTableRow(\n cells: Map<number, TableCell>,\n maxCol: number,\n cellTag: 'th' | 'td',\n embedRenderers: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>,\n pretty: boolean,\n depth: number,\n blockHandlers?: BlockHandlerRegistry,\n options?: DeltaToHtmlOptions,\n presentation?: ReturnType<typeof resolveTablePresentation> | null,\n headerRowCount = 0,\n bodyRowIndex?: number,\n): string {\n const indent = pretty ? ' '.repeat(depth) : '';\n const cellIndent = pretty ? ' '.repeat(depth + 1) : '';\n const nl = pretty ? '\\n' : '';\n\n let html = `${indent}<tr>${nl}`;\n\n for (let col = 0; col <= maxCol; col++) {\n const cell = cells.get(col);\n const content = cell ? renderLineContent(cell.ops, embedRenderers, blockHandlers, options) : '';\n let styleAttr = '';\n if (presentation) {\n styleAttr = buildTableCellStyleAttr({\n presentation,\n cellTag,\n colAlign: cell?.colAlign,\n headerRowCount,\n bodyRowIndex: cellTag === 'td' ? bodyRowIndex : undefined,\n });\n } else {\n styleAttr =\n cell?.colAlign && cell.colAlign !== 'left' ? ` style=\"text-align: ${cell.colAlign}\"` : '';\n }\n html += `${cellIndent}<${cellTag}${styleAttr}>${content}</${cellTag}>${nl}`;\n }\n\n html += `${indent}</tr>${nl}`;\n return html;\n}\n\n/**\n * Get block element info from line attributes\n */\nfunction getBlockInfo(attributes: AttributeMap | undefined): {\n tag: string;\n isList: boolean;\n isCodeBlock: boolean;\n listType: string | undefined;\n indent: number;\n} {\n if (!attributes) {\n return { tag: 'p', isList: false, isCodeBlock: false, listType: undefined, indent: 0 };\n }\n\n const indent = typeof attributes.indent === 'number' ? attributes.indent : 0;\n\n // Check for code block (handled separately with grouping)\n if (attributes['code-block']) {\n return { tag: 'pre', isList: false, isCodeBlock: true, listType: undefined, indent };\n }\n\n // Check for list\n if (attributes.list) {\n const listVal = attributes.list;\n const listType = typeof listVal === 'string' ? listVal : 'bullet';\n return { tag: 'li', isList: true, isCodeBlock: false, listType, indent };\n }\n\n // Check for other block formats\n for (const [format, tagOrFn] of Object.entries(BLOCK_FORMAT_TAGS)) {\n if (format in attributes && format !== 'list' && format !== 'code-block') {\n const tag = typeof tagOrFn === 'function' ? tagOrFn(attributes[format]) : tagOrFn;\n return { tag, isList: false, isCodeBlock: false, listType: undefined, indent };\n }\n }\n\n return { tag: 'p', isList: false, isCodeBlock: false, listType: undefined, indent };\n}\n\n/**\n * Collect consecutive code block lines (same language)\n */\nfunction collectCodeBlockLines(lines: LineContent[], startIndex: number): LineContent[] {\n const codeLines: LineContent[] = [];\n const startLine = lines[startIndex];\n if (!startLine) return codeLines;\n\n const startLang = getCodeBlockLanguage(startLine.attributes);\n\n for (let i = startIndex; i < lines.length; i++) {\n const line = lines[i];\n if (!line || !line.attributes?.['code-block']) break;\n\n const lang = getCodeBlockLanguage(line.attributes);\n if (i > startIndex && lang !== startLang) break;\n\n codeLines.push(line);\n }\n\n return codeLines;\n}\n\n/**\n * Get language from code-block attribute\n */\nfunction getCodeBlockLanguage(attributes: AttributeMap | undefined): string | undefined {\n if (!attributes) return undefined;\n const codeBlock = attributes['code-block'];\n if (typeof codeBlock === 'string' && codeBlock !== 'true') {\n return codeBlock;\n }\n return undefined;\n}\n\n/**\n * Render a code block (grouped lines)\n */\nfunction renderCodeBlock(\n codeLines: LineContent[],\n language: string | undefined,\n embedRenderers: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>,\n pretty: boolean,\n blockHandlers?: BlockHandlerRegistry,\n options?: DeltaToHtmlOptions,\n): string {\n // Render each line's content (no HTML escaping of structure — just text)\n const lineContents = codeLines.map((line) =>\n renderLineContent(line.ops, embedRenderers, blockHandlers, options),\n );\n const code = lineContents.join('\\n');\n\n const langClass = language ? ` class=\"language-${escapeHtml(language)}\"` : '';\n const langAttr = language ? ` data-language=\"${escapeHtml(language)}\"` : '';\n const html = `<pre${langAttr}><code${langClass}>${code}\\n</code></pre>`;\n return pretty ? html + '\\n' : html;\n}\n\n/**\n * Handle opening list tags based on indent level\n */\nfunction handleListOpen(\n stack: { type: string; indent: number }[],\n listType: string,\n indent: number,\n pretty: boolean,\n): string {\n let html = '';\n const wrapperTag = LIST_WRAPPER_TAGS[listType] || 'ul';\n\n // Close lists that are at higher indent levels\n while (stack.length > 0) {\n const last = stack[stack.length - 1];\n if (!last || last.indent <= indent) break;\n const closed = stack.pop();\n if (closed) {\n const closeTag = LIST_WRAPPER_TAGS[closed.type] || 'ul';\n if (pretty) html += getIndent(stack.length);\n html += `</${closeTag}>`;\n if (pretty) html += '\\n';\n }\n }\n\n // Close and reopen if list type changed at same level\n const top = stack[stack.length - 1];\n if (top && top.indent === indent && top.type !== listType) {\n const closed = stack.pop();\n if (closed) {\n const closeTag = LIST_WRAPPER_TAGS[closed.type] || 'ul';\n if (pretty) html += getIndent(stack.length);\n html += `</${closeTag}>`;\n if (pretty) html += '\\n';\n }\n }\n\n // Open new lists as needed\n while (true) {\n const last = stack[stack.length - 1];\n const currentIndent = last ? last.indent + 1 : 0;\n\n if (currentIndent > indent) break;\n\n if (pretty) html += getIndent(stack.length);\n html += `<${wrapperTag}>`;\n if (pretty) html += '\\n';\n stack.push({ type: listType, indent: currentIndent });\n\n if (currentIndent >= indent) break;\n }\n\n // Ensure list is open at current level\n const current = stack[stack.length - 1];\n if (!current || current.indent < indent) {\n if (pretty) html += getIndent(stack.length);\n html += `<${wrapperTag}>`;\n if (pretty) html += '\\n';\n stack.push({ type: listType, indent });\n }\n\n return html;\n}\n\n/**\n * Close all open lists\n */\nfunction closeAllLists(stack: { type: string; indent: number }[], pretty: boolean): string {\n let html = '';\n while (stack.length > 0) {\n const closed = stack.pop()!;\n const closeTag = LIST_WRAPPER_TAGS[closed.type] || 'ul';\n if (pretty) html += getIndent(stack.length);\n html += `</${closeTag}>`;\n if (pretty) html += '\\n';\n }\n return html;\n}\n\n/**\n * Get list item specific attributes (checked/unchecked)\n */\nfunction getListItemAttributes(attributes: AttributeMap | undefined): string {\n if (!attributes) return '';\n\n const listType = attributes.list;\n if (listType === 'checked') {\n return ' data-checked=\"true\"';\n }\n if (listType === 'unchecked') {\n return ' data-checked=\"false\"';\n }\n\n return '';\n}\n\n/**\n * Render a list item\n */\nfunction renderListItem(\n content: string,\n attrs: string,\n pretty: boolean,\n indentLevel: number,\n hierarchicalNumber?: string,\n resolvedDocumentPresentation?: ReturnType<typeof resolveDocumentPresentation>,\n): string {\n const indent = pretty ? getIndent(indentLevel) : '';\n // Use <br> for empty list items so they have height in browser\n const innerContent = content || '<br>';\n\n // Add data-number attribute for hierarchical numbering\n let fullAttrs = attrs;\n if (hierarchicalNumber) {\n fullAttrs += ` data-number=\"${hierarchicalNumber}\"`;\n }\n\n const styleAttr = joinStyleParts(\n documentPresentationStyleParts('li', resolvedDocumentPresentation),\n );\n fullAttrs += styleAttr;\n\n const html = `${indent}<li${fullAttrs}>${innerContent}</li>`;\n return pretty ? html + '\\n' : html;\n}\n\n/**\n * Render a block element\n */\nfunction renderBlock(\n content: string,\n tag: string,\n attributes: AttributeMap | undefined,\n pretty?: boolean,\n id?: string,\n resolvedDocumentPresentation?: ReturnType<typeof resolveDocumentPresentation>,\n): string {\n const idAttr = id ? ` id=\"${escapeHtml(id)}\"` : '';\n const styleAttr = getBlockStyleAttribute(tag, attributes, resolvedDocumentPresentation);\n // Use <br> for empty paragraphs so they have height in browser\n const innerContent = content || '<br>';\n const html = `<${tag}${idAttr}${styleAttr}>${innerContent}</${tag}>`;\n return pretty ? html + '\\n' : html;\n}\n\n/**\n * Get style attribute for block element (alignment, document presentation, etc.)\n */\nfunction getBlockStyleAttribute(\n tag: string,\n attributes: AttributeMap | undefined,\n resolvedDocumentPresentation?: ReturnType<typeof resolveDocumentPresentation>,\n): string {\n const styles: string[] = documentPresentationStyleParts(tag, resolvedDocumentPresentation);\n\n if (attributes) {\n const alignVal = attributes.align;\n if (alignVal && typeof alignVal === 'string' && alignVal !== 'left') {\n styles.push(`text-align: ${alignVal}`);\n }\n\n if (attributes.indent && typeof attributes.indent === 'number') {\n // Skip indent for lists (handled by nesting)\n if (!attributes.list) {\n styles.push(`margin-left: ${attributes.indent * 2}em`);\n }\n }\n }\n\n return joinStyleParts(styles);\n}\n\n/**\n * Extract plain text from line ops (for slugify).\n * Walks insert ops, collecting text strings and ignoring embeds/formatting.\n */\nfunction extractPlainText(ops: Op[]): string {\n let text = '';\n for (const op of ops) {\n if (isInsert(op) && typeof op.insert === 'string') {\n text += op.insert;\n }\n }\n return text;\n}\n\n/**\n * Render line content (inline elements and embeds)\n */\nfunction renderLineContent(\n ops: Op[],\n embedRenderers: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>,\n blockHandlers?: BlockHandlerRegistry,\n options?: DeltaToHtmlOptions,\n): string {\n let html = '';\n\n for (const op of ops) {\n if (!isInsert(op)) continue;\n\n if (isEmbedInsert(op)) {\n html += renderEmbed(\n op.insert as Record<string, unknown>,\n op.attributes,\n embedRenderers,\n blockHandlers,\n options,\n );\n } else {\n html += renderInlineText(op.insert as string, op.attributes);\n }\n }\n\n return html;\n}\n\n/**\n * Render inline text with formatting\n */\nfunction renderInlineText(text: string, attributes: AttributeMap | undefined): string {\n if (!text) return '';\n\n let html = escapeHtml(text);\n\n if (!attributes) return html;\n\n // Apply style-based formats first (wrap in span if needed)\n const styles: string[] = [];\n for (const [format, cssProperty] of Object.entries(INLINE_STYLE_FORMATS)) {\n if (format in attributes) {\n styles.push(`${cssProperty}: ${String(attributes[format])}`);\n }\n }\n\n if (styles.length > 0) {\n html = `<span style=\"${styles.join('; ')}\">${html}</span>`;\n }\n\n // Apply tag-based formats (in reverse order for proper nesting)\n for (let i = INLINE_FORMAT_ORDER.length - 1; i >= 0; i--) {\n const format = INLINE_FORMAT_ORDER[i];\n if (!format) continue;\n if (!(format in attributes)) continue;\n\n const tag = INLINE_FORMAT_TAGS[format];\n if (!tag) continue;\n\n if (format === 'link') {\n const href = escapeHtml(String(attributes.link));\n html = `<a href=\"${href}\">${html}</a>`;\n } else {\n html = `<${tag}>${html}</${tag}>`;\n }\n }\n\n return html;\n}\n\n/**\n * Render an embed\n */\nfunction renderEmbed(\n value: Record<string, unknown>,\n attributes: AttributeMap | undefined,\n renderers: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>,\n blockHandlers?: BlockHandlerRegistry,\n options?: DeltaToHtmlOptions,\n): string {\n const embedType: string | undefined = Object.keys(value)[0];\n if (!embedType) return '';\n\n // Block embed dispatch: { block: { type: \"table\", ... } }\n if (embedType === 'block' && blockHandlers) {\n const blockData = value.block as Record<string, unknown>;\n if (blockData && typeof blockData.type === 'string') {\n const handler = blockHandlers.get(blockData.type);\n if (handler) {\n // Validate block data before rendering — skip invalid blocks gracefully\n if (handler.validate && !handler.validate(blockData)) {\n return ''; // invalid block data — skip\n }\n const context: BlockContext = {\n registry: null as unknown as Registry,\n options: { pretty: options?.pretty ?? false },\n renderDelta: (ops: Op[]) => deltaToHtml(new Delta(ops), options ?? {}),\n ...(attributes ? { opAttributes: attributes as Record<string, unknown> } : {}),\n };\n return handler.toHtml(blockData, context);\n }\n }\n return ''; // unknown block type — graceful fallback\n }\n\n const embedValue: unknown = value[embedType];\n\n // Check registry format render() first\n const registry = options?.registry;\n if (registry) {\n const format = registry.get(embedType);\n if (format?.render) {\n return format.render(embedValue, attributes);\n }\n }\n\n const renderer: ((value: unknown, attrs?: Record<string, unknown>) => string) | undefined =\n renderers[embedType];\n if (renderer) {\n return renderer(embedValue, attributes as Record<string, unknown> | undefined);\n }\n\n // Fallback: render as data attribute\n return `<span data-embed=\"${escapeHtml(embedType)}\" data-value=\"${escapeHtml(String(embedValue))}\"></span>`;\n}\n","/**\n * GitHub-compatible slugify for heading anchor links.\n *\n * Algorithm matches GitHub's heading-to-id conversion:\n * 1. Trim leading/trailing whitespace\n * 2. Convert to lowercase\n * 3. Remove everything except word characters (letters, digits, underscore),\n * spaces, hyphens (preserves Unicode letters via \\p{L})\n * 4. Replace spaces with hyphens\n * 5. Collapse consecutive hyphens\n * 6. Trim leading/trailing hyphens\n *\n * @param text - heading plain text content\n * @returns slugified string suitable for HTML id attribute\n *\n * @example\n * ```typescript\n * slugify('Getting Started'); // 'getting-started'\n * slugify('API Reference (v2)'); // 'api-reference-v2'\n * slugify('Что нового?'); // 'что-нового'\n * slugify(' Hello World '); // 'hello--world' → 'hello-world'\n * ```\n */\nexport function slugify(text: string): string {\n return (\n text\n .trim()\n .toLowerCase()\n // Remove everything except: letters (Unicode), digits, spaces, hyphens, underscores\n .replace(/[^\\p{L}\\p{N}\\s\\-_]/gu, '')\n // Replace whitespace with hyphens\n .replace(/\\s+/g, '-')\n // Collapse consecutive hyphens\n .replace(/-{2,}/g, '-')\n // Trim leading/trailing hyphens\n .replace(/^-+|-+$/g, '')\n );\n}\n\n/**\n * Slugify with deduplication: appends `-1`, `-2`, etc. on collision.\n *\n * Tracks used slugs via a Map. Call this for each heading in order during\n * a single document render pass.\n *\n * @param text - heading plain text content\n * @param usedSlugs - mutable map tracking slug usage counts\n * @returns unique slugified string\n *\n * @example\n * ```typescript\n * const used = new Map<string, number>();\n * slugifyWithDedup('FAQ', used); // 'faq'\n * slugifyWithDedup('FAQ', used); // 'faq-1'\n * slugifyWithDedup('FAQ', used); // 'faq-2'\n * ```\n */\nexport function slugifyWithDedup(text: string, usedSlugs: Map<string, number>): string {\n const base = slugify(text);\n const count = usedSlugs.get(base) ?? 0;\n usedSlugs.set(base, count + 1);\n\n if (count === 0) {\n return base;\n }\n return `${base}-${count}`;\n}\n","/**\n * Document-level HTML presentation for deltaToHtml (clipboard, export).\n * Not stored in Delta — mirrors editor Settings (line spacing, first-line indent).\n */\n\nexport interface DocumentPresentation {\n /** Line spacing multiplier, e.g. 1.5 */\n lineSpacing?: number;\n /** First-line indent in centimeters, e.g. 1.25 */\n textIndentCm?: number;\n}\n\nexport interface ResolvedDocumentPresentation {\n lineSpacing: number | undefined;\n textIndentCm: number | undefined;\n}\n\nexport function resolveDocumentPresentation(\n presentation?: DocumentPresentation,\n): ResolvedDocumentPresentation | undefined {\n if (!presentation) return undefined;\n\n const lineSpacing =\n typeof presentation.lineSpacing === 'number' && presentation.lineSpacing > 0\n ? presentation.lineSpacing\n : undefined;\n const textIndentCm =\n typeof presentation.textIndentCm === 'number' && presentation.textIndentCm > 0\n ? presentation.textIndentCm\n : undefined;\n\n if (lineSpacing === undefined && textIndentCm === undefined) return undefined;\n\n return { lineSpacing, textIndentCm };\n}\n\n/** Block tags that receive document line spacing (not headings). */\nconst LINE_HEIGHT_TAGS = new Set(['p', 'li', 'blockquote']);\n\n/** Block tags that receive document first-line indent (not headings). */\nconst TEXT_INDENT_TAGS = new Set(['p', 'li']);\n\nexport function documentPresentationStyleParts(\n tag: string,\n resolved: ResolvedDocumentPresentation | undefined,\n): string[] {\n if (!resolved) return [];\n\n const parts: string[] = [];\n\n if (resolved.lineSpacing !== undefined && LINE_HEIGHT_TAGS.has(tag)) {\n const pct = Math.round(resolved.lineSpacing * 100);\n parts.push(`line-height:${resolved.lineSpacing}`);\n parts.push(`mso-line-height-alt:${pct}%`);\n }\n\n if (resolved.textIndentCm !== undefined && TEXT_INDENT_TAGS.has(tag)) {\n parts.push(`text-indent:${resolved.textIndentCm}cm`);\n }\n\n return parts;\n}\n\nexport function joinStyleParts(parts: string[]): string {\n return parts.length > 0 ? ` style=\"${parts.join('; ')}\"` : '';\n}\n","/**\n * Simple Table HTML presentation options for deltaToHtml (clipboard, export).\n * Structural data stays in Delta (table-row, table-col-align); this only affects inline styles.\n */\n\n/** Column/cell horizontal alignment (GFM subset). */\nexport type TableCellAlign = 'left' | 'center' | 'right';\n\n/** Optional styling when serializing Simple Tables to HTML. */\nexport interface TablePresentation {\n /** Full 1px border on all cell sides. When true, `line` is ignored. */\n grid?: boolean;\n /** Bottom border only (DeepSeek / ChatGPT). Used when `grid` is not true. */\n line?: boolean;\n /** Border color as explicit hex (e.g. `#e7e7e7`). */\n borderColor?: string;\n /** Background on header cells (`th`). */\n headerShade?: boolean;\n /** Background on even table rows in the body (see `isZebraBodyRow`). */\n zebraRows?: boolean;\n /** `font-weight: bold` on `th`. */\n headerBold?: boolean;\n /** `text-align: center` on `th` (GitHub-style header). */\n headerCenter?: boolean;\n /**\n * Alignment for cells without `table-col-align` in Delta. Never overrides GFM column align.\n * @default 'left'\n */\n defaultCellAlign?: TableCellAlign;\n}\n\nconst DEFAULT_BORDER_COLOR = '#e7e7e7';\nconst DEFAULT_HEADER_BG = '#f5f5f5';\nconst DEFAULT_ZEBRA_BG = '#fafafa';\nconst CELL_PADDING = '6px 13px';\n\nexport interface ResolvedTablePresentation {\n grid: boolean;\n line: boolean;\n borderColor: string;\n headerShade: boolean;\n zebraRows: boolean;\n headerBold: boolean;\n headerCenter: boolean;\n defaultCellAlign: TableCellAlign;\n}\n\nexport function resolveTablePresentation(\n presentation?: TablePresentation,\n): ResolvedTablePresentation {\n return {\n grid: presentation?.grid === true,\n line: presentation?.line === true && presentation?.grid !== true,\n borderColor: presentation?.borderColor ?? DEFAULT_BORDER_COLOR,\n headerShade: presentation?.headerShade === true,\n zebraRows: presentation?.zebraRows === true,\n headerBold: presentation?.headerBold === true,\n headerCenter: presentation?.headerCenter === true,\n defaultCellAlign: presentation?.defaultCellAlign ?? 'left',\n };\n}\n\n/** Match CSS `tr:nth-child(even) td` when header rows precede body in `<table>`. */\nexport function isZebraBodyRow(headerRowCount: number, bodyRowIndex: number): boolean {\n return (headerRowCount + bodyRowIndex + 1) % 2 === 0;\n}\n\nfunction isTableCellAlign(value: string | undefined): value is TableCellAlign {\n return value === 'left' || value === 'center' || value === 'right';\n}\n\nexport function tableOpenTag(presentation: ResolvedTablePresentation): string {\n if (!presentation.grid && !presentation.line) {\n return '<table>';\n }\n return `<table style=\"border-collapse: collapse\">`;\n}\n\nexport interface TableCellStyleParams {\n presentation: ResolvedTablePresentation;\n cellTag: 'th' | 'td';\n colAlign?: string | undefined;\n headerRowCount: number;\n /** Index among body rows only (0 = first `<tr>` in `<tbody>`). */\n bodyRowIndex?: number | undefined;\n}\n\nexport function buildTableCellStyleAttr(params: TableCellStyleParams): string {\n const { presentation, cellTag, colAlign, headerRowCount, bodyRowIndex } = params;\n const parts: string[] = [];\n\n parts.push(`padding: ${CELL_PADDING}`);\n\n const color = presentation.borderColor;\n if (presentation.grid) {\n parts.push(`border: 1px solid ${color}`);\n } else if (presentation.line) {\n const width = cellTag === 'th' ? '1px' : '0.5px';\n parts.push(`border-bottom: ${width} solid ${color}`);\n }\n\n let textAlign: TableCellAlign | undefined;\n if (cellTag === 'th' && presentation.headerCenter) {\n textAlign = 'center';\n } else if (isTableCellAlign(colAlign)) {\n textAlign = colAlign;\n } else if (colAlign == null || colAlign === 'left') {\n textAlign = presentation.defaultCellAlign;\n }\n\n if (textAlign && textAlign !== 'left') {\n parts.push(`text-align: ${textAlign}`);\n }\n\n if (cellTag === 'th' && presentation.headerBold) {\n parts.push('font-weight: bold');\n }\n\n if (cellTag === 'th' && presentation.headerShade) {\n parts.push(`background-color: ${DEFAULT_HEADER_BG}`);\n } else if (\n cellTag === 'td' &&\n presentation.zebraRows &&\n bodyRowIndex !== undefined &&\n isZebraBodyRow(headerRowCount, bodyRowIndex)\n ) {\n parts.push(`background-color: ${DEFAULT_ZEBRA_BG}`);\n }\n\n return ` style=\"${parts.join('; ')}\"`;\n}\n","/**\n * HTML → Delta Conversion\n *\n * Converts HTML string to a Delta document.\n */\n\nimport { Delta } from '@scrider/delta';\nimport type { AttributeMap, Op } from '@scrider/delta';\nimport type { DOMAdapter, DOMNode, DOMElement } from '../adapters/types';\nimport { NODE_TYPE, isElement } from '../adapters/types';\nimport { getAdapter } from '../adapters';\nimport type { BlockHandlerRegistry } from '../../schema/BlockHandlerRegistry';\nimport type { BlockContext } from '../../schema/BlockHandler';\nimport type { Registry } from '../../schema/Registry';\nimport {\n TAG_TO_INLINE_FORMAT,\n TAG_TO_BLOCK_FORMAT,\n CSS_ALIGN_TO_FORMAT,\n fromVideoEmbedUrl,\n} from './config';\nimport { slugify } from '../utils/slugify';\n\n/**\n * Options for HTML → Delta conversion\n */\nexport interface HtmlToDeltaOptions {\n /**\n * DOM adapter to use (defaults to auto-detected)\n */\n adapter?: DOMAdapter;\n\n /**\n * Normalize whitespace (collapse multiple spaces, trim)\n * @default true\n */\n normalizeWhitespace?: boolean;\n\n /**\n * Custom tag handlers for special elements\n */\n tagHandlers?: Record<string, TagHandler>;\n\n /**\n * Block handler registry for Extended Table and other block embeds.\n * When provided and a handler for 'table' is registered,\n * `<table>` elements will be parsed as block embeds instead of Simple Table.\n */\n blockHandlers?: BlockHandlerRegistry;\n\n /**\n * Format registry for custom embed matching.\n *\n * When provided, embed formats with a `match()` method are tried\n * before falling back to built-in tag handlers (img, video, iframe, etc.).\n * This enables extensibility without modifying converter internals.\n */\n registry?: Registry;\n}\n\n/**\n * Custom tag handler function\n */\nexport type TagHandler = (element: DOMElement, context: ParserContext) => void;\n\n/**\n * Parser context passed to tag handlers\n */\nexport interface ParserContext {\n delta: Delta;\n attributes: AttributeMap;\n blockAttributes: AttributeMap;\n pushText(text: string): void;\n pushEmbed(embed: Record<string, unknown>, attrs?: AttributeMap): void;\n pushNewline(): void;\n}\n\n/**\n * Convert HTML string to Delta\n *\n * @param html - The HTML string to convert\n * @param options - Conversion options\n * @returns Delta document\n *\n * @example\n * ```typescript\n * const html = '<p><strong>Hello</strong> World</p>';\n * const delta = htmlToDelta(html);\n * // { ops: [\n * // { insert: 'Hello', attributes: { bold: true } },\n * // { insert: ' World\\n' }\n * // ]}\n * ```\n */\nexport function htmlToDelta(html: string, options: HtmlToDeltaOptions = {}): Delta {\n const adapter = options.adapter ?? getAdapter();\n const normalizeWhitespace = options.normalizeWhitespace ?? true;\n const tagHandlers = { ...DEFAULT_TAG_HANDLERS, ...options.tagHandlers };\n\n // Parse HTML\n const fragment = adapter.parseHTML(html);\n\n // Initialize delta and state\n const delta = new Delta();\n let currentAttributes: AttributeMap = {};\n let currentBlockAttributes: AttributeMap = {};\n let pendingText = '';\n let atLineStart = true; // Track if we're at the start of a line\n\n // Context for tag handlers\n const context: ParserContext = {\n delta,\n get attributes() {\n return { ...currentAttributes };\n },\n get blockAttributes() {\n return { ...currentBlockAttributes };\n },\n pushText(text: string) {\n if (normalizeWhitespace) {\n text = normalizeText(text, pendingText, atLineStart);\n }\n if (text) {\n pendingText += text;\n atLineStart = false;\n }\n },\n pushEmbed(embed: Record<string, unknown>, attrs?: AttributeMap) {\n // Flush pending text first\n flushText();\n const finalAttrs = { ...currentAttributes, ...attrs };\n if (Object.keys(finalAttrs).length > 0) {\n delta.insert(embed, finalAttrs);\n } else {\n delta.insert(embed);\n }\n atLineStart = false;\n },\n pushNewline() {\n flushText();\n const attrs = { ...currentBlockAttributes };\n if (Object.keys(attrs).length > 0) {\n delta.insert('\\n', attrs);\n } else {\n delta.insert('\\n');\n }\n currentBlockAttributes = {};\n atLineStart = true;\n },\n };\n\n /**\n * Flush pending text to delta\n */\n function flushText(): void {\n if (pendingText) {\n const attrs = { ...currentAttributes };\n if (Object.keys(attrs).length > 0) {\n delta.insert(pendingText, attrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n // Note: atLineStart is NOT reset here - we're still on the same line\n }\n }\n\n /**\n * Process a node recursively\n */\n function processNode(node: DOMNode): void {\n // Text node\n if (node.nodeType === NODE_TYPE.TEXT_NODE) {\n const text = node.textContent ?? '';\n context.pushText(text);\n return;\n }\n\n // Element node\n if (!isElement(node)) return;\n\n const tagName = node.tagName.toLowerCase();\n\n // Check for custom handler (supports \"tag\" and \"tag.class\" keys)\n const handler = findTagHandler(tagHandlers, node, tagName);\n if (handler) {\n handler(node, context);\n return;\n }\n\n // Check for block element\n const blockFormat = TAG_TO_BLOCK_FORMAT[tagName];\n if (blockFormat) {\n processBlockElement(node, blockFormat);\n return;\n }\n\n // Check for list element\n if (tagName === 'ul' || tagName === 'ol') {\n processListElement(node, tagName);\n return;\n }\n\n // Check for inline element\n const inlineFormat = TAG_TO_INLINE_FORMAT[tagName];\n if (inlineFormat) {\n processInlineElement(node, inlineFormat);\n return;\n }\n\n // Check for link\n if (tagName === 'a') {\n processLinkElement(node);\n return;\n }\n\n // Check for span with styles\n if (tagName === 'span') {\n processSpanElement(node);\n return;\n }\n\n // Check for table\n if (tagName === 'table') {\n processTableElement(node);\n return;\n }\n\n // Check registry embed formats (custom match before hardcoded handlers)\n if (options.registry) {\n const embedFormats = options.registry.getByScope('embed');\n for (const format of embedFormats) {\n if (format.match) {\n const result = format.match(node);\n if (result != null) {\n context.pushEmbed({ [format.name]: result.value }, result.attributes);\n return;\n }\n }\n }\n }\n\n // Check for embeds\n if (tagName === 'img') {\n processImageElement(node);\n return;\n }\n\n if (tagName === 'video' || tagName === 'iframe') {\n processVideoElement(node);\n return;\n }\n\n if (tagName === 'hr') {\n context.pushEmbed({ divider: true });\n context.pushNewline();\n return;\n }\n\n // Check for footnotes section: <section class=\"footnotes\">\n if (tagName === 'section' || tagName === 'div') {\n const className = node.getAttribute('class') || '';\n if (className.includes('footnotes')) {\n processFootnotesSection(node);\n return;\n }\n if (className.includes('markdown-alert')) {\n processAlertElement(node);\n return;\n }\n if (/\\bcolumns\\b/.test(className)) {\n processColumnsElement(node);\n return;\n }\n if (className.includes('inline-box')) {\n processBoxElement(node);\n return;\n }\n }\n\n // Check for paragraph/div (default block)\n if (tagName === 'p' || tagName === 'div') {\n processDefaultBlock(node);\n return;\n }\n\n // Check for br\n if (tagName === 'br') {\n // Soft line break disambiguation (Phase 7 Part 0):\n // 1. `<br data-scrider-embed>` — explicit marker emitted by our own\n // `deltaToHtml` for a `{ softBreak: true }` embed. Always treated\n // as an embed, regardless of position.\n // 2. `<br>` between content (sibling-aware heuristic) — typical for\n // browser-inserted Shift+Enter (`<p>foo<br>bar</p>`) or copy-paste\n // from rich-text sources. Treated as a softBreak embed.\n // 3. `<br>` at the start of a block / placeholder — treated as a\n // regular newline to preserve historical behaviour for the\n // `<p><br>text</p>` shape. The `<p><br></p>` (br-only) shape is\n // already short-circuited earlier by `processDefaultBlock`.\n // 4. Browser-added trailing line-box filler `<br>` (Phase 7 Part 0,\n // v1.3.3): a plain `<br>` whose immediately-preceding element is\n // ALSO a `<br>` and that has no semantic content after it inside\n // its parent block. contenteditable browsers append this marker\n // to give a trailing empty line a visual line-box; admitting it\n // as a softBreak embed corrupts the Delta (extra soft break that\n // survives subsequent edits and de-styles the parent block when\n // the user presses Enter/Backspace nearby).\n const hasMarker = node.hasAttribute('data-scrider-embed');\n if (hasMarker) {\n context.pushEmbed({ softBreak: true });\n return;\n }\n if (isBrowserEmptyLineFiller(node)) {\n // silently drop — it has no semantic meaning\n return;\n }\n if (hasMeaningfulPrevSibling(node)) {\n context.pushEmbed({ softBreak: true });\n } else {\n context.pushNewline();\n }\n return;\n }\n\n // Unknown element - process children\n processChildren(node);\n }\n\n /**\n * Process children of a node\n */\n function processChildren(node: DOMNode): void {\n const children = node.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child) processNode(child);\n }\n }\n\n /**\n * Process a block element (h1, blockquote, pre, etc.)\n */\n function processBlockElement(\n element: DOMElement,\n format: { format: string; value: unknown },\n ): void {\n // Special handling for <pre> — code blocks\n if (format.format === 'code-block') {\n processCodeBlockElement(element);\n return;\n }\n\n const prevBlockAttrs = { ...currentBlockAttributes };\n currentBlockAttributes[format.format] = format.value;\n\n // Add alignment if present\n const align = getAlignment(element);\n if (align) {\n currentBlockAttributes.align = align;\n }\n\n // Extract custom header id (only if different from computed slug)\n if (format.format === 'header') {\n const id = element.getAttribute('id');\n if (id) {\n const text = element.textContent || '';\n const computedSlug = slugify(text);\n if (id !== computedSlug) {\n currentBlockAttributes['header-id'] = id;\n }\n }\n }\n\n processChildren(element);\n context.pushNewline();\n\n currentBlockAttributes = prevBlockAttrs;\n }\n\n /**\n * Process a code block element (<pre>, possibly with <code> child)\n */\n function processCodeBlockElement(element: DOMElement): void {\n const prevBlockAttrs = { ...currentBlockAttributes };\n\n // Extract language from <code class=\"language-xxx\"> or <pre data-language=\"xxx\">\n let language: string | undefined;\n\n // Check <pre data-language=\"xxx\">\n const dataLang = element.getAttribute('data-language');\n if (dataLang) {\n language = dataLang;\n }\n\n // Check for <code class=\"language-xxx\"> child\n const children = element.childNodes;\n let codeElement: DOMElement | null = null;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child && isElement(child) && child.tagName.toLowerCase() === 'code') {\n codeElement = child;\n break;\n }\n }\n\n if (codeElement && !language) {\n const className = codeElement.getAttribute('class') || '';\n const match = className.match(/language-(\\S+)/);\n if (match?.[1]) {\n language = match[1];\n }\n }\n\n // Set code-block attribute with language or true\n const codeBlockValue: unknown = language || true;\n currentBlockAttributes['code-block'] = codeBlockValue;\n\n // Get text content from the code element or pre directly\n const sourceElement = codeElement || element;\n const rawText = sourceElement.textContent ?? '';\n\n // Remove trailing newline (code blocks always end with \\n in the HTML)\n const text = rawText.endsWith('\\n') ? rawText.slice(0, -1) : rawText;\n\n // Split by lines — each line gets its own code-block attribute\n const codeLines = text.split('\\n');\n for (let i = 0; i < codeLines.length; i++) {\n const line = codeLines[i];\n if (line !== undefined && line.length > 0) {\n flushText();\n pendingText = line;\n }\n flushText();\n const attrs = { ...currentBlockAttributes };\n if (Object.keys(attrs).length > 0) {\n delta.insert('\\n', attrs);\n } else {\n delta.insert('\\n');\n }\n atLineStart = true;\n }\n\n currentBlockAttributes = prevBlockAttrs;\n }\n\n /**\n * Process a list element (ul/ol)\n */\n function processListElement(element: DOMElement, listTag: string, indent: number = 0): void {\n const children = element.childNodes;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child)) continue;\n\n const childTag = child.tagName.toLowerCase();\n if (childTag === 'li') {\n processListItem(child, listTag, indent);\n } else if (childTag === 'ul' || childTag === 'ol') {\n // Nested list without li wrapper - increment indent\n processListElement(child, childTag, indent + 1);\n }\n }\n }\n\n /**\n * Process a list item\n */\n function processListItem(element: DOMElement, listTag: string, indent: number): void {\n const prevBlockAttrs = { ...currentBlockAttributes };\n\n // Determine list type\n let listType = listTag === 'ol' ? 'ordered' : 'bullet';\n\n // Check for checkbox (task list)\n const dataChecked = element.getAttribute('data-checked');\n if (dataChecked === 'true') {\n listType = 'checked';\n } else if (dataChecked === 'false') {\n listType = 'unchecked';\n }\n\n currentBlockAttributes.list = listType;\n if (indent > 0) {\n currentBlockAttributes.indent = indent;\n }\n\n // Process content, but handle nested lists specially\n const children = element.childNodes;\n let hasNestedList = false;\n\n // Check if this is an empty list item with only <br> for visibility\n // (generated by deltaToHtml for empty lines, or by browser on Enter)\n const firstChild = children[0];\n const isBrOnlyListItem =\n children.length === 1 &&\n firstChild !== undefined &&\n isElement(firstChild) &&\n firstChild.tagName.toLowerCase() === 'br';\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child) continue;\n\n if (isElement(child)) {\n const childTag = child.tagName.toLowerCase();\n if (childTag === 'ul' || childTag === 'ol') {\n // Flush current content before nested list\n if (!hasNestedList) {\n context.pushNewline();\n hasNestedList = true;\n }\n // Process nested list with increased indent\n processNestedList(child, childTag, indent + 1);\n continue;\n }\n }\n\n // Skip processing <br> in empty list items\n if (!hasNestedList && !isBrOnlyListItem) {\n processNode(child);\n }\n }\n\n if (!hasNestedList) {\n context.pushNewline();\n }\n\n currentBlockAttributes = prevBlockAttrs;\n }\n\n /**\n * Process a nested list\n */\n function processNestedList(element: DOMElement, listTag: string, indent: number): void {\n const children = element.childNodes;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child || !isElement(child)) continue;\n\n const childTag = child.tagName.toLowerCase();\n if (childTag === 'li') {\n processListItem(child, listTag, indent);\n }\n }\n }\n\n /**\n * Process an inline element (strong, em, etc.)\n */\n function processInlineElement(\n element: DOMElement,\n format: { format: string; value: unknown },\n ): void {\n // Flush before changing attributes\n flushText();\n\n const prevAttrs = { ...currentAttributes };\n currentAttributes[format.format] = format.value;\n\n processChildren(element);\n\n // Flush before restoring attributes\n flushText();\n currentAttributes = prevAttrs;\n }\n\n /**\n * Process a link element\n */\n function processLinkElement(element: DOMElement): void {\n const href = element.getAttribute('href');\n if (!href) {\n processChildren(element);\n return;\n }\n\n // Flush before changing attributes\n flushText();\n\n const prevAttrs = { ...currentAttributes };\n currentAttributes.link = href;\n\n processChildren(element);\n\n // Flush before restoring attributes\n flushText();\n currentAttributes = prevAttrs;\n }\n\n /**\n * Process a span element (for styles)\n */\n function processSpanElement(element: DOMElement): void {\n // Flush before changing attributes\n flushText();\n\n const prevAttrs = { ...currentAttributes };\n\n // Extract color\n const color = element.style?.color || element.style?.getPropertyValue?.('color');\n if (color) {\n currentAttributes.color = color;\n }\n\n // Extract background\n const bg =\n element.style?.backgroundColor || element.style?.getPropertyValue?.('background-color');\n if (bg) {\n currentAttributes.background = bg;\n }\n\n // Extract font-family\n const fontFamily =\n element.style?.fontFamily || element.style?.getPropertyValue?.('font-family');\n if (fontFamily) {\n currentAttributes.font = fontFamily.replace(/^[\"']|[\"']$/g, '');\n }\n\n // Extract font-size\n const fontSize = element.style?.fontSize || element.style?.getPropertyValue?.('font-size');\n if (fontSize) {\n currentAttributes.size = fontSize;\n }\n\n processChildren(element);\n\n // Flush before restoring attributes\n flushText();\n currentAttributes = prevAttrs;\n }\n\n /**\n * Process an image element\n */\n function processImageElement(element: DOMElement): void {\n const src = element.getAttribute('src');\n if (!src) return;\n\n const attrs: AttributeMap = {};\n const alt = element.getAttribute('alt');\n const width = element.getAttribute('width');\n const height = element.getAttribute('height');\n const float = element.getAttribute('data-float');\n\n if (alt) attrs.alt = alt;\n if (width) attrs.width = parseInt(width, 10);\n if (height) attrs.height = parseInt(height, 10);\n if (float) attrs.float = float;\n\n context.pushEmbed({ image: src }, attrs);\n }\n\n /**\n * Process a video/iframe element.\n * Converts embed URLs back to canonical form (e.g. youtube.com/embed/X → youtube.com/watch?v=X).\n */\n function processVideoElement(element: DOMElement): void {\n const src = element.getAttribute('src');\n if (!src) return;\n\n const attrs: AttributeMap = {};\n const float = element.getAttribute('data-float');\n const style = element.getAttribute('style') || '';\n\n if (float) attrs.float = float;\n\n // Extract width/height from inline style (used for floated videos)\n // Strip 'px' suffix to store clean numeric strings for roundtrip consistency\n const widthMatch = style.match(/(?:^|;\\s*)width:\\s*([^;]+)/);\n if (widthMatch?.[1]) attrs.width = widthMatch[1].trim().replace(/px$/, '');\n const heightMatch = style.match(/(?:^|;\\s*)height:\\s*([^;]+)/);\n if (heightMatch?.[1]) attrs.height = heightMatch[1].trim().replace(/px$/, '');\n\n const embedAttrs = Object.keys(attrs).length > 0 ? attrs : undefined;\n context.pushEmbed({ video: fromVideoEmbedUrl(src) }, embedAttrs);\n }\n\n /**\n * Process a <section class=\"footnotes\"> element.\n * If blockHandlers has a 'footnotes' handler registered, parse as block embed.\n * Otherwise, process children normally (graceful fallback).\n */\n function processFootnotesSection(section: DOMElement): void {\n const footnotesHandler = options.blockHandlers?.get('footnotes');\n if (footnotesHandler) {\n const blockContext: BlockContext = {\n registry: undefined as never, // Registry not needed for fromHtml parsing\n parseElement: (el: DOMElement): Op[] => {\n // Recursive: parse element's inner HTML → Delta ops\n const innerHtml = el.innerHTML ?? '';\n if (!innerHtml) return [{ insert: '\\n' }];\n return htmlToDelta(innerHtml, options).ops;\n },\n };\n const data = footnotesHandler.fromHtml(section, blockContext);\n if (data) {\n flushText();\n delta.insert({ block: data });\n delta.insert('\\n');\n atLineStart = true;\n return;\n }\n }\n\n // Fallback: process children normally\n processChildren(section);\n }\n\n /**\n * Process a <div class=\"markdown-alert markdown-alert-{type}\"> element.\n * If blockHandlers has an 'alert' handler registered, parse as block embed.\n * Otherwise, process children normally (graceful fallback).\n */\n function processAlertElement(element: DOMElement): void {\n const alertHandler = options.blockHandlers?.get('alert');\n if (alertHandler) {\n const blockContext: BlockContext = {\n registry: undefined as never,\n parseElement: (el: DOMElement): Op[] => {\n const innerHtml = el.innerHTML ?? '';\n if (!innerHtml) return [{ insert: '\\n' }];\n return htmlToDelta(innerHtml, options).ops;\n },\n };\n const data = alertHandler.fromHtml(element, blockContext);\n if (data) {\n flushText();\n delta.insert({ block: data });\n delta.insert('\\n');\n atLineStart = true;\n return;\n }\n }\n\n // Fallback: process children normally\n processChildren(element);\n }\n\n /**\n * Process a <div class=\"columns\"> element.\n * If blockHandlers has a 'columns' handler registered, parse as block embed.\n * Otherwise, process children normally (graceful fallback).\n */\n function processColumnsElement(element: DOMElement): void {\n const columnsHandler = options.blockHandlers?.get('columns');\n if (columnsHandler) {\n const blockContext: BlockContext = {\n registry: undefined as never,\n parseElement: (el: DOMElement): Op[] => {\n const innerHtml = el.innerHTML ?? '';\n if (!innerHtml) return [{ insert: '\\n' }];\n return htmlToDelta(innerHtml, options).ops;\n },\n };\n const data = columnsHandler.fromHtml(element, blockContext);\n if (data) {\n flushText();\n delta.insert({ block: data });\n delta.insert('\\n');\n atLineStart = true;\n return;\n }\n }\n\n // Fallback: process children normally\n processChildren(element);\n }\n\n /**\n * Process a <div class=\"inline-box\"> element.\n * If blockHandlers has a 'box' handler registered, parse as block embed.\n * Extracts op attributes (float, width, height, overflow) from HTML data-attrs and style.\n * Otherwise, process children normally (graceful fallback).\n */\n function processBoxElement(element: DOMElement): void {\n const boxHandler = options.blockHandlers?.get('box');\n if (boxHandler) {\n const blockContext: BlockContext = {\n registry: undefined as never,\n parseElement: (el: DOMElement): Op[] => {\n const innerHtml = el.innerHTML ?? '';\n if (!innerHtml) return [{ insert: '\\n' }];\n return htmlToDelta(innerHtml, options).ops;\n },\n };\n const data = boxHandler.fromHtml(element, blockContext);\n if (data) {\n flushText();\n\n // Extract op attributes from HTML element\n const opAttrs: Record<string, string> = {};\n\n const dataFloat = element.getAttribute('data-float');\n if (dataFloat) opAttrs.float = dataFloat;\n\n const dataOverflow = element.getAttribute('data-overflow');\n if (dataOverflow) opAttrs.overflow = dataOverflow;\n\n // Extract width/height from inline style\n const style = element.getAttribute('style') || '';\n const widthMatch = style.match(/(?:^|;\\s*)width:\\s*([^;]+)/);\n if (widthMatch?.[1]) opAttrs.width = widthMatch[1].trim();\n\n const heightMatch = style.match(/(?:^|;\\s*)height:\\s*([^;]+)/);\n if (heightMatch?.[1]) opAttrs.height = heightMatch[1].trim();\n\n const hasAttrs = Object.keys(opAttrs).length > 0;\n delta.insert({ block: data }, hasAttrs ? opAttrs : undefined);\n delta.insert('\\n');\n atLineStart = true;\n return;\n }\n }\n\n // Fallback: process children normally\n processChildren(element);\n }\n\n /**\n * Process a <table> element.\n * If blockHandlers has a 'table' handler registered, parse as Extended Table (block embed).\n * Otherwise, fall back to Simple Table (linear block attributes).\n */\n function processTableElement(table: DOMElement): void {\n // Opt-in: Extended Table via BlockHandler\n const tableHandler = options.blockHandlers?.get('table');\n if (tableHandler) {\n const blockContext: BlockContext = {\n registry: undefined as never, // Registry not needed for fromHtml parsing\n parseElement: (el: DOMElement): Op[] => {\n // Recursive: parse element's inner HTML → Delta ops\n const innerHtml = el.innerHTML ?? '';\n if (!innerHtml) return [{ insert: '\\n' }];\n return htmlToDelta(innerHtml, options).ops;\n },\n };\n const data = tableHandler.fromHtml(table, blockContext);\n if (data) {\n flushText();\n delta.insert({ block: data });\n delta.insert('\\n');\n atLineStart = true;\n return;\n }\n // If fromHtml returns null, fall through to Simple Table\n }\n\n // Simple Table: linear block attributes\n let rowIdx = 0;\n\n // Iterate over direct children: <thead>, <tbody>, or direct <tr>\n const tableChildren = table.childNodes;\n for (let i = 0; i < tableChildren.length; i++) {\n const section = tableChildren[i];\n if (!section || !isElement(section)) continue;\n\n const sectionTag = section.tagName.toLowerCase();\n\n if (sectionTag === 'thead' || sectionTag === 'tbody' || sectionTag === 'tfoot') {\n const isHeader = sectionTag === 'thead';\n const sectionChildren = section.childNodes;\n for (let j = 0; j < sectionChildren.length; j++) {\n const row = sectionChildren[j];\n if (!row || !isElement(row) || row.tagName.toLowerCase() !== 'tr') continue;\n processTableRow(row, rowIdx, isHeader);\n rowIdx++;\n }\n } else if (sectionTag === 'tr') {\n // Direct <tr> without <thead>/<tbody> wrapper\n processTableRow(section, rowIdx, false);\n rowIdx++;\n }\n }\n }\n\n /**\n * Process a single <tr> element\n */\n function processTableRow(tr: DOMElement, rowIdx: number, isHeader: boolean): void {\n let colIdx = 0;\n\n const cells = tr.childNodes;\n for (let i = 0; i < cells.length; i++) {\n const cell = cells[i];\n if (!cell || !isElement(cell)) continue;\n\n const cellTag = cell.tagName.toLowerCase();\n if (cellTag !== 'td' && cellTag !== 'th') continue;\n\n const cellIsHeader = isHeader || cellTag === 'th';\n\n // Extract column alignment from style\n const textAlign = cell.style?.textAlign || cell.style?.getPropertyValue?.('text-align');\n const colAlign =\n textAlign && (textAlign === 'left' || textAlign === 'center' || textAlign === 'right')\n ? textAlign\n : undefined;\n\n // Save and set block attributes for this cell\n const prevBlockAttrs = { ...currentBlockAttributes };\n currentBlockAttributes['table-row'] = rowIdx;\n currentBlockAttributes['table-col'] = colIdx;\n if (cellIsHeader) {\n currentBlockAttributes['table-header'] = true;\n }\n if (colAlign) {\n currentBlockAttributes['table-col-align'] = colAlign;\n }\n\n // Process cell content (inline elements)\n processChildren(cell);\n context.pushNewline();\n\n currentBlockAttributes = prevBlockAttrs;\n colIdx++;\n }\n }\n\n /**\n * Process a default block element (p, div)\n */\n function processDefaultBlock(element: DOMElement): void {\n const prevBlockAttrs = { ...currentBlockAttributes };\n\n // Check for alignment\n const align = getAlignment(element);\n if (align) {\n currentBlockAttributes.align = align;\n }\n\n // Check if this is an empty paragraph with only <br> for visibility\n // (generated by deltaToHtml for empty lines).\n //\n // Exception (Phase 7 Part 0 — softBreak): a lone `<br data-scrider-embed>`\n // inside `<p>` is NOT a placeholder. It encodes a `{ softBreak: true }`\n // embed that happens to occupy an otherwise empty paragraph (e.g. the\n // output of `softBreakFormat.render()` followed by the block `\\n`, or a\n // copy-paste of a structurally-isolated soft line break). The short-\n // circuit below would otherwise skip `processChildren`, the `br` branch\n // in `processNode` would never run, and the embed would silently\n // degrade to a plain block newline. Keep `processChildren` for that\n // case so the marker is honoured.\n const children = element.childNodes;\n const firstChild = children[0];\n const isBrOnlyParagraph =\n children.length === 1 &&\n firstChild !== undefined &&\n isElement(firstChild) &&\n firstChild.tagName.toLowerCase() === 'br' &&\n !firstChild.hasAttribute('data-scrider-embed');\n\n if (!isBrOnlyParagraph) {\n processChildren(element);\n }\n context.pushNewline();\n\n currentBlockAttributes = prevBlockAttrs;\n }\n\n /**\n * Get alignment from element style\n */\n function getAlignment(element: DOMElement): string | null {\n const textAlign = element.style?.textAlign || element.style?.getPropertyValue?.('text-align');\n\n if (textAlign && CSS_ALIGN_TO_FORMAT[textAlign]) {\n return CSS_ALIGN_TO_FORMAT[textAlign];\n }\n\n return null;\n }\n\n // Process all nodes in fragment\n const children = fragment.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child) processNode(child);\n }\n\n // Flush any remaining text\n flushText();\n\n // Ensure document ends with newline if not empty\n if (delta.ops.length > 0) {\n const lastOp = delta.ops[delta.ops.length - 1];\n if (lastOp && 'insert' in lastOp) {\n const lastInsert = lastOp.insert as string | Record<string, unknown>;\n if (typeof lastInsert === 'string' && !lastInsert.endsWith('\\n')) {\n delta.insert('\\n');\n }\n }\n }\n\n return delta;\n}\n\n/**\n * Normalize whitespace in text\n */\nfunction normalizeText(text: string, pendingText: string, atLineStart: boolean): string {\n // Replace multiple whitespace with single space\n text = text.replace(/[\\t\\n\\r]+/g, ' ');\n\n // Collapse multiple spaces\n text = text.replace(/ +/g, ' ');\n\n // Trim leading space only if at start of line AND no pending text\n if (atLineStart && pendingText === '' && text.startsWith(' ')) {\n text = text.slice(1);\n }\n\n return text;\n}\n\n/**\n * Sibling-aware heuristic for `<br>` disambiguation.\n *\n * Returns `true` when the given `<br>` node has at least one previous\n * sibling that contributes content (non-whitespace text or any element).\n * Such a `<br>` is treated as a soft line break embed; otherwise it is\n * treated as a regular newline (preserving historical behaviour for\n * placeholder shapes like `<p><br>text</p>`).\n *\n * The DOMAdapter interface does not expose `previousSibling`, so we walk\n * the parent's `childNodes` list up to the current node.\n */\nfunction hasMeaningfulPrevSibling(brNode: DOMElement): boolean {\n const parent = brNode.parentNode;\n if (!parent) return false;\n const children = parent.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child) continue;\n if (child === brNode) return false; // reached <br> with no prior content\n if (child.nodeType === NODE_TYPE.TEXT_NODE) {\n const text = child.textContent ?? '';\n if (text.trim().length > 0) return true;\n } else if (isElement(child)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Phase 7 Part 0 (v1.3.3) — detect a browser-added trailing line-box\n * filler `<br>`.\n *\n * contenteditable engines (Chrome especially) append a plain `<br>` after\n * a \"real\" `<br>` to give the trailing empty line a visual line-box. This\n * filler carries no user intent — keeping it as a `softBreak` embed in the\n * Delta corrupts subsequent edits (extra embed shifts caret positions and\n * makes `splitBlock` / `deleteBackward` operate on the wrong newline).\n *\n * A `<br>` qualifies as a filler when ALL of:\n * - it has NO `data-scrider-embed` attribute (caller checks first);\n * - its immediately-preceding sibling element is also a `<br>` (with or\n * without the marker — either kind of \"real\" line break is OK);\n * - any sibling that comes AFTER it is whitespace-only text, a ZWSP\n * (`\\u200B`, our own caret slot), or another filler `<br>` — i.e. no\n * semantic content follows it inside the parent block.\n *\n * The check ignores ZWSP/whitespace so the renderToDOM caret-slot ZWSP\n * appended by ScriderEditor does not defeat the heuristic.\n */\nfunction isBrowserEmptyLineFiller(brNode: DOMElement): boolean {\n const parent = brNode.parentNode;\n if (!parent) return false;\n const children = parent.childNodes;\n\n let prevElement: DOMElement | null = null;\n let foundCurrent = false;\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (!child) continue;\n if (child === brNode) {\n foundCurrent = true;\n continue;\n }\n if (!foundCurrent) {\n // BEFORE current: track the immediate preceding element. Skip pure\n // whitespace text. Any non-whitespace text RESETS the element chain\n // (the preceding <br> would no longer be \"immediate\" if real text\n // sits between them).\n if (child.nodeType === NODE_TYPE.TEXT_NODE) {\n const text = (child.textContent ?? '').replace(/[\\s\\u200B]/g, '');\n if (text.length > 0) prevElement = null;\n } else if (isElement(child)) {\n prevElement = child;\n }\n } else {\n // AFTER current: any semantic content disqualifies the filler.\n if (child.nodeType === NODE_TYPE.TEXT_NODE) {\n const text = (child.textContent ?? '').replace(/[\\s\\u200B]/g, '');\n if (text.length > 0) return false;\n } else if (isElement(child)) {\n const tag = child.tagName?.toLowerCase();\n // Another <br> after us is also filler-shaped (browsers sometimes\n // emit a chain), so don't disqualify on that alone.\n if (tag !== 'br') return false;\n }\n }\n }\n\n if (!prevElement) return false;\n return prevElement.tagName?.toLowerCase() === 'br';\n}\n\n/**\n * Find a matching tag handler for an element.\n * Supports keys in formats:\n * - \"tag\" — matches by tag name only\n * - \"tag.class\" — matches by tag name AND CSS class\n * Class-specific handlers take priority over tag-only handlers.\n */\nfunction findTagHandler(\n handlers: Record<string, TagHandler>,\n element: DOMElement,\n tagName: string,\n): TagHandler | null {\n // First try class-specific handlers (tag.class)\n const className = element.getAttribute('class');\n if (className) {\n const classes = className.split(/\\s+/);\n for (const cls of classes) {\n const key = `${tagName}.${cls}`;\n if (handlers[key]) {\n return handlers[key];\n }\n }\n }\n\n // Then try tag-only handler\n if (handlers[tagName]) {\n return handlers[tagName];\n }\n\n return null;\n}\n\n/**\n * Default tag handlers\n */\nconst DEFAULT_TAG_HANDLERS: Record<string, TagHandler> = {\n // Formula span\n 'span.formula': (element, context) => {\n const formula = element.getAttribute('data-formula');\n if (formula) {\n context.pushEmbed({ formula });\n }\n },\n\n // Diagram (Mermaid) span — inline mode\n 'span.diagram': (element, context) => {\n const diagram = element.getAttribute('data-diagram');\n if (diagram) {\n context.pushEmbed({ diagram });\n }\n },\n\n // Draw.io diagram span — file reference\n 'span.drawio': (element, context) => {\n const src = element.getAttribute('data-drawio-src');\n if (src) {\n const attrs: Record<string, unknown> = {};\n const alt = element.getAttribute('data-alt');\n if (alt) attrs.alt = alt;\n context.pushEmbed({ drawio: src }, Object.keys(attrs).length > 0 ? attrs : undefined);\n }\n },\n\n // Footnote reference: <sup class=\"footnote-ref\"><a href=\"#fn-{id}\">{label}</a></sup>\n 'sup.footnote-ref': (element, context) => {\n // Extract id from the nested <a> href=\"#fn-{id}\"\n const children = element.childNodes;\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (child && isElement(child) && child.tagName.toLowerCase() === 'a') {\n const href = child.getAttribute('href') || '';\n const match = href.match(/#fn-(.+)/);\n if (match?.[1]) {\n context.pushEmbed({ 'footnote-ref': match[1] });\n return;\n }\n }\n }\n // Fallback: try id attribute on <sup> itself\n const id = element.getAttribute('id') || '';\n const refMatch = id.match(/^fnref-(.+)/);\n if (refMatch?.[1]) {\n context.pushEmbed({ 'footnote-ref': refMatch[1] });\n }\n },\n};\n","/**\n * Delta → Markdown Conversion\n *\n * Converts a Delta document to Markdown string.\n */\n\nimport { Delta, isInsert, isTextInsert, isEmbedInsert } from '@scrider/delta';\nimport type { Op, AttributeMap, InsertOp } from '@scrider/delta';\nimport type { BlockHandlerRegistry } from '../../schema/BlockHandlerRegistry';\nimport type { BlockContext } from '../../schema/BlockHandler';\nimport type { Registry } from '../../schema/Registry';\nimport {\n escapeMarkdown,\n INLINE_FORMAT_SYNTAX,\n MD_INLINE_FORMAT_ORDER,\n BLOCK_FORMAT_PREFIX,\n LIST_TYPE_PREFIX,\n getIndentPrefix,\n renderImage,\n renderLink,\n renderCodeBlock,\n} from './config';\nimport { escapeHtml, toVideoEmbedUrl } from '../html/config';\nimport { deltaToHtml } from '../html/delta-to-html';\n\n/**\n * Options for Delta → Markdown conversion\n */\nexport interface DeltaToMarkdownOptions {\n /**\n * Use strict Markdown (no GFM extensions)\n * @default false\n */\n strict?: boolean;\n\n /**\n * Preserve empty lines using <br> tags\n * When false, multiple empty lines collapse to one paragraph break\n * @default false\n */\n preserveEmptyLines?: boolean;\n\n /**\n * Math syntax for formula output\n * - 'dollar': $...$ for inline, $$...$$ for block (default, GFM-compatible)\n * - 'latex': \\(...\\) for inline, \\[...\\] for block (used by LLMs: DeepSeek, ChatGPT, Claude)\n * @default 'dollar'\n */\n mathSyntax?: 'dollar' | 'latex';\n\n /**\n * Display math rendering mode\n * - true (default): code-block \"math\" → ```math ``` (GFM code block)\n * - false: code-block \"math\" → $...$ on its own line (inline syntax)\n *\n * Does NOT affect inline formulas ({ formula }) — they always render as $...$\n * @default true\n */\n mathBlock?: boolean;\n\n /**\n * Mermaid diagram rendering mode\n * - true (default): code-block \"mermaid\" → ```mermaid ``` (fenced block)\n * - false: code-block \"mermaid\" → ```mermaid ``` (same output, but { diagram } embeds also → ```mermaid)\n *\n * Does NOT affect the Markdown output for code-block \"mermaid\" (always fenced).\n * Controls how { diagram } embeds are rendered.\n * @default true\n */\n mermaidBlock?: boolean;\n\n /**\n * PlantUML diagram rendering mode\n * - true (default): code-block \"plantuml\" → ```plantuml ``` (fenced block)\n * - false: code-block \"plantuml\" → ```plantuml ``` (same output, but { diagram } embeds with @startuml → ```plantuml)\n *\n * Does NOT affect the Markdown output for code-block \"plantuml\" (always fenced).\n * Controls how { diagram } embeds containing PlantUML are rendered.\n * @default true\n */\n plantumlBlock?: boolean;\n\n /**\n * Custom embed renderers\n */\n embedRenderers?: Record<string, (value: unknown, attrs?: AttributeMap) => string>;\n\n /**\n * Block handler registry for Extended Table and other block embeds.\n * When provided, block embeds will be rendered via handler.toMarkdown() → fallback to handler.toHtml().\n */\n blockHandlers?: BlockHandlerRegistry;\n\n /**\n * Pretty-print HTML output for block embeds (Extended Table, Columns, etc.)\n * When true, HTML fallback in Markdown is indented and line-broken for readability.\n * When false (default), HTML is compact single-line — safer for CommonMark.\n * @default false\n */\n prettyHtml?: boolean;\n\n /**\n * Format registry for custom embed Markdown rendering.\n *\n * When provided, embed formats with a `toMarkdown()` method are used\n * before falling back to built-in handlers. If `toMarkdown()` returns null,\n * `render()` is used as HTML fallback in Markdown.\n */\n registry?: Registry;\n\n /**\n * Rendering style for `{ softBreak: true }` embeds (Phase 7 Part 0).\n *\n * - `'spaces'` (default): GFM-canonical hard break — two trailing spaces\n * followed by `\\n` (`\" \\n\"`). Round-trips losslessly through remark.\n * - `'html'`: inline `<br>` tag. Slightly more visible in source view\n * and immune to editor whitespace trimming. Recommended for the\n * LFM (LLM-Flavored Markdown) flavour exposed by the editor's\n * \"source\" toggle.\n *\n * Does not affect how soft breaks are rendered inside table cells —\n * those always use inline `<br>` because GFM tables forbid raw `\\n`.\n *\n * @default 'spaces'\n */\n softBreakStyle?: 'spaces' | 'html';\n\n /**\n * Strip trailing newlines from the final output.\n *\n * Useful when serialising a single block (e.g. one table for inline\n * editing) where the GFM padding (blank line after a table, trailing\n * paragraph newline, etc.) is not wanted. The internal structure of the\n * markdown is unaffected — only trailing `\\n+` at the very end of the\n * returned string is removed.\n *\n * @default false\n */\n trimTrailingNewlines?: boolean;\n}\n\n/**\n * Line data for processing\n */\ninterface Line {\n ops: InsertOp[];\n attributes: AttributeMap;\n}\n\n/**\n * Convert Delta to Markdown\n *\n * @param delta - The Delta document to convert\n * @param options - Conversion options\n * @returns Markdown string\n *\n * @example\n * ```typescript\n * const delta = new Delta()\n * .insert('Hello', { bold: true })\n * .insert(' World\\n');\n *\n * const md = deltaToMarkdown(delta);\n * // '**Hello** World\\n'\n * ```\n */\nexport function deltaToMarkdown(delta: Delta, options: DeltaToMarkdownOptions = {}): string {\n const {\n strict = false,\n preserveEmptyLines = false,\n mathSyntax = 'dollar',\n mathBlock = true,\n embedRenderers = {},\n blockHandlers,\n prettyHtml = false,\n registry,\n softBreakStyle = 'spaces',\n trimTrailingNewlines = false,\n } = options;\n const useLatexDelimiters = mathSyntax === 'latex';\n\n // Split ops into lines\n const lines = splitIntoLines(delta.ops);\n\n // Track list state for proper numbering\n let orderedListIndex = 0;\n let lastListType: string | null = null;\n let lastIndent = 0;\n let lastWasBlockquote = false;\n\n const result: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (!line) continue;\n const attrs = line.attributes;\n const isBlockquote = !!attrs.blockquote;\n\n // Check for table - needs special handling (group adjacent table lines)\n if (typeof attrs['table-row'] === 'number' && typeof attrs['table-col'] === 'number') {\n const tableLines = collectTableLines(lines, i);\n result.push(\n renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters, registry, softBreakStyle),\n );\n result.push(''); // Blank line after table — GFM requires it to end the table block\n i += tableLines.length - 1;\n lastListType = null;\n orderedListIndex = 0;\n lastWasBlockquote = false;\n continue;\n }\n\n // Check for code block - needs special handling\n if (attrs['code-block']) {\n if (lastWasBlockquote) {\n result.push('');\n lastWasBlockquote = false;\n }\n const codeLines = collectCodeBlock(lines, i);\n const language = getCodeBlockLanguage(attrs);\n const code = codeLines\n .map((l) =>\n renderLineContent(\n l.ops,\n embedRenderers,\n true,\n false,\n blockHandlers,\n false,\n registry,\n softBreakStyle,\n ),\n )\n .join('\\n');\n\n if (language === 'math') {\n if (mathBlock === false) {\n // Render display math as inline $...$ on its own line\n // Blank lines around ensure it's not absorbed by adjacent lists/paragraphs\n result.push('');\n result.push(`$${code}$`);\n result.push('');\n } else if (useLatexDelimiters) {\n // Use \\[...\\] for display math in LaTeX mode\n result.push(`\\\\[\\n${code}\\n\\\\]`);\n } else {\n // Default: GFM code block ```math\n result.push(renderCodeBlock(code, language));\n }\n } else {\n result.push(renderCodeBlock(code, language));\n }\n\n i += codeLines.length - 1; // Skip processed lines\n lastListType = null;\n orderedListIndex = 0;\n continue;\n }\n\n // Insert blank line at blockquote boundary to prevent lazy continuation\n if (lastWasBlockquote && !isBlockquote) {\n result.push('');\n } else if (!lastWasBlockquote && isBlockquote && result.length > 0) {\n // Also add blank line before blockquote if preceded by content\n const lastLine = result[result.length - 1];\n if (lastLine !== undefined && lastLine !== '') {\n result.push('');\n }\n }\n\n // Handle list numbering reset\n const listType = typeof attrs.list === 'string' ? attrs.list : undefined;\n const indent = typeof attrs.indent === 'number' ? attrs.indent : 0;\n\n if (listType) {\n if (listType !== lastListType || indent !== lastIndent) {\n orderedListIndex = 0;\n }\n if (listType === 'ordered') {\n orderedListIndex++;\n }\n } else {\n lastListType = null;\n orderedListIndex = 0;\n }\n\n // Render line content\n const content = renderLineContent(\n line.ops,\n embedRenderers,\n false,\n useLatexDelimiters,\n blockHandlers,\n prettyHtml,\n registry,\n softBreakStyle,\n );\n\n // Handle empty lines\n if (!content && !hasBlockFormat(attrs)) {\n // Empty line with no block formatting\n result.push(preserveEmptyLines ? '<br>' : '');\n lastWasBlockquote = false;\n continue;\n }\n\n // Apply block formatting\n const markdown = renderBlockFormat(content, attrs, orderedListIndex, strict);\n result.push(markdown);\n\n // After a standalone <img> tag (floated/sized image), add a blank line so\n // CommonMark type-7 HTML block terminates before the next paragraph.\n if (/^<img\\s/.test(content) && !hasBlockFormat(attrs)) {\n result.push('');\n }\n\n lastListType = listType ?? null;\n lastIndent = indent;\n lastWasBlockquote = isBlockquote;\n }\n\n const md = result.join('\\n');\n return trimTrailingNewlines ? md.replace(/\\n+$/, '') : md;\n}\n\n/**\n * Check if attributes contain any block formatting\n */\nfunction hasBlockFormat(attrs: AttributeMap): boolean {\n return !!(\n attrs.header ||\n attrs.list ||\n attrs.blockquote ||\n attrs['code-block'] ||\n attrs.align ||\n attrs.indent\n );\n}\n\n/**\n * Split ops into lines based on newline characters\n */\nfunction splitIntoLines(ops: Op[]): Line[] {\n const lines: Line[] = [];\n let currentOps: InsertOp[] = [];\n\n for (const op of ops) {\n if (!isInsert(op)) continue;\n\n const opAttrs: AttributeMap = op.attributes ?? {};\n\n if (isTextInsert(op)) {\n const text: string = op.insert;\n const parts: string[] = text.split('\\n');\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n if (part === undefined) continue;\n\n // Add text content to current line (with inline attributes only)\n if (part.length > 0) {\n const newOp: InsertOp = { insert: part };\n // Only copy inline attributes, not block attributes\n const inlineAttrs: AttributeMap = {};\n for (const [key, value] of Object.entries(opAttrs)) {\n // Skip block attributes\n if (\n ![\n 'header',\n 'blockquote',\n 'code-block',\n 'list',\n 'indent',\n 'align',\n 'direction',\n 'table-row',\n 'table-col',\n 'table-header',\n 'table-col-align',\n ].includes(key)\n ) {\n inlineAttrs[key] = value;\n }\n }\n if (Object.keys(inlineAttrs).length > 0) {\n newOp.attributes = inlineAttrs;\n }\n currentOps.push(newOp);\n }\n\n // If not the last part, this is a line break\n if (i < parts.length - 1) {\n lines.push({\n ops: currentOps,\n attributes: opAttrs, // Line attributes come from the \\n op\n });\n currentOps = [];\n }\n }\n } else {\n // Embed\n currentOps.push(op);\n }\n }\n\n // Don't forget the last line if there's content\n if (currentOps.length > 0) {\n lines.push({ ops: currentOps, attributes: {} });\n }\n\n return lines;\n}\n\n/**\n * Collect consecutive code block lines\n */\nfunction collectCodeBlock(lines: Line[], startIndex: number): Line[] {\n const codeLines: Line[] = [];\n const startLine = lines[startIndex];\n if (!startLine) return codeLines;\n\n const startLang = getCodeBlockLanguage(startLine.attributes);\n\n for (let i = startIndex; i < lines.length; i++) {\n const line = lines[i];\n if (!line || !line.attributes['code-block']) break;\n\n const lang = getCodeBlockLanguage(line.attributes);\n if (i > startIndex && lang !== startLang) break;\n\n codeLines.push(line);\n }\n\n return codeLines;\n}\n\n/**\n * Collect consecutive table lines\n */\nfunction collectTableLines(lines: Line[], startIndex: number): Line[] {\n const result: Line[] = [];\n for (let i = startIndex; i < lines.length; i++) {\n const line = lines[i];\n if (\n !line ||\n typeof line.attributes['table-row'] !== 'number' ||\n typeof line.attributes['table-col'] !== 'number'\n ) {\n break;\n }\n result.push(line);\n }\n return result;\n}\n\n/**\n * Table cell data for Markdown rendering\n */\ninterface MdTableCell {\n ops: InsertOp[];\n colAlign?: string | undefined;\n}\n\n/**\n * Render a group of table lines as a GFM Markdown table\n */\nfunction renderMarkdownTable(\n tableLines: Line[],\n embedRenderers: Record<string, (value: unknown, attrs?: AttributeMap) => string>,\n useLatexDelimiters: boolean = false,\n registry?: Registry,\n softBreakStyle: 'spaces' | 'html' = 'spaces',\n): string {\n // Group by row\n const rows = new Map<number, { isHeader: boolean; cells: Map<number, MdTableCell> }>();\n\n for (const line of tableLines) {\n const attrs = line.attributes;\n const rowIdx = attrs['table-row'] as number;\n const colIdx = attrs['table-col'] as number;\n\n if (!rows.has(rowIdx)) {\n rows.set(rowIdx, { isHeader: !!attrs['table-header'], cells: new Map() });\n }\n\n const row = rows.get(rowIdx)!;\n if (attrs['table-header']) row.isHeader = true;\n row.cells.set(colIdx, {\n ops: line.ops,\n colAlign: typeof attrs['table-col-align'] === 'string' ? attrs['table-col-align'] : undefined,\n });\n }\n\n // Sort rows by index\n const sortedRows = [...rows.entries()].sort((a, b) => a[0] - b[0]);\n\n // Determine max columns\n let maxCol = 0;\n for (const [, row] of sortedRows) {\n for (const colIdx of row.cells.keys()) {\n if (colIdx > maxCol) maxCol = colIdx;\n }\n }\n\n // Separate header and body rows\n const headerRows = sortedRows.filter(([, r]) => r.isHeader);\n const bodyRows = sortedRows.filter(([, r]) => !r.isHeader);\n\n // Collect column alignments from header row (or first row)\n const colAligns: (string | undefined)[] = [];\n const alignSource = headerRows.length > 0 ? headerRows : bodyRows;\n if (alignSource.length > 0) {\n const firstRow = alignSource[0]!;\n for (let col = 0; col <= maxCol; col++) {\n const cell = firstRow[1].cells.get(col);\n colAligns.push(cell?.colAlign);\n }\n }\n\n const mdLines: string[] = [];\n\n // If there's a header, render it + separator\n if (headerRows.length > 0) {\n for (const [, row] of headerRows) {\n mdLines.push(\n renderMdRow(row.cells, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle),\n );\n }\n mdLines.push(renderMdSeparator(maxCol, colAligns));\n } else {\n // No header: render a synthetic empty header + separator (GFM requires header)\n const emptyRow = new Map<number, MdTableCell>();\n for (let col = 0; col <= maxCol; col++) {\n emptyRow.set(col, { ops: [] });\n }\n mdLines.push(\n renderMdRow(emptyRow, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle),\n );\n mdLines.push(renderMdSeparator(maxCol, colAligns));\n }\n\n // Render body rows\n for (const [, row] of bodyRows) {\n mdLines.push(\n renderMdRow(row.cells, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle),\n );\n }\n\n return mdLines.join('\\n');\n}\n\n/**\n * Render a single GFM table row\n */\nfunction renderMdRow(\n cells: Map<number, MdTableCell>,\n maxCol: number,\n embedRenderers: Record<string, (value: unknown, attrs?: AttributeMap) => string>,\n useLatexDelimiters: boolean = false,\n registry?: Registry,\n softBreakStyle: 'spaces' | 'html' = 'spaces',\n): string {\n const parts: string[] = [];\n for (let col = 0; col <= maxCol; col++) {\n const cell = cells.get(col);\n const content = cell\n ? renderLineContent(\n cell.ops,\n embedRenderers,\n false,\n useLatexDelimiters,\n undefined,\n false,\n registry,\n softBreakStyle,\n true, // inTableCell — softBreak must use <br>, never \" \\n\"\n )\n : '';\n // Escape pipe characters in cell content\n parts.push(content.replace(/\\|/g, '\\\\|'));\n }\n return '| ' + parts.join(' | ') + ' |';\n}\n\n/**\n * Render the GFM separator row (with alignment)\n */\nfunction renderMdSeparator(maxCol: number, colAligns: (string | undefined)[]): string {\n const parts: string[] = [];\n for (let col = 0; col <= maxCol; col++) {\n const align = colAligns[col];\n if (align === 'center') {\n parts.push(':---:');\n } else if (align === 'right') {\n parts.push('---:');\n } else if (align === 'left') {\n parts.push(':---');\n } else {\n parts.push('---');\n }\n }\n return '| ' + parts.join(' | ') + ' |';\n}\n\n/**\n * Get code block language from attributes\n */\nfunction getCodeBlockLanguage(attributes: AttributeMap): string | undefined {\n const codeBlock = attributes['code-block'];\n if (typeof codeBlock === 'string' && codeBlock !== 'true') {\n return codeBlock;\n }\n return undefined;\n}\n\n/**\n * Render inline content of a line\n */\nfunction renderLineContent(\n ops: InsertOp[],\n embedRenderers: Record<string, (value: unknown, attrs?: AttributeMap) => string>,\n inCodeBlock: boolean,\n useLatexDelimiters: boolean = false,\n blockHandlers?: BlockHandlerRegistry,\n prettyHtml: boolean = false,\n registry?: Registry,\n softBreakStyle: 'spaces' | 'html' = 'spaces',\n inTableCell: boolean = false,\n): string {\n let result = '';\n\n for (const op of ops) {\n const attrs: AttributeMap | undefined = op.attributes;\n\n if (isTextInsert(op)) {\n const text: string = op.insert;\n if (inCodeBlock) {\n // Don't escape or format in code blocks\n result += text;\n } else {\n result += renderInlineText(text, attrs);\n }\n } else if (isEmbedInsert(op)) {\n const embed: Record<string, unknown> = op.insert;\n result += renderEmbed(\n embed,\n attrs,\n embedRenderers,\n useLatexDelimiters,\n blockHandlers,\n prettyHtml,\n registry,\n softBreakStyle,\n inTableCell,\n );\n }\n }\n\n return result;\n}\n\n/**\n * Render inline text with formatting\n */\nfunction renderInlineText(text: string, attributes?: AttributeMap): string {\n if (!attributes || Object.keys(attributes).length === 0) {\n return escapeMarkdown(text);\n }\n\n // Handle link specially (wraps everything)\n const link = typeof attributes.link === 'string' ? attributes.link : undefined;\n\n // Escape text first (skip for inline code — backtick content is literal)\n let result = attributes.code ? text : escapeMarkdown(text);\n\n // Apply inline formats in order (inner to outer for wrapping)\n // We iterate in reverse so outer formats wrap inner ones\n for (let i = MD_INLINE_FORMAT_ORDER.length - 1; i >= 0; i--) {\n const format = MD_INLINE_FORMAT_ORDER[i];\n if (!format || !attributes[format]) continue;\n\n const syntax = INLINE_FORMAT_SYNTAX[format];\n if (syntax) {\n result = `${syntax.prefix}${result}${syntax.suffix}`;\n }\n }\n\n // Apply link last (outermost, before style spans)\n if (link) {\n result = renderLink(result, link);\n }\n\n // Apply style-based formats as <span style=\"...\"> (outermost wrapping)\n const styleProps: string[] = [];\n if (typeof attributes.color === 'string') styleProps.push(`color: ${attributes.color}`);\n if (typeof attributes.background === 'string')\n styleProps.push(`background-color: ${attributes.background}`);\n if (typeof attributes.font === 'string') styleProps.push(`font-family: ${attributes.font}`);\n if (typeof attributes.size === 'string') styleProps.push(`font-size: ${attributes.size}`);\n if (styleProps.length > 0) {\n result = `<span style=\"${styleProps.join('; ')}\">${result}</span>`;\n }\n\n return result;\n}\n\n/**\n * Render an embed to Markdown\n */\nfunction renderEmbed(\n embed: Record<string, unknown>,\n attributes: AttributeMap | undefined,\n customRenderers: Record<string, (value: unknown, attrs?: AttributeMap) => string>,\n useLatexDelimiters: boolean = false,\n blockHandlers?: BlockHandlerRegistry,\n prettyHtml: boolean = false,\n registry?: Registry,\n softBreakStyle: 'spaces' | 'html' = 'spaces',\n inTableCell: boolean = false,\n): string {\n const entries = Object.entries(embed);\n if (entries.length === 0) return '';\n\n const firstEntry = entries[0];\n if (!firstEntry) return '';\n\n const embedType: string = firstEntry[0];\n const embedValue: unknown = firstEntry[1];\n\n // Soft line break (Phase 7 Part 0) — handled here (before registry\n // / custom-renderer lookup) so the caller-controlled `softBreakStyle`\n // option always wins over any registered `Format.toMarkdown`.\n // Inside table cells, GFM forbids raw `\\n`, so the embed is always\n // rendered as inline `<br>` regardless of the style preference.\n if (embedType === 'softBreak') {\n if (inTableCell) return '<br>';\n return softBreakStyle === 'html' ? '<br>' : ' \\n';\n }\n\n // Handle block embeds via BlockHandler\n if (embedType === 'block' && blockHandlers) {\n const blockData = embedValue as Record<string, unknown>;\n if (blockData && typeof blockData.type === 'string') {\n const handler = blockHandlers.get(blockData.type);\n if (handler) {\n const opAttrs = attributes ? { opAttributes: attributes as Record<string, unknown> } : {};\n\n // Try toMarkdown first — renderDelta produces Markdown\n if (handler.toMarkdown) {\n const mdContext: BlockContext = {\n registry: undefined as never,\n renderDelta: (ops: Op[]): string => deltaToMarkdown(new Delta(ops), { blockHandlers }),\n ...opAttrs,\n };\n const md = handler.toMarkdown(blockData, mdContext);\n if (md !== null) return md;\n }\n\n // Fallback: render as HTML directly in Markdown (valid per CommonMark).\n // renderDelta must produce HTML so cell content is proper HTML, not\n // Markdown syntax that would be lost during htmlToDelta roundtrip.\n const htmlContext: BlockContext = {\n registry: undefined as never,\n ...(prettyHtml ? { options: { pretty: true } } : {}),\n renderDelta: (ops: Op[]): string =>\n deltaToHtml(new Delta(ops), { blockHandlers, pretty: prettyHtml }),\n ...opAttrs,\n };\n return '\\n' + handler.toHtml(blockData, htmlContext) + '\\n';\n }\n }\n return '';\n }\n\n // Check for custom renderer\n const customRenderer = customRenderers[embedType];\n if (customRenderer) {\n return customRenderer(embedValue, attributes);\n }\n\n // Check registry format toMarkdown() / render() fallback\n if (registry) {\n const format = registry.get(embedType);\n if (format) {\n // Try toMarkdown first\n if (format.toMarkdown) {\n const md = format.toMarkdown(embedValue, attributes);\n if (md !== null) return md;\n }\n // Fallback to render() as HTML-in-Markdown\n if (format.render) {\n return format.render(embedValue, attributes);\n }\n }\n }\n\n // Built-in embed handling\n if (embedType === 'image') {\n const src = typeof embedValue === 'string' ? embedValue : '';\n const alt = typeof attributes?.alt === 'string' ? attributes.alt : undefined;\n\n // When float/width/height are present, use HTML <img> to preserve attributes\n const hasFloat =\n attributes?.float != null &&\n typeof attributes.float === 'string' &&\n attributes.float !== 'none';\n const hasWidth = attributes?.width != null;\n const hasHeight = attributes?.height != null;\n\n if (hasFloat || hasWidth || hasHeight) {\n const altAttr = alt ? ` alt=\"${escapeHtml(alt)}\"` : '';\n const floatAttr = hasFloat ? ` data-float=\"${escapeHtml(String(attributes.float))}\"` : '';\n const widthAttr = hasWidth ? ` width=\"${escapeHtml(String(attributes.width))}\"` : '';\n const heightAttr = hasHeight ? ` height=\"${escapeHtml(String(attributes.height))}\"` : '';\n return `<img src=\"${escapeHtml(src)}\"${altAttr}${floatAttr}${widthAttr}${heightAttr}>`;\n }\n\n return renderImage(src, alt);\n }\n\n if (embedType === 'video') {\n const src = typeof embedValue === 'string' ? embedValue : '';\n\n // When float/width/height are present, use HTML to preserve attributes\n const hasFloat =\n attributes?.float != null &&\n typeof attributes.float === 'string' &&\n attributes.float !== 'none';\n const hasWidth = attributes?.width != null;\n const hasHeight = attributes?.height != null;\n\n if (hasFloat || hasWidth || hasHeight) {\n const floatAttr = hasFloat ? ` data-float=\"${escapeHtml(String(attributes.float))}\"` : '';\n const styles: string[] = [];\n if (hasWidth) {\n const w =\n typeof attributes.width === 'string' || typeof attributes.width === 'number'\n ? String(attributes.width)\n : '';\n if (w && w !== 'auto') styles.push(`width: ${/^\\d+$/.test(w) ? w + 'px' : w}`);\n }\n if (hasHeight) {\n const h =\n typeof attributes.height === 'string' || typeof attributes.height === 'number'\n ? String(attributes.height)\n : '';\n if (h && h !== 'auto') styles.push(`height: ${/^\\d+$/.test(h) ? h + 'px' : h}`);\n }\n const styleAttr = styles.length > 0 ? ` style=\"${styles.join('; ')}\"` : '';\n const embedSrc = toVideoEmbedUrl(src);\n if (embedSrc) {\n return `<iframe src=\"${escapeHtml(embedSrc)}\" frameborder=\"0\" allowfullscreen${floatAttr}${styleAttr}></iframe>`;\n }\n return `<video src=\"${escapeHtml(src)}\" controls${floatAttr}${styleAttr}></video>`;\n }\n\n // Simple video without attributes → readable Markdown (like images)\n return ``;\n }\n\n if (embedType === 'formula') {\n const latex = typeof embedValue === 'string' ? embedValue : '';\n return useLatexDelimiters ? `\\\\(${latex}\\\\)` : `$${latex}$`;\n }\n\n if (embedType === 'diagram') {\n // Diagram embed → render as fenced code block with appropriate language\n const source = typeof embedValue === 'string' ? embedValue : '';\n const lang = source.trimStart().startsWith('@startuml') ? 'plantuml' : 'mermaid';\n return `\\n\\`\\`\\`${lang}\\n${source}\\n\\`\\`\\`\\n`;\n }\n\n if (embedType === 'drawio') {\n // Draw.io embeds use image-like syntax in Markdown (file reference)\n const src = typeof embedValue === 'string' ? embedValue : '';\n const alt = typeof attributes?.alt === 'string' ? attributes.alt : undefined;\n return renderImage(src, alt);\n }\n\n if (embedType === 'footnote-ref') {\n // Footnote reference: [^id]\n const id = typeof embedValue === 'string' ? embedValue : String(embedValue);\n return `[^${id}]`;\n }\n\n if (embedType === 'divider') {\n return '\\n---\\n';\n }\n\n // Unknown embed - skip\n return '';\n}\n\n/**\n * Render block formatting (headers, lists, etc.)\n */\nfunction renderBlockFormat(\n content: string,\n attributes: AttributeMap,\n orderedIndex: number,\n _strict: boolean,\n): string {\n const indent = typeof attributes.indent === 'number' ? attributes.indent : 0;\n const indentPrefix = getIndentPrefix(indent);\n\n // Header\n const header = typeof attributes.header === 'number' ? attributes.header : undefined;\n if (header) {\n const prefixFn = BLOCK_FORMAT_PREFIX.header;\n if (typeof prefixFn === 'function') {\n let line = prefixFn(header) + content;\n // Append custom header-id if present\n const headerId = attributes['header-id'];\n if (typeof headerId === 'string' && headerId.length > 0) {\n line += ` {#${headerId}}`;\n }\n return line;\n }\n }\n\n // Blockquote\n if (attributes.blockquote) {\n return '> ' + content;\n }\n\n // List\n const listType = typeof attributes.list === 'string' ? attributes.list : undefined;\n if (listType) {\n const prefixDef = LIST_TYPE_PREFIX[listType];\n let prefix: string;\n\n if (typeof prefixDef === 'function') {\n prefix = prefixDef(orderedIndex - 1);\n } else if (prefixDef) {\n prefix = prefixDef;\n } else {\n prefix = '- ';\n }\n\n return indentPrefix + prefix + content;\n }\n\n // Align - not supported in basic Markdown, skip\n // content remains unchanged\n\n // Regular paragraph\n return content;\n}\n","/**\n * Markdown ↔ Delta Mapping Configuration\n *\n * Defines the mapping between Markdown syntax and Delta attributes.\n */\n\n/**\n * Characters that need escaping in Markdown text\n *\n * Note: `.` is only special at line start after a number (ordered lists)\n * We escape only the most impactful chars: \\ ` * _ [ ] < > #\n * Chars like `.` `!` `|` are context-dependent and rarely need escaping inline.\n */\nexport const MARKDOWN_ESCAPE_CHARS = /[\\\\`*_[\\]<>#]/g;\n\n/**\n * Escape special Markdown characters\n */\nexport function escapeMarkdown(text: string): string {\n return text.replace(MARKDOWN_ESCAPE_CHARS, '\\\\$&');\n}\n\n/**\n * Inline format to Markdown syntax mapping\n *\n * Note: underline, subscript, superscript, mark use HTML tags\n * since Markdown has no native syntax for them\n */\nexport const INLINE_FORMAT_SYNTAX: Record<string, { prefix: string; suffix: string }> = {\n bold: { prefix: '**', suffix: '**' },\n italic: { prefix: '_', suffix: '_' },\n underline: { prefix: '<u>', suffix: '</u>' },\n strike: { prefix: '~~', suffix: '~~' },\n subscript: { prefix: '<sub>', suffix: '</sub>' },\n superscript: { prefix: '<sup>', suffix: '</sup>' },\n code: { prefix: '`', suffix: '`' },\n mark: { prefix: '<mark>', suffix: '</mark>' },\n kbd: { prefix: '<kbd>', suffix: '</kbd>' },\n};\n\n/**\n * Order of inline formats for nesting (outer to inner)\n *\n * Bold + Italic → ***text***\n * Bold + Strike → **~~text~~**\n * Underline, subscript, superscript, mark → HTML tags in Markdown\n */\nexport const MD_INLINE_FORMAT_ORDER: string[] = [\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'subscript',\n 'superscript',\n 'code',\n 'mark',\n 'kbd',\n];\n\n/**\n * Block format to Markdown prefix mapping\n */\nexport const BLOCK_FORMAT_PREFIX: Record<string, string | ((value: unknown) => string)> = {\n header: (value: unknown) => {\n const level = typeof value === 'number' ? value : 1;\n return '#'.repeat(Math.min(Math.max(level, 1), 6)) + ' ';\n },\n blockquote: '> ',\n 'code-block': '', // Handled separately with fences\n};\n\n/**\n * List type to Markdown prefix\n */\nexport const LIST_TYPE_PREFIX: Record<string, string | ((index: number) => string)> = {\n bullet: '- ',\n ordered: (index: number) => `${index + 1}. `,\n checked: '- [x] ',\n unchecked: '- [ ] ',\n};\n\n/**\n * Generate indent prefix for nested lists\n */\nexport function getIndentPrefix(level: number): string {\n // Use 4 spaces for indentation (works for both bullet and ordered lists)\n return ' '.repeat(level);\n}\n\n/**\n * Render an image embed to Markdown\n */\nexport function renderImage(src: string, alt?: string, _title?: string): string {\n const altText = alt ?? '';\n return ``;\n}\n\n/**\n * Render a link to Markdown\n */\nexport function renderLink(text: string, href: string, _title?: string): string {\n return `[${text}](${href})`;\n}\n\n/**\n * Render a code block with optional language\n */\nexport function renderCodeBlock(code: string, language?: string): string {\n const lang = language ?? '';\n return `\\`\\`\\`${lang}\\n${code}\\n\\`\\`\\``;\n}\n","/**\n * Markdown → Delta Conversion\n *\n * Converts Markdown string to a Delta document using remark (unified).\n */\n\nimport { Delta } from '@scrider/delta';\nimport type { AttributeMap } from '@scrider/delta';\nimport type { BlockHandlerRegistry } from '../../schema/BlockHandlerRegistry';\nimport { htmlToDelta } from '../html/html-to-delta';\n\n/**\n * Options for Markdown → Delta conversion\n */\nexport interface MarkdownToDeltaOptions {\n /**\n * Enable GFM (GitHub Flavored Markdown) extensions\n * Includes: tables, strikethrough, task lists, autolinks\n * @default true\n */\n gfm?: boolean;\n\n /**\n * Display math rendering mode\n * - true (default): $$...$$ / ```math → code-block \"math\" in Delta\n * - false: $$...$$ / ```math → inline { formula } embed in Delta\n *\n * Does NOT affect inline math ($...$) — always becomes { formula } embed\n * @default true\n */\n mathBlock?: boolean;\n\n /**\n * Mermaid diagram rendering mode\n * - true (default): ```mermaid → code-block \"mermaid\" in Delta\n * - false: ```mermaid → inline { diagram } embed in Delta\n * @default true\n */\n mermaidBlock?: boolean;\n\n /**\n * PlantUML diagram rendering mode\n * - true (default): ```plantuml → code-block \"plantuml\" in Delta\n * - false: ```plantuml → inline { diagram } embed in Delta\n * @default true\n */\n plantumlBlock?: boolean;\n\n /**\n * Custom node handlers for special elements\n */\n nodeHandlers?: Record<string, NodeHandler>;\n\n /**\n * Block handler registry for Extended Table and other block embeds.\n * Reserved for future use — GFM tables don't support Extended Table features.\n * HTML tables in Markdown are parsed via htmlToDelta when blockHandlers is provided.\n */\n blockHandlers?: BlockHandlerRegistry;\n}\n\n/**\n * MDAST node type (simplified)\n */\ninterface MdastNode {\n type: string;\n children?: MdastNode[];\n value?: string;\n url?: string;\n alt?: string;\n title?: string;\n lang?: string;\n meta?: string;\n depth?: number;\n ordered?: boolean;\n checked?: boolean | null;\n spread?: boolean;\n /** Footnote identifier (for footnoteReference / footnoteDefinition) */\n identifier?: string;\n /** Footnote label (for footnoteReference / footnoteDefinition) */\n label?: string;\n}\n\n/**\n * Custom node handler function\n */\nexport type NodeHandler = (node: MdastNode, context: ParserContext) => void;\n\n/**\n * Parser context for building Delta\n */\nexport interface ParserContext {\n delta: Delta;\n pushText(text: string, attrs?: AttributeMap): void;\n pushEmbed(embed: Record<string, unknown>, attrs?: AttributeMap): void;\n pushNewline(attrs?: AttributeMap): void;\n}\n\n// Lazy-loaded remark modules\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet remarkParse: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet remarkGfm: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet remarkMath: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet unified: any = null;\n\n/**\n * Check if remark is available for synchronous use.\n *\n * Returns true if either:\n * - remark modules have been preloaded (via {@link preloadRemark} or a prior\n * `markdownToDelta` / `markdownToDeltaSync` call), OR\n * - CommonJS `require()` is available and can resolve `unified` and\n * `remark-parse` (Node.js without ESM-only mode).\n *\n * In browser ESM environments where `require` is undefined, this returns\n * `false` until {@link preloadRemark} has been awaited at least once.\n */\nexport function isRemarkAvailable(): boolean {\n if (unified && remarkParse) return true;\n if (typeof require === 'undefined') return false;\n try {\n require.resolve('unified');\n require.resolve('remark-parse');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Preload remark modules (`unified`, `remark-parse`, `remark-gfm`, optionally\n * `remark-math`) asynchronously. After this resolves successfully, the\n * synchronous {@link markdownToDeltaSync} is usable in environments where\n * `require()` is not available (e.g. browser ESM).\n *\n * Safe to call multiple times: subsequent calls short-circuit if modules are\n * already loaded.\n *\n * @returns `true` if mandatory modules (`unified`, `remark-parse`,\n * `remark-gfm`) are now loaded; `false` if any required module is missing.\n * The function never throws — callers can branch on the boolean for\n * graceful degradation.\n *\n * @example\n * // On editor mount:\n * useEffect(() => {\n * preloadRemark();\n * }, []);\n */\nexport async function preloadRemark(): Promise<boolean> {\n if (unified && remarkParse && remarkGfm) return true;\n\n try {\n const [unifiedMod, remarkParseMod, remarkGfmMod] = await Promise.all([\n import('unified'),\n import('remark-parse'),\n import('remark-gfm'),\n ]);\n unified = unifiedMod.unified;\n remarkParse = remarkParseMod.default;\n remarkGfm = remarkGfmMod.default;\n } catch {\n return false;\n }\n\n // remark-math is optional — enables $...$ and $$...$$ syntax\n if (!remarkMath) {\n try {\n const remarkMathMod = await import('remark-math');\n remarkMath = remarkMathMod.default;\n } catch {\n // remark-math not installed — $...$ will be treated as plain text\n }\n }\n\n return true;\n}\n\n/**\n * Preprocess markdown before parsing:\n * - Convert LaTeX math delimiters \\(...\\) → $...$ and \\[...\\] → $$...$$\n * - When mathBlock=true, promote standalone $...$ (entire line) to $$...$$ display math\n *\n * LaTeX delimiters are widely used by LLMs (DeepSeek, ChatGPT, Claude)\n * and are safe to convert since \\( \\) in plain Markdown is just escaped parens.\n *\n * Note: standalone <br> tags are replaced with <!--empty-line--> HTML comment sentinels\n * surrounded by blank lines. This makes remark parse them as block-level HTML nodes\n * (not inline HTML within a paragraph), avoiding newline duplication during roundtrip.\n * The sentinel is detected in processInlineHtml() which calls pushNewline().\n */\nfunction preprocessMarkdown(markdown: string, mathBlock: boolean): string {\n // Convert \\(...\\) → $...$ (inline math, single line)\n markdown = markdown.replace(/\\\\\\((.+?)\\\\\\)/g, (_match, content: string) => `$${content}$`);\n\n // Convert \\[...\\] → $$...$$ (display math, may span multiple lines)\n markdown = markdown.replace(/\\\\\\[([\\s\\S]+?)\\\\\\]/g, (_match, content: string) => `$$${content}$$`);\n\n // When mathBlock=true, promote standalone $...$ to $$\\n...\\n$$ (display math)\n // A line containing ONLY a single $...$ formula → display math block\n // remark-math requires $$ on separate lines for display math recognition\n // This handles DeepSeek/LLM output where $...$ is used on its own line for display formulas\n if (mathBlock) {\n markdown = markdown.replace(\n /^\\$([^$\\n]+)\\$\\s*$/gm,\n (_match, content: string) => `$$\\n${content}\\n$$`,\n );\n }\n\n // Replace standalone <br> with <!--empty-line--> sentinel surrounded by blank lines.\n // <br> tags are emitted by deltaToMarkdown(preserveEmptyLines: true) to represent\n // empty lines in the Delta. We convert them to block-level HTML comments so remark\n // creates a separate 'html' AST node (not inline HTML merged with paragraph text).\n // The sentinel is detected in processInlineHtml() which calls pushNewline(),\n // producing exactly one \\n per <br> — preserving empty lines through roundtrip.\n return markdown.replace(/^<br\\s*\\/?>$/gim, '\\n<!--empty-line-->\\n');\n}\n\n/**\n * Convert Markdown to Delta (async)\n */\nexport async function markdownToDelta(\n markdown: string,\n options: MarkdownToDeltaOptions = {},\n): Promise<Delta> {\n const {\n gfm = true,\n mathBlock = true,\n mermaidBlock = true,\n plantumlBlock = true,\n nodeHandlers = {},\n } = options;\n\n markdown = preprocessMarkdown(markdown, mathBlock);\n\n const loaded = await preloadRemark();\n if (!loaded || !unified || !remarkParse) {\n throw new Error(\n 'remark is not installed. Install with: pnpm add unified remark-parse remark-gfm',\n );\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n let processor = unified().use(remarkParse);\n\n if (gfm && remarkGfm) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n processor = processor.use(remarkGfm);\n }\n\n if (remarkMath) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n processor = processor.use(remarkMath);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n const tree = processor.parse(markdown) as MdastNode;\n\n return astToDelta(\n tree,\n nodeHandlers,\n mathBlock,\n mermaidBlock,\n plantumlBlock,\n options.blockHandlers,\n );\n}\n\n/**\n * Synchronous version (requires remark to be pre-loaded or uses require)\n */\nexport function markdownToDeltaSync(markdown: string, options: MarkdownToDeltaOptions = {}): Delta {\n const {\n gfm = true,\n mathBlock = true,\n mermaidBlock = true,\n plantumlBlock = true,\n nodeHandlers = {},\n } = options;\n\n markdown = preprocessMarkdown(markdown, mathBlock);\n\n if (!unified || !remarkParse) {\n if (typeof require === 'undefined') {\n throw new Error(\n 'markdownToDeltaSync requires remark to be preloaded in this environment. ' +\n '`require()` is not available (likely browser ESM). ' +\n 'Call `await preloadRemark()` once on application startup before using the sync API, ' +\n 'or use the async `markdownToDelta()` instead.',\n );\n }\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment\n const unifiedMod = require('unified');\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment\n const remarkParseMod = require('remark-parse');\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment\n const remarkGfmMod = require('remark-gfm');\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n unified = unifiedMod.unified;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n remarkParse = remarkParseMod.default;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n remarkGfm = remarkGfmMod.default;\n } catch {\n throw new Error(\n 'remark is not installed. Install with: pnpm add unified remark-parse remark-gfm',\n );\n }\n\n // remark-math is optional\n if (!remarkMath) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment\n const remarkMathMod = require('remark-math');\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n remarkMath = remarkMathMod.default;\n } catch {\n // remark-math not installed\n }\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n let processor = unified().use(remarkParse);\n\n if (gfm && remarkGfm) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n processor = processor.use(remarkGfm);\n }\n\n if (remarkMath) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n processor = processor.use(remarkMath);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n const tree = processor.parse(markdown) as MdastNode;\n\n return astToDelta(\n tree,\n nodeHandlers,\n mathBlock,\n mermaidBlock,\n plantumlBlock,\n options.blockHandlers,\n );\n}\n\n/**\n * Convert MDAST to Delta\n */\nfunction astToDelta(\n tree: MdastNode,\n customHandlers: Record<string, NodeHandler>,\n mathBlock: boolean,\n mermaidBlock: boolean,\n plantumlBlock: boolean,\n blockHandlers?: BlockHandlerRegistry,\n): Delta {\n const delta = new Delta();\n let currentInlineAttrs: AttributeMap = {};\n let pendingText = '';\n // Stack for tracking which attributes each <span style> added (for correct nested span handling)\n const spanAttrStack: string[][] = [];\n\n // Footnote definitions collected during AST traversal (for finalization)\n const footnoteDefinitions = new Map<string, MdastNode>();\n\n const context: ParserContext = {\n delta,\n pushText(text: string, attrs?: AttributeMap) {\n if (attrs && Object.keys(attrs).length > 0) {\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n delta.insert(text, { ...currentInlineAttrs, ...attrs });\n } else {\n pendingText += text;\n }\n },\n pushEmbed(embed: Record<string, unknown>, attrs?: AttributeMap) {\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n if (attrs && Object.keys(attrs).length > 0) {\n delta.insert(embed, attrs);\n } else {\n delta.insert(embed);\n }\n },\n pushNewline(attrs?: AttributeMap) {\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n if (attrs && Object.keys(attrs).length > 0) {\n delta.insert('\\n', attrs);\n } else {\n delta.insert('\\n');\n }\n },\n };\n\n // Heading ID extraction: parse {#custom-id} from heading text\n const HEADING_ID_RE = /\\s*\\{#([\\w-]+)\\}\\s*$/;\n\n /**\n * Extract custom heading id from `{#id}` suffix in heading text.\n * Mutates the last text child to strip the `{#id}` part.\n * Returns the extracted id, or null if none found.\n */\n function extractHeadingId(heading: MdastNode): string | null {\n const children = heading.children;\n if (!children || children.length === 0) return null;\n\n // Find the last text node\n const lastChild = children[children.length - 1];\n if (!lastChild || lastChild.type !== 'text' || !lastChild.value) return null;\n\n const match = lastChild.value.match(HEADING_ID_RE);\n if (!match) return null;\n\n // Strip {#id} from the text node\n lastChild.value = lastChild.value.replace(HEADING_ID_RE, '');\n\n return match[1]!;\n }\n\n // Alert type detection: check if blockquote starts with [!TYPE]\n const ALERT_TYPE_RE = /^\\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\]\\s*$/i;\n\n function extractAlertType(blockquote: MdastNode): string | null {\n const bqChildren = blockquote.children;\n if (!bqChildren || bqChildren.length === 0) return null;\n\n const firstChild = bqChildren[0];\n if (!firstChild || firstChild.type !== 'paragraph') return null;\n\n const paraChildren = firstChild.children;\n if (!paraChildren || paraChildren.length === 0) return null;\n\n const firstInline = paraChildren[0];\n if (!firstInline || firstInline.type !== 'text' || !firstInline.value) return null;\n\n const firstLine = firstInline.value.split('\\n')[0] ?? '';\n const match = ALERT_TYPE_RE.exec(firstLine.trim());\n if (!match || !match[1]) return null;\n\n return match[1].toLowerCase();\n }\n\n function processAlertBlockquote(blockquote: MdastNode, alertType: string): void {\n // Build a synthetic root with the blockquote's content, minus the [!TYPE] tag\n const children: MdastNode[] = [...(blockquote.children || [])];\n\n const first = children[0];\n if (first && first.type === 'paragraph' && first.children) {\n const firstPara: MdastNode = { ...first, children: [...first.children] };\n const firstInline = firstPara.children![0];\n\n if (firstInline && firstInline.type === 'text' && firstInline.value) {\n // Remove the [!TYPE] line from the text\n const lines = firstInline.value.split('\\n');\n lines.shift(); // remove \"[!TYPE]\" line\n const remaining = lines.join('\\n');\n\n if (remaining.trim().length > 0) {\n firstPara.children![0] = { ...firstInline, value: remaining };\n } else {\n firstPara.children!.shift();\n }\n\n if (firstPara.children!.length === 0) {\n children.shift();\n } else {\n children[0] = firstPara;\n }\n }\n }\n\n // Convert remaining content to nested Delta\n const syntheticRoot: MdastNode = {\n type: 'root',\n children,\n };\n const contentDelta = astToDelta(\n syntheticRoot,\n customHandlers,\n mathBlock,\n mermaidBlock,\n plantumlBlock,\n blockHandlers,\n );\n\n context.pushEmbed({\n block: {\n type: 'alert',\n alertType,\n content: { ops: contentDelta.ops },\n },\n });\n context.pushNewline();\n }\n\n function processNode(node: MdastNode, blockAttrs: AttributeMap = {}): void {\n const customHandler = customHandlers[node.type];\n if (customHandler) {\n customHandler(node, context);\n return;\n }\n\n switch (node.type) {\n case 'root':\n processChildren(node, blockAttrs);\n break;\n\n case 'paragraph':\n processChildren(node, blockAttrs);\n context.pushNewline(blockAttrs);\n break;\n\n case 'heading': {\n const headerId = extractHeadingId(node);\n processChildren(node, {});\n const headerAttrs: Record<string, unknown> = { header: node.depth ?? 1 };\n if (headerId) {\n headerAttrs['header-id'] = headerId;\n }\n context.pushNewline(headerAttrs);\n break;\n }\n\n case 'blockquote': {\n // Check for GitHub-style alert: > [!NOTE] / > [!TIP] / etc.\n const alertType = extractAlertType(node);\n if (alertType) {\n processAlertBlockquote(node, alertType);\n } else {\n processChildren(node, { blockquote: true });\n }\n break;\n }\n\n case 'list':\n processList(node);\n break;\n\n case 'listItem':\n break;\n\n case 'code':\n processCodeBlock(node);\n break;\n\n case 'table':\n processTable(node);\n break;\n\n case 'tableRow':\n case 'tableCell':\n // Handled inside processTable\n break;\n\n case 'thematicBreak':\n context.pushEmbed({ divider: true });\n context.pushNewline();\n break;\n\n case 'text':\n context.pushText(node.value ?? '');\n break;\n\n case 'strong':\n processInline(node, { bold: true });\n break;\n\n case 'emphasis':\n processInline(node, { italic: true });\n break;\n\n case 'delete':\n processInline(node, { strike: true });\n break;\n\n case 'inlineCode':\n context.pushText(node.value ?? '', { code: true });\n break;\n\n case 'link':\n processLink(node);\n break;\n\n case 'image':\n processImage(node);\n break;\n\n case 'inlineMath':\n // $...$ inline LaTeX formula → formula embed\n context.pushEmbed({ formula: node.value ?? '' });\n break;\n\n case 'math':\n // $$...$$ display math block → code-block with lang \"math\"\n processMathBlock(node);\n break;\n\n case 'footnoteReference':\n context.pushEmbed({ 'footnote-ref': node.identifier ?? '' });\n break;\n\n case 'footnoteDefinition':\n // Collect for post-processing — skip inline output\n footnoteDefinitions.set(node.identifier ?? '', node);\n break;\n\n case 'break':\n // GFM hard break (` \\n` or `\\\\\\n`) — soft line break inside the\n // current block, NOT a paragraph split. Emitted as a `softBreak`\n // embed so that round-trip with HTML `<br>` and editor-driven\n // Shift+Enter is consistent.\n context.pushEmbed({ softBreak: true });\n break;\n\n case 'html': {\n const htmlContent = node.value ?? '';\n if (isBlockLevelHtml(htmlContent)) {\n processBlockHtml(htmlContent);\n } else {\n processInlineHtml(node);\n }\n break;\n }\n\n default:\n if (node.children) {\n processChildren(node, blockAttrs);\n }\n }\n }\n\n function processChildren(node: MdastNode, blockAttrs: AttributeMap): void {\n if (!node.children) return;\n for (const child of node.children) {\n processNode(child, blockAttrs);\n }\n }\n\n function processInline(node: MdastNode, attrs: AttributeMap): void {\n const prevAttrs = { ...currentInlineAttrs };\n\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n\n currentInlineAttrs = { ...currentInlineAttrs, ...attrs };\n\n if (node.children) {\n for (const child of node.children) {\n processNode(child);\n }\n }\n\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n\n currentInlineAttrs = prevAttrs;\n }\n\n function processLink(node: MdastNode): void {\n processInline(node, { link: node.url ?? '' });\n }\n\n function processImage(node: MdastNode): void {\n const url = node.url ?? '';\n const alt = node.alt ?? '';\n\n //  → video embed (case-insensitive: ![video], ![VIDEO])\n if (alt.toLowerCase() === 'video') {\n context.pushEmbed({ video: url });\n return;\n }\n\n const attrs: AttributeMap = {};\n if (node.alt) attrs.alt = node.alt;\n\n // Detect .drawio files by extension — render as drawio embed instead of image\n if (url.toLowerCase().endsWith('.drawio')) {\n context.pushEmbed({ drawio: url }, Object.keys(attrs).length > 0 ? attrs : undefined);\n } else {\n context.pushEmbed({ image: url }, Object.keys(attrs).length > 0 ? attrs : undefined);\n }\n }\n\n function processList(node: MdastNode, indent = 0): void {\n if (!node.children) return;\n\n const ordered = node.ordered ?? false;\n\n for (const item of node.children) {\n if (item.type !== 'listItem') continue;\n\n let listType: string;\n if (item.checked === true) {\n listType = 'checked';\n } else if (item.checked === false) {\n listType = 'unchecked';\n } else {\n listType = ordered ? 'ordered' : 'bullet';\n }\n\n const blockAttrs: AttributeMap = { list: listType };\n if (indent > 0) {\n blockAttrs.indent = indent;\n }\n\n if (item.children) {\n for (const child of item.children) {\n if (child.type === 'list') {\n processList(child, indent + 1);\n } else if (child.type === 'paragraph') {\n processChildren(child, {});\n context.pushNewline(blockAttrs);\n } else {\n processNode(child, blockAttrs);\n }\n }\n }\n }\n }\n\n function processCodeBlock(node: MdastNode): void {\n const code = node.value ?? '';\n const lang = node.lang;\n\n // Mermaid: when mermaidBlock=false, flatten to inline { diagram } embed\n if (lang === 'mermaid' && mermaidBlock === false) {\n context.pushEmbed({ diagram: code });\n context.pushNewline();\n return;\n }\n\n // PlantUML: when plantumlBlock=false, flatten to inline { diagram } embed\n if (lang === 'plantuml' && plantumlBlock === false) {\n context.pushEmbed({ diagram: code });\n context.pushNewline();\n return;\n }\n\n const lines = code.split('\\n');\n const codeBlockAttr: AttributeMap = {\n 'code-block': lang ?? true,\n };\n\n for (const line of lines) {\n context.pushText(line);\n context.pushNewline(codeBlockAttr);\n }\n }\n\n /**\n * Process $$...$$ display math block.\n * mathBlock=true → code-block with lang \"math\"\n * mathBlock=false → inline { formula } embed\n */\n function processMathBlock(node: MdastNode): void {\n const value = node.value ?? '';\n\n if (mathBlock === false) {\n // Flatten display math to inline formula embed\n context.pushEmbed({ formula: value });\n context.pushNewline();\n } else {\n // Default: render as code-block \"math\"\n const lines = value.split('\\n');\n const mathBlockAttr: AttributeMap = { 'code-block': 'math' };\n\n for (const line of lines) {\n context.pushText(line);\n context.pushNewline(mathBlockAttr);\n }\n }\n }\n\n /**\n * Process GFM table node.\n * In MDAST, `table.align` is Array<'left'|'center'|'right'|null>.\n * First `tableRow` child is the header row.\n */\n function processTable(node: MdastNode): void {\n if (!node.children) return;\n\n // Table-level alignment array from remark-gfm\n const aligns: (string | null)[] = (node as unknown as { align: (string | null)[] }).align || [];\n\n for (let rowIdx = 0; rowIdx < node.children.length; rowIdx++) {\n const rowNode = node.children[rowIdx];\n if (!rowNode || rowNode.type !== 'tableRow') continue;\n\n const isHeader = rowIdx === 0; // GFM: first row is always header\n\n if (!rowNode.children) continue;\n\n for (let colIdx = 0; colIdx < rowNode.children.length; colIdx++) {\n const cellNode = rowNode.children[colIdx];\n if (!cellNode || cellNode.type !== 'tableCell') continue;\n\n // Build block attributes for this cell\n const cellBlockAttrs: AttributeMap = {\n 'table-row': rowIdx,\n 'table-col': colIdx,\n };\n if (isHeader) {\n cellBlockAttrs['table-header'] = true;\n }\n const colAlign = aligns[colIdx];\n if (colAlign) {\n cellBlockAttrs['table-col-align'] = colAlign;\n }\n\n // Process inline content of the cell\n if (cellNode.children) {\n for (const child of cellNode.children) {\n processNode(child);\n }\n }\n\n context.pushNewline(cellBlockAttrs);\n }\n }\n }\n\n /**\n * Check if HTML content starts with a block-level element tag.\n * Block-level HTML in Markdown is dispatched to htmlToDelta() for full parsing.\n */\n function isBlockLevelHtml(html: string): boolean {\n return /^\\s*<(div|table|section|article|aside|nav|header|footer|figure|pre|hr|ol|ul|dl|details|iframe|video)\\b/i.test(\n html,\n );\n }\n\n /**\n * Process block-level HTML by delegating to the existing htmlToDelta() converter.\n * This enables Markdown roundtrip for block embeds (Extended Table, Columns, Inline-Box, etc.)\n * that output HTML fallback in deltaToMarkdown.\n */\n function processBlockHtml(html: string): void {\n // Flush pending inline content\n flushInlineText();\n\n // Delegate to existing htmlToDelta with all registered block handlers\n const blockDelta = htmlToDelta(html, blockHandlers ? { blockHandlers } : {});\n\n // Merge ops from block conversion into current delta\n for (const op of blockDelta.ops) {\n delta.push(op);\n }\n }\n\n /**\n * Flush pending text into delta with current inline attributes.\n */\n function flushInlineText(): void {\n if (pendingText) {\n if (Object.keys(currentInlineAttrs).length > 0) {\n delta.insert(pendingText, currentInlineAttrs);\n } else {\n delta.insert(pendingText);\n }\n pendingText = '';\n }\n }\n\n /**\n * Map an HTML tag name to the corresponding Delta inline attribute.\n * Returns [attrName, attrValue] or null if not recognized.\n */\n function tagToInlineAttr(tag: string): [string, unknown] | null {\n switch (tag) {\n case 'u':\n case 'ins':\n return ['underline', true];\n case 'sub':\n return ['subscript', true];\n case 'sup':\n return ['superscript', true];\n case 'mark':\n return ['mark', true];\n case 'kbd':\n return ['kbd', true];\n case 'b':\n case 'strong':\n return ['bold', true];\n case 'i':\n case 'em':\n return ['italic', true];\n case 's':\n case 'del':\n case 'strike':\n return ['strike', true];\n default:\n return null;\n }\n }\n\n /**\n * Process inline HTML tags: <u>, <ins>, <sub>, <sup>, <mark>, <kbd>,\n * <b>, <strong>, <i>, <em>, <s>, <del>, <strike>, <span style=\"color/background\">.\n */\n function processInlineHtml(node: MdastNode): void {\n // Trim whitespace: remark HTML-block nodes may carry trailing newlines\n // that would prevent our ^…$ regex anchors from matching.\n const html = (node.value ?? '').trim();\n\n // Match opening tags: simple inline format tags\n const openTagMatch = html.match(/^<(u|ins|sub|sup|mark|kbd|b|strong|i|em|s|del|strike)>$/i);\n if (openTagMatch) {\n const tag = openTagMatch[1]?.toLowerCase() ?? '';\n flushInlineText();\n const attr = tagToInlineAttr(tag);\n if (attr) {\n currentInlineAttrs = { ...currentInlineAttrs, [attr[0]]: attr[1] };\n }\n return;\n }\n\n // Match closing tags: simple inline format tags\n const closeTagMatch = html.match(/^<\\/(u|ins|sub|sup|mark|kbd|b|strong|i|em|s|del|strike)>$/i);\n if (closeTagMatch) {\n const tag = closeTagMatch[1]?.toLowerCase() ?? '';\n flushInlineText();\n const attr = tagToInlineAttr(tag);\n if (attr) {\n const newAttrs = { ...currentInlineAttrs };\n delete newAttrs[attr[0]];\n currentInlineAttrs = newAttrs;\n }\n return;\n }\n\n // Opening <span style=\"...\"> — extract color and/or background-color\n const spanMatch = html.match(/^<span\\s+style=\"([^\"]*)\">/i);\n if (spanMatch) {\n flushInlineText();\n const style = spanMatch[1] ?? '';\n const addedKeys: string[] = [];\n\n const colorMatch = style.match(/(?:^|;)\\s*color\\s*:\\s*([^;]+)/i);\n if (colorMatch) {\n currentInlineAttrs = { ...currentInlineAttrs, color: colorMatch[1]!.trim() };\n addedKeys.push('color');\n }\n\n const bgMatch = style.match(/(?:^|;)\\s*background(?:-color)?\\s*:\\s*([^;]+)/i);\n if (bgMatch) {\n currentInlineAttrs = { ...currentInlineAttrs, background: bgMatch[1]!.trim() };\n addedKeys.push('background');\n }\n\n const fontMatch = style.match(/(?:^|;)\\s*font-family\\s*:\\s*([^;]+)/i);\n if (fontMatch) {\n currentInlineAttrs = {\n ...currentInlineAttrs,\n font: fontMatch[1]!.trim().replace(/^[\"']|[\"']$/g, ''),\n };\n addedKeys.push('font');\n }\n\n const sizeMatch = style.match(/(?:^|;)\\s*font-size\\s*:\\s*([^;]+)/i);\n if (sizeMatch) {\n currentInlineAttrs = { ...currentInlineAttrs, size: sizeMatch[1]!.trim() };\n addedKeys.push('size');\n }\n\n spanAttrStack.push(addedKeys);\n return;\n }\n\n // Closing </span> — pop attributes added by the matching opening <span>\n if (/^<\\/span>$/i.test(html)) {\n flushInlineText();\n const keys = spanAttrStack.pop();\n if (keys) {\n const newAttrs = { ...currentInlineAttrs };\n for (const key of keys) delete newAttrs[key];\n currentInlineAttrs = newAttrs;\n }\n return;\n }\n\n // Handle <img> void element with attributes (float, width, height)\n // This enables roundtrip for floated images: Delta→MD outputs <img data-float=\"...\">,\n // remark-parse sees it as inline HTML, and we reconstruct the image embed here.\n const imgMatch = html.match(/^<img\\s+([^>]*)\\/?>$/i);\n if (imgMatch) {\n const attrStr = imgMatch[1] ?? '';\n const srcMatch = attrStr.match(/src=\"([^\"]*)\"/);\n if (srcMatch) {\n flushInlineText();\n const attrs: AttributeMap = {};\n const altMatch = attrStr.match(/alt=\"([^\"]*)\"/);\n const floatMatch = attrStr.match(/data-float=\"([^\"]*)\"/);\n const widthMatch = attrStr.match(/width=\"([^\"]*)\"/);\n const heightMatch = attrStr.match(/height=\"([^\"]*)\"/);\n if (altMatch?.[1]) attrs.alt = altMatch[1];\n if (floatMatch?.[1]) attrs.float = floatMatch[1];\n if (widthMatch?.[1]) attrs.width = parseInt(widthMatch[1], 10) || widthMatch[1];\n if (heightMatch?.[1]) attrs.height = parseInt(heightMatch[1], 10) || heightMatch[1];\n context.pushEmbed(\n { image: srcMatch[1]! },\n Object.keys(attrs).length > 0 ? attrs : undefined,\n );\n // When <img> appears as a standalone HTML block (type-7), it needs a\n // trailing newline to close the Delta \"line\" — just like the original\n // Delta structure {insert:{image:…}} + {insert:\"\\n\"}.\n context.pushNewline();\n }\n return;\n }\n\n // Handle <!--empty-line--> sentinel (from preprocessMarkdown <br> replacement)\n if (html.trim() === '<!--empty-line-->') {\n context.pushNewline();\n return;\n }\n\n // Handle <br> / <br/> / <br data-scrider-embed> — inline line break\n // (e.g. `text1<br>text2`). Always becomes a softBreak embed so that\n // the construct survives round-trip through HTML, Delta and Markdown.\n if (/^<br\\b[^>]*\\/?>$/i.test(html)) {\n context.pushEmbed({ softBreak: true });\n return;\n }\n\n // For other HTML, just output as text (or skip)\n }\n\n processNode(tree);\n\n // Finalization: create footnotes block embed from collected definitions\n if (footnoteDefinitions.size > 0) {\n const notes: Record<string, { ops: unknown[] }> = {};\n for (const [id, defNode] of footnoteDefinitions) {\n // Convert each definition's children to a separate Delta\n const syntheticRoot: MdastNode = {\n type: 'root',\n children: defNode.children || [],\n };\n const defDelta = astToDelta(\n syntheticRoot,\n customHandlers,\n mathBlock,\n mermaidBlock,\n plantumlBlock,\n blockHandlers,\n );\n notes[id] = { ops: defDelta.ops };\n }\n context.pushEmbed({ block: { type: 'footnotes', notes } });\n context.pushNewline();\n }\n\n if (delta.ops.length > 0) {\n const lastOp = delta.ops[delta.ops.length - 1];\n if (lastOp && 'insert' in lastOp) {\n const lastInsert = lastOp.insert;\n // Add trailing \\n if the document doesn't end with one.\n // Covers both text not ending with \\n and embed objects (which have no \\n).\n if (typeof lastInsert !== 'string' || !lastInsert.endsWith('\\n')) {\n delta.insert('\\n');\n }\n }\n }\n\n return delta;\n}\n","/**\n * Simple-table region detection in flat Delta.\n *\n * Helpers for callers (e.g. editors that need to find the boundaries of a\n * markdown-style table within a Delta op stream — for example to enter\n * \"edit as markdown source\" mode on double-click of a rendered table cell).\n *\n * A simple-table region is a contiguous run of ops that ends, for each cell,\n * with a `\\n`-op carrying the `table-row` attribute (the standard format\n * produced by {@link markdownToDelta} for GFM tables and consumed by\n * {@link deltaToMarkdown}).\n */\n\nimport type { InsertOp, Op } from '@scrider/delta';\nimport { isInsert, isTextInsert } from '@scrider/delta';\n\n/**\n * Detected boundaries of a simple-table region.\n */\nexport interface TableRegion {\n /** Inclusive start index in the original ops array. */\n startOpIdx: number;\n /**\n * Inclusive end index — always points at the last `\\n`-op of the table\n * (the terminator of the last cell of the last row).\n */\n endOpIdx: number;\n /** Slice of the original ops array covering the region. */\n ops: InsertOp[];\n}\n\n/**\n * Predicate: this op is a `\\n`-op that terminates a simple-table cell\n * (i.e. it carries a `table-row` attribute).\n */\nexport function isTableNewlineOp(op: Op | undefined): boolean {\n if (!op || !isInsert(op) || !isTextInsert(op)) return false;\n if (!op.insert.includes('\\n')) return false;\n return !!op.attributes && 'table-row' in op.attributes;\n}\n\n/**\n * Find the boundaries of the simple-table region containing the given hint\n * op index. The hint may be:\n * - an inline op inside a cell,\n * - the cell-terminating `\\n`-op itself,\n * - any op between two table newlines.\n *\n * The function walks **forward** from the hint to find the nearest `\\n`-op:\n * if it does not carry a `table-row` attribute, the hint is not inside a\n * table and `null` is returned. Otherwise the algorithm extends the region\n * forward through contiguous table newlines and backward to the op just\n * after the previous non-table `\\n`-op (or the start of the array).\n *\n * @param ops - The full ops array (e.g. `delta.ops`).\n * @param hintOpIdx - Any op index known or guessed to be within a table.\n * @returns The detected region, or `null` if `hintOpIdx` is out of range or\n * not within any simple-table region.\n *\n * @example\n * // After hit-testing a `<td>` element to a Delta op index:\n * const region = extractTableRegion(state.delta.ops, hitOpIdx);\n * if (region) {\n * const md = deltaToMarkdown(new Delta(region.ops), {\n * trimTrailingNewlines: true,\n * });\n * // replace ops in [region.startOpIdx, region.endOpIdx] with a single\n * // { insert: md + '\\n' } op to enter source-edit mode\n * }\n */\nexport function extractTableRegion(\n ops: readonly Op[],\n hintOpIdx: number,\n): TableRegion | null {\n if (hintOpIdx < 0 || hintOpIdx >= ops.length) return null;\n\n // Step 1: find the first \\n-op at or after the hint. If it is not a\n // table-newline, the hint is not inside a table cell.\n let probeIdx = -1;\n for (let i = hintOpIdx; i < ops.length; i++) {\n const op = ops[i];\n if (!op || !isInsert(op)) continue;\n if (isTextInsert(op) && op.insert.includes('\\n')) {\n probeIdx = i;\n break;\n }\n }\n if (probeIdx < 0) return null;\n if (!isTableNewlineOp(ops[probeIdx])) return null;\n\n // Step 2: extend forward. The last contiguous table-newline is the end.\n let endOpIdx = probeIdx;\n for (let i = probeIdx + 1; i < ops.length; i++) {\n const op = ops[i];\n if (!op || !isInsert(op)) break;\n if (isTextInsert(op) && op.insert.includes('\\n')) {\n if (isTableNewlineOp(op)) {\n endOpIdx = i;\n } else {\n break;\n }\n }\n }\n\n // Step 3: extend backward. The table starts right after the previous\n // non-table \\n-op (or at index 0 if none).\n let startOpIdx = 0;\n for (let i = probeIdx - 1; i >= 0; i--) {\n const op = ops[i];\n if (!op || !isInsert(op)) {\n startOpIdx = i + 1;\n break;\n }\n if (isTextInsert(op) && op.insert.includes('\\n') && !isTableNewlineOp(op)) {\n startOpIdx = i + 1;\n break;\n }\n }\n\n const regionOps = ops.slice(startOpIdx, endOpIdx + 1) as InsertOp[];\n return { startOpIdx, endOpIdx, ops: regionOps };\n}\n"],"mappings":"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","names":["import_delta","import_delta","import_delta","import_delta","import_delta","import_delta","import_delta","blockFormat","children","import_delta","renderCodeBlock","splitIntoLines","collectTableLines","getCodeBlockLanguage","renderLineContent","renderCodeBlock","renderInlineText","renderEmbed","import_delta","import_delta"]}
|