rich-text-editor-renderer 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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.js"],
4
+ "sourcesContent": ["const DEFAULT_OPTIONS = {\n mathMode: 'tex',\n className: 'rte-render-root',\n injectStyles: true,\n autoMathJaxTypeset: true,\n};\n\nconst STYLE_ID = 'rich-text-editor-renderer-styles';\nconst MIN_IMAGE_WIDTH = 32;\nconst MAX_IMAGE_WIDTH = 720;\nconst MIN_IMAGE_HEIGHT = 28;\nconst MAX_IMAGE_HEIGHT = 720;\n\nexport function renderRichTextDocument({\n element,\n document,\n options = {},\n}) {\n if (!element) {\n throw new Error('renderRichTextDocument requires an element');\n }\n\n const resolvedOptions = { ...DEFAULT_OPTIONS, ...options };\n const documentModel = normalizeDocument(document);\n\n if (resolvedOptions.injectStyles) {\n ensureStyles();\n }\n\n element.innerHTML = '';\n element.classList.add(resolvedOptions.className);\n\n const flowRoot = document.createElement('div');\n flowRoot.className = 'rte-flow-root';\n const floatingRoot = document.createElement('div');\n floatingRoot.className = 'rte-floating-root';\n\n element.appendChild(flowRoot);\n element.appendChild(floatingRoot);\n\n renderStaticNodes(flowRoot, documentModel);\n rerenderLayout({ host: element, flowRoot, floatingRoot, documentModel });\n\n if (resolvedOptions.autoMathJaxTypeset) {\n requestMathTypeset(element);\n }\n\n return {\n rerender() {\n rerenderLayout({ host: element, flowRoot, floatingRoot, documentModel });\n if (resolvedOptions.autoMathJaxTypeset) {\n requestMathTypeset(element);\n }\n },\n destroy() {\n element.innerHTML = '';\n element.classList.remove(resolvedOptions.className);\n },\n };\n}\n\nexport function autoMountRichTextDocuments({\n selector = '[data-rich-text-json]',\n options = {},\n} = {}) {\n const mounts = [];\n document.querySelectorAll(selector).forEach((element) => {\n const raw = element.getAttribute('data-rich-text-json');\n if (!raw) {\n return;\n }\n mounts.push(\n renderRichTextDocument({\n element,\n document: JSON.parse(raw),\n options,\n }),\n );\n });\n return mounts;\n}\n\nfunction normalizeDocument(value) {\n if (typeof value === 'string') {\n return JSON.parse(value);\n }\n return value;\n}\n\nfunction ensureStyles() {\n if (document.getElementById(STYLE_ID)) {\n return;\n }\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n .rte-render-root {\n position: relative;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n color: #1f2937;\n line-height: 1.6;\n word-break: break-word;\n }\n .rte-flow-root {\n position: relative;\n z-index: 1;\n }\n .rte-floating-root {\n position: absolute;\n inset: 0;\n pointer-events: none;\n z-index: 2;\n }\n .rte-node {\n margin-bottom: 12px;\n }\n .rte-paragraph,\n .rte-list-item {\n font-size: 16px;\n line-height: 1.4;\n font-weight: 400;\n }\n .rte-heading1 {\n font-size: 30px;\n line-height: 1.25;\n font-weight: 700;\n }\n .rte-heading2 {\n font-size: 22px;\n line-height: 1.3;\n font-weight: 600;\n }\n .rte-list {\n margin: 0 0 12px 0;\n padding-left: 24px;\n }\n .rte-line {\n display: flex;\n align-items: flex-start;\n min-height: 1em;\n }\n .rte-line-block {\n display: flex;\n align-items: flex-start;\n }\n .rte-token {\n white-space: pre;\n }\n .rte-token.bold {\n font-weight: 700;\n }\n .rte-token.italic {\n font-style: italic;\n }\n .rte-token.underline {\n text-decoration: underline;\n }\n .rte-token.link {\n color: #0a66c2;\n text-decoration: underline;\n }\n .rte-block-image,\n .rte-floating-image {\n overflow: hidden;\n border-radius: 12px;\n background: #e5e7eb;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n }\n .rte-block-image img,\n .rte-floating-image img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n .rte-floating-image {\n position: absolute;\n }\n .rte-wrap-block {\n display: flex;\n gap: 16px;\n align-items: flex-start;\n }\n .rte-wrap-block.right {\n flex-direction: row-reverse;\n }\n .rte-wrap-text {\n flex: 1;\n min-width: 0;\n }\n `;\n document.head.appendChild(style);\n}\n\nfunction renderStaticNodes(flowRoot, documentModel) {\n flowRoot.innerHTML = '';\n for (const node of documentModel.nodes || []) {\n switch (node.type) {\n case 'textBlock':\n renderStaticTextNode(flowRoot, node);\n break;\n case 'list':\n renderStaticListNode(flowRoot, node);\n break;\n case 'math':\n renderStaticMathNode(flowRoot, node);\n break;\n case 'image':\n renderStaticImageNode(flowRoot, node);\n break;\n default:\n break;\n }\n }\n}\n\nfunction renderStaticTextNode(flowRoot, node) {\n const wrapper = document.createElement('div');\n wrapper.className = 'rte-node';\n wrapper.dataset.nodeId = node.id;\n wrapper.dataset.nodeType = node.type;\n flowRoot.appendChild(wrapper);\n}\n\nfunction renderStaticListNode(flowRoot, node) {\n const list = document.createElement(node.style === 'ordered' ? 'ol' : 'ul');\n list.className = 'rte-node rte-list';\n list.dataset.nodeId = node.id;\n list.dataset.nodeType = node.type;\n (node.items || []).forEach((_, index) => {\n const item = document.createElement('li');\n item.className = 'rte-list-item';\n item.dataset.nodeId = `${node.id}::${index}`;\n item.dataset.parentNodeId = node.id;\n item.dataset.nodeType = 'list-item';\n list.appendChild(item);\n });\n flowRoot.appendChild(list);\n}\n\nfunction renderStaticMathNode(flowRoot, node) {\n const wrapper = document.createElement('div');\n wrapper.className = 'rte-node';\n wrapper.dataset.nodeId = node.id;\n wrapper.dataset.nodeType = node.type;\n wrapper.innerHTML = node.displayMode === 'inline'\n ? `<span data-node=\"math-inline\" data-latex=\"${escapeHtml(node.latex)}\">\\\\(${escapeHtml(node.latex)}\\\\)</span>`\n : `<div data-node=\"math-block\" data-latex=\"${escapeHtml(node.latex)}\">\\\\[${escapeHtml(node.latex)}\\\\]</div>`;\n flowRoot.appendChild(wrapper);\n}\n\nfunction renderStaticImageNode(flowRoot, node) {\n if (node.layoutMode === 'floating') {\n return;\n }\n\n const wrapper = document.createElement('div');\n wrapper.className = 'rte-node';\n wrapper.dataset.nodeId = node.id;\n wrapper.dataset.nodeType = node.type;\n\n const width = node.width ? ` style=\"width:${node.width}px\"` : '';\n const imageHtml = `<div class=\"rte-block-image\"${width}><img src=\"${escapeHtml(node.url)}\" alt=\"${escapeHtml(node.altText || '')}\"></div>`;\n\n if (node.wrapAlignment && node.wrapAlignment !== 'none' && hasWrapSegments(node.wrapSegments)) {\n wrapper.innerHTML = `<div class=\"rte-wrap-block ${node.wrapAlignment === 'right' ? 'right' : 'left'}\">${imageHtml}<div class=\"rte-wrap-text rte-paragraph\">${segmentsHtml(node.wrapSegments)}</div></div>`;\n } else {\n wrapper.innerHTML = imageHtml;\n }\n flowRoot.appendChild(wrapper);\n}\n\nfunction rerenderLayout({ host, flowRoot, floatingRoot, documentModel }) {\n const nodeRects = readNodeRects(host, flowRoot);\n const floatRects = buildFloatingRects(documentModel, nodeRects);\n renderFloatingImages(host, floatingRoot, floatRects);\n rerenderTextNodes(flowRoot, documentModel, nodeRects, floatRects);\n const nextRects = readNodeRects(host, flowRoot);\n const nextFloatRects = buildFloatingRects(documentModel, nextRects);\n renderFloatingImages(host, floatingRoot, nextFloatRects);\n rerenderTextNodes(flowRoot, documentModel, nextRects, nextFloatRects);\n}\n\nfunction readNodeRects(host, flowRoot) {\n const rects = {};\n const rootRect = host.getBoundingClientRect();\n flowRoot.querySelectorAll('[data-node-id]').forEach((element) => {\n const rect = element.getBoundingClientRect();\n rects[element.dataset.nodeId] = {\n left: rect.left - rootRect.left,\n top: rect.top - rootRect.top,\n width: rect.width,\n height: rect.height,\n right: rect.right - rootRect.left,\n bottom: rect.bottom - rootRect.top,\n };\n });\n return rects;\n}\n\nfunction buildFloatingRects(documentModel, nodeRects) {\n const rects = {};\n for (const node of documentModel.nodes || []) {\n if (node.type !== 'image' || node.layoutMode !== 'floating') {\n continue;\n }\n const anchor = node.anchorBlockId ? nodeRects[node.anchorBlockId] : null;\n const baseLeft = anchor ? anchor.left : 0;\n const baseTop = anchor ? anchor.top : 0;\n const width = clamp(node.width || 280, MIN_IMAGE_WIDTH, MAX_IMAGE_WIDTH);\n const height = clamp(node.height || width * 0.72, MIN_IMAGE_HEIGHT, MAX_IMAGE_HEIGHT);\n rects[node.id] = {\n node,\n left: baseLeft + (node.x || 0),\n top: baseTop + (node.y || 0),\n width,\n height,\n right: baseLeft + (node.x || 0) + width,\n bottom: baseTop + (node.y || 0) + height,\n };\n }\n return rects;\n}\n\nfunction renderFloatingImages(host, floatingRoot, floatRects) {\n floatingRoot.innerHTML = '';\n let maxBottom = 0;\n Object.values(floatRects)\n .sort((a, b) => (a.node.zIndex || 0) - (b.node.zIndex || 0))\n .forEach((entry) => {\n const element = document.createElement('div');\n element.className = 'rte-floating-image';\n element.style.left = `${entry.left}px`;\n element.style.top = `${entry.top}px`;\n element.style.width = `${entry.width}px`;\n element.style.height = `${entry.height}px`;\n element.style.zIndex = String(entry.node.zIndex || 0);\n if (entry.node.rotationDegrees) {\n element.style.transform = `rotate(${entry.node.rotationDegrees}deg)`;\n }\n element.innerHTML = `<img src=\"${escapeHtml(entry.node.url)}\" alt=\"${escapeHtml(entry.node.altText || '')}\">`;\n floatingRoot.appendChild(element);\n maxBottom = Math.max(maxBottom, entry.bottom);\n });\n host.style.minHeight = `${Math.max(flowRootHeight(host), maxBottom)}px`;\n}\n\nfunction flowRootHeight(host) {\n const flowRoot = host.querySelector('.rte-flow-root');\n return flowRoot ? flowRoot.scrollHeight : 0;\n}\n\nfunction rerenderTextNodes(flowRoot, documentModel, nodeRects, floatRects) {\n for (const node of documentModel.nodes || []) {\n if (node.type === 'textBlock') {\n const element = queryNode(flowRoot, node.id);\n const rect = nodeRects[node.id];\n if (!element || !rect) {\n continue;\n }\n const style = styleForTextBlock(node.style);\n const bands = buildBands(rect, floatRects);\n element.innerHTML = '';\n if (bands.length === 0) {\n const block = document.createElement(style.tag);\n block.className = style.className;\n block.innerHTML = segmentsHtml(node.segments);\n element.appendChild(block);\n } else {\n element.appendChild(buildWrappedLayout(node.segments, style, bands, rect.width));\n }\n continue;\n }\n\n if (node.type === 'list') {\n (node.items || []).forEach((item, index) => {\n const itemId = `${node.id}::${index}`;\n const element = queryNode(flowRoot, itemId);\n const rect = nodeRects[itemId];\n if (!element || !rect) {\n return;\n }\n const style = {\n ...styleForTextBlock('paragraph'),\n className: 'rte-list-item',\n };\n const bands = buildBands(rect, floatRects);\n element.innerHTML = '';\n if (bands.length === 0) {\n element.innerHTML = segmentsHtml(item);\n } else {\n element.appendChild(buildWrappedLayout(item, style, bands, rect.width));\n }\n });\n }\n }\n}\n\nfunction queryNode(root, id) {\n for (const element of root.querySelectorAll('[data-node-id]')) {\n if (element.dataset.nodeId === id) {\n return element;\n }\n }\n return null;\n}\n\nfunction buildBands(targetRect, floatRects) {\n const bands = [];\n Object.values(floatRects).forEach((entry) => {\n const overlapTop = Math.max(entry.top, targetRect.top);\n const overlapBottom = Math.min(entry.bottom, targetRect.bottom);\n if (overlapBottom <= overlapTop) {\n return;\n }\n bands.push({\n top: overlapTop - targetRect.top,\n bottom: overlapBottom - targetRect.top,\n blockedStart: clamp(entry.left - targetRect.left, 0, targetRect.width),\n blockedEnd: clamp(entry.right - targetRect.left, 0, targetRect.width),\n });\n });\n return bands.sort((a, b) => a.top - b.top);\n}\n\nfunction buildWrappedLayout(segments, style, bands, width) {\n const container = document.createElement('div');\n container.className = style.className;\n const tokens = tokenizeSegments(segments);\n const canvas = document.createElement('canvas');\n const context = canvas.getContext('2d');\n const lineHeight = style.fontSize * style.lineHeight;\n let tokenIndex = 0;\n let currentTop = 0;\n\n while (tokenIndex < tokens.length) {\n const band = bands.find((entry) => currentTop + lineHeight > entry.top && currentTop < entry.bottom);\n if (!band) {\n const built = takeTokens(tokens, tokenIndex, width, style, context);\n tokenIndex += built.consumed;\n const line = document.createElement('div');\n line.className = 'rte-line';\n built.accepted.forEach((token) => line.appendChild(buildTokenElement(token)));\n container.appendChild(line);\n currentTop += lineHeight;\n continue;\n }\n\n const leftWidth = clamp(band.blockedStart, 0, width);\n const blockedWidth = clamp(band.blockedEnd - band.blockedStart, 0, width - leftWidth);\n const rightWidth = clamp(width - leftWidth - blockedWidth, 0, width);\n const leftBuilt = leftWidth > 48 ? takeTokens(tokens, tokenIndex, leftWidth, style, context) : { accepted: [], consumed: 0 };\n tokenIndex += leftBuilt.consumed;\n const rightBuilt = rightWidth > 48 ? takeTokens(tokens, tokenIndex, rightWidth, style, context) : { accepted: [], consumed: 0 };\n tokenIndex += rightBuilt.consumed;\n\n const row = document.createElement('div');\n row.className = `rte-line-block ${style.className}`;\n\n const left = document.createElement('div');\n left.className = 'rte-line';\n left.style.width = `${leftWidth}px`;\n left.style.minWidth = `${leftWidth}px`;\n leftBuilt.accepted.forEach((token) => left.appendChild(buildTokenElement(token)));\n\n const blocked = document.createElement('div');\n blocked.style.width = `${blockedWidth}px`;\n blocked.style.minWidth = `${blockedWidth}px`;\n\n const right = document.createElement('div');\n right.className = 'rte-line';\n right.style.width = `${rightWidth}px`;\n right.style.minWidth = `${rightWidth}px`;\n rightBuilt.accepted.forEach((token) => right.appendChild(buildTokenElement(token)));\n\n row.appendChild(left);\n row.appendChild(blocked);\n row.appendChild(right);\n container.appendChild(row);\n currentTop += lineHeight;\n }\n\n if (tokens.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'rte-line';\n empty.innerHTML = '&nbsp;';\n container.appendChild(empty);\n }\n\n return container;\n}\n\nfunction tokenizeSegments(segments = []) {\n const tokens = [];\n segments.forEach((segment, index) => {\n if (segment.inlineMathLatex) {\n tokens.push({\n value: `\\\\(${segment.inlineMathLatex}\\\\)`,\n bold: false,\n italic: false,\n underline: false,\n link: null,\n isMath: true,\n });\n if (index !== segments.length - 1) {\n tokens.push({ value: ' ', bold: false, italic: false, underline: false, link: null, isMath: false });\n }\n return;\n }\n\n const text = segment.text || '';\n const matches = text.match(/\\S+\\s*/g);\n if (!matches || matches.length === 0) {\n if (text.length > 0) {\n tokens.push(toTextToken(segment, text));\n }\n return;\n }\n matches.forEach((part) => tokens.push(toTextToken(segment, part)));\n });\n return tokens;\n}\n\nfunction toTextToken(segment, value) {\n return {\n value,\n bold: !!segment.bold,\n italic: !!segment.italic,\n underline: !!segment.underline,\n link: segment.link || null,\n isMath: false,\n };\n}\n\nfunction takeTokens(tokens, startIndex, width, style, context) {\n if (startIndex >= tokens.length || width <= 0) {\n return { accepted: [], consumed: 0 };\n }\n const accepted = [];\n let consumed = 0;\n let totalWidth = 0;\n\n for (let index = startIndex; index < tokens.length; index += 1) {\n const token = tokens[index];\n const tokenWidth = measureToken(token, style, context);\n if (accepted.length > 0 && totalWidth + tokenWidth > width) {\n break;\n }\n accepted.push(token);\n consumed += 1;\n totalWidth += tokenWidth;\n }\n\n if (consumed === 0) {\n return { accepted: [tokens[startIndex]], consumed: 1 };\n }\n return { accepted, consumed };\n}\n\nfunction measureToken(token, style, context) {\n if (!context) {\n return token.value.length * style.fontSize * 0.58;\n }\n context.font = `${token.bold ? 700 : style.fontWeight} ${token.italic ? 'italic ' : ''}${style.fontSize}px -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif`;\n return context.measureText(token.value).width;\n}\n\nfunction buildTokenElement(token) {\n const element = token.link ? document.createElement('a') : document.createElement('span');\n const classes = ['rte-token'];\n if (token.bold) classes.push('bold');\n if (token.italic) classes.push('italic');\n if (token.underline) classes.push('underline');\n if (token.link) classes.push('link');\n element.className = classes.join(' ');\n if (token.link) {\n element.href = token.link;\n }\n element.innerHTML = token.isMath ? token.value : escapeHtml(token.value);\n return element;\n}\n\nfunction styleForTextBlock(style) {\n if (style === 'heading1') {\n return { tag: 'h1', className: 'rte-heading1', fontSize: 30, lineHeight: 1.25, fontWeight: 700 };\n }\n if (style === 'heading2') {\n return { tag: 'h2', className: 'rte-heading2', fontSize: 22, lineHeight: 1.3, fontWeight: 600 };\n }\n return { tag: 'p', className: 'rte-paragraph', fontSize: 16, lineHeight: 1.4, fontWeight: 400 };\n}\n\nfunction segmentsHtml(segments = []) {\n return segments.map((segment) => {\n if (segment.inlineMathLatex) {\n return `<span data-node=\"math-inline\" data-latex=\"${escapeHtml(segment.inlineMathLatex)}\">\\\\(${escapeHtml(segment.inlineMathLatex)}\\\\)</span>`;\n }\n let content = escapeHtml(segment.text || '');\n if (segment.bold) content = `<strong>${content}</strong>`;\n if (segment.italic) content = `<em>${content}</em>`;\n if (segment.underline) content = `<u>${content}</u>`;\n if (segment.link) content = `<a href=\"${escapeHtml(segment.link)}\">${content}</a>`;\n return content;\n }).join('');\n}\n\nfunction hasWrapSegments(segments = []) {\n return segments.some((segment) => (segment.text || '').trim().length > 0 || segment.inlineMathLatex);\n}\n\nfunction requestMathTypeset(element) {\n if (window.MathJax && typeof window.MathJax.typesetPromise === 'function') {\n window.MathJax.typesetPromise([element]).catch(() => {});\n }\n}\n\nfunction clamp(value, min, max) {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction escapeHtml(value) {\n return String(value)\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["document"]
7
+ }
package/dist/index.js ADDED
@@ -0,0 +1,572 @@
1
+ // src/index.js
2
+ var DEFAULT_OPTIONS = {
3
+ mathMode: "tex",
4
+ className: "rte-render-root",
5
+ injectStyles: true,
6
+ autoMathJaxTypeset: true
7
+ };
8
+ var STYLE_ID = "rich-text-editor-renderer-styles";
9
+ var MIN_IMAGE_WIDTH = 32;
10
+ var MAX_IMAGE_WIDTH = 720;
11
+ var MIN_IMAGE_HEIGHT = 28;
12
+ var MAX_IMAGE_HEIGHT = 720;
13
+ function renderRichTextDocument({
14
+ element,
15
+ document: document2,
16
+ options = {}
17
+ }) {
18
+ if (!element) {
19
+ throw new Error("renderRichTextDocument requires an element");
20
+ }
21
+ const resolvedOptions = { ...DEFAULT_OPTIONS, ...options };
22
+ const documentModel = normalizeDocument(document2);
23
+ if (resolvedOptions.injectStyles) {
24
+ ensureStyles();
25
+ }
26
+ element.innerHTML = "";
27
+ element.classList.add(resolvedOptions.className);
28
+ const flowRoot = document2.createElement("div");
29
+ flowRoot.className = "rte-flow-root";
30
+ const floatingRoot = document2.createElement("div");
31
+ floatingRoot.className = "rte-floating-root";
32
+ element.appendChild(flowRoot);
33
+ element.appendChild(floatingRoot);
34
+ renderStaticNodes(flowRoot, documentModel);
35
+ rerenderLayout({ host: element, flowRoot, floatingRoot, documentModel });
36
+ if (resolvedOptions.autoMathJaxTypeset) {
37
+ requestMathTypeset(element);
38
+ }
39
+ return {
40
+ rerender() {
41
+ rerenderLayout({ host: element, flowRoot, floatingRoot, documentModel });
42
+ if (resolvedOptions.autoMathJaxTypeset) {
43
+ requestMathTypeset(element);
44
+ }
45
+ },
46
+ destroy() {
47
+ element.innerHTML = "";
48
+ element.classList.remove(resolvedOptions.className);
49
+ }
50
+ };
51
+ }
52
+ function autoMountRichTextDocuments({
53
+ selector = "[data-rich-text-json]",
54
+ options = {}
55
+ } = {}) {
56
+ const mounts = [];
57
+ document.querySelectorAll(selector).forEach((element) => {
58
+ const raw = element.getAttribute("data-rich-text-json");
59
+ if (!raw) {
60
+ return;
61
+ }
62
+ mounts.push(
63
+ renderRichTextDocument({
64
+ element,
65
+ document: JSON.parse(raw),
66
+ options
67
+ })
68
+ );
69
+ });
70
+ return mounts;
71
+ }
72
+ function normalizeDocument(value) {
73
+ if (typeof value === "string") {
74
+ return JSON.parse(value);
75
+ }
76
+ return value;
77
+ }
78
+ function ensureStyles() {
79
+ if (document.getElementById(STYLE_ID)) {
80
+ return;
81
+ }
82
+ const style = document.createElement("style");
83
+ style.id = STYLE_ID;
84
+ style.textContent = `
85
+ .rte-render-root {
86
+ position: relative;
87
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
88
+ color: #1f2937;
89
+ line-height: 1.6;
90
+ word-break: break-word;
91
+ }
92
+ .rte-flow-root {
93
+ position: relative;
94
+ z-index: 1;
95
+ }
96
+ .rte-floating-root {
97
+ position: absolute;
98
+ inset: 0;
99
+ pointer-events: none;
100
+ z-index: 2;
101
+ }
102
+ .rte-node {
103
+ margin-bottom: 12px;
104
+ }
105
+ .rte-paragraph,
106
+ .rte-list-item {
107
+ font-size: 16px;
108
+ line-height: 1.4;
109
+ font-weight: 400;
110
+ }
111
+ .rte-heading1 {
112
+ font-size: 30px;
113
+ line-height: 1.25;
114
+ font-weight: 700;
115
+ }
116
+ .rte-heading2 {
117
+ font-size: 22px;
118
+ line-height: 1.3;
119
+ font-weight: 600;
120
+ }
121
+ .rte-list {
122
+ margin: 0 0 12px 0;
123
+ padding-left: 24px;
124
+ }
125
+ .rte-line {
126
+ display: flex;
127
+ align-items: flex-start;
128
+ min-height: 1em;
129
+ }
130
+ .rte-line-block {
131
+ display: flex;
132
+ align-items: flex-start;
133
+ }
134
+ .rte-token {
135
+ white-space: pre;
136
+ }
137
+ .rte-token.bold {
138
+ font-weight: 700;
139
+ }
140
+ .rte-token.italic {
141
+ font-style: italic;
142
+ }
143
+ .rte-token.underline {
144
+ text-decoration: underline;
145
+ }
146
+ .rte-token.link {
147
+ color: #0a66c2;
148
+ text-decoration: underline;
149
+ }
150
+ .rte-block-image,
151
+ .rte-floating-image {
152
+ overflow: hidden;
153
+ border-radius: 12px;
154
+ background: #e5e7eb;
155
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
156
+ }
157
+ .rte-block-image img,
158
+ .rte-floating-image img {
159
+ display: block;
160
+ width: 100%;
161
+ height: 100%;
162
+ object-fit: cover;
163
+ }
164
+ .rte-floating-image {
165
+ position: absolute;
166
+ }
167
+ .rte-wrap-block {
168
+ display: flex;
169
+ gap: 16px;
170
+ align-items: flex-start;
171
+ }
172
+ .rte-wrap-block.right {
173
+ flex-direction: row-reverse;
174
+ }
175
+ .rte-wrap-text {
176
+ flex: 1;
177
+ min-width: 0;
178
+ }
179
+ `;
180
+ document.head.appendChild(style);
181
+ }
182
+ function renderStaticNodes(flowRoot, documentModel) {
183
+ flowRoot.innerHTML = "";
184
+ for (const node of documentModel.nodes || []) {
185
+ switch (node.type) {
186
+ case "textBlock":
187
+ renderStaticTextNode(flowRoot, node);
188
+ break;
189
+ case "list":
190
+ renderStaticListNode(flowRoot, node);
191
+ break;
192
+ case "math":
193
+ renderStaticMathNode(flowRoot, node);
194
+ break;
195
+ case "image":
196
+ renderStaticImageNode(flowRoot, node);
197
+ break;
198
+ default:
199
+ break;
200
+ }
201
+ }
202
+ }
203
+ function renderStaticTextNode(flowRoot, node) {
204
+ const wrapper = document.createElement("div");
205
+ wrapper.className = "rte-node";
206
+ wrapper.dataset.nodeId = node.id;
207
+ wrapper.dataset.nodeType = node.type;
208
+ flowRoot.appendChild(wrapper);
209
+ }
210
+ function renderStaticListNode(flowRoot, node) {
211
+ const list = document.createElement(node.style === "ordered" ? "ol" : "ul");
212
+ list.className = "rte-node rte-list";
213
+ list.dataset.nodeId = node.id;
214
+ list.dataset.nodeType = node.type;
215
+ (node.items || []).forEach((_, index) => {
216
+ const item = document.createElement("li");
217
+ item.className = "rte-list-item";
218
+ item.dataset.nodeId = `${node.id}::${index}`;
219
+ item.dataset.parentNodeId = node.id;
220
+ item.dataset.nodeType = "list-item";
221
+ list.appendChild(item);
222
+ });
223
+ flowRoot.appendChild(list);
224
+ }
225
+ function renderStaticMathNode(flowRoot, node) {
226
+ const wrapper = document.createElement("div");
227
+ wrapper.className = "rte-node";
228
+ wrapper.dataset.nodeId = node.id;
229
+ wrapper.dataset.nodeType = node.type;
230
+ wrapper.innerHTML = node.displayMode === "inline" ? `<span data-node="math-inline" data-latex="${escapeHtml(node.latex)}">\\(${escapeHtml(node.latex)}\\)</span>` : `<div data-node="math-block" data-latex="${escapeHtml(node.latex)}">\\[${escapeHtml(node.latex)}\\]</div>`;
231
+ flowRoot.appendChild(wrapper);
232
+ }
233
+ function renderStaticImageNode(flowRoot, node) {
234
+ if (node.layoutMode === "floating") {
235
+ return;
236
+ }
237
+ const wrapper = document.createElement("div");
238
+ wrapper.className = "rte-node";
239
+ wrapper.dataset.nodeId = node.id;
240
+ wrapper.dataset.nodeType = node.type;
241
+ const width = node.width ? ` style="width:${node.width}px"` : "";
242
+ const imageHtml = `<div class="rte-block-image"${width}><img src="${escapeHtml(node.url)}" alt="${escapeHtml(node.altText || "")}"></div>`;
243
+ if (node.wrapAlignment && node.wrapAlignment !== "none" && hasWrapSegments(node.wrapSegments)) {
244
+ wrapper.innerHTML = `<div class="rte-wrap-block ${node.wrapAlignment === "right" ? "right" : "left"}">${imageHtml}<div class="rte-wrap-text rte-paragraph">${segmentsHtml(node.wrapSegments)}</div></div>`;
245
+ } else {
246
+ wrapper.innerHTML = imageHtml;
247
+ }
248
+ flowRoot.appendChild(wrapper);
249
+ }
250
+ function rerenderLayout({ host, flowRoot, floatingRoot, documentModel }) {
251
+ const nodeRects = readNodeRects(host, flowRoot);
252
+ const floatRects = buildFloatingRects(documentModel, nodeRects);
253
+ renderFloatingImages(host, floatingRoot, floatRects);
254
+ rerenderTextNodes(flowRoot, documentModel, nodeRects, floatRects);
255
+ const nextRects = readNodeRects(host, flowRoot);
256
+ const nextFloatRects = buildFloatingRects(documentModel, nextRects);
257
+ renderFloatingImages(host, floatingRoot, nextFloatRects);
258
+ rerenderTextNodes(flowRoot, documentModel, nextRects, nextFloatRects);
259
+ }
260
+ function readNodeRects(host, flowRoot) {
261
+ const rects = {};
262
+ const rootRect = host.getBoundingClientRect();
263
+ flowRoot.querySelectorAll("[data-node-id]").forEach((element) => {
264
+ const rect = element.getBoundingClientRect();
265
+ rects[element.dataset.nodeId] = {
266
+ left: rect.left - rootRect.left,
267
+ top: rect.top - rootRect.top,
268
+ width: rect.width,
269
+ height: rect.height,
270
+ right: rect.right - rootRect.left,
271
+ bottom: rect.bottom - rootRect.top
272
+ };
273
+ });
274
+ return rects;
275
+ }
276
+ function buildFloatingRects(documentModel, nodeRects) {
277
+ const rects = {};
278
+ for (const node of documentModel.nodes || []) {
279
+ if (node.type !== "image" || node.layoutMode !== "floating") {
280
+ continue;
281
+ }
282
+ const anchor = node.anchorBlockId ? nodeRects[node.anchorBlockId] : null;
283
+ const baseLeft = anchor ? anchor.left : 0;
284
+ const baseTop = anchor ? anchor.top : 0;
285
+ const width = clamp(node.width || 280, MIN_IMAGE_WIDTH, MAX_IMAGE_WIDTH);
286
+ const height = clamp(node.height || width * 0.72, MIN_IMAGE_HEIGHT, MAX_IMAGE_HEIGHT);
287
+ rects[node.id] = {
288
+ node,
289
+ left: baseLeft + (node.x || 0),
290
+ top: baseTop + (node.y || 0),
291
+ width,
292
+ height,
293
+ right: baseLeft + (node.x || 0) + width,
294
+ bottom: baseTop + (node.y || 0) + height
295
+ };
296
+ }
297
+ return rects;
298
+ }
299
+ function renderFloatingImages(host, floatingRoot, floatRects) {
300
+ floatingRoot.innerHTML = "";
301
+ let maxBottom = 0;
302
+ Object.values(floatRects).sort((a, b) => (a.node.zIndex || 0) - (b.node.zIndex || 0)).forEach((entry) => {
303
+ const element = document.createElement("div");
304
+ element.className = "rte-floating-image";
305
+ element.style.left = `${entry.left}px`;
306
+ element.style.top = `${entry.top}px`;
307
+ element.style.width = `${entry.width}px`;
308
+ element.style.height = `${entry.height}px`;
309
+ element.style.zIndex = String(entry.node.zIndex || 0);
310
+ if (entry.node.rotationDegrees) {
311
+ element.style.transform = `rotate(${entry.node.rotationDegrees}deg)`;
312
+ }
313
+ element.innerHTML = `<img src="${escapeHtml(entry.node.url)}" alt="${escapeHtml(entry.node.altText || "")}">`;
314
+ floatingRoot.appendChild(element);
315
+ maxBottom = Math.max(maxBottom, entry.bottom);
316
+ });
317
+ host.style.minHeight = `${Math.max(flowRootHeight(host), maxBottom)}px`;
318
+ }
319
+ function flowRootHeight(host) {
320
+ const flowRoot = host.querySelector(".rte-flow-root");
321
+ return flowRoot ? flowRoot.scrollHeight : 0;
322
+ }
323
+ function rerenderTextNodes(flowRoot, documentModel, nodeRects, floatRects) {
324
+ for (const node of documentModel.nodes || []) {
325
+ if (node.type === "textBlock") {
326
+ const element = queryNode(flowRoot, node.id);
327
+ const rect = nodeRects[node.id];
328
+ if (!element || !rect) {
329
+ continue;
330
+ }
331
+ const style = styleForTextBlock(node.style);
332
+ const bands = buildBands(rect, floatRects);
333
+ element.innerHTML = "";
334
+ if (bands.length === 0) {
335
+ const block = document.createElement(style.tag);
336
+ block.className = style.className;
337
+ block.innerHTML = segmentsHtml(node.segments);
338
+ element.appendChild(block);
339
+ } else {
340
+ element.appendChild(buildWrappedLayout(node.segments, style, bands, rect.width));
341
+ }
342
+ continue;
343
+ }
344
+ if (node.type === "list") {
345
+ (node.items || []).forEach((item, index) => {
346
+ const itemId = `${node.id}::${index}`;
347
+ const element = queryNode(flowRoot, itemId);
348
+ const rect = nodeRects[itemId];
349
+ if (!element || !rect) {
350
+ return;
351
+ }
352
+ const style = {
353
+ ...styleForTextBlock("paragraph"),
354
+ className: "rte-list-item"
355
+ };
356
+ const bands = buildBands(rect, floatRects);
357
+ element.innerHTML = "";
358
+ if (bands.length === 0) {
359
+ element.innerHTML = segmentsHtml(item);
360
+ } else {
361
+ element.appendChild(buildWrappedLayout(item, style, bands, rect.width));
362
+ }
363
+ });
364
+ }
365
+ }
366
+ }
367
+ function queryNode(root, id) {
368
+ for (const element of root.querySelectorAll("[data-node-id]")) {
369
+ if (element.dataset.nodeId === id) {
370
+ return element;
371
+ }
372
+ }
373
+ return null;
374
+ }
375
+ function buildBands(targetRect, floatRects) {
376
+ const bands = [];
377
+ Object.values(floatRects).forEach((entry) => {
378
+ const overlapTop = Math.max(entry.top, targetRect.top);
379
+ const overlapBottom = Math.min(entry.bottom, targetRect.bottom);
380
+ if (overlapBottom <= overlapTop) {
381
+ return;
382
+ }
383
+ bands.push({
384
+ top: overlapTop - targetRect.top,
385
+ bottom: overlapBottom - targetRect.top,
386
+ blockedStart: clamp(entry.left - targetRect.left, 0, targetRect.width),
387
+ blockedEnd: clamp(entry.right - targetRect.left, 0, targetRect.width)
388
+ });
389
+ });
390
+ return bands.sort((a, b) => a.top - b.top);
391
+ }
392
+ function buildWrappedLayout(segments, style, bands, width) {
393
+ const container = document.createElement("div");
394
+ container.className = style.className;
395
+ const tokens = tokenizeSegments(segments);
396
+ const canvas = document.createElement("canvas");
397
+ const context = canvas.getContext("2d");
398
+ const lineHeight = style.fontSize * style.lineHeight;
399
+ let tokenIndex = 0;
400
+ let currentTop = 0;
401
+ while (tokenIndex < tokens.length) {
402
+ const band = bands.find((entry) => currentTop + lineHeight > entry.top && currentTop < entry.bottom);
403
+ if (!band) {
404
+ const built = takeTokens(tokens, tokenIndex, width, style, context);
405
+ tokenIndex += built.consumed;
406
+ const line = document.createElement("div");
407
+ line.className = "rte-line";
408
+ built.accepted.forEach((token) => line.appendChild(buildTokenElement(token)));
409
+ container.appendChild(line);
410
+ currentTop += lineHeight;
411
+ continue;
412
+ }
413
+ const leftWidth = clamp(band.blockedStart, 0, width);
414
+ const blockedWidth = clamp(band.blockedEnd - band.blockedStart, 0, width - leftWidth);
415
+ const rightWidth = clamp(width - leftWidth - blockedWidth, 0, width);
416
+ const leftBuilt = leftWidth > 48 ? takeTokens(tokens, tokenIndex, leftWidth, style, context) : { accepted: [], consumed: 0 };
417
+ tokenIndex += leftBuilt.consumed;
418
+ const rightBuilt = rightWidth > 48 ? takeTokens(tokens, tokenIndex, rightWidth, style, context) : { accepted: [], consumed: 0 };
419
+ tokenIndex += rightBuilt.consumed;
420
+ const row = document.createElement("div");
421
+ row.className = `rte-line-block ${style.className}`;
422
+ const left = document.createElement("div");
423
+ left.className = "rte-line";
424
+ left.style.width = `${leftWidth}px`;
425
+ left.style.minWidth = `${leftWidth}px`;
426
+ leftBuilt.accepted.forEach((token) => left.appendChild(buildTokenElement(token)));
427
+ const blocked = document.createElement("div");
428
+ blocked.style.width = `${blockedWidth}px`;
429
+ blocked.style.minWidth = `${blockedWidth}px`;
430
+ const right = document.createElement("div");
431
+ right.className = "rte-line";
432
+ right.style.width = `${rightWidth}px`;
433
+ right.style.minWidth = `${rightWidth}px`;
434
+ rightBuilt.accepted.forEach((token) => right.appendChild(buildTokenElement(token)));
435
+ row.appendChild(left);
436
+ row.appendChild(blocked);
437
+ row.appendChild(right);
438
+ container.appendChild(row);
439
+ currentTop += lineHeight;
440
+ }
441
+ if (tokens.length === 0) {
442
+ const empty = document.createElement("div");
443
+ empty.className = "rte-line";
444
+ empty.innerHTML = "&nbsp;";
445
+ container.appendChild(empty);
446
+ }
447
+ return container;
448
+ }
449
+ function tokenizeSegments(segments = []) {
450
+ const tokens = [];
451
+ segments.forEach((segment, index) => {
452
+ if (segment.inlineMathLatex) {
453
+ tokens.push({
454
+ value: `\\(${segment.inlineMathLatex}\\)`,
455
+ bold: false,
456
+ italic: false,
457
+ underline: false,
458
+ link: null,
459
+ isMath: true
460
+ });
461
+ if (index !== segments.length - 1) {
462
+ tokens.push({ value: " ", bold: false, italic: false, underline: false, link: null, isMath: false });
463
+ }
464
+ return;
465
+ }
466
+ const text = segment.text || "";
467
+ const matches = text.match(/\S+\s*/g);
468
+ if (!matches || matches.length === 0) {
469
+ if (text.length > 0) {
470
+ tokens.push(toTextToken(segment, text));
471
+ }
472
+ return;
473
+ }
474
+ matches.forEach((part) => tokens.push(toTextToken(segment, part)));
475
+ });
476
+ return tokens;
477
+ }
478
+ function toTextToken(segment, value) {
479
+ return {
480
+ value,
481
+ bold: !!segment.bold,
482
+ italic: !!segment.italic,
483
+ underline: !!segment.underline,
484
+ link: segment.link || null,
485
+ isMath: false
486
+ };
487
+ }
488
+ function takeTokens(tokens, startIndex, width, style, context) {
489
+ if (startIndex >= tokens.length || width <= 0) {
490
+ return { accepted: [], consumed: 0 };
491
+ }
492
+ const accepted = [];
493
+ let consumed = 0;
494
+ let totalWidth = 0;
495
+ for (let index = startIndex; index < tokens.length; index += 1) {
496
+ const token = tokens[index];
497
+ const tokenWidth = measureToken(token, style, context);
498
+ if (accepted.length > 0 && totalWidth + tokenWidth > width) {
499
+ break;
500
+ }
501
+ accepted.push(token);
502
+ consumed += 1;
503
+ totalWidth += tokenWidth;
504
+ }
505
+ if (consumed === 0) {
506
+ return { accepted: [tokens[startIndex]], consumed: 1 };
507
+ }
508
+ return { accepted, consumed };
509
+ }
510
+ function measureToken(token, style, context) {
511
+ if (!context) {
512
+ return token.value.length * style.fontSize * 0.58;
513
+ }
514
+ context.font = `${token.bold ? 700 : style.fontWeight} ${token.italic ? "italic " : ""}${style.fontSize}px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif`;
515
+ return context.measureText(token.value).width;
516
+ }
517
+ function buildTokenElement(token) {
518
+ const element = token.link ? document.createElement("a") : document.createElement("span");
519
+ const classes = ["rte-token"];
520
+ if (token.bold) classes.push("bold");
521
+ if (token.italic) classes.push("italic");
522
+ if (token.underline) classes.push("underline");
523
+ if (token.link) classes.push("link");
524
+ element.className = classes.join(" ");
525
+ if (token.link) {
526
+ element.href = token.link;
527
+ }
528
+ element.innerHTML = token.isMath ? token.value : escapeHtml(token.value);
529
+ return element;
530
+ }
531
+ function styleForTextBlock(style) {
532
+ if (style === "heading1") {
533
+ return { tag: "h1", className: "rte-heading1", fontSize: 30, lineHeight: 1.25, fontWeight: 700 };
534
+ }
535
+ if (style === "heading2") {
536
+ return { tag: "h2", className: "rte-heading2", fontSize: 22, lineHeight: 1.3, fontWeight: 600 };
537
+ }
538
+ return { tag: "p", className: "rte-paragraph", fontSize: 16, lineHeight: 1.4, fontWeight: 400 };
539
+ }
540
+ function segmentsHtml(segments = []) {
541
+ return segments.map((segment) => {
542
+ if (segment.inlineMathLatex) {
543
+ return `<span data-node="math-inline" data-latex="${escapeHtml(segment.inlineMathLatex)}">\\(${escapeHtml(segment.inlineMathLatex)}\\)</span>`;
544
+ }
545
+ let content = escapeHtml(segment.text || "");
546
+ if (segment.bold) content = `<strong>${content}</strong>`;
547
+ if (segment.italic) content = `<em>${content}</em>`;
548
+ if (segment.underline) content = `<u>${content}</u>`;
549
+ if (segment.link) content = `<a href="${escapeHtml(segment.link)}">${content}</a>`;
550
+ return content;
551
+ }).join("");
552
+ }
553
+ function hasWrapSegments(segments = []) {
554
+ return segments.some((segment) => (segment.text || "").trim().length > 0 || segment.inlineMathLatex);
555
+ }
556
+ function requestMathTypeset(element) {
557
+ if (window.MathJax && typeof window.MathJax.typesetPromise === "function") {
558
+ window.MathJax.typesetPromise([element]).catch(() => {
559
+ });
560
+ }
561
+ }
562
+ function clamp(value, min, max) {
563
+ return Math.min(Math.max(value, min), max);
564
+ }
565
+ function escapeHtml(value) {
566
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
567
+ }
568
+ export {
569
+ autoMountRichTextDocuments,
570
+ renderRichTextDocument
571
+ };
572
+ //# sourceMappingURL=index.js.map