@scrider/formatter 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1658 @@
1
+ import { AttributeMap, Op, Delta } from '@scrider/delta';
2
+ export * from '@scrider/delta';
3
+
4
+ /**
5
+ * DOM Adapter Interface
6
+ *
7
+ * Provides a unified interface for DOM operations across different environments:
8
+ * - Browser: uses native DOM APIs
9
+ * - Node.js: uses jsdom
10
+ *
11
+ * This abstraction allows the same conversion code to work in both environments.
12
+ */
13
+ /**
14
+ * Minimal Document interface required for HTML parsing/rendering
15
+ */
16
+ interface DOMDocument {
17
+ createElement(tagName: string): DOMElement;
18
+ createTextNode(text: string): DOMNode;
19
+ createDocumentFragment(): DOMDocumentFragment;
20
+ readonly body: DOMElement;
21
+ }
22
+ /**
23
+ * Minimal DocumentFragment interface
24
+ */
25
+ interface DOMDocumentFragment {
26
+ appendChild(node: DOMNode): DOMNode;
27
+ readonly childNodes: DOMNodeList;
28
+ readonly firstChild: DOMNode | null;
29
+ readonly nodeType: number;
30
+ readonly textContent: string | null;
31
+ }
32
+ /**
33
+ * Minimal Node interface
34
+ */
35
+ interface DOMNode {
36
+ readonly nodeType: number;
37
+ readonly nodeName: string;
38
+ readonly parentNode: DOMNode | null;
39
+ readonly childNodes: DOMNodeList;
40
+ readonly firstChild: DOMNode | null;
41
+ readonly nextSibling: DOMNode | null;
42
+ textContent: string | null;
43
+ appendChild(node: DOMNode): DOMNode;
44
+ cloneNode(deep?: boolean): DOMNode;
45
+ }
46
+ /**
47
+ * Minimal Element interface
48
+ */
49
+ interface DOMElement extends DOMNode {
50
+ readonly tagName: string;
51
+ innerHTML: string;
52
+ outerHTML: string;
53
+ getAttribute(name: string): string | null;
54
+ setAttribute(name: string, value: string): void;
55
+ hasAttribute(name: string): boolean;
56
+ removeAttribute(name: string): void;
57
+ readonly style: DOMCSSStyleDeclaration;
58
+ readonly classList: DOMTokenList;
59
+ querySelector(selector: string): DOMElement | null;
60
+ querySelectorAll(selector: string): DOMNodeList;
61
+ }
62
+ /**
63
+ * Minimal CSSStyleDeclaration interface
64
+ */
65
+ interface DOMCSSStyleDeclaration {
66
+ getPropertyValue(property: string): string;
67
+ setProperty(property: string, value: string): void;
68
+ color?: string;
69
+ backgroundColor?: string;
70
+ fontWeight?: string;
71
+ fontStyle?: string;
72
+ textDecoration?: string;
73
+ textAlign?: string;
74
+ }
75
+ /**
76
+ * Minimal DOMTokenList interface (for classList)
77
+ */
78
+ interface DOMTokenList {
79
+ add(...tokens: string[]): void;
80
+ remove(...tokens: string[]): void;
81
+ contains(token: string): boolean;
82
+ readonly length: number;
83
+ }
84
+ /**
85
+ * Minimal NodeList interface
86
+ */
87
+ interface DOMNodeList {
88
+ readonly length: number;
89
+ item(index: number): DOMNode | null;
90
+ [index: number]: DOMNode;
91
+ forEach(callback: (node: DOMNode, index: number) => void): void;
92
+ }
93
+ /**
94
+ * Node type constants
95
+ */
96
+ declare const NODE_TYPE: {
97
+ readonly ELEMENT_NODE: 1;
98
+ readonly TEXT_NODE: 3;
99
+ readonly DOCUMENT_NODE: 9;
100
+ readonly DOCUMENT_FRAGMENT_NODE: 11;
101
+ };
102
+ /**
103
+ * DOM Adapter interface
104
+ *
105
+ * Provides methods for creating and manipulating DOM structures
106
+ * in a platform-agnostic way.
107
+ */
108
+ interface DOMAdapter {
109
+ /**
110
+ * Parse HTML string into a document fragment
111
+ */
112
+ parseHTML(html: string): DOMDocumentFragment;
113
+ /**
114
+ * Serialize a node to HTML string
115
+ */
116
+ serializeHTML(node: DOMNode | DOMDocumentFragment): string;
117
+ /**
118
+ * Create a new document for building DOM structures
119
+ */
120
+ createDocument(): DOMDocument;
121
+ /**
122
+ * Check if this adapter is available in the current environment
123
+ */
124
+ isAvailable(): boolean;
125
+ }
126
+ /**
127
+ * Type guard: check if node is an Element
128
+ */
129
+ declare function isElement(node: DOMNode): node is DOMElement;
130
+ /**
131
+ * Type guard: check if node is a Text node
132
+ */
133
+ declare function isTextNode(node: DOMNode): boolean;
134
+
135
+ /**
136
+ * Scope of a format
137
+ *
138
+ * - inline: applies to text runs (bold, italic, link, color...)
139
+ * - block: applies to lines (header, list, blockquote...)
140
+ * - embed: non-text content (image, video, formula...)
141
+ */
142
+ type FormatScope = 'inline' | 'block' | 'embed';
143
+ /**
144
+ * Result returned by Format.match() when an HTML element is recognized.
145
+ */
146
+ interface FormatMatchResult<T = unknown> {
147
+ /** The embed value for Delta (e.g. URL string, boolean, etc.) */
148
+ value: T;
149
+ /** Optional attributes to attach to the op (e.g. alt, width, height) */
150
+ attributes?: AttributeMap;
151
+ }
152
+ /**
153
+ * Format interface with optional conversion methods.
154
+ *
155
+ * Three-level extensibility:
156
+ * - Level 1 (validate/normalize): format works in Delta, no conversion
157
+ * - Level 2 (render/match): HTML roundtrip — Delta ↔ HTML
158
+ * - Level 3 (toMarkdown/fromMarkdown): Markdown roundtrip — Delta ↔ Markdown
159
+ *
160
+ * @template T - The type of the attribute value
161
+ */
162
+ interface Format<T = unknown> {
163
+ /**
164
+ * Name of the attribute in Delta
165
+ * Must be unique within a Registry
166
+ */
167
+ readonly name: string;
168
+ /**
169
+ * Scope of the format
170
+ */
171
+ readonly scope: FormatScope;
172
+ /**
173
+ * Normalize value to canonical form
174
+ *
175
+ * Examples:
176
+ * - 'red' → '#ff0000'
177
+ * - 'RGB(255,0,0)' → '#ff0000'
178
+ * - 7 (header) → 6 (clamped)
179
+ *
180
+ * @param value - The value to normalize
181
+ * @returns Normalized value
182
+ */
183
+ normalize?(value: T): T;
184
+ /**
185
+ * Validate that a value is acceptable
186
+ *
187
+ * @param value - The value to validate
188
+ * @returns true if value is valid
189
+ */
190
+ validate?(value: T): boolean;
191
+ /**
192
+ * Render Delta value to HTML string.
193
+ *
194
+ * Used by deltaToHtml for embed formats. If not provided,
195
+ * the converter falls back to built-in EMBED_RENDERERS config.
196
+ *
197
+ * @param value - The embed value (e.g. URL string)
198
+ * @param attributes - Op-level attributes (alt, width, height, etc.)
199
+ * @returns HTML string
200
+ */
201
+ render?(value: T, attributes?: AttributeMap): string;
202
+ /**
203
+ * Match an HTML element and extract Delta embed value.
204
+ *
205
+ * Used by htmlToDelta to recognize custom elements.
206
+ * Return null if this element is not a match for this format.
207
+ *
208
+ * @param element - The DOM element to inspect
209
+ * @returns Match result with value and optional attributes, or null
210
+ */
211
+ match?(element: DOMElement): FormatMatchResult<T> | null;
212
+ /**
213
+ * Render Delta value to Markdown string.
214
+ *
215
+ * Return null to fall back to HTML-in-Markdown (current behavior
216
+ * for embeds without native Markdown representation).
217
+ *
218
+ * @param value - The embed value
219
+ * @param attributes - Op-level attributes
220
+ * @returns Markdown string, or null for HTML fallback
221
+ */
222
+ toMarkdown?(value: T, attributes?: AttributeMap): string | null;
223
+ /**
224
+ * Parse a Markdown AST node into a Delta embed value.
225
+ *
226
+ * Used by markdownToDelta to recognize custom Markdown patterns
227
+ * (e.g. image-like URLs, fenced code blocks with custom language).
228
+ *
229
+ * @param node - Markdown AST node (MDAST)
230
+ * @returns Match result with value and optional attributes, or null
231
+ */
232
+ fromMarkdown?(node: unknown): FormatMatchResult<T> | null;
233
+ }
234
+ /**
235
+ * Helper type for creating format objects
236
+ */
237
+ type FormatDefinition<T = unknown> = Format<T>;
238
+
239
+ /**
240
+ * Registry of formats
241
+ *
242
+ * Manages a collection of Format definitions for validation,
243
+ * normalization, and sanitization of Delta attributes.
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * const registry = new Registry()
248
+ * .register(boldFormat)
249
+ * .register(italicFormat)
250
+ * .register(colorFormat);
251
+ *
252
+ * // Normalize attributes
253
+ * registry.normalize({ color: 'red' });
254
+ * // { color: '#ff0000' }
255
+ *
256
+ * // Validate attributes
257
+ * registry.validate({ header: 3 }); // true
258
+ * registry.validate({ header: 10 }); // false
259
+ * ```
260
+ */
261
+ declare class Registry {
262
+ private formats;
263
+ /**
264
+ * Register a format or array of formats
265
+ *
266
+ * @param format - Format or array of formats to register
267
+ * @returns this for chaining
268
+ */
269
+ register(format: Format): this;
270
+ register(formats: Format[]): this;
271
+ /**
272
+ * Get a format by name
273
+ *
274
+ * @param name - Format name
275
+ * @returns Format or undefined if not found
276
+ */
277
+ get(name: string): Format | undefined;
278
+ /**
279
+ * Check if a format is registered
280
+ *
281
+ * @param name - Format name
282
+ * @returns true if format exists
283
+ */
284
+ has(name: string): boolean;
285
+ /**
286
+ * Get all formats with a specific scope
287
+ *
288
+ * @param scope - Format scope to filter by
289
+ * @returns Array of formats with the given scope
290
+ */
291
+ getByScope(scope: FormatScope): Format[];
292
+ /**
293
+ * Get all registered format names
294
+ *
295
+ * @returns Array of format names
296
+ */
297
+ getNames(): string[];
298
+ /**
299
+ * Normalize all attributes using registered formats
300
+ *
301
+ * Applies normalize() for each attribute that has a registered format.
302
+ * Unknown attributes are passed through unchanged.
303
+ *
304
+ * @param attributes - Attributes to normalize
305
+ * @returns New object with normalized attributes
306
+ */
307
+ normalize(attributes: AttributeMap | undefined): AttributeMap | undefined;
308
+ /**
309
+ * Validate all attributes
310
+ *
311
+ * @param attributes - Attributes to validate
312
+ * @returns true if all known attributes are valid
313
+ */
314
+ validate(attributes: AttributeMap | undefined): boolean;
315
+ /**
316
+ * Sanitize attributes by removing invalid values
317
+ *
318
+ * Removes attributes that:
319
+ * - Are not registered (unknown formats)
320
+ * - Fail validation
321
+ *
322
+ * @param attributes - Attributes to sanitize
323
+ * @param removeUnknown - If true, remove unregistered attributes (default: true)
324
+ * @returns New object with only valid attributes
325
+ */
326
+ sanitize(attributes: AttributeMap | undefined, removeUnknown?: boolean): AttributeMap | undefined;
327
+ /**
328
+ * Get the number of registered formats
329
+ */
330
+ get size(): number;
331
+ }
332
+
333
+ /**
334
+ * Options for block rendering
335
+ */
336
+ interface BlockRenderOptions {
337
+ /** Pretty-print HTML output */
338
+ pretty?: boolean;
339
+ /** Indentation level for pretty-print */
340
+ indent?: number;
341
+ /** How to interpret colWidths: percent (default) or pixel */
342
+ tableWidthMode?: 'percent' | 'pixel';
343
+ }
344
+ /**
345
+ * Context injected by converters into BlockHandler methods.
346
+ *
347
+ * Solves cyclic dependencies: handlers live in schema layer,
348
+ * converters live in conversion layer. Converters pass themselves
349
+ * as callbacks via context — no direct imports between layers.
350
+ */
351
+ interface BlockContext {
352
+ /** Format registry for attribute validation/normalization */
353
+ registry: Registry;
354
+ /** Render options */
355
+ options?: BlockRenderOptions;
356
+ /** Render nested Delta ops → HTML (injected by deltaToHtml) */
357
+ renderDelta?: (ops: Op[]) => string;
358
+ /** Parse HTML element → Delta ops (injected by htmlToDelta) */
359
+ parseElement?: (element: DOMElement) => Op[];
360
+ /**
361
+ * Op-level attributes from the Delta operation containing this block embed.
362
+ * Used by handlers that store visual properties (float, width, height, overflow)
363
+ * in op attributes rather than in block data (e.g. Inline-Box).
364
+ */
365
+ opAttributes?: Record<string, unknown>;
366
+ }
367
+ /**
368
+ * Generic handler for complex block embeds with nested Delta content.
369
+ *
370
+ * Block embeds use a single `block` key in Delta:
371
+ * `{ insert: { block: { type: "table", ... } } }`
372
+ *
373
+ * The `type` field dispatches to the appropriate BlockHandler
374
+ * via BlockHandlerRegistry.
375
+ *
376
+ * T includes `type` — data is stored as `{ block: T }` where T
377
+ * is the full object including `type`. No destructuring needed.
378
+ *
379
+ * @template T - Block data type (e.g. TableBlockData)
380
+ */
381
+ interface BlockHandler<T = unknown> {
382
+ /** Unique block type — value of `type` field in block embed */
383
+ readonly type: string;
384
+ /** Semantic validation of block data (cells, colWidths, etc.) */
385
+ validate(data: T): boolean;
386
+ /** Delta → HTML (context.renderDelta for nested Delta) */
387
+ toHtml(data: T, context: BlockContext): string;
388
+ /** HTML element → block data (context.parseElement for cells) */
389
+ fromHtml(element: DOMElement, context: BlockContext): T | null;
390
+ /** Delta → Markdown (null = fallback to toHtml) */
391
+ toMarkdown?(data: T, context: BlockContext): string | null;
392
+ /** Markdown AST node → block data */
393
+ fromMarkdown?(node: unknown, context: BlockContext): T | null;
394
+ /** Normalize block data + recursive normalization of nested Deltas */
395
+ normalize?(data: T, registry: Registry): T;
396
+ /** Extract all nested Deltas from block */
397
+ getNestedDeltas?(data: T): Op[][];
398
+ /** Replace nested Deltas (immutable, returns new T) */
399
+ setNestedDeltas?(data: T, deltas: Op[][]): T;
400
+ compose?(base: T, change: T): T;
401
+ transform?(a: T, b: T, priority: boolean): T;
402
+ }
403
+
404
+ /**
405
+ * Registry for BlockHandler implementations.
406
+ *
407
+ * Separate from Registry (FormatRegistry) — different responsibilities:
408
+ * - Registry: attribute validation/normalization (key-value pairs, primitives)
409
+ * - BlockHandlerRegistry: block rendering/parsing (complex structures with nested Delta)
410
+ *
411
+ * Connected to converters via options:
412
+ * ```typescript
413
+ * deltaToHtml(delta, { registry, blockHandlers });
414
+ * htmlToDelta(html, { registry, blockHandlers });
415
+ * ```
416
+ *
417
+ * @example
418
+ * ```typescript
419
+ * const blockHandlers = new BlockHandlerRegistry()
420
+ * .register(tableBlockHandler);
421
+ *
422
+ * deltaToHtml(delta, { registry, blockHandlers });
423
+ * ```
424
+ */
425
+ declare class BlockHandlerRegistry {
426
+ private handlers;
427
+ /**
428
+ * Register a block handler
429
+ *
430
+ * @param handler - BlockHandler to register
431
+ * @returns this for chaining
432
+ * @throws Error if handler with same type is already registered
433
+ */
434
+ register(handler: BlockHandler): this;
435
+ /**
436
+ * Get a handler by block type
437
+ *
438
+ * @param type - Block type (e.g. "table")
439
+ * @returns BlockHandler or undefined if not found
440
+ */
441
+ get(type: string): BlockHandler | undefined;
442
+ /**
443
+ * Check if a handler is registered for a block type
444
+ *
445
+ * @param type - Block type
446
+ * @returns true if handler exists
447
+ */
448
+ has(type: string): boolean;
449
+ /**
450
+ * Get the number of registered handlers
451
+ */
452
+ get size(): number;
453
+ /**
454
+ * Get all registered block type names
455
+ */
456
+ getTypes(): string[];
457
+ }
458
+
459
+ /**
460
+ * Cell alignment options
461
+ */
462
+ type CellAlign = 'left' | 'center' | 'right';
463
+ /**
464
+ * Data for a single cell in an Extended Table.
465
+ *
466
+ * Every non-merged cell must have `ops` — a nested Delta (Op[]).
467
+ * Empty cells use `{ ops: [{ insert: "\n" }] }`.
468
+ */
469
+ interface CellData {
470
+ /** Nested Delta content (full rich-text) */
471
+ ops: Op[];
472
+ /** Number of columns this cell spans (default: 1) */
473
+ colspan?: number;
474
+ /** Number of rows this cell spans (default: 1) */
475
+ rowspan?: number;
476
+ }
477
+ /**
478
+ * Extended Table block data.
479
+ *
480
+ * Stored in Delta as: `{ insert: { block: <TableBlockData> } }`
481
+ *
482
+ * All coordinates "r:c" within the grid MUST be present in `cells`.
483
+ * - `CellData` — cell with content
484
+ * - `null` — cell absorbed by neighbor's colspan/rowspan
485
+ * - Missing key — INVALID (validate() rejects)
486
+ */
487
+ interface TableBlockData {
488
+ /** Block type discriminator */
489
+ type: 'table';
490
+ /** Number of header rows (default: 0) */
491
+ headerRows?: number;
492
+ /** Column widths (percentages by default) */
493
+ colWidths?: number[];
494
+ /** Column alignments */
495
+ colAligns?: (CellAlign | null)[];
496
+ /** Cells indexed by "row:col" */
497
+ cells: Record<string, CellData | null>;
498
+ }
499
+ /**
500
+ * BlockHandler implementation for Extended Table.
501
+ *
502
+ * Handles validation, HTML conversion, and nested Delta access.
503
+ * toHtml/fromHtml are implemented in E.3/E.4 stages.
504
+ */
505
+ declare const tableBlockHandler: BlockHandler<TableBlockData>;
506
+
507
+ /**
508
+ * Footnotes block data — a collection of footnote definitions.
509
+ *
510
+ * Stored in Delta as: `{ insert: { block: <FootnotesBlockData> } }`
511
+ *
512
+ * Each note is keyed by its string identifier (e.g. "1", "note", "my-ref").
513
+ * Values contain nested Delta content (rich-text).
514
+ *
515
+ * Placed at the end of the document, after all content.
516
+ */
517
+ interface FootnotesBlockData {
518
+ /** Block type discriminator */
519
+ type: 'footnotes';
520
+ /** Map of footnote id → content (nested Delta ops) */
521
+ notes: Record<string, {
522
+ ops: Op[];
523
+ }>;
524
+ }
525
+ /**
526
+ * BlockHandler implementation for Footnotes.
527
+ *
528
+ * Handles a single block embed containing all footnote definitions.
529
+ * Each footnote has an id and nested Delta content.
530
+ *
531
+ * HTML: <section class="footnotes"><ol><li id="fn-{id}">...</li></ol></section>
532
+ * Markdown: [^id]: content
533
+ */
534
+ declare const footnotesBlockHandler: BlockHandler<FootnotesBlockData>;
535
+
536
+ /** The 5 standard GitHub alert types */
537
+ declare const ALERT_TYPES: readonly ["note", "tip", "important", "warning", "caution"];
538
+ /** Union of valid alert types */
539
+ type AlertType = (typeof ALERT_TYPES)[number];
540
+ /**
541
+ * Alert / Admonition block data.
542
+ *
543
+ * Stored in Delta as: `{ insert: { block: <AlertBlockData> } }`
544
+ *
545
+ * GitHub-style alerts:
546
+ * ```markdown
547
+ * > [!NOTE]
548
+ * > Useful information.
549
+ * ```
550
+ *
551
+ * HTML:
552
+ * ```html
553
+ * <div class="markdown-alert markdown-alert-note">
554
+ * <p class="markdown-alert-title">Note</p>
555
+ * <p>Useful information.</p>
556
+ * </div>
557
+ * ```
558
+ */
559
+ interface AlertBlockData {
560
+ /** Block type discriminator */
561
+ type: 'alert';
562
+ /** Alert variant (note, tip, important, warning, caution) */
563
+ alertType: AlertType;
564
+ /** Nested Delta content (rich text) */
565
+ content: {
566
+ ops: Op[];
567
+ };
568
+ }
569
+ /**
570
+ * BlockHandler implementation for Alerts / Admonitions.
571
+ *
572
+ * Handles GitHub-style alerts (5 types: note, tip, important, warning, caution).
573
+ * Each alert contains nested Delta content (rich text).
574
+ *
575
+ * HTML: `<div class="markdown-alert markdown-alert-{type}"><p class="markdown-alert-title">{Type}</p>...</div>`
576
+ * Markdown: `> [!TYPE]\n> content`
577
+ */
578
+ declare const alertBlockHandler: BlockHandler<AlertBlockData>;
579
+
580
+ /**
581
+ * Columns Layout block data.
582
+ *
583
+ * Stored in Delta as: `{ insert: { block: <ColumnsBlockData> } }`
584
+ *
585
+ * Each column contains a full nested Delta (rich text, embeds, nested blocks).
586
+ *
587
+ * HTML:
588
+ * ```html
589
+ * <div class="columns columns-2">
590
+ * <div class="column"><p>Column 1</p></div>
591
+ * <div class="column"><p>Column 2</p></div>
592
+ * </div>
593
+ * ```
594
+ *
595
+ * With custom widths:
596
+ * ```html
597
+ * <div class="columns columns-2" style="grid-template-columns: 30% 70%">
598
+ * <div class="column"><p>Sidebar</p></div>
599
+ * <div class="column"><p>Main content</p></div>
600
+ * </div>
601
+ * ```
602
+ *
603
+ * Markdown: no native equivalent → toMarkdown returns null → HTML fallback.
604
+ *
605
+ * Resize-ready: `widths` for per-column resize (future scrider-editor),
606
+ * `width`/`height` in op attributes for overall dimensions.
607
+ */
608
+ interface ColumnsBlockData {
609
+ /** Block type discriminator */
610
+ type: 'columns';
611
+ /** Column contents — array of nested Deltas */
612
+ columns: {
613
+ ops: Op[];
614
+ }[];
615
+ /** Optional: column widths in percent (sum ≈ 100). Default: equal (CSS 1fr each) */
616
+ widths?: number[];
617
+ }
618
+ /**
619
+ * BlockHandler implementation for Columns Layout.
620
+ *
621
+ * Multi-column layout with nested Delta content in each column.
622
+ * Analogous to Alert (nested Delta) but with an array of columns.
623
+ *
624
+ * HTML: `<div class="columns columns-N" [style="grid-template-columns: W1% W2%"]>
625
+ * <div class="column">...</div>...
626
+ * </div>`
627
+ * Markdown: no equivalent → toMarkdown returns null → HTML fallback
628
+ */
629
+ declare const columnsBlockHandler: BlockHandler<ColumnsBlockData>;
630
+
631
+ /** Valid float positions for Inline-Box */
632
+ declare const BOX_FLOAT_VALUES: readonly ["left", "right", "center"];
633
+ /** Valid overflow modes for Inline-Box */
634
+ declare const BOX_OVERFLOW_VALUES: readonly ["auto", "hidden", "visible"];
635
+ /** Union of valid float positions */
636
+ type BoxFloat = (typeof BOX_FLOAT_VALUES)[number];
637
+ /** Union of valid overflow modes */
638
+ type BoxOverflow = (typeof BOX_OVERFLOW_VALUES)[number];
639
+ /**
640
+ * Inline-Box block data.
641
+ *
642
+ * Stored in Delta as: `{ insert: { block: <BoxBlockData> }, attributes: { float, width, height, overflow } }`
643
+ *
644
+ * A float container with nested Delta content and text wrapping.
645
+ * Visual properties (float, width, height, overflow) are stored in op attributes,
646
+ * not in block data — clean separation of semantics vs presentation.
647
+ *
648
+ * HTML (float left/right):
649
+ * ```html
650
+ * <div class="inline-box" data-float="left" data-overflow="auto"
651
+ * style="width: 200px; height: 300px;">
652
+ * <p>Rich content</p>
653
+ * </div>
654
+ * ```
655
+ *
656
+ * HTML (center — no wrapping):
657
+ * ```html
658
+ * <div class="inline-box" data-float="center" data-overflow="auto"
659
+ * style="width: 200px; height: 300px;">
660
+ * <p>Content</p>
661
+ * </div>
662
+ * ```
663
+ *
664
+ * Markdown: no native equivalent → toMarkdown returns null → HTML fallback.
665
+ */
666
+ interface BoxBlockData {
667
+ /** Block type discriminator */
668
+ type: 'box';
669
+ /** Nested Delta content (rich text) */
670
+ content: {
671
+ ops: Op[];
672
+ };
673
+ }
674
+ /**
675
+ * Op-level attributes for box block embed.
676
+ * Stored in `op.attributes`, not in block data.
677
+ */
678
+ interface BoxOpAttributes {
679
+ /** Float position: left/right = text wrapping, center = no wrapping */
680
+ float?: BoxFloat;
681
+ /** Container width (e.g. "200px", "30%") */
682
+ width?: string;
683
+ /** Container height (e.g. "300px", "auto") */
684
+ height?: string;
685
+ /** Overflow behavior when content exceeds dimensions */
686
+ overflow?: BoxOverflow;
687
+ }
688
+ /**
689
+ * BlockHandler implementation for Inline-Box (Float Container).
690
+ *
691
+ * A container with nested Delta content that supports float positioning
692
+ * and text wrapping. Like Alert (single nested Delta), but visual
693
+ * properties are stored in op attributes, not in block data.
694
+ *
695
+ * HTML: `<div class="inline-box" data-float="F" data-overflow="O" style="width: W; height: H">...</div>`
696
+ * Markdown: no equivalent → toMarkdown returns null → HTML fallback
697
+ */
698
+ declare const boxBlockHandler: BlockHandler<BoxBlockData>;
699
+ /**
700
+ * Extract op attributes for box from an HTML element.
701
+ *
702
+ * Used by html-to-delta intercept to reconstruct op attributes
703
+ * (float, width, height, overflow) from the HTML representation.
704
+ */
705
+ declare function extractBoxOpAttributes(element: DOMElement): BoxOpAttributes;
706
+
707
+ /**
708
+ * All default inline formats
709
+ */
710
+ declare const defaultInlineFormats: Format[];
711
+ /**
712
+ * All default block formats
713
+ */
714
+ declare const defaultBlockFormats: Format[];
715
+ /**
716
+ * All default embed formats
717
+ */
718
+ declare const defaultEmbedFormats: Format[];
719
+ /**
720
+ * All default formats combined
721
+ */
722
+ declare const defaultFormats: Format[];
723
+ /**
724
+ * Create a Registry with all default formats registered
725
+ *
726
+ * @returns Registry with standard formats
727
+ *
728
+ * @example
729
+ * ```typescript
730
+ * const registry = createDefaultRegistry();
731
+ * registry.normalize({ color: 'red' }); // { color: '#ff0000' }
732
+ * ```
733
+ */
734
+ declare function createDefaultRegistry(): Registry;
735
+ /**
736
+ * Create a BlockHandlerRegistry with default block handlers
737
+ *
738
+ * Includes:
739
+ * - tableBlockHandler (Extended Table)
740
+ * - footnotesBlockHandler (Footnotes)
741
+ * - alertBlockHandler (Alerts/Admonitions)
742
+ * - columnsBlockHandler (Columns Layout)
743
+ * - boxBlockHandler (Inline-Box / Float Container)
744
+ *
745
+ * @returns BlockHandlerRegistry with default handlers
746
+ *
747
+ * @example
748
+ * ```typescript
749
+ * const blockHandlers = createDefaultBlockHandlers();
750
+ * blockHandlers.has('table'); // true
751
+ * blockHandlers.has('footnotes'); // true
752
+ * blockHandlers.has('alert'); // true
753
+ * blockHandlers.has('columns'); // true
754
+ * blockHandlers.has('box'); // true
755
+ * ```
756
+ */
757
+ declare function createDefaultBlockHandlers(): BlockHandlerRegistry;
758
+
759
+ /**
760
+ * Background color format
761
+ *
762
+ * Delta: { insert: "text", attributes: { background: "#ff0000" } }
763
+ *
764
+ * Normalizes all color formats (rgb, named, etc.) to lowercase hex (#rrggbb)
765
+ */
766
+ declare const backgroundFormat: Format<string>;
767
+
768
+ /**
769
+ * Bold format
770
+ *
771
+ * Delta: { insert: "text", attributes: { bold: true } }
772
+ */
773
+ declare const boldFormat: Format<boolean>;
774
+
775
+ /**
776
+ * Inline code format
777
+ *
778
+ * Delta: { insert: "text", attributes: { code: true } }
779
+ */
780
+ declare const codeFormat: Format<boolean>;
781
+
782
+ /**
783
+ * Text color format
784
+ *
785
+ * Delta: { insert: "text", attributes: { color: "#ff0000" } }
786
+ *
787
+ * Normalizes all color formats (rgb, named, etc.) to lowercase hex (#rrggbb)
788
+ */
789
+ declare const colorFormat: Format<string>;
790
+
791
+ /**
792
+ * Italic format
793
+ *
794
+ * Delta: { insert: "text", attributes: { italic: true } }
795
+ */
796
+ declare const italicFormat: Format<boolean>;
797
+
798
+ /**
799
+ * Keyboard input format
800
+ *
801
+ * Delta: { insert: "text", attributes: { kbd: true } }
802
+ * HTML: <kbd>text</kbd>
803
+ * Markdown: <kbd>text</kbd> (inline HTML)
804
+ */
805
+ declare const kbdFormat: Format<boolean>;
806
+
807
+ /**
808
+ * Link format
809
+ *
810
+ * Delta: { insert: "text", attributes: { link: "https://example.com" } }
811
+ *
812
+ * Supports:
813
+ * - Absolute URLs (http://, https://)
814
+ * - Relative URLs (/path, ./path, ../path)
815
+ * - Protocol-relative URLs (//example.com)
816
+ * - mailto: and tel: links
817
+ */
818
+ declare const linkFormat: Format<string>;
819
+
820
+ /**
821
+ * Mark (highlight) format
822
+ *
823
+ * Delta: { insert: "text", attributes: { mark: true } }
824
+ * HTML: <mark>text</mark>
825
+ */
826
+ declare const markFormat: Format<boolean>;
827
+
828
+ /**
829
+ * Strikethrough format
830
+ *
831
+ * Delta: { insert: "text", attributes: { strike: true } }
832
+ */
833
+ declare const strikeFormat: Format<boolean>;
834
+
835
+ /**
836
+ * Subscript format
837
+ *
838
+ * Delta: { insert: "text", attributes: { subscript: true } }
839
+ * HTML: <sub>text</sub>
840
+ */
841
+ declare const subscriptFormat: Format<boolean>;
842
+
843
+ /**
844
+ * Superscript format
845
+ *
846
+ * Delta: { insert: "text", attributes: { superscript: true } }
847
+ * HTML: <sup>text</sup>
848
+ */
849
+ declare const superscriptFormat: Format<boolean>;
850
+
851
+ /**
852
+ * Underline format
853
+ *
854
+ * Delta: { insert: "text", attributes: { underline: true } }
855
+ */
856
+ declare const underlineFormat: Format<boolean>;
857
+
858
+ /**
859
+ * Valid alignment values
860
+ */
861
+ type AlignType = 'left' | 'center' | 'right' | 'justify';
862
+ /**
863
+ * Text alignment format
864
+ *
865
+ * Delta: { insert: "\n", attributes: { align: "center" } }
866
+ */
867
+ declare const alignFormat: Format<AlignType>;
868
+
869
+ /**
870
+ * Blockquote format
871
+ *
872
+ * Delta: { insert: "\n", attributes: { blockquote: true } }
873
+ */
874
+ declare const blockquoteFormat: Format<boolean>;
875
+
876
+ /**
877
+ * Code block format
878
+ *
879
+ * Delta: { insert: "\n", attributes: { "code-block": true } }
880
+ * Delta: { insert: "\n", attributes: { "code-block": "javascript" } }
881
+ *
882
+ * Value can be:
883
+ * - true: generic code block
884
+ * - string: language identifier for syntax highlighting
885
+ */
886
+ declare const codeBlockFormat: Format<boolean | string>;
887
+
888
+ /**
889
+ * Header format (h1-h6)
890
+ *
891
+ * Delta: { insert: "\n", attributes: { header: 1 } }
892
+ *
893
+ * Values: 1-6 (corresponding to h1-h6)
894
+ */
895
+ declare const headerFormat: Format<number>;
896
+
897
+ /**
898
+ * Header ID format — optional custom anchor id for headings
899
+ *
900
+ * Delta: { insert: "\n", attributes: { header: 2, "header-id": "getting-started" } }
901
+ *
902
+ * When present, the heading gets this exact id in HTML output.
903
+ * When absent, id is computed via slugify(text) at render time (if anchorLinks is enabled).
904
+ *
905
+ * Markdown: ## Title {#custom-id}
906
+ */
907
+ declare const headerIdFormat: Format<string>;
908
+
909
+ /**
910
+ * Indent format
911
+ *
912
+ * Delta: { insert: "\n", attributes: { indent: 1 } }
913
+ *
914
+ * Values: 0-8 (0 = no indent)
915
+ */
916
+ declare const indentFormat: Format<number>;
917
+
918
+ /**
919
+ * Valid list types
920
+ */
921
+ type ListType = 'ordered' | 'bullet' | 'checked' | 'unchecked';
922
+ /**
923
+ * List format
924
+ *
925
+ * Delta: { insert: "\n", attributes: { list: "ordered" } }
926
+ * Delta: { insert: "\n", attributes: { list: "bullet" } }
927
+ * Delta: { insert: "\n", attributes: { list: "checked" } }
928
+ * Delta: { insert: "\n", attributes: { list: "unchecked" } }
929
+ */
930
+ declare const listFormat: Format<ListType>;
931
+
932
+ /**
933
+ * Table row index format
934
+ *
935
+ * Delta: { insert: "\n", attributes: { "table-row": 0 } }
936
+ */
937
+ declare const tableRowFormat: Format<number>;
938
+
939
+ /**
940
+ * Table column index format
941
+ *
942
+ * Delta: { insert: "\n", attributes: { "table-col": 0 } }
943
+ */
944
+ declare const tableColFormat: Format<number>;
945
+
946
+ /**
947
+ * Table header cell format
948
+ *
949
+ * Delta: { insert: "\n", attributes: { "table-header": true } }
950
+ *
951
+ * When true, the cell is rendered as <th> inside <thead>.
952
+ */
953
+ declare const tableHeaderFormat: Format<boolean>;
954
+
955
+ /**
956
+ * Valid table column alignment values
957
+ */
958
+ type TableColAlignType = 'left' | 'center' | 'right';
959
+ /**
960
+ * Table column alignment format
961
+ *
962
+ * Delta: { insert: "\n", attributes: { "table-col-align": "center" } }
963
+ *
964
+ * Controls text-align of the column (rendered via style on <th>/<td>).
965
+ * Compatible with GFM alignment syntax (:---|:---:|---:).
966
+ */
967
+ declare const tableColAlignFormat: Format<TableColAlignType>;
968
+
969
+ /**
970
+ * Block embed format — structural validation for complex block embeds.
971
+ *
972
+ * Delta: `{ insert: { block: { type: "table", ... } } }`
973
+ *
974
+ * This is the first level of two-level validation:
975
+ * 1. blockFormat.validate() — structural: is it an object with `type`?
976
+ * 2. BlockHandlerRegistry.get(type).validate() — semantic: is it a valid table?
977
+ *
978
+ * The `block` key is a **category**, not "just another embed".
979
+ * It signals to converters and OT layer: "nested structure, needs special handling".
980
+ */
981
+ declare const blockFormat: Format<Record<string, unknown>>;
982
+
983
+ /**
984
+ * Divider (Horizontal Rule) embed format
985
+ *
986
+ * Delta: { insert: { divider: true } }
987
+ * HTML: <hr>
988
+ * Markdown: ---
989
+ *
990
+ * Value is always `true` (no additional data needed)
991
+ */
992
+ declare const dividerFormat: Format<boolean>;
993
+
994
+ /**
995
+ * Footnote reference embed format
996
+ *
997
+ * Delta: { insert: { "footnote-ref": "1" } }
998
+ *
999
+ * Value is the footnote identifier string (e.g. "1", "note", "my-ref").
1000
+ * Rendered as superscript link in HTML: <sup class="footnote-ref"><a href="#fn-1">1</a></sup>
1001
+ * Markdown: [^1]
1002
+ */
1003
+ declare const footnoteRefFormat: Format<string>;
1004
+
1005
+ /**
1006
+ * Formula (LaTeX) embed format
1007
+ *
1008
+ * Delta: { insert: { formula: "E = mc^2" } }
1009
+ *
1010
+ * Value is LaTeX string
1011
+ */
1012
+ declare const formulaFormat: Format<string>;
1013
+
1014
+ /**
1015
+ * Image embed format
1016
+ *
1017
+ * Delta: { insert: { image: "https://example.com/image.png" } }
1018
+ *
1019
+ * Value is the image URL (http, https, data URI, or relative path)
1020
+ */
1021
+ declare const imageFormat: Format<string>;
1022
+
1023
+ /**
1024
+ * Video embed format
1025
+ *
1026
+ * Delta: { insert: { video: "https://youtube.com/watch?v=..." } }
1027
+ *
1028
+ * Value is the video URL
1029
+ */
1030
+ declare const videoFormat: Format<string>;
1031
+
1032
+ /**
1033
+ * Convert any color format to lowercase hex (#rrggbb)
1034
+ *
1035
+ * Supports:
1036
+ * - Hex: #rgb, #rrggbb, #rrggbbaa
1037
+ * - RGB: rgb(r, g, b), rgb(r g b)
1038
+ * - RGBA: rgba(r, g, b, a), rgba(r g b / a)
1039
+ * - Named colors: red, blue, etc.
1040
+ *
1041
+ * @param value - Color value to convert
1042
+ * @returns Lowercase hex color (#rrggbb) or original value if not recognized
1043
+ */
1044
+ declare function toHexColor(value: string): string;
1045
+ /**
1046
+ * Check if a value is a valid hex color
1047
+ *
1048
+ * @param value - Value to check
1049
+ * @returns true if valid hex color (#rrggbb or #rgb)
1050
+ */
1051
+ declare function isValidHexColor(value: string): boolean;
1052
+ /**
1053
+ * Check if a value is a valid color (hex, rgb, rgba, or named)
1054
+ *
1055
+ * @param value - Value to check
1056
+ * @returns true if valid color
1057
+ */
1058
+ declare function isValidColor(value: string): boolean;
1059
+ /**
1060
+ * Get list of all named colors
1061
+ */
1062
+ declare function getNamedColors(): string[];
1063
+
1064
+ /**
1065
+ * Browser DOM Adapter
1066
+ *
1067
+ * Uses native browser DOM APIs for HTML parsing and serialization.
1068
+ * Only available in browser environments.
1069
+ */
1070
+
1071
+ /**
1072
+ * Browser DOM Adapter implementation
1073
+ *
1074
+ * Uses native browser APIs:
1075
+ * - DOMParser for parsing HTML
1076
+ * - Element.outerHTML for serialization
1077
+ */
1078
+ declare class BrowserDOMAdapter implements DOMAdapter {
1079
+ /**
1080
+ * Parse HTML string into a document fragment
1081
+ *
1082
+ * Uses a template element to parse arbitrary HTML safely.
1083
+ */
1084
+ parseHTML(html: string): DOMDocumentFragment;
1085
+ /**
1086
+ * Serialize a node to HTML string
1087
+ */
1088
+ serializeHTML(node: DOMNode | DOMDocumentFragment): string;
1089
+ /**
1090
+ * Create a new document for building DOM structures
1091
+ */
1092
+ createDocument(): DOMDocument;
1093
+ /**
1094
+ * Check if browser DOM APIs are available
1095
+ */
1096
+ isAvailable(): boolean;
1097
+ }
1098
+ /**
1099
+ * Singleton instance of browser adapter
1100
+ */
1101
+ declare const browserAdapter: BrowserDOMAdapter;
1102
+
1103
+ /**
1104
+ * Node.js DOM Adapter
1105
+ *
1106
+ * Uses jsdom for HTML parsing and serialization in Node.js environment.
1107
+ */
1108
+
1109
+ /**
1110
+ * Node.js DOM Adapter implementation
1111
+ *
1112
+ * Uses jsdom for DOM operations in Node.js environment.
1113
+ * jsdom is loaded lazily to avoid issues in browser bundles.
1114
+ */
1115
+ declare class NodeDOMAdapter implements DOMAdapter {
1116
+ private jsdom;
1117
+ /**
1118
+ * Parse HTML string into a document fragment
1119
+ */
1120
+ parseHTML(html: string): DOMDocumentFragment;
1121
+ /**
1122
+ * Serialize a node to HTML string
1123
+ */
1124
+ serializeHTML(node: DOMNode | DOMDocumentFragment): string;
1125
+ /**
1126
+ * Create a new document for building DOM structures
1127
+ */
1128
+ createDocument(): DOMDocument;
1129
+ /**
1130
+ * Check if jsdom is available
1131
+ */
1132
+ isAvailable(): boolean;
1133
+ /**
1134
+ * Initialize the adapter with jsdom (async)
1135
+ *
1136
+ * Call this before using the adapter if you want to handle
1137
+ * loading errors gracefully.
1138
+ */
1139
+ initialize(): Promise<void>;
1140
+ /**
1141
+ * Get or create jsdom instance (sync, throws if not available)
1142
+ */
1143
+ private getOrCreateJsdom;
1144
+ }
1145
+ /**
1146
+ * Singleton instance of Node adapter
1147
+ */
1148
+ declare const nodeAdapter: NodeDOMAdapter;
1149
+
1150
+ /**
1151
+ * DOM Adapters
1152
+ *
1153
+ * Platform-agnostic DOM manipulation for HTML ↔ Delta conversion.
1154
+ */
1155
+
1156
+ /**
1157
+ * Get the appropriate DOM adapter for the current environment
1158
+ *
1159
+ * - In browser: returns BrowserDOMAdapter (native DOM)
1160
+ * - In Node.js: returns NodeDOMAdapter (jsdom)
1161
+ *
1162
+ * @returns The appropriate DOM adapter
1163
+ * @throws Error if no adapter is available
1164
+ */
1165
+ declare function getAdapter(): DOMAdapter;
1166
+ /**
1167
+ * Check if any DOM adapter is available
1168
+ */
1169
+ declare function isAdapterAvailable(): boolean;
1170
+
1171
+ /**
1172
+ * Delta Sanitization
1173
+ *
1174
+ * Cleans Delta by removing unknown attributes, validating values,
1175
+ * and normalizing through Registry.
1176
+ */
1177
+
1178
+ /**
1179
+ * Options for sanitizeDelta
1180
+ */
1181
+ interface SanitizeOptions {
1182
+ /**
1183
+ * Remove attributes not registered in the registry
1184
+ * @default true
1185
+ */
1186
+ removeUnknown?: boolean;
1187
+ /**
1188
+ * Normalize attribute values (e.g., color: 'red' → '#ff0000')
1189
+ * @default true
1190
+ */
1191
+ normalize?: boolean;
1192
+ /**
1193
+ * Remove operations with invalid embed values
1194
+ * @default false
1195
+ */
1196
+ removeInvalidEmbeds?: boolean;
1197
+ /**
1198
+ * List of embed types that are allowed (if not set, all registered are allowed)
1199
+ */
1200
+ allowedEmbeds?: string[];
1201
+ }
1202
+ /**
1203
+ * Sanitize a Delta using a Registry
1204
+ *
1205
+ * Performs the following operations:
1206
+ * 1. Removes attributes not registered in the registry (if removeUnknown=true)
1207
+ * 2. Removes attributes with invalid values
1208
+ * 3. Normalizes attribute values (if normalize=true)
1209
+ * 4. Optionally removes invalid embed operations
1210
+ *
1211
+ * @param delta - The Delta to sanitize
1212
+ * @param registry - The Registry to use for validation/normalization
1213
+ * @param options - Sanitization options
1214
+ * @returns A new sanitized Delta
1215
+ *
1216
+ * @example
1217
+ * ```typescript
1218
+ * const registry = createDefaultRegistry();
1219
+ * const dirty = new Delta()
1220
+ * .insert('Hello', { bold: true, unknown: 'value', color: 'red' })
1221
+ * .insert('\n');
1222
+ *
1223
+ * const clean = sanitizeDelta(dirty, registry);
1224
+ * // { bold: true, color: '#ff0000' } - unknown removed, color normalized
1225
+ * ```
1226
+ */
1227
+ declare function sanitizeDelta(delta: Delta, registry: Registry, options?: SanitizeOptions): Delta;
1228
+ /**
1229
+ * Normalize a Delta's attributes without removing anything
1230
+ *
1231
+ * This is a lighter operation that only normalizes values,
1232
+ * without removing unknown or invalid attributes.
1233
+ *
1234
+ * @param delta - The Delta to normalize
1235
+ * @param registry - The Registry to use for normalization
1236
+ * @returns A new Delta with normalized attributes
1237
+ */
1238
+ declare function normalizeDelta(delta: Delta, registry: Registry): Delta;
1239
+ /**
1240
+ * Validate a Delta against a Registry
1241
+ *
1242
+ * @param delta - The Delta to validate
1243
+ * @param registry - The Registry to use for validation
1244
+ * @returns true if all attributes in the Delta are valid
1245
+ */
1246
+ declare function validateDelta(delta: Delta, registry: Registry): boolean;
1247
+ /**
1248
+ * Deep clone a Delta
1249
+ *
1250
+ * @param delta - The Delta to clone
1251
+ * @returns A new Delta with cloned ops
1252
+ */
1253
+ declare function cloneDelta(delta: Delta): Delta;
1254
+
1255
+ /**
1256
+ * Delta → HTML Conversion
1257
+ *
1258
+ * Converts a Delta document to an HTML string.
1259
+ */
1260
+
1261
+ /**
1262
+ * Options for Delta → HTML conversion
1263
+ */
1264
+ interface DeltaToHtmlOptions {
1265
+ /**
1266
+ * Pretty print output with indentation
1267
+ * @default false
1268
+ */
1269
+ pretty?: boolean;
1270
+ /**
1271
+ * Custom embed renderers (merged with defaults)
1272
+ */
1273
+ embedRenderers?: Record<string, (value: unknown, attrs?: Record<string, unknown>) => string>;
1274
+ /**
1275
+ * Wrap output in a container element
1276
+ * @default undefined (no wrapper)
1277
+ */
1278
+ wrapper?: string;
1279
+ /**
1280
+ * Use semantic HTML5 elements
1281
+ * @default true
1282
+ */
1283
+ semantic?: boolean;
1284
+ /**
1285
+ * Use hierarchical numbering for ordered lists (e.g., 1, 1.1, 1.1.1)
1286
+ * When enabled, list items get data-number attribute with calculated number
1287
+ * @default false
1288
+ */
1289
+ hierarchicalNumbers?: boolean;
1290
+ /**
1291
+ * Block handler registry for complex block embeds (Extended Table, etc.)
1292
+ * When provided, `{ insert: { block: { type, ... } } }` ops are dispatched
1293
+ * to the matching BlockHandler.toHtml() for rendering.
1294
+ */
1295
+ blockHandlers?: BlockHandlerRegistry;
1296
+ /**
1297
+ * Generate anchor link `id` attributes on heading elements (`<h1>`-`<h6>`).
1298
+ *
1299
+ * When enabled, headings get an `id` computed via slugify(text).
1300
+ * If a heading has an explicit `header-id` attribute in Delta, that id is used instead.
1301
+ * Duplicate slugs are deduplicated with `-1`, `-2` suffixes.
1302
+ *
1303
+ * @default false
1304
+ */
1305
+ anchorLinks?: boolean;
1306
+ /**
1307
+ * Format registry for custom embed rendering.
1308
+ *
1309
+ * When provided, embed formats with a `render()` method are used
1310
+ * before falling back to built-in EMBED_RENDERERS.
1311
+ * This enables extensibility without modifying converter internals.
1312
+ */
1313
+ registry?: Registry;
1314
+ }
1315
+ /**
1316
+ * Convert a Delta to an HTML string
1317
+ *
1318
+ * @param delta - The Delta to convert
1319
+ * @param options - Conversion options
1320
+ * @returns HTML string
1321
+ *
1322
+ * @example
1323
+ * ```typescript
1324
+ * const delta = new Delta()
1325
+ * .insert('Hello ', { bold: true })
1326
+ * .insert('World')
1327
+ * .insert('\n', { header: 1 });
1328
+ *
1329
+ * const html = deltaToHtml(delta);
1330
+ * // '<h1><strong>Hello </strong>World</h1>'
1331
+ * ```
1332
+ */
1333
+ declare function deltaToHtml(delta: Delta, options?: DeltaToHtmlOptions): string;
1334
+
1335
+ /**
1336
+ * HTML → Delta Conversion
1337
+ *
1338
+ * Converts HTML string to a Delta document.
1339
+ */
1340
+
1341
+ /**
1342
+ * Options for HTML → Delta conversion
1343
+ */
1344
+ interface HtmlToDeltaOptions {
1345
+ /**
1346
+ * DOM adapter to use (defaults to auto-detected)
1347
+ */
1348
+ adapter?: DOMAdapter;
1349
+ /**
1350
+ * Normalize whitespace (collapse multiple spaces, trim)
1351
+ * @default true
1352
+ */
1353
+ normalizeWhitespace?: boolean;
1354
+ /**
1355
+ * Custom tag handlers for special elements
1356
+ */
1357
+ tagHandlers?: Record<string, TagHandler>;
1358
+ /**
1359
+ * Block handler registry for Extended Table and other block embeds.
1360
+ * When provided and a handler for 'table' is registered,
1361
+ * `<table>` elements will be parsed as block embeds instead of Simple Table.
1362
+ */
1363
+ blockHandlers?: BlockHandlerRegistry;
1364
+ /**
1365
+ * Format registry for custom embed matching.
1366
+ *
1367
+ * When provided, embed formats with a `match()` method are tried
1368
+ * before falling back to built-in tag handlers (img, video, iframe, etc.).
1369
+ * This enables extensibility without modifying converter internals.
1370
+ */
1371
+ registry?: Registry;
1372
+ }
1373
+ /**
1374
+ * Custom tag handler function
1375
+ */
1376
+ type TagHandler = (element: DOMElement, context: ParserContext$1) => void;
1377
+ /**
1378
+ * Parser context passed to tag handlers
1379
+ */
1380
+ interface ParserContext$1 {
1381
+ delta: Delta;
1382
+ attributes: AttributeMap;
1383
+ blockAttributes: AttributeMap;
1384
+ pushText(text: string): void;
1385
+ pushEmbed(embed: Record<string, unknown>, attrs?: AttributeMap): void;
1386
+ pushNewline(): void;
1387
+ }
1388
+ /**
1389
+ * Convert HTML string to Delta
1390
+ *
1391
+ * @param html - The HTML string to convert
1392
+ * @param options - Conversion options
1393
+ * @returns Delta document
1394
+ *
1395
+ * @example
1396
+ * ```typescript
1397
+ * const html = '<p><strong>Hello</strong> World</p>';
1398
+ * const delta = htmlToDelta(html);
1399
+ * // { ops: [
1400
+ * // { insert: 'Hello', attributes: { bold: true } },
1401
+ * // { insert: ' World\n' }
1402
+ * // ]}
1403
+ * ```
1404
+ */
1405
+ declare function htmlToDelta(html: string, options?: HtmlToDeltaOptions): Delta;
1406
+
1407
+ /**
1408
+ * Escape HTML special characters
1409
+ */
1410
+ declare function escapeHtml(text: string): string;
1411
+ /**
1412
+ * Unescape HTML entities
1413
+ */
1414
+ declare function unescapeHtml(text: string): string;
1415
+
1416
+ /**
1417
+ * GitHub-compatible slugify for heading anchor links.
1418
+ *
1419
+ * Algorithm matches GitHub's heading-to-id conversion:
1420
+ * 1. Trim leading/trailing whitespace
1421
+ * 2. Convert to lowercase
1422
+ * 3. Remove everything except word characters (letters, digits, underscore),
1423
+ * spaces, hyphens (preserves Unicode letters via \p{L})
1424
+ * 4. Replace spaces with hyphens
1425
+ * 5. Collapse consecutive hyphens
1426
+ * 6. Trim leading/trailing hyphens
1427
+ *
1428
+ * @param text - heading plain text content
1429
+ * @returns slugified string suitable for HTML id attribute
1430
+ *
1431
+ * @example
1432
+ * ```typescript
1433
+ * slugify('Getting Started'); // 'getting-started'
1434
+ * slugify('API Reference (v2)'); // 'api-reference-v2'
1435
+ * slugify('Что нового?'); // 'что-нового'
1436
+ * slugify(' Hello World '); // 'hello--world' → 'hello-world'
1437
+ * ```
1438
+ */
1439
+ declare function slugify(text: string): string;
1440
+ /**
1441
+ * Slugify with deduplication: appends `-1`, `-2`, etc. on collision.
1442
+ *
1443
+ * Tracks used slugs via a Map. Call this for each heading in order during
1444
+ * a single document render pass.
1445
+ *
1446
+ * @param text - heading plain text content
1447
+ * @param usedSlugs - mutable map tracking slug usage counts
1448
+ * @returns unique slugified string
1449
+ *
1450
+ * @example
1451
+ * ```typescript
1452
+ * const used = new Map<string, number>();
1453
+ * slugifyWithDedup('FAQ', used); // 'faq'
1454
+ * slugifyWithDedup('FAQ', used); // 'faq-1'
1455
+ * slugifyWithDedup('FAQ', used); // 'faq-2'
1456
+ * ```
1457
+ */
1458
+ declare function slugifyWithDedup(text: string, usedSlugs: Map<string, number>): string;
1459
+
1460
+ /**
1461
+ * Delta → Markdown Conversion
1462
+ *
1463
+ * Converts a Delta document to Markdown string.
1464
+ */
1465
+
1466
+ /**
1467
+ * Options for Delta → Markdown conversion
1468
+ */
1469
+ interface DeltaToMarkdownOptions {
1470
+ /**
1471
+ * Use strict Markdown (no GFM extensions)
1472
+ * @default false
1473
+ */
1474
+ strict?: boolean;
1475
+ /**
1476
+ * Preserve empty lines using <br> tags
1477
+ * When false, multiple empty lines collapse to one paragraph break
1478
+ * @default false
1479
+ */
1480
+ preserveEmptyLines?: boolean;
1481
+ /**
1482
+ * Math syntax for formula output
1483
+ * - 'dollar': $...$ for inline, $$...$$ for block (default, GFM-compatible)
1484
+ * - 'latex': \(...\) for inline, \[...\] for block (used by LLMs: DeepSeek, ChatGPT, Claude)
1485
+ * @default 'dollar'
1486
+ */
1487
+ mathSyntax?: 'dollar' | 'latex';
1488
+ /**
1489
+ * Display math rendering mode
1490
+ * - true (default): code-block "math" → ```math ``` (GFM code block)
1491
+ * - false: code-block "math" → $...$ on its own line (inline syntax)
1492
+ *
1493
+ * Does NOT affect inline formulas ({ formula }) — they always render as $...$
1494
+ * @default true
1495
+ */
1496
+ mathBlock?: boolean;
1497
+ /**
1498
+ * Mermaid diagram rendering mode
1499
+ * - true (default): code-block "mermaid" → ```mermaid ``` (fenced block)
1500
+ * - false: code-block "mermaid" → ```mermaid ``` (same output, but { diagram } embeds also → ```mermaid)
1501
+ *
1502
+ * Does NOT affect the Markdown output for code-block "mermaid" (always fenced).
1503
+ * Controls how { diagram } embeds are rendered.
1504
+ * @default true
1505
+ */
1506
+ mermaidBlock?: boolean;
1507
+ /**
1508
+ * PlantUML diagram rendering mode
1509
+ * - true (default): code-block "plantuml" → ```plantuml ``` (fenced block)
1510
+ * - false: code-block "plantuml" → ```plantuml ``` (same output, but { diagram } embeds with @startuml → ```plantuml)
1511
+ *
1512
+ * Does NOT affect the Markdown output for code-block "plantuml" (always fenced).
1513
+ * Controls how { diagram } embeds containing PlantUML are rendered.
1514
+ * @default true
1515
+ */
1516
+ plantumlBlock?: boolean;
1517
+ /**
1518
+ * Custom embed renderers
1519
+ */
1520
+ embedRenderers?: Record<string, (value: unknown, attrs?: AttributeMap) => string>;
1521
+ /**
1522
+ * Block handler registry for Extended Table and other block embeds.
1523
+ * When provided, block embeds will be rendered via handler.toMarkdown() → fallback to handler.toHtml().
1524
+ */
1525
+ blockHandlers?: BlockHandlerRegistry;
1526
+ /**
1527
+ * Pretty-print HTML output for block embeds (Extended Table, Columns, etc.)
1528
+ * When true, HTML fallback in Markdown is indented and line-broken for readability.
1529
+ * When false (default), HTML is compact single-line — safer for CommonMark.
1530
+ * @default false
1531
+ */
1532
+ prettyHtml?: boolean;
1533
+ /**
1534
+ * Format registry for custom embed Markdown rendering.
1535
+ *
1536
+ * When provided, embed formats with a `toMarkdown()` method are used
1537
+ * before falling back to built-in handlers. If `toMarkdown()` returns null,
1538
+ * `render()` is used as HTML fallback in Markdown.
1539
+ */
1540
+ registry?: Registry;
1541
+ }
1542
+ /**
1543
+ * Convert Delta to Markdown
1544
+ *
1545
+ * @param delta - The Delta document to convert
1546
+ * @param options - Conversion options
1547
+ * @returns Markdown string
1548
+ *
1549
+ * @example
1550
+ * ```typescript
1551
+ * const delta = new Delta()
1552
+ * .insert('Hello', { bold: true })
1553
+ * .insert(' World\n');
1554
+ *
1555
+ * const md = deltaToMarkdown(delta);
1556
+ * // '**Hello** World\n'
1557
+ * ```
1558
+ */
1559
+ declare function deltaToMarkdown(delta: Delta, options?: DeltaToMarkdownOptions): string;
1560
+
1561
+ /**
1562
+ * Markdown → Delta Conversion
1563
+ *
1564
+ * Converts Markdown string to a Delta document using remark (unified).
1565
+ */
1566
+
1567
+ /**
1568
+ * Options for Markdown → Delta conversion
1569
+ */
1570
+ interface MarkdownToDeltaOptions {
1571
+ /**
1572
+ * Enable GFM (GitHub Flavored Markdown) extensions
1573
+ * Includes: tables, strikethrough, task lists, autolinks
1574
+ * @default true
1575
+ */
1576
+ gfm?: boolean;
1577
+ /**
1578
+ * Display math rendering mode
1579
+ * - true (default): $$...$$ / ```math → code-block "math" in Delta
1580
+ * - false: $$...$$ / ```math → inline { formula } embed in Delta
1581
+ *
1582
+ * Does NOT affect inline math ($...$) — always becomes { formula } embed
1583
+ * @default true
1584
+ */
1585
+ mathBlock?: boolean;
1586
+ /**
1587
+ * Mermaid diagram rendering mode
1588
+ * - true (default): ```mermaid → code-block "mermaid" in Delta
1589
+ * - false: ```mermaid → inline { diagram } embed in Delta
1590
+ * @default true
1591
+ */
1592
+ mermaidBlock?: boolean;
1593
+ /**
1594
+ * PlantUML diagram rendering mode
1595
+ * - true (default): ```plantuml → code-block "plantuml" in Delta
1596
+ * - false: ```plantuml → inline { diagram } embed in Delta
1597
+ * @default true
1598
+ */
1599
+ plantumlBlock?: boolean;
1600
+ /**
1601
+ * Custom node handlers for special elements
1602
+ */
1603
+ nodeHandlers?: Record<string, NodeHandler>;
1604
+ /**
1605
+ * Block handler registry for Extended Table and other block embeds.
1606
+ * Reserved for future use — GFM tables don't support Extended Table features.
1607
+ * HTML tables in Markdown are parsed via htmlToDelta when blockHandlers is provided.
1608
+ */
1609
+ blockHandlers?: BlockHandlerRegistry;
1610
+ }
1611
+ /**
1612
+ * MDAST node type (simplified)
1613
+ */
1614
+ interface MdastNode {
1615
+ type: string;
1616
+ children?: MdastNode[];
1617
+ value?: string;
1618
+ url?: string;
1619
+ alt?: string;
1620
+ title?: string;
1621
+ lang?: string;
1622
+ meta?: string;
1623
+ depth?: number;
1624
+ ordered?: boolean;
1625
+ checked?: boolean | null;
1626
+ spread?: boolean;
1627
+ /** Footnote identifier (for footnoteReference / footnoteDefinition) */
1628
+ identifier?: string;
1629
+ /** Footnote label (for footnoteReference / footnoteDefinition) */
1630
+ label?: string;
1631
+ }
1632
+ /**
1633
+ * Custom node handler function
1634
+ */
1635
+ type NodeHandler = (node: MdastNode, context: ParserContext) => void;
1636
+ /**
1637
+ * Parser context for building Delta
1638
+ */
1639
+ interface ParserContext {
1640
+ delta: Delta;
1641
+ pushText(text: string, attrs?: AttributeMap): void;
1642
+ pushEmbed(embed: Record<string, unknown>, attrs?: AttributeMap): void;
1643
+ pushNewline(attrs?: AttributeMap): void;
1644
+ }
1645
+ /**
1646
+ * Check if remark is available
1647
+ */
1648
+ declare function isRemarkAvailable(): boolean;
1649
+ /**
1650
+ * Convert Markdown to Delta (async)
1651
+ */
1652
+ declare function markdownToDelta(markdown: string, options?: MarkdownToDeltaOptions): Promise<Delta>;
1653
+ /**
1654
+ * Synchronous version (requires remark to be pre-loaded or uses require)
1655
+ */
1656
+ declare function markdownToDeltaSync(markdown: string, options?: MarkdownToDeltaOptions): Delta;
1657
+
1658
+ export { ALERT_TYPES, type AlertBlockData, type AlertType, type AlignType, BOX_FLOAT_VALUES, BOX_OVERFLOW_VALUES, type BlockContext, type BlockHandler, BlockHandlerRegistry, type BlockRenderOptions, type BoxBlockData, type BoxFloat, type BoxOpAttributes, type BoxOverflow, BrowserDOMAdapter, type CellAlign, type CellData, type ColumnsBlockData, type DOMAdapter, type DOMDocument, type DOMDocumentFragment, type DOMElement, type DOMNode, type DOMNodeList, type DeltaToHtmlOptions, type DeltaToMarkdownOptions, type FootnotesBlockData, type Format, type FormatDefinition, type FormatMatchResult, type FormatScope, type HtmlToDeltaOptions, type ListType, type MarkdownToDeltaOptions, NODE_TYPE, NodeDOMAdapter, Registry, type SanitizeOptions, type TableBlockData, type TableColAlignType, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, colorFormat, columnsBlockHandler, createDefaultBlockHandlers, createDefaultRegistry, defaultBlockFormats, defaultEmbedFormats, defaultFormats, defaultInlineFormats, deltaToHtml, deltaToMarkdown, dividerFormat, escapeHtml, extractBoxOpAttributes, footnoteRefFormat, footnotesBlockHandler, formulaFormat, getAdapter, getNamedColors, headerFormat, headerIdFormat, htmlToDelta, imageFormat, indentFormat, isAdapterAvailable, isElement, isRemarkAvailable, isTextNode, isValidColor, isValidHexColor, italicFormat, kbdFormat, linkFormat, listFormat, markFormat, markdownToDelta, markdownToDeltaSync, nodeAdapter, normalizeDelta, sanitizeDelta, slugify, slugifyWithDedup, strikeFormat, subscriptFormat, superscriptFormat, tableBlockHandler, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };