md2x 0.1.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.
Files changed (127) hide show
  1. package/README.md +43 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.mjs +128069 -0
  4. package/dist/md2x.mjs +128296 -0
  5. package/dist/renderer/puppeteer-render-worker.js +815 -0
  6. package/dist/renderer/puppeteer-render.html +2829 -0
  7. package/dist/themes/code-themes/business-contrast.json +31 -0
  8. package/dist/themes/code-themes/colorful.json +32 -0
  9. package/dist/themes/code-themes/cool-modern.json +31 -0
  10. package/dist/themes/code-themes/high-contrast.json +31 -0
  11. package/dist/themes/code-themes/light-clean.json +31 -0
  12. package/dist/themes/code-themes/warm-book.json +31 -0
  13. package/dist/themes/color-schemes/candy.json +34 -0
  14. package/dist/themes/color-schemes/cool.json +34 -0
  15. package/dist/themes/color-schemes/coral.json +34 -0
  16. package/dist/themes/color-schemes/dino.json +34 -0
  17. package/dist/themes/color-schemes/forest.json +34 -0
  18. package/dist/themes/color-schemes/garden.json +34 -0
  19. package/dist/themes/color-schemes/neutral.json +34 -0
  20. package/dist/themes/color-schemes/ocean.json +34 -0
  21. package/dist/themes/color-schemes/rainbow.json +43 -0
  22. package/dist/themes/color-schemes/sakura.json +34 -0
  23. package/dist/themes/color-schemes/sepia.json +34 -0
  24. package/dist/themes/color-schemes/space.json +34 -0
  25. package/dist/themes/color-schemes/starry.json +34 -0
  26. package/dist/themes/color-schemes/sunset.json +34 -0
  27. package/dist/themes/color-schemes/warm.json +34 -0
  28. package/dist/themes/font-config.json +184 -0
  29. package/dist/themes/layout-schemes/academic.json +40 -0
  30. package/dist/themes/layout-schemes/book.json +40 -0
  31. package/dist/themes/layout-schemes/document.json +40 -0
  32. package/dist/themes/layout-schemes/magazine.json +40 -0
  33. package/dist/themes/layout-schemes/student.json +40 -0
  34. package/dist/themes/layout-schemes/technical.json +40 -0
  35. package/dist/themes/presets/academic.json +24 -0
  36. package/dist/themes/presets/business.json +22 -0
  37. package/dist/themes/presets/candy.json +23 -0
  38. package/dist/themes/presets/century.json +22 -0
  39. package/dist/themes/presets/coral.json +22 -0
  40. package/dist/themes/presets/default.json +22 -0
  41. package/dist/themes/presets/dinosaur.json +23 -0
  42. package/dist/themes/presets/elegant.json +22 -0
  43. package/dist/themes/presets/forest.json +22 -0
  44. package/dist/themes/presets/garamond.json +22 -0
  45. package/dist/themes/presets/garden.json +23 -0
  46. package/dist/themes/presets/handwritten.json +23 -0
  47. package/dist/themes/presets/heiti.json +22 -0
  48. package/dist/themes/presets/magazine.json +24 -0
  49. package/dist/themes/presets/manuscript.json +22 -0
  50. package/dist/themes/presets/minimal.json +22 -0
  51. package/dist/themes/presets/mixed.json +24 -0
  52. package/dist/themes/presets/newspaper.json +24 -0
  53. package/dist/themes/presets/ocean.json +22 -0
  54. package/dist/themes/presets/palatino.json +22 -0
  55. package/dist/themes/presets/rainbow.json +23 -0
  56. package/dist/themes/presets/space.json +23 -0
  57. package/dist/themes/presets/starry.json +23 -0
  58. package/dist/themes/presets/sunset.json +22 -0
  59. package/dist/themes/presets/swiss.json +22 -0
  60. package/dist/themes/presets/technical.json +22 -0
  61. package/dist/themes/presets/typewriter.json +23 -0
  62. package/dist/themes/presets/verdana.json +22 -0
  63. package/dist/themes/presets/water.json +22 -0
  64. package/dist/themes/registry.json +270 -0
  65. package/dist/themes/table-styles/academic.json +30 -0
  66. package/dist/themes/table-styles/borderless.json +26 -0
  67. package/dist/themes/table-styles/compact.json +24 -0
  68. package/dist/themes/table-styles/grid.json +22 -0
  69. package/dist/themes/table-styles/high-contrast.json +22 -0
  70. package/dist/themes/table-styles/minimal-gray.json +26 -0
  71. package/dist/themes/table-styles/modern-tech.json +34 -0
  72. package/dist/themes/table-styles/professional.json +34 -0
  73. package/dist/themes/table-styles/zebra.json +22 -0
  74. package/dist/types/node/src/host/browser-renderer.d.ts +40 -0
  75. package/dist/types/node/src/host/node-exporter.d.ts +63 -0
  76. package/dist/types/node/src/host/node-platform.d.ts +30 -0
  77. package/dist/types/node/src/index.d.ts +8 -0
  78. package/dist/types/src/core/markdown-block-splitter.d.ts +16 -0
  79. package/dist/types/src/core/markdown-document.d.ts +286 -0
  80. package/dist/types/src/core/markdown-processor.d.ts +228 -0
  81. package/dist/types/src/core/viewer/viewer-controller.d.ts +85 -0
  82. package/dist/types/src/exporters/docx-blockquote-converter.d.ts +24 -0
  83. package/dist/types/src/exporters/docx-code-highlighter.d.ts +14 -0
  84. package/dist/types/src/exporters/docx-download.d.ts +27 -0
  85. package/dist/types/src/exporters/docx-exporter.d.ts +77 -0
  86. package/dist/types/src/exporters/docx-image-utils.d.ts +71 -0
  87. package/dist/types/src/exporters/docx-inline-converter.d.ts +124 -0
  88. package/dist/types/src/exporters/docx-list-converter.d.ts +50 -0
  89. package/dist/types/src/exporters/docx-math-converter.d.ts +11 -0
  90. package/dist/types/src/exporters/docx-table-converter.d.ts +22 -0
  91. package/dist/types/src/exporters/mml2omml.d.ts +2 -0
  92. package/dist/types/src/exporters/theme-to-docx.d.ts +144 -0
  93. package/dist/types/src/plugins/base-plugin.d.ts +67 -0
  94. package/dist/types/src/plugins/canvas-plugin.d.ts +9 -0
  95. package/dist/types/src/plugins/dot-plugin.d.ts +9 -0
  96. package/dist/types/src/plugins/html-plugin.d.ts +28 -0
  97. package/dist/types/src/plugins/index.d.ts +56 -0
  98. package/dist/types/src/plugins/infographic-plugin.d.ts +9 -0
  99. package/dist/types/src/plugins/mermaid-plugin.d.ts +9 -0
  100. package/dist/types/src/plugins/plugin-content-utils.d.ts +40 -0
  101. package/dist/types/src/plugins/plugin-html-utils.d.ts +23 -0
  102. package/dist/types/src/plugins/rehype-image-uri.d.ts +13 -0
  103. package/dist/types/src/plugins/remark-super-sub.d.ts +17 -0
  104. package/dist/types/src/plugins/remark-toc-filter.d.ts +10 -0
  105. package/dist/types/src/plugins/svg-plugin.d.ts +51 -0
  106. package/dist/types/src/plugins/vega-plugin.d.ts +10 -0
  107. package/dist/types/src/plugins/vegalite-plugin.d.ts +23 -0
  108. package/dist/types/src/types/cache.d.ts +85 -0
  109. package/dist/types/src/types/core.d.ts +99 -0
  110. package/dist/types/src/types/docx.d.ts +240 -0
  111. package/dist/types/src/types/index.d.ts +18 -0
  112. package/dist/types/src/types/messaging.d.ts +142 -0
  113. package/dist/types/src/types/platform.d.ts +203 -0
  114. package/dist/types/src/types/plugin.d.ts +101 -0
  115. package/dist/types/src/types/render.d.ts +57 -0
  116. package/dist/types/src/types/theme.d.ts +234 -0
  117. package/dist/types/src/types/toolbar.d.ts +53 -0
  118. package/dist/types/src/ui/popup/i18n-helpers.d.ts +21 -0
  119. package/dist/types/src/ui/popup/settings-tab.d.ts +56 -0
  120. package/dist/types/src/ui/popup/storage-helper.d.ts +12 -0
  121. package/dist/types/src/utils/fetch-utils.d.ts +12 -0
  122. package/dist/types/src/utils/hash.d.ts +17 -0
  123. package/dist/types/src/utils/html-sanitizer.d.ts +26 -0
  124. package/dist/types/src/utils/localization.d.ts +49 -0
  125. package/dist/types/src/utils/theme-manager.d.ts +152 -0
  126. package/dist/types/src/utils/theme-to-css.d.ts +171 -0
  127. package/package.json +47 -0
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Markdown Document - In-memory document structure for incremental updates
3
+ *
4
+ * This module provides a pure data structure for managing markdown documents
5
+ * without any DOM dependencies. It handles:
6
+ * - Block-level parsing and tracking with stable IDs
7
+ * - Content hashing for change detection
8
+ * - Incremental diff computation
9
+ * - Virtual DOM with precise DOM operation commands
10
+ * - Line number mapping for scroll sync
11
+ */
12
+ /**
13
+ * Block metadata stored in memory
14
+ */
15
+ export interface BlockMeta {
16
+ /** Unique block ID (stable across updates for same content position) */
17
+ id: string;
18
+ /** Block hash (content-based) */
19
+ hash: string;
20
+ /** Source line number (0-based) */
21
+ startLine: number;
22
+ /** Number of source lines */
23
+ lineCount: number;
24
+ /** Raw markdown content */
25
+ content: string;
26
+ /** Rendered HTML (if available) */
27
+ html?: string;
28
+ /** Whether this block contains async placeholder */
29
+ hasPlaceholder?: boolean;
30
+ }
31
+ /**
32
+ * Block attributes for DOM elements
33
+ */
34
+ export interface BlockAttrs {
35
+ 'data-block-id': string;
36
+ 'data-block-hash': string;
37
+ 'data-line': number;
38
+ 'data-line-count': number;
39
+ }
40
+ /**
41
+ * DOM operation command - platform-agnostic instructions for updating the DOM
42
+ */
43
+ export type DOMCommand = {
44
+ type: 'clear';
45
+ } | {
46
+ type: 'append';
47
+ blockId: string;
48
+ html: string;
49
+ attrs: BlockAttrs;
50
+ } | {
51
+ type: 'insertBefore';
52
+ blockId: string;
53
+ html: string;
54
+ refId: string;
55
+ attrs: BlockAttrs;
56
+ } | {
57
+ type: 'remove';
58
+ blockId: string;
59
+ } | {
60
+ type: 'replace';
61
+ blockId: string;
62
+ html: string;
63
+ attrs: BlockAttrs;
64
+ } | {
65
+ type: 'updateAttrs';
66
+ blockId: string;
67
+ attrs: Partial<BlockAttrs>;
68
+ };
69
+ /**
70
+ * Result of computing DOM commands
71
+ */
72
+ export interface DOMCommandResult {
73
+ commands: DOMCommand[];
74
+ stats: {
75
+ kept: number;
76
+ inserted: number;
77
+ removed: number;
78
+ replaced: number;
79
+ };
80
+ }
81
+ /**
82
+ * Normalize math blocks in markdown text
83
+ * Converts single-line $$...$$ to multi-line format for proper display math rendering
84
+ */
85
+ export declare function normalizeMathBlocks(markdown: string): string;
86
+ /**
87
+ * In-memory markdown document with virtual DOM support
88
+ */
89
+ export declare class MarkdownDocument {
90
+ private blocks;
91
+ private blockIdMap;
92
+ private rawContent;
93
+ private normalizedContent;
94
+ private idCounter;
95
+ /**
96
+ * Create a new document (optionally with initial content)
97
+ */
98
+ constructor(markdown?: string);
99
+ /**
100
+ * Rebuild the blockId -> index map
101
+ */
102
+ private rebuildBlockIdMap;
103
+ /**
104
+ * Get all blocks
105
+ */
106
+ getBlocks(): readonly BlockMeta[];
107
+ /**
108
+ * Get block by index
109
+ */
110
+ getBlock(index: number): BlockMeta | undefined;
111
+ /**
112
+ * Get block by ID (O(1) lookup)
113
+ */
114
+ getBlockById(id: string): BlockMeta | undefined;
115
+ /**
116
+ * Get block index by ID (O(1) lookup)
117
+ */
118
+ getBlockIndexById(id: string): number;
119
+ /**
120
+ * Get block count
121
+ */
122
+ get blockCount(): number;
123
+ /**
124
+ * Get raw markdown content
125
+ */
126
+ getRawContent(): string;
127
+ /**
128
+ * Get normalized content (math blocks expanded)
129
+ */
130
+ getNormalizedContent(): string;
131
+ /**
132
+ * Find block by line number
133
+ */
134
+ findBlockByLine(line: number): {
135
+ block: BlockMeta;
136
+ index: number;
137
+ } | null;
138
+ /**
139
+ * Get total line count of the document
140
+ */
141
+ getTotalLineCount(): number;
142
+ /**
143
+ * Get line position info for scroll sync.
144
+ * Returns the block containing the line and progress within that block.
145
+ *
146
+ * @param line - Source line number (can be fractional for sub-line precision)
147
+ * @returns Object with block info and progress (0-1) within block, or null if out of range
148
+ */
149
+ getLinePosition(line: number): {
150
+ block: BlockMeta;
151
+ index: number;
152
+ progress: number;
153
+ } | null;
154
+ /**
155
+ * Calculate line number from block index and progress within block.
156
+ * Inverse of getLinePosition.
157
+ *
158
+ * @param index - Block index
159
+ * @param progress - Progress within block (0-1)
160
+ * @returns Line number (with fractional part)
161
+ */
162
+ getLineFromPosition(index: number, progress: number): number;
163
+ /**
164
+ * Find surrounding blocks for a given line (for interpolation).
165
+ * Returns previous and next blocks relative to the line.
166
+ */
167
+ getSurroundingBlocks(line: number): {
168
+ previous?: {
169
+ block: BlockMeta;
170
+ index: number;
171
+ };
172
+ next?: {
173
+ block: BlockMeta;
174
+ index: number;
175
+ };
176
+ };
177
+ /**
178
+ * Calculate source line number from block ID and progress within block.
179
+ * Used by scroll sync: DOM provides blockId + pixel progress, we compute line.
180
+ *
181
+ * @param blockId - Block ID from DOM element's data-block-id
182
+ * @param progress - Progress within block (0-1) based on pixel position
183
+ * @returns Line number (with fractional part), or null if block not found
184
+ */
185
+ getLineFromBlockId(blockId: string, progress?: number): number | null;
186
+ /**
187
+ * Get block position for a source line number.
188
+ * Used by scroll sync: editor provides line, we compute blockId + progress for DOM scroll.
189
+ *
190
+ * @param line - Source line number (can be fractional)
191
+ * @returns Object with blockId and progress (0-1) within block, or null if out of range
192
+ */
193
+ getBlockPositionFromLine(line: number): {
194
+ blockId: string;
195
+ progress: number;
196
+ } | null;
197
+ /**
198
+ * Update document content and return DOM commands for incremental update
199
+ */
200
+ update(markdown: string): DOMCommandResult;
201
+ /**
202
+ * Generate a new unique block ID
203
+ */
204
+ private generateNewId;
205
+ /**
206
+ * Compute diff between old and new block arrays using LCS-based algorithm
207
+ */
208
+ private computeDiff;
209
+ /**
210
+ * Generate DOM commands from diff operations
211
+ */
212
+ private generateDOMCommands;
213
+ /**
214
+ * Get block attributes for DOM element
215
+ */
216
+ private getBlockAttrs;
217
+ /**
218
+ * Set rendered HTML for a block by index
219
+ */
220
+ setBlockHtml(index: number, html: string): void;
221
+ /**
222
+ * Set rendered HTML for a block by ID
223
+ */
224
+ setBlockHtmlById(id: string, html: string): void;
225
+ /**
226
+ * Get blocks that need rendering (no cached HTML or has placeholder)
227
+ */
228
+ getBlocksNeedingRender(): {
229
+ block: BlockMeta;
230
+ index: number;
231
+ }[];
232
+ /**
233
+ * Get all block IDs in order
234
+ */
235
+ getBlockIds(): string[];
236
+ /**
237
+ * Clear all cached HTML
238
+ */
239
+ clearHtmlCache(): void;
240
+ /**
241
+ * Get full HTML content (all blocks concatenated)
242
+ */
243
+ getFullHtml(): string;
244
+ /**
245
+ * Wrap block HTML with container div and attributes
246
+ */
247
+ wrapBlockHtml(block: BlockMeta): string;
248
+ /**
249
+ * Export document state for serialization
250
+ */
251
+ toJSON(): {
252
+ blocks: Omit<BlockMeta, 'html' | 'hasPlaceholder'>[];
253
+ rawContent: string;
254
+ idCounter: number;
255
+ };
256
+ /**
257
+ * Create document from serialized state
258
+ */
259
+ static fromJSON(data: {
260
+ blocks: Omit<BlockMeta, 'html' | 'hasPlaceholder'>[];
261
+ rawContent: string;
262
+ idCounter: number;
263
+ }): MarkdownDocument;
264
+ }
265
+ /**
266
+ * Extract title from markdown content
267
+ */
268
+ export declare function extractTitle(markdown: string): string | null;
269
+ /**
270
+ * Heading info for TOC
271
+ */
272
+ export interface HeadingInfo {
273
+ level: number;
274
+ text: string;
275
+ id: string;
276
+ line: number;
277
+ }
278
+ /**
279
+ * Extract headings from parsed blocks (without DOM)
280
+ */
281
+ export declare function extractHeadingsFromBlocks(blocks: readonly BlockMeta[]): HeadingInfo[];
282
+ /**
283
+ * Execute DOM commands on a container element
284
+ * This is the only function that touches the real DOM
285
+ */
286
+ export declare function executeDOMCommands(container: HTMLElement, commands: DOMCommand[], document: Document): void;
@@ -0,0 +1,228 @@
1
+ import { type Processor } from 'unified';
2
+ import { type BlockWithLine } from './markdown-block-splitter';
3
+ import type { TranslateFunction, TaskStatus, TaskData, PluginRenderer, AsyncTaskPlugin } from '../types/index';
4
+ export type { TranslateFunction };
5
+ /**
6
+ * Task context for cancellation
7
+ */
8
+ interface TaskContext {
9
+ cancelled: boolean;
10
+ }
11
+ /**
12
+ * Plugin interface for async tasks
13
+ */
14
+ type Plugin = AsyncTaskPlugin;
15
+ /**
16
+ * Async task interface
17
+ */
18
+ interface AsyncTask {
19
+ id: string;
20
+ callback: (data: TaskData) => Promise<void>;
21
+ data: TaskData;
22
+ type: string;
23
+ status: TaskStatus;
24
+ error: Error | null;
25
+ context: TaskContext;
26
+ setReady: () => void;
27
+ setError: (error: Error) => void;
28
+ }
29
+ /**
30
+ * Normalize math blocks in markdown text
31
+ * Converts single-line $$...$$ to multi-line format for proper display math rendering
32
+ * @param markdown - Raw markdown content
33
+ * @returns Normalized markdown
34
+ */
35
+ export declare function normalizeMathBlocks(markdown: string): string;
36
+ export type { BlockWithLine };
37
+ /**
38
+ * Split markdown into semantic blocks (paragraphs, code blocks, tables, etc.)
39
+ * Each block is a complete markdown element that can be processed independently.
40
+ * @param markdown - Raw markdown content
41
+ * @returns Array of markdown blocks
42
+ */
43
+ export declare function splitMarkdownIntoBlocks(markdown: string): string[];
44
+ /**
45
+ * Split markdown into semantic blocks with source line numbers.
46
+ * Each block includes its starting line number for scroll sync.
47
+ * @param markdown - Raw markdown content
48
+ * @returns Array of blocks with line info
49
+ */
50
+ export declare function splitMarkdownIntoBlocksWithLines(markdown: string): BlockWithLine[];
51
+ /**
52
+ * Escape HTML special characters
53
+ * @param text - Text to escape
54
+ * @returns Escaped text
55
+ */
56
+ export declare function escapeHtml(text: string): string;
57
+ /**
58
+ * Check if a block is a frontmatter block
59
+ * Frontmatter must start and end with ---, and typically appears at line 0
60
+ */
61
+ export declare function isFrontmatterBlock(block: string, startLine: number): boolean;
62
+ /**
63
+ * Parse frontmatter YAML content (simple key: value parsing)
64
+ */
65
+ export declare function parseFrontmatter(block: string): Record<string, string>;
66
+ /**
67
+ * Render frontmatter as HTML table
68
+ */
69
+ export declare function renderFrontmatterAsTable(data: Record<string, string>): string;
70
+ /**
71
+ * Render frontmatter as pre block (raw format)
72
+ */
73
+ export declare function renderFrontmatterAsRaw(block: string): string;
74
+ /**
75
+ * Validate URL values and block javascript-style protocols
76
+ * @param url - URL to validate
77
+ * @returns True when URL is considered safe
78
+ */
79
+ export declare function isSafeUrl(url: string | null | undefined): boolean;
80
+ /**
81
+ * Validate that every URL candidate in a srcset attribute is safe
82
+ * @param value - Raw srcset value
83
+ * @returns True when every entry is safe
84
+ */
85
+ export declare function isSafeSrcset(value: string | null | undefined): boolean;
86
+ /**
87
+ * Sanitize rendered HTML to remove active content like scripts before injection
88
+ * @param html - Raw HTML string produced by the markdown pipeline
89
+ * @returns Sanitized HTML safe for innerHTML assignment
90
+ */
91
+ export declare function sanitizeRenderedHtml(html: string): string;
92
+ /**
93
+ * Process tables to add centering attributes for Word compatibility
94
+ * @param html - HTML content
95
+ * @returns HTML with centered tables
96
+ */
97
+ export declare function processTablesForWordCompatibility(html: string): string;
98
+ /**
99
+ * Async task manager for plugin rendering
100
+ */
101
+ export interface AsyncTaskManagerOptions {
102
+ /** Callback triggered when abort() is called, for cleanup of downstream resources */
103
+ onAbort?: () => void;
104
+ }
105
+ export declare class AsyncTaskManager {
106
+ private queue;
107
+ private idCounter;
108
+ private translate;
109
+ private aborted;
110
+ private context;
111
+ private onAbort?;
112
+ constructor(translate?: TranslateFunction, options?: AsyncTaskManagerOptions);
113
+ /**
114
+ * Abort all pending tasks
115
+ * Called when starting a new render to cancel previous tasks
116
+ */
117
+ abort(): void;
118
+ /**
119
+ * Reset abort flag (call before starting new task collection)
120
+ */
121
+ reset(): void;
122
+ /**
123
+ * Check if manager has been aborted
124
+ */
125
+ isAborted(): boolean;
126
+ /**
127
+ * Get current context for callbacks to reference
128
+ */
129
+ getContext(): TaskContext;
130
+ /**
131
+ * Generate unique ID for async tasks
132
+ */
133
+ generateId(): string;
134
+ /**
135
+ * Register async task for later execution
136
+ * @param callback - The async callback function
137
+ * @param data - Data to pass to callback
138
+ * @param plugin - Plugin instance
139
+ * @param initialStatus - Initial task status
140
+ * @returns Task control and placeholder content
141
+ */
142
+ createTask(callback: (data: TaskData, context: TaskContext) => Promise<void>, data?: Record<string, unknown>, plugin?: Plugin | null, initialStatus?: TaskStatus): {
143
+ task: AsyncTask;
144
+ placeholder: {
145
+ type: 'html';
146
+ value: string;
147
+ };
148
+ };
149
+ /**
150
+ * Process all async tasks in parallel
151
+ * @param onProgress - Progress callback (completed, total)
152
+ * @param onError - Error handler for individual task
153
+ * @returns Returns true if completed, false if aborted
154
+ */
155
+ processAll(onProgress?: ((completed: number, total: number) => void) | null, onError?: ((error: Error, task: AsyncTask) => void) | null): Promise<boolean>;
156
+ /**
157
+ * Get pending task count
158
+ */
159
+ get pendingCount(): number;
160
+ }
161
+ /**
162
+ * Create the unified markdown processor pipeline
163
+ * @param renderer - Renderer instance for diagrams
164
+ * @param taskManager - Async task manager
165
+ * @param translate - Translation function
166
+ * @returns Configured unified processor
167
+ */
168
+ export declare function createMarkdownProcessor(renderer: PluginRenderer, taskManager: AsyncTaskManager, translate?: TranslateFunction): Processor;
169
+ /**
170
+ * Frontmatter display mode
171
+ */
172
+ export type FrontmatterDisplay = 'hide' | 'table' | 'raw';
173
+ /**
174
+ * Options for processing markdown to HTML
175
+ */
176
+ interface ProcessMarkdownOptions {
177
+ renderer: PluginRenderer;
178
+ taskManager: AsyncTaskManager;
179
+ translate?: TranslateFunction;
180
+ frontmatterDisplay?: FrontmatterDisplay;
181
+ }
182
+ /**
183
+ * Clear the HTML result cache (call when settings change)
184
+ */
185
+ export declare function clearHtmlResultCache(): void;
186
+ /**
187
+ * Process markdown to HTML with block-level caching
188
+ * Each block's top-level elements are tagged with hash for efficient DOM diffing.
189
+ * @param markdown - Raw markdown content
190
+ * @param options - Processing options
191
+ * @returns Processed HTML
192
+ */
193
+ export declare function processMarkdownToHtml(markdown: string, options: ProcessMarkdownOptions): Promise<string>;
194
+ /**
195
+ * Extract title from markdown content
196
+ * @param markdown - Markdown content
197
+ * @returns Extracted title or null
198
+ */
199
+ export declare function extractTitle(markdown: string): string | null;
200
+ /**
201
+ * Heading information for TOC
202
+ */
203
+ export interface HeadingInfo {
204
+ level: number;
205
+ text: string;
206
+ id: string;
207
+ }
208
+ /**
209
+ * Extract headings for TOC generation (from DOM)
210
+ * @param container - DOM container with rendered content
211
+ * @returns Array of heading objects
212
+ */
213
+ export declare function extractHeadings(container: Element): HeadingInfo[];
214
+ /**
215
+ * Options for incremental HTML rendering
216
+ */
217
+ interface RenderHtmlOptions {
218
+ batchSize?: number;
219
+ yieldDelay?: number;
220
+ }
221
+ /**
222
+ * Render HTML content incrementally to avoid blocking the main thread.
223
+ * Parses HTML, then appends top-level nodes in batches with yields between them.
224
+ * @param container - Target container element
225
+ * @param html - Full HTML content to render
226
+ * @param options - Rendering options
227
+ */
228
+ export declare function renderHtmlIncrementally(container: HTMLElement, html: string, options?: RenderHtmlOptions): Promise<void>;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * ViewerController - Shared, platform-agnostic markdown rendering orchestration.
3
+ *
4
+ * This version uses MarkdownDocument for block-ID based virtual DOM,
5
+ * providing precise incremental updates without morphdom.
6
+ */
7
+ import { AsyncTaskManager, type HeadingInfo } from '../markdown-processor';
8
+ import { MarkdownDocument } from '../markdown-document';
9
+ import type { PluginRenderer, TranslateFunction } from '../../types/index';
10
+ export type { HeadingInfo };
11
+ export type ViewerRenderResult = {
12
+ title: string | null;
13
+ headings: HeadingInfo[];
14
+ taskManager: AsyncTaskManager;
15
+ };
16
+ /**
17
+ * Frontmatter display mode
18
+ */
19
+ export type FrontmatterDisplay = 'hide' | 'table' | 'raw';
20
+ export type RenderMarkdownOptions = {
21
+ markdown: string;
22
+ container: HTMLElement;
23
+ renderer: PluginRenderer;
24
+ translate: TranslateFunction;
25
+ /**
26
+ * Optional external task manager, useful for cancellation.
27
+ * If not provided, a new AsyncTaskManager will be created.
28
+ */
29
+ taskManager?: AsyncTaskManager;
30
+ /**
31
+ * When true, container.innerHTML will be cleared before rendering.
32
+ * Keep false if the caller wants to clear before applying theme to avoid flicker.
33
+ */
34
+ clearContainer?: boolean;
35
+ /**
36
+ * When true, use incremental DOM diffing instead of full re-render.
37
+ * This preserves already-rendered plugin content when possible.
38
+ * @deprecated Now always uses block-ID based incremental update
39
+ */
40
+ incrementalUpdate?: boolean;
41
+ /** Called when headings are extracted (may be called multiple times during streaming) */
42
+ onHeadings?: (headings: HeadingInfo[]) => void;
43
+ /** Called when initial DOM streaming is complete (before async tasks) */
44
+ onStreamingComplete?: () => void;
45
+ /** Frontmatter display mode: 'hide', 'table', or 'raw' */
46
+ frontmatterDisplay?: FrontmatterDisplay;
47
+ };
48
+ /**
49
+ * Get or create the markdown document instance
50
+ */
51
+ export declare function getDocument(): MarkdownDocument;
52
+ /**
53
+ * Reset the document instance (call when switching files)
54
+ */
55
+ export declare function resetDocument(): void;
56
+ /**
57
+ * Clear HTML cache (for backward compatibility)
58
+ * @deprecated Use resetDocument() instead
59
+ */
60
+ export declare function clearHtmlCache(): void;
61
+ /**
62
+ * Sync block HTML from DOM after async rendering completes.
63
+ * Called when a placeholder is replaced with rendered content.
64
+ * This ensures the in-memory cache matches the actual DOM state.
65
+ *
66
+ * @param placeholderId - The ID of the placeholder element that was replaced
67
+ */
68
+ export declare function syncBlockHtmlFromDOM(placeholderId: string): void;
69
+ /**
70
+ * Main render function using MarkdownDocument architecture
71
+ */
72
+ export declare function renderMarkdownDocument(options: RenderMarkdownOptions): Promise<ViewerRenderResult>;
73
+ /**
74
+ * Find block element by ID
75
+ */
76
+ export declare function findBlockElement(container: HTMLElement, blockId: string): HTMLElement | null;
77
+ /**
78
+ * Get all block elements in order
79
+ */
80
+ export declare function getBlockElements(container: HTMLElement): HTMLElement[];
81
+ /**
82
+ * Check if incremental update is possible (for backward compatibility)
83
+ * @deprecated Always returns true now since we use block-ID based updates
84
+ */
85
+ export declare function canIncrementalUpdate(container: HTMLElement): boolean;
@@ -0,0 +1,24 @@
1
+ import { Table, type FileChild } from 'docx';
2
+ import type { DOCXThemeStyles, DOCXBlockquoteNode, DOCXASTNode } from '../types/docx';
3
+ import type { InlineResult, InlineNode } from './docx-inline-converter';
4
+ type ConvertInlineNodesFunction = (children: InlineNode[], options?: {
5
+ color?: string;
6
+ }) => Promise<InlineResult[]>;
7
+ type ConvertChildNodeFunction = (node: DOCXASTNode, blockquoteNestLevel?: number) => Promise<FileChild | FileChild[] | null>;
8
+ interface BlockquoteConverterOptions {
9
+ themeStyles: DOCXThemeStyles;
10
+ convertInlineNodes: ConvertInlineNodesFunction;
11
+ convertChildNode?: ConvertChildNodeFunction;
12
+ }
13
+ export interface BlockquoteConverter {
14
+ convertBlockquote(node: DOCXBlockquoteNode, listLevel?: number): Promise<Table>;
15
+ setConvertChildNode(fn: ConvertChildNodeFunction): void;
16
+ }
17
+ /**
18
+ * Create a blockquote converter using table-based approach
19
+ * This allows true nesting and supports any content type inside blockquotes
20
+ * @param options - Configuration options
21
+ * @returns Blockquote converter
22
+ */
23
+ export declare function createBlockquoteConverter({ themeStyles, convertInlineNodes, convertChildNode: initialConvertChildNode }: BlockquoteConverterOptions): BlockquoteConverter;
24
+ export {};
@@ -0,0 +1,14 @@
1
+ import { TextRun } from 'docx';
2
+ import type { DOCXThemeStyles } from '../types/docx';
3
+ export interface CodeHighlighter {
4
+ getHighlightColor(classList: string | string[] | DOMTokenList | null): string | null;
5
+ appendCodeTextRuns(text: string, runs: TextRun[], color: string | null): void;
6
+ collectHighlightedRuns(node: Node, runs: TextRun[], inheritedColor?: string | null): void;
7
+ getHighlightedRunsForCode(code: string, language: string | null | undefined): TextRun[];
8
+ }
9
+ /**
10
+ * Create a code highlighter for DOCX export
11
+ * @param themeStyles - Theme configuration with code colors
12
+ * @returns Highlighter instance with methods
13
+ */
14
+ export declare function createCodeHighlighter(themeStyles: DOCXThemeStyles | null): CodeHighlighter;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * DOCX Download Utilities
3
+ * Functions for downloading DOCX files
4
+ */
5
+ /**
6
+ * Convert byte array chunk to base64 without exceeding call stack limits
7
+ * @param bytes - Binary chunk
8
+ * @returns Base64 encoded chunk
9
+ */
10
+ export declare function encodeBytesToBase64(bytes: Uint8Array): string;
11
+ /**
12
+ * Fallback download method using <a> element
13
+ * @param blob - File blob
14
+ * @param filename - Output filename
15
+ */
16
+ export declare function fallbackDownload(blob: Blob, filename: string): void;
17
+ /**
18
+ * Progress callback for upload phase
19
+ */
20
+ export type UploadProgressCallback = (uploaded: number, total: number) => void;
21
+ /**
22
+ * Download blob as file using platform file service
23
+ * @param blob - File blob
24
+ * @param filename - Output filename
25
+ * @param onProgress - Optional progress callback for upload phase
26
+ */
27
+ export declare function downloadBlob(blob: Blob, filename: string, onProgress?: UploadProgressCallback): Promise<void>;