@ox-content/vite-plugin 2.62.0 → 2.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/incremental-dom.cjs +179 -0
- package/dist/incremental-dom.cjs.map +1 -0
- package/dist/incremental-dom.d.cts +101 -0
- package/dist/incremental-dom.d.cts.map +1 -0
- package/dist/incremental-dom.d.mts +101 -0
- package/dist/incremental-dom.d.mts.map +1 -0
- package/dist/incremental-dom.mjs +170 -0
- package/dist/incremental-dom.mjs.map +1 -0
- package/dist/index.cjs +107 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +85 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +85 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +103 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -2
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
require("./chunk.cjs");
|
|
3
|
+
//#region src/incremental-dom-styles.ts
|
|
4
|
+
const DEFAULT_COMMITTED_CLASS = "ox-incremental-committed";
|
|
5
|
+
const DEFAULT_PENDING_CLASS = "ox-incremental-pending";
|
|
6
|
+
const DEFAULT_CHAR_CLASS = "ox-incremental-char";
|
|
7
|
+
const DEFAULT_VISIBLE_CLASS = "ox-incremental-char--visible";
|
|
8
|
+
const DEFAULT_ATOM_CLASS = "ox-incremental-atom";
|
|
9
|
+
const incrementalMarkdownDomStyles = `
|
|
10
|
+
.${DEFAULT_COMMITTED_CLASS},
|
|
11
|
+
.${DEFAULT_PENDING_CLASS} {
|
|
12
|
+
display: contents;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.${DEFAULT_CHAR_CLASS},
|
|
16
|
+
.${DEFAULT_ATOM_CLASS} {
|
|
17
|
+
animation: ox-incremental-char-in var(--ox-incremental-duration, 170ms) ease-out both;
|
|
18
|
+
animation-delay: var(--ox-incremental-delay, 0ms);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.${DEFAULT_VISIBLE_CLASS} {
|
|
22
|
+
animation: none;
|
|
23
|
+
opacity: 1;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@keyframes ox-incremental-char-in {
|
|
27
|
+
from {
|
|
28
|
+
opacity: 0;
|
|
29
|
+
}
|
|
30
|
+
to {
|
|
31
|
+
opacity: 1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
`.trim();
|
|
35
|
+
function injectIncrementalMarkdownDomStyles(document = globalThis.document) {
|
|
36
|
+
const existing = document.querySelector("style[data-ox-incremental-dom]");
|
|
37
|
+
if (existing) return existing;
|
|
38
|
+
const style = document.createElement("style");
|
|
39
|
+
style.dataset.oxIncrementalDom = "";
|
|
40
|
+
style.textContent = incrementalMarkdownDomStyles;
|
|
41
|
+
document.head.append(style);
|
|
42
|
+
return style;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/incremental-dom-animation.ts
|
|
46
|
+
function resolveAnimationOptions(animation) {
|
|
47
|
+
if (!animation) return {
|
|
48
|
+
mode: "none",
|
|
49
|
+
durationMs: 0,
|
|
50
|
+
staggerMs: 0,
|
|
51
|
+
committed: false,
|
|
52
|
+
pending: false,
|
|
53
|
+
charClassName: DEFAULT_CHAR_CLASS,
|
|
54
|
+
visibleClassName: DEFAULT_VISIBLE_CLASS,
|
|
55
|
+
atomClassName: DEFAULT_ATOM_CLASS
|
|
56
|
+
};
|
|
57
|
+
const options = animation === true ? {} : animation;
|
|
58
|
+
return {
|
|
59
|
+
mode: options.mode ?? "character",
|
|
60
|
+
durationMs: options.durationMs ?? 170,
|
|
61
|
+
staggerMs: options.staggerMs ?? 2,
|
|
62
|
+
committed: options.committed ?? true,
|
|
63
|
+
pending: options.pending ?? true,
|
|
64
|
+
charClassName: options.charClassName ?? "ox-incremental-char",
|
|
65
|
+
visibleClassName: options.visibleClassName ?? "ox-incremental-char--visible",
|
|
66
|
+
atomClassName: options.atomClassName ?? "ox-incremental-atom"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function prepareCharacterFade(document, root, animation, visibleTextPrefix) {
|
|
70
|
+
if (animation.mode === "none") return;
|
|
71
|
+
const textNodes = collectTextNodes(document, root);
|
|
72
|
+
let index = 0;
|
|
73
|
+
let textOffset = 0;
|
|
74
|
+
for (const textNode of textNodes) {
|
|
75
|
+
const value = textNode.nodeValue ?? "";
|
|
76
|
+
const parent = textNode.parentElement;
|
|
77
|
+
const preserveWhitespace = Boolean(parent?.closest("pre, code"));
|
|
78
|
+
if (!value || !preserveWhitespace && !value.trim()) continue;
|
|
79
|
+
const fragment = document.createDocumentFragment();
|
|
80
|
+
for (const char of [...value]) {
|
|
81
|
+
const span = document.createElement("span");
|
|
82
|
+
if (textOffset < visibleTextPrefix) span.className = `${animation.charClassName} ${animation.visibleClassName}`;
|
|
83
|
+
else {
|
|
84
|
+
span.className = animation.charClassName;
|
|
85
|
+
span.style.setProperty("--ox-incremental-delay", `${index * animation.staggerMs}ms`);
|
|
86
|
+
span.style.setProperty("--ox-incremental-duration", `${animation.durationMs}ms`);
|
|
87
|
+
index += 1;
|
|
88
|
+
}
|
|
89
|
+
span.textContent = char;
|
|
90
|
+
fragment.append(span);
|
|
91
|
+
textOffset += 1;
|
|
92
|
+
}
|
|
93
|
+
textNode.replaceWith(fragment);
|
|
94
|
+
}
|
|
95
|
+
for (const atom of root.querySelectorAll("input, img, hr, br, iframe, svg")) {
|
|
96
|
+
if (textOffset < visibleTextPrefix) continue;
|
|
97
|
+
const element = atom;
|
|
98
|
+
atom.classList.add(animation.atomClassName);
|
|
99
|
+
element.style.setProperty("--ox-incremental-delay", `${index * animation.staggerMs}ms`);
|
|
100
|
+
element.style.setProperty("--ox-incremental-duration", `${animation.durationMs}ms`);
|
|
101
|
+
index += 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function collectTextNodes(document, root) {
|
|
105
|
+
const textNodes = [];
|
|
106
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
107
|
+
while (walker.nextNode()) textNodes.push(walker.currentNode);
|
|
108
|
+
return textNodes;
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/incremental-dom-renderer.ts
|
|
112
|
+
function createIncrementalMarkdownDomRenderer(options) {
|
|
113
|
+
const document = options.preview.ownerDocument;
|
|
114
|
+
const animation = resolveAnimationOptions(options.animation);
|
|
115
|
+
const committedRoot = document.createElement("div");
|
|
116
|
+
const pendingRoot = document.createElement("div");
|
|
117
|
+
const committedClassName = options.committedClassName ?? "ox-incremental-committed";
|
|
118
|
+
const pendingClassName = options.pendingClassName ?? "ox-incremental-pending";
|
|
119
|
+
let markdown = "";
|
|
120
|
+
committedRoot.className = committedClassName;
|
|
121
|
+
pendingRoot.className = pendingClassName;
|
|
122
|
+
options.preview.replaceChildren(committedRoot, pendingRoot);
|
|
123
|
+
function apply(result, applyOptions = {}) {
|
|
124
|
+
const previousPendingText = pendingRoot.textContent ?? "";
|
|
125
|
+
if (applyOptions.chunk !== void 0 && options.source) {
|
|
126
|
+
markdown += applyOptions.chunk;
|
|
127
|
+
options.source.textContent = markdown;
|
|
128
|
+
}
|
|
129
|
+
if (result.deltaHtml) appendCommittedHtml(result.deltaHtml, previousPendingText);
|
|
130
|
+
setPendingHtml(result.pendingHtml);
|
|
131
|
+
}
|
|
132
|
+
function reset() {
|
|
133
|
+
markdown = "";
|
|
134
|
+
if (options.source) options.source.textContent = "";
|
|
135
|
+
committedRoot.replaceChildren();
|
|
136
|
+
pendingRoot.replaceChildren();
|
|
137
|
+
}
|
|
138
|
+
function appendCommittedHtml(html, previousPendingText) {
|
|
139
|
+
const fragment = parseHtml(html);
|
|
140
|
+
const visiblePrefix = commonPrefixLength(previousPendingText, fragment.textContent ?? "");
|
|
141
|
+
prepareCharacterFade(document, fragment, animation, animation.committed ? visiblePrefix : Infinity);
|
|
142
|
+
committedRoot.append(fragment);
|
|
143
|
+
}
|
|
144
|
+
function setPendingHtml(html) {
|
|
145
|
+
const previousText = pendingRoot.textContent ?? "";
|
|
146
|
+
const fragment = parseHtml(html);
|
|
147
|
+
const nextText = fragment.textContent ?? "";
|
|
148
|
+
prepareCharacterFade(document, fragment, animation, animation.pending ? commonPrefixLength(previousText, nextText) : Infinity);
|
|
149
|
+
pendingRoot.replaceChildren(fragment);
|
|
150
|
+
}
|
|
151
|
+
function parseHtml(html) {
|
|
152
|
+
const template = document.createElement("template");
|
|
153
|
+
template.innerHTML = html;
|
|
154
|
+
return template.content;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
committedRoot,
|
|
158
|
+
pendingRoot,
|
|
159
|
+
apply,
|
|
160
|
+
reset
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function commonPrefixLength(left, right) {
|
|
164
|
+
const max = Math.min(left.length, right.length);
|
|
165
|
+
let index = 0;
|
|
166
|
+
while (index < max && left[index] === right[index]) index += 1;
|
|
167
|
+
return index;
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
170
|
+
exports.DEFAULT_ATOM_CLASS = DEFAULT_ATOM_CLASS;
|
|
171
|
+
exports.DEFAULT_CHAR_CLASS = DEFAULT_CHAR_CLASS;
|
|
172
|
+
exports.DEFAULT_COMMITTED_CLASS = DEFAULT_COMMITTED_CLASS;
|
|
173
|
+
exports.DEFAULT_PENDING_CLASS = DEFAULT_PENDING_CLASS;
|
|
174
|
+
exports.DEFAULT_VISIBLE_CLASS = DEFAULT_VISIBLE_CLASS;
|
|
175
|
+
exports.createIncrementalMarkdownDomRenderer = createIncrementalMarkdownDomRenderer;
|
|
176
|
+
exports.incrementalMarkdownDomStyles = incrementalMarkdownDomStyles;
|
|
177
|
+
exports.injectIncrementalMarkdownDomStyles = injectIncrementalMarkdownDomStyles;
|
|
178
|
+
|
|
179
|
+
//# sourceMappingURL=incremental-dom.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incremental-dom.cjs","names":[],"sources":["../src/incremental-dom-styles.ts","../src/incremental-dom-animation.ts","../src/incremental-dom-renderer.ts"],"sourcesContent":["/// <reference lib=\"dom\" />\n\nexport const DEFAULT_COMMITTED_CLASS = \"ox-incremental-committed\";\nexport const DEFAULT_PENDING_CLASS = \"ox-incremental-pending\";\nexport const DEFAULT_CHAR_CLASS = \"ox-incremental-char\";\nexport const DEFAULT_VISIBLE_CLASS = \"ox-incremental-char--visible\";\nexport const DEFAULT_ATOM_CLASS = \"ox-incremental-atom\";\n\nexport const incrementalMarkdownDomStyles = `\n.${DEFAULT_COMMITTED_CLASS},\n.${DEFAULT_PENDING_CLASS} {\n display: contents;\n}\n\n.${DEFAULT_CHAR_CLASS},\n.${DEFAULT_ATOM_CLASS} {\n animation: ox-incremental-char-in var(--ox-incremental-duration, 170ms) ease-out both;\n animation-delay: var(--ox-incremental-delay, 0ms);\n}\n\n.${DEFAULT_VISIBLE_CLASS} {\n animation: none;\n opacity: 1;\n}\n\n@keyframes ox-incremental-char-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n`.trim();\n\nexport function injectIncrementalMarkdownDomStyles(\n document: Document = globalThis.document,\n): HTMLStyleElement {\n const existing = document.querySelector<HTMLStyleElement>(\"style[data-ox-incremental-dom]\");\n if (existing) {\n return existing;\n }\n\n const style = document.createElement(\"style\");\n style.dataset.oxIncrementalDom = \"\";\n style.textContent = incrementalMarkdownDomStyles;\n document.head.append(style);\n return style;\n}\n","/// <reference lib=\"dom\" />\n\nimport {\n DEFAULT_ATOM_CLASS,\n DEFAULT_CHAR_CLASS,\n DEFAULT_VISIBLE_CLASS,\n} from \"./incremental-dom-styles\";\nimport type { IncrementalMarkdownDomAnimationOptions } from \"./incremental-dom-types\";\n\nexport interface ResolvedAnimationOptions {\n mode: \"none\" | \"character\";\n durationMs: number;\n staggerMs: number;\n committed: boolean;\n pending: boolean;\n charClassName: string;\n visibleClassName: string;\n atomClassName: string;\n}\n\nexport function resolveAnimationOptions(\n animation: boolean | IncrementalMarkdownDomAnimationOptions | undefined,\n): ResolvedAnimationOptions {\n if (!animation) {\n return {\n mode: \"none\",\n durationMs: 0,\n staggerMs: 0,\n committed: false,\n pending: false,\n charClassName: DEFAULT_CHAR_CLASS,\n visibleClassName: DEFAULT_VISIBLE_CLASS,\n atomClassName: DEFAULT_ATOM_CLASS,\n };\n }\n\n const options = animation === true ? {} : animation;\n return {\n mode: options.mode ?? \"character\",\n durationMs: options.durationMs ?? 170,\n staggerMs: options.staggerMs ?? 2,\n committed: options.committed ?? true,\n pending: options.pending ?? true,\n charClassName: options.charClassName ?? DEFAULT_CHAR_CLASS,\n visibleClassName: options.visibleClassName ?? DEFAULT_VISIBLE_CLASS,\n atomClassName: options.atomClassName ?? DEFAULT_ATOM_CLASS,\n };\n}\n\nexport function prepareCharacterFade(\n document: Document,\n root: ParentNode,\n animation: ResolvedAnimationOptions,\n visibleTextPrefix: number,\n): void {\n if (animation.mode === \"none\") {\n return;\n }\n\n const textNodes = collectTextNodes(document, root);\n let index = 0;\n let textOffset = 0;\n\n for (const textNode of textNodes) {\n const value = textNode.nodeValue ?? \"\";\n const parent = textNode.parentElement;\n const preserveWhitespace = Boolean(parent?.closest(\"pre, code\"));\n\n if (!value || (!preserveWhitespace && !value.trim())) {\n continue;\n }\n\n const fragment = document.createDocumentFragment();\n for (const char of [...value]) {\n const span = document.createElement(\"span\");\n if (textOffset < visibleTextPrefix) {\n span.className = `${animation.charClassName} ${animation.visibleClassName}`;\n } else {\n span.className = animation.charClassName;\n span.style.setProperty(\"--ox-incremental-delay\", `${index * animation.staggerMs}ms`);\n span.style.setProperty(\"--ox-incremental-duration\", `${animation.durationMs}ms`);\n index += 1;\n }\n span.textContent = char;\n fragment.append(span);\n textOffset += 1;\n }\n textNode.replaceWith(fragment);\n }\n\n for (const atom of root.querySelectorAll(\"input, img, hr, br, iframe, svg\")) {\n if (textOffset < visibleTextPrefix) {\n continue;\n }\n const element = atom as HTMLElement;\n atom.classList.add(animation.atomClassName);\n element.style.setProperty(\"--ox-incremental-delay\", `${index * animation.staggerMs}ms`);\n element.style.setProperty(\"--ox-incremental-duration\", `${animation.durationMs}ms`);\n index += 1;\n }\n}\n\nfunction collectTextNodes(document: Document, root: ParentNode): Text[] {\n const textNodes: Text[] = [];\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n\n while (walker.nextNode()) {\n textNodes.push(walker.currentNode as Text);\n }\n\n return textNodes;\n}\n","/// <reference lib=\"dom\" />\n\nimport { prepareCharacterFade, resolveAnimationOptions } from \"./incremental-dom-animation\";\nimport { DEFAULT_COMMITTED_CLASS, DEFAULT_PENDING_CLASS } from \"./incremental-dom-styles\";\nimport type {\n IncrementalMarkdownDomApplyOptions,\n IncrementalMarkdownDomOptions,\n IncrementalMarkdownDomRenderer,\n IncrementalMarkdownRenderResultLike,\n} from \"./incremental-dom-types\";\n\nexport function createIncrementalMarkdownDomRenderer(\n options: IncrementalMarkdownDomOptions,\n): IncrementalMarkdownDomRenderer {\n const document = options.preview.ownerDocument;\n const animation = resolveAnimationOptions(options.animation);\n const committedRoot = document.createElement(\"div\");\n const pendingRoot = document.createElement(\"div\");\n const committedClassName = options.committedClassName ?? DEFAULT_COMMITTED_CLASS;\n const pendingClassName = options.pendingClassName ?? DEFAULT_PENDING_CLASS;\n let markdown = \"\";\n\n committedRoot.className = committedClassName;\n pendingRoot.className = pendingClassName;\n options.preview.replaceChildren(committedRoot, pendingRoot);\n\n function apply(\n result: IncrementalMarkdownRenderResultLike,\n applyOptions: IncrementalMarkdownDomApplyOptions = {},\n ): void {\n const previousPendingText = pendingRoot.textContent ?? \"\";\n\n if (applyOptions.chunk !== undefined && options.source) {\n markdown += applyOptions.chunk;\n options.source.textContent = markdown;\n }\n\n if (result.deltaHtml) {\n appendCommittedHtml(result.deltaHtml, previousPendingText);\n }\n\n setPendingHtml(result.pendingHtml);\n }\n\n function reset(): void {\n markdown = \"\";\n if (options.source) {\n options.source.textContent = \"\";\n }\n committedRoot.replaceChildren();\n pendingRoot.replaceChildren();\n }\n\n function appendCommittedHtml(html: string, previousPendingText: string): void {\n const fragment = parseHtml(html);\n const committedText = fragment.textContent ?? \"\";\n const visiblePrefix = commonPrefixLength(previousPendingText, committedText);\n prepareCharacterFade(\n document,\n fragment,\n animation,\n animation.committed ? visiblePrefix : Infinity,\n );\n committedRoot.append(fragment);\n }\n\n function setPendingHtml(html: string): void {\n const previousText = pendingRoot.textContent ?? \"\";\n const fragment = parseHtml(html);\n const nextText = fragment.textContent ?? \"\";\n const visiblePrefix = animation.pending ? commonPrefixLength(previousText, nextText) : Infinity;\n prepareCharacterFade(document, fragment, animation, visiblePrefix);\n pendingRoot.replaceChildren(fragment);\n }\n\n function parseHtml(html: string): DocumentFragment {\n const template = document.createElement(\"template\");\n template.innerHTML = html;\n return template.content;\n }\n\n return { committedRoot, pendingRoot, apply, reset };\n}\n\nfunction commonPrefixLength(left: string, right: string): number {\n const max = Math.min(left.length, right.length);\n let index = 0;\n\n while (index < max && left[index] === right[index]) {\n index += 1;\n }\n\n return index;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
//#region src/incremental-dom-styles.d.ts
|
|
2
|
+
declare const DEFAULT_COMMITTED_CLASS = "ox-incremental-committed";
|
|
3
|
+
declare const DEFAULT_PENDING_CLASS = "ox-incremental-pending";
|
|
4
|
+
declare const DEFAULT_CHAR_CLASS = "ox-incremental-char";
|
|
5
|
+
declare const DEFAULT_VISIBLE_CLASS = "ox-incremental-char--visible";
|
|
6
|
+
declare const DEFAULT_ATOM_CLASS = "ox-incremental-atom";
|
|
7
|
+
declare const incrementalMarkdownDomStyles: string;
|
|
8
|
+
declare function injectIncrementalMarkdownDomStyles(document?: Document): HTMLStyleElement;
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/incremental-dom-types.d.ts
|
|
11
|
+
interface IncrementalMarkdownRenderResultLike {
|
|
12
|
+
deltaHtml: string;
|
|
13
|
+
committedHtml: string;
|
|
14
|
+
pendingHtml: string;
|
|
15
|
+
html: string;
|
|
16
|
+
committedBytes: number;
|
|
17
|
+
pendingBytes: number;
|
|
18
|
+
totalBytes: number;
|
|
19
|
+
didCommit: boolean;
|
|
20
|
+
isFinal: boolean;
|
|
21
|
+
errors: string[];
|
|
22
|
+
}
|
|
23
|
+
interface IncrementalMarkdownDomAnimationOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Animate newly-seen text one character at a time.
|
|
26
|
+
* @default "character"
|
|
27
|
+
*/
|
|
28
|
+
mode?: "none" | "character";
|
|
29
|
+
/**
|
|
30
|
+
* Duration for each character fade.
|
|
31
|
+
* @default 170
|
|
32
|
+
*/
|
|
33
|
+
durationMs?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Delay added per new character.
|
|
36
|
+
* @default 2
|
|
37
|
+
*/
|
|
38
|
+
staggerMs?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Animate newly committed HTML.
|
|
41
|
+
* @default true
|
|
42
|
+
*/
|
|
43
|
+
committed?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Animate newly appended pending text. Existing pending prefixes are not re-animated.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
pending?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* CSS class for animated characters.
|
|
51
|
+
* @default "ox-incremental-char"
|
|
52
|
+
*/
|
|
53
|
+
charClassName?: string;
|
|
54
|
+
/**
|
|
55
|
+
* CSS class for characters that have already been visible in the pending region.
|
|
56
|
+
* @default "ox-incremental-char--visible"
|
|
57
|
+
*/
|
|
58
|
+
visibleClassName?: string;
|
|
59
|
+
/**
|
|
60
|
+
* CSS class for non-text atoms such as checkboxes, images, and rules.
|
|
61
|
+
* @default "ox-incremental-atom"
|
|
62
|
+
*/
|
|
63
|
+
atomClassName?: string;
|
|
64
|
+
}
|
|
65
|
+
interface IncrementalMarkdownDomOptions {
|
|
66
|
+
/** Element that owns the committed and pending render regions. */
|
|
67
|
+
preview: Element;
|
|
68
|
+
/** Optional element that displays the raw Markdown stream. */
|
|
69
|
+
source?: HTMLElement;
|
|
70
|
+
/**
|
|
71
|
+
* Character fade is opt-in. Pass `true` for defaults or an option object.
|
|
72
|
+
* @default false
|
|
73
|
+
*/
|
|
74
|
+
animation?: boolean | IncrementalMarkdownDomAnimationOptions;
|
|
75
|
+
/**
|
|
76
|
+
* CSS class for the committed render root.
|
|
77
|
+
* @default "ox-incremental-committed"
|
|
78
|
+
*/
|
|
79
|
+
committedClassName?: string;
|
|
80
|
+
/**
|
|
81
|
+
* CSS class for the replaceable pending render root.
|
|
82
|
+
* @default "ox-incremental-pending"
|
|
83
|
+
*/
|
|
84
|
+
pendingClassName?: string;
|
|
85
|
+
}
|
|
86
|
+
interface IncrementalMarkdownDomApplyOptions {
|
|
87
|
+
/** Raw Markdown chunk to append to `source`, when one is configured. */
|
|
88
|
+
chunk?: string;
|
|
89
|
+
}
|
|
90
|
+
interface IncrementalMarkdownDomRenderer {
|
|
91
|
+
readonly committedRoot: HTMLElement;
|
|
92
|
+
readonly pendingRoot: HTMLElement;
|
|
93
|
+
apply(result: IncrementalMarkdownRenderResultLike, options?: IncrementalMarkdownDomApplyOptions): void;
|
|
94
|
+
reset(): void;
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/incremental-dom-renderer.d.ts
|
|
98
|
+
declare function createIncrementalMarkdownDomRenderer(options: IncrementalMarkdownDomOptions): IncrementalMarkdownDomRenderer;
|
|
99
|
+
//#endregion
|
|
100
|
+
export { DEFAULT_ATOM_CLASS, DEFAULT_CHAR_CLASS, DEFAULT_COMMITTED_CLASS, DEFAULT_PENDING_CLASS, DEFAULT_VISIBLE_CLASS, type IncrementalMarkdownDomAnimationOptions, type IncrementalMarkdownDomApplyOptions, type IncrementalMarkdownDomOptions, type IncrementalMarkdownDomRenderer, type IncrementalMarkdownRenderResultLike, createIncrementalMarkdownDomRenderer, incrementalMarkdownDomStyles, injectIncrementalMarkdownDomStyles };
|
|
101
|
+
//# sourceMappingURL=incremental-dom.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incremental-dom.d.cts","names":[],"sources":["../src/incremental-dom-styles.ts","../src/incremental-dom-types.ts","../src/incremental-dom-renderer.ts"],"mappings":";cAEa,uBAAA;AAAA,cACA,qBAAA;AAAA,cACA,kBAAA;AAAA,cACA,qBAAA;AAAA,cACA,kBAAA;AAAA,cAEA,4BAAA;AAAA,iBA2BG,kCAAA,CACd,QAAA,GAAU,QAAA,GACT,gBAAA;;;UCnCc,mCAAA;EACf,SAAA;EACA,aAAA;EACA,WAAA;EACA,IAAA;EACA,cAAA;EACA,YAAA;EACA,UAAA;EACA,SAAA;EACA,OAAA;EACA,MAAA;AAAA;AAAA,UAGe,sCAAA;;;;ADVjB;ECeE,IAAA;;;;ADdF;ECmBE,UAAA;;;;ADjBF;ECsBE,SAAA;;;;ADKF;ECAE,SAAA;;;;;EAKA,OAAA;EDHiB;;;;ECQjB,aAAA;EA3Ce;;;;EAgDf,gBAAA;EA9CA;;;;EAmDA,aAAA;AAAA;AAAA,UAGe,6BAAA;EA/Cf;EAiDA,OAAA,EAAS,OAAA;EAhDH;EAkDN,MAAA,GAAS,WAAA;EA/CM;;;;EAoDf,SAAA,aAAsB,sCAAA;EA1CtB;;;;EA+CA,kBAAA;EAtBA;;;;EA2BA,gBAAA;AAAA;AAAA,UAGe,kCAAA;EApBN;EAsBT,KAAA;AAAA;AAAA,UAGe,8BAAA;EAAA,SACN,aAAA,EAAe,WAAA;EAAA,SACf,WAAA,EAAa,WAAA;EACtB,KAAA,CACE,MAAA,EAAQ,mCAAA,EACR,OAAA,GAAU,kCAAA;EAEZ,KAAA;AAAA;;;iBCjFc,oCAAA,CACd,OAAA,EAAS,6BAAA,GACR,8BAAA"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
//#region src/incremental-dom-styles.d.ts
|
|
2
|
+
declare const DEFAULT_COMMITTED_CLASS = "ox-incremental-committed";
|
|
3
|
+
declare const DEFAULT_PENDING_CLASS = "ox-incremental-pending";
|
|
4
|
+
declare const DEFAULT_CHAR_CLASS = "ox-incremental-char";
|
|
5
|
+
declare const DEFAULT_VISIBLE_CLASS = "ox-incremental-char--visible";
|
|
6
|
+
declare const DEFAULT_ATOM_CLASS = "ox-incremental-atom";
|
|
7
|
+
declare const incrementalMarkdownDomStyles: string;
|
|
8
|
+
declare function injectIncrementalMarkdownDomStyles(document?: Document): HTMLStyleElement;
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/incremental-dom-types.d.ts
|
|
11
|
+
interface IncrementalMarkdownRenderResultLike {
|
|
12
|
+
deltaHtml: string;
|
|
13
|
+
committedHtml: string;
|
|
14
|
+
pendingHtml: string;
|
|
15
|
+
html: string;
|
|
16
|
+
committedBytes: number;
|
|
17
|
+
pendingBytes: number;
|
|
18
|
+
totalBytes: number;
|
|
19
|
+
didCommit: boolean;
|
|
20
|
+
isFinal: boolean;
|
|
21
|
+
errors: string[];
|
|
22
|
+
}
|
|
23
|
+
interface IncrementalMarkdownDomAnimationOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Animate newly-seen text one character at a time.
|
|
26
|
+
* @default "character"
|
|
27
|
+
*/
|
|
28
|
+
mode?: "none" | "character";
|
|
29
|
+
/**
|
|
30
|
+
* Duration for each character fade.
|
|
31
|
+
* @default 170
|
|
32
|
+
*/
|
|
33
|
+
durationMs?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Delay added per new character.
|
|
36
|
+
* @default 2
|
|
37
|
+
*/
|
|
38
|
+
staggerMs?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Animate newly committed HTML.
|
|
41
|
+
* @default true
|
|
42
|
+
*/
|
|
43
|
+
committed?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Animate newly appended pending text. Existing pending prefixes are not re-animated.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
pending?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* CSS class for animated characters.
|
|
51
|
+
* @default "ox-incremental-char"
|
|
52
|
+
*/
|
|
53
|
+
charClassName?: string;
|
|
54
|
+
/**
|
|
55
|
+
* CSS class for characters that have already been visible in the pending region.
|
|
56
|
+
* @default "ox-incremental-char--visible"
|
|
57
|
+
*/
|
|
58
|
+
visibleClassName?: string;
|
|
59
|
+
/**
|
|
60
|
+
* CSS class for non-text atoms such as checkboxes, images, and rules.
|
|
61
|
+
* @default "ox-incremental-atom"
|
|
62
|
+
*/
|
|
63
|
+
atomClassName?: string;
|
|
64
|
+
}
|
|
65
|
+
interface IncrementalMarkdownDomOptions {
|
|
66
|
+
/** Element that owns the committed and pending render regions. */
|
|
67
|
+
preview: Element;
|
|
68
|
+
/** Optional element that displays the raw Markdown stream. */
|
|
69
|
+
source?: HTMLElement;
|
|
70
|
+
/**
|
|
71
|
+
* Character fade is opt-in. Pass `true` for defaults or an option object.
|
|
72
|
+
* @default false
|
|
73
|
+
*/
|
|
74
|
+
animation?: boolean | IncrementalMarkdownDomAnimationOptions;
|
|
75
|
+
/**
|
|
76
|
+
* CSS class for the committed render root.
|
|
77
|
+
* @default "ox-incremental-committed"
|
|
78
|
+
*/
|
|
79
|
+
committedClassName?: string;
|
|
80
|
+
/**
|
|
81
|
+
* CSS class for the replaceable pending render root.
|
|
82
|
+
* @default "ox-incremental-pending"
|
|
83
|
+
*/
|
|
84
|
+
pendingClassName?: string;
|
|
85
|
+
}
|
|
86
|
+
interface IncrementalMarkdownDomApplyOptions {
|
|
87
|
+
/** Raw Markdown chunk to append to `source`, when one is configured. */
|
|
88
|
+
chunk?: string;
|
|
89
|
+
}
|
|
90
|
+
interface IncrementalMarkdownDomRenderer {
|
|
91
|
+
readonly committedRoot: HTMLElement;
|
|
92
|
+
readonly pendingRoot: HTMLElement;
|
|
93
|
+
apply(result: IncrementalMarkdownRenderResultLike, options?: IncrementalMarkdownDomApplyOptions): void;
|
|
94
|
+
reset(): void;
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/incremental-dom-renderer.d.ts
|
|
98
|
+
declare function createIncrementalMarkdownDomRenderer(options: IncrementalMarkdownDomOptions): IncrementalMarkdownDomRenderer;
|
|
99
|
+
//#endregion
|
|
100
|
+
export { DEFAULT_ATOM_CLASS, DEFAULT_CHAR_CLASS, DEFAULT_COMMITTED_CLASS, DEFAULT_PENDING_CLASS, DEFAULT_VISIBLE_CLASS, type IncrementalMarkdownDomAnimationOptions, type IncrementalMarkdownDomApplyOptions, type IncrementalMarkdownDomOptions, type IncrementalMarkdownDomRenderer, type IncrementalMarkdownRenderResultLike, createIncrementalMarkdownDomRenderer, incrementalMarkdownDomStyles, injectIncrementalMarkdownDomStyles };
|
|
101
|
+
//# sourceMappingURL=incremental-dom.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incremental-dom.d.mts","names":[],"sources":["../src/incremental-dom-styles.ts","../src/incremental-dom-types.ts","../src/incremental-dom-renderer.ts"],"mappings":";cAEa,uBAAA;AAAA,cACA,qBAAA;AAAA,cACA,kBAAA;AAAA,cACA,qBAAA;AAAA,cACA,kBAAA;AAAA,cAEA,4BAAA;AAAA,iBA2BG,kCAAA,CACd,QAAA,GAAU,QAAA,GACT,gBAAA;;;UCnCc,mCAAA;EACf,SAAA;EACA,aAAA;EACA,WAAA;EACA,IAAA;EACA,cAAA;EACA,YAAA;EACA,UAAA;EACA,SAAA;EACA,OAAA;EACA,MAAA;AAAA;AAAA,UAGe,sCAAA;;;;ADVjB;ECeE,IAAA;;;;ADdF;ECmBE,UAAA;;;;ADjBF;ECsBE,SAAA;;;;ADKF;ECAE,SAAA;;;;;EAKA,OAAA;EDHiB;;;;ECQjB,aAAA;EA3Ce;;;;EAgDf,gBAAA;EA9CA;;;;EAmDA,aAAA;AAAA;AAAA,UAGe,6BAAA;EA/Cf;EAiDA,OAAA,EAAS,OAAA;EAhDH;EAkDN,MAAA,GAAS,WAAA;EA/CM;;;;EAoDf,SAAA,aAAsB,sCAAA;EA1CtB;;;;EA+CA,kBAAA;EAtBA;;;;EA2BA,gBAAA;AAAA;AAAA,UAGe,kCAAA;EApBN;EAsBT,KAAA;AAAA;AAAA,UAGe,8BAAA;EAAA,SACN,aAAA,EAAe,WAAA;EAAA,SACf,WAAA,EAAa,WAAA;EACtB,KAAA,CACE,MAAA,EAAQ,mCAAA,EACR,OAAA,GAAU,kCAAA;EAEZ,KAAA;AAAA;;;iBCjFc,oCAAA,CACd,OAAA,EAAS,6BAAA,GACR,8BAAA"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
//#region src/incremental-dom-styles.ts
|
|
2
|
+
const DEFAULT_COMMITTED_CLASS = "ox-incremental-committed";
|
|
3
|
+
const DEFAULT_PENDING_CLASS = "ox-incremental-pending";
|
|
4
|
+
const DEFAULT_CHAR_CLASS = "ox-incremental-char";
|
|
5
|
+
const DEFAULT_VISIBLE_CLASS = "ox-incremental-char--visible";
|
|
6
|
+
const DEFAULT_ATOM_CLASS = "ox-incremental-atom";
|
|
7
|
+
const incrementalMarkdownDomStyles = `
|
|
8
|
+
.${DEFAULT_COMMITTED_CLASS},
|
|
9
|
+
.${DEFAULT_PENDING_CLASS} {
|
|
10
|
+
display: contents;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.${DEFAULT_CHAR_CLASS},
|
|
14
|
+
.${DEFAULT_ATOM_CLASS} {
|
|
15
|
+
animation: ox-incremental-char-in var(--ox-incremental-duration, 170ms) ease-out both;
|
|
16
|
+
animation-delay: var(--ox-incremental-delay, 0ms);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.${DEFAULT_VISIBLE_CLASS} {
|
|
20
|
+
animation: none;
|
|
21
|
+
opacity: 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@keyframes ox-incremental-char-in {
|
|
25
|
+
from {
|
|
26
|
+
opacity: 0;
|
|
27
|
+
}
|
|
28
|
+
to {
|
|
29
|
+
opacity: 1;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`.trim();
|
|
33
|
+
function injectIncrementalMarkdownDomStyles(document = globalThis.document) {
|
|
34
|
+
const existing = document.querySelector("style[data-ox-incremental-dom]");
|
|
35
|
+
if (existing) return existing;
|
|
36
|
+
const style = document.createElement("style");
|
|
37
|
+
style.dataset.oxIncrementalDom = "";
|
|
38
|
+
style.textContent = incrementalMarkdownDomStyles;
|
|
39
|
+
document.head.append(style);
|
|
40
|
+
return style;
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/incremental-dom-animation.ts
|
|
44
|
+
function resolveAnimationOptions(animation) {
|
|
45
|
+
if (!animation) return {
|
|
46
|
+
mode: "none",
|
|
47
|
+
durationMs: 0,
|
|
48
|
+
staggerMs: 0,
|
|
49
|
+
committed: false,
|
|
50
|
+
pending: false,
|
|
51
|
+
charClassName: DEFAULT_CHAR_CLASS,
|
|
52
|
+
visibleClassName: DEFAULT_VISIBLE_CLASS,
|
|
53
|
+
atomClassName: DEFAULT_ATOM_CLASS
|
|
54
|
+
};
|
|
55
|
+
const options = animation === true ? {} : animation;
|
|
56
|
+
return {
|
|
57
|
+
mode: options.mode ?? "character",
|
|
58
|
+
durationMs: options.durationMs ?? 170,
|
|
59
|
+
staggerMs: options.staggerMs ?? 2,
|
|
60
|
+
committed: options.committed ?? true,
|
|
61
|
+
pending: options.pending ?? true,
|
|
62
|
+
charClassName: options.charClassName ?? "ox-incremental-char",
|
|
63
|
+
visibleClassName: options.visibleClassName ?? "ox-incremental-char--visible",
|
|
64
|
+
atomClassName: options.atomClassName ?? "ox-incremental-atom"
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function prepareCharacterFade(document, root, animation, visibleTextPrefix) {
|
|
68
|
+
if (animation.mode === "none") return;
|
|
69
|
+
const textNodes = collectTextNodes(document, root);
|
|
70
|
+
let index = 0;
|
|
71
|
+
let textOffset = 0;
|
|
72
|
+
for (const textNode of textNodes) {
|
|
73
|
+
const value = textNode.nodeValue ?? "";
|
|
74
|
+
const parent = textNode.parentElement;
|
|
75
|
+
const preserveWhitespace = Boolean(parent?.closest("pre, code"));
|
|
76
|
+
if (!value || !preserveWhitespace && !value.trim()) continue;
|
|
77
|
+
const fragment = document.createDocumentFragment();
|
|
78
|
+
for (const char of [...value]) {
|
|
79
|
+
const span = document.createElement("span");
|
|
80
|
+
if (textOffset < visibleTextPrefix) span.className = `${animation.charClassName} ${animation.visibleClassName}`;
|
|
81
|
+
else {
|
|
82
|
+
span.className = animation.charClassName;
|
|
83
|
+
span.style.setProperty("--ox-incremental-delay", `${index * animation.staggerMs}ms`);
|
|
84
|
+
span.style.setProperty("--ox-incremental-duration", `${animation.durationMs}ms`);
|
|
85
|
+
index += 1;
|
|
86
|
+
}
|
|
87
|
+
span.textContent = char;
|
|
88
|
+
fragment.append(span);
|
|
89
|
+
textOffset += 1;
|
|
90
|
+
}
|
|
91
|
+
textNode.replaceWith(fragment);
|
|
92
|
+
}
|
|
93
|
+
for (const atom of root.querySelectorAll("input, img, hr, br, iframe, svg")) {
|
|
94
|
+
if (textOffset < visibleTextPrefix) continue;
|
|
95
|
+
const element = atom;
|
|
96
|
+
atom.classList.add(animation.atomClassName);
|
|
97
|
+
element.style.setProperty("--ox-incremental-delay", `${index * animation.staggerMs}ms`);
|
|
98
|
+
element.style.setProperty("--ox-incremental-duration", `${animation.durationMs}ms`);
|
|
99
|
+
index += 1;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function collectTextNodes(document, root) {
|
|
103
|
+
const textNodes = [];
|
|
104
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
105
|
+
while (walker.nextNode()) textNodes.push(walker.currentNode);
|
|
106
|
+
return textNodes;
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/incremental-dom-renderer.ts
|
|
110
|
+
function createIncrementalMarkdownDomRenderer(options) {
|
|
111
|
+
const document = options.preview.ownerDocument;
|
|
112
|
+
const animation = resolveAnimationOptions(options.animation);
|
|
113
|
+
const committedRoot = document.createElement("div");
|
|
114
|
+
const pendingRoot = document.createElement("div");
|
|
115
|
+
const committedClassName = options.committedClassName ?? "ox-incremental-committed";
|
|
116
|
+
const pendingClassName = options.pendingClassName ?? "ox-incremental-pending";
|
|
117
|
+
let markdown = "";
|
|
118
|
+
committedRoot.className = committedClassName;
|
|
119
|
+
pendingRoot.className = pendingClassName;
|
|
120
|
+
options.preview.replaceChildren(committedRoot, pendingRoot);
|
|
121
|
+
function apply(result, applyOptions = {}) {
|
|
122
|
+
const previousPendingText = pendingRoot.textContent ?? "";
|
|
123
|
+
if (applyOptions.chunk !== void 0 && options.source) {
|
|
124
|
+
markdown += applyOptions.chunk;
|
|
125
|
+
options.source.textContent = markdown;
|
|
126
|
+
}
|
|
127
|
+
if (result.deltaHtml) appendCommittedHtml(result.deltaHtml, previousPendingText);
|
|
128
|
+
setPendingHtml(result.pendingHtml);
|
|
129
|
+
}
|
|
130
|
+
function reset() {
|
|
131
|
+
markdown = "";
|
|
132
|
+
if (options.source) options.source.textContent = "";
|
|
133
|
+
committedRoot.replaceChildren();
|
|
134
|
+
pendingRoot.replaceChildren();
|
|
135
|
+
}
|
|
136
|
+
function appendCommittedHtml(html, previousPendingText) {
|
|
137
|
+
const fragment = parseHtml(html);
|
|
138
|
+
const visiblePrefix = commonPrefixLength(previousPendingText, fragment.textContent ?? "");
|
|
139
|
+
prepareCharacterFade(document, fragment, animation, animation.committed ? visiblePrefix : Infinity);
|
|
140
|
+
committedRoot.append(fragment);
|
|
141
|
+
}
|
|
142
|
+
function setPendingHtml(html) {
|
|
143
|
+
const previousText = pendingRoot.textContent ?? "";
|
|
144
|
+
const fragment = parseHtml(html);
|
|
145
|
+
const nextText = fragment.textContent ?? "";
|
|
146
|
+
prepareCharacterFade(document, fragment, animation, animation.pending ? commonPrefixLength(previousText, nextText) : Infinity);
|
|
147
|
+
pendingRoot.replaceChildren(fragment);
|
|
148
|
+
}
|
|
149
|
+
function parseHtml(html) {
|
|
150
|
+
const template = document.createElement("template");
|
|
151
|
+
template.innerHTML = html;
|
|
152
|
+
return template.content;
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
committedRoot,
|
|
156
|
+
pendingRoot,
|
|
157
|
+
apply,
|
|
158
|
+
reset
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function commonPrefixLength(left, right) {
|
|
162
|
+
const max = Math.min(left.length, right.length);
|
|
163
|
+
let index = 0;
|
|
164
|
+
while (index < max && left[index] === right[index]) index += 1;
|
|
165
|
+
return index;
|
|
166
|
+
}
|
|
167
|
+
//#endregion
|
|
168
|
+
export { DEFAULT_ATOM_CLASS, DEFAULT_CHAR_CLASS, DEFAULT_COMMITTED_CLASS, DEFAULT_PENDING_CLASS, DEFAULT_VISIBLE_CLASS, createIncrementalMarkdownDomRenderer, incrementalMarkdownDomStyles, injectIncrementalMarkdownDomStyles };
|
|
169
|
+
|
|
170
|
+
//# sourceMappingURL=incremental-dom.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incremental-dom.mjs","names":[],"sources":["../src/incremental-dom-styles.ts","../src/incremental-dom-animation.ts","../src/incremental-dom-renderer.ts"],"sourcesContent":["/// <reference lib=\"dom\" />\n\nexport const DEFAULT_COMMITTED_CLASS = \"ox-incremental-committed\";\nexport const DEFAULT_PENDING_CLASS = \"ox-incremental-pending\";\nexport const DEFAULT_CHAR_CLASS = \"ox-incremental-char\";\nexport const DEFAULT_VISIBLE_CLASS = \"ox-incremental-char--visible\";\nexport const DEFAULT_ATOM_CLASS = \"ox-incremental-atom\";\n\nexport const incrementalMarkdownDomStyles = `\n.${DEFAULT_COMMITTED_CLASS},\n.${DEFAULT_PENDING_CLASS} {\n display: contents;\n}\n\n.${DEFAULT_CHAR_CLASS},\n.${DEFAULT_ATOM_CLASS} {\n animation: ox-incremental-char-in var(--ox-incremental-duration, 170ms) ease-out both;\n animation-delay: var(--ox-incremental-delay, 0ms);\n}\n\n.${DEFAULT_VISIBLE_CLASS} {\n animation: none;\n opacity: 1;\n}\n\n@keyframes ox-incremental-char-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n`.trim();\n\nexport function injectIncrementalMarkdownDomStyles(\n document: Document = globalThis.document,\n): HTMLStyleElement {\n const existing = document.querySelector<HTMLStyleElement>(\"style[data-ox-incremental-dom]\");\n if (existing) {\n return existing;\n }\n\n const style = document.createElement(\"style\");\n style.dataset.oxIncrementalDom = \"\";\n style.textContent = incrementalMarkdownDomStyles;\n document.head.append(style);\n return style;\n}\n","/// <reference lib=\"dom\" />\n\nimport {\n DEFAULT_ATOM_CLASS,\n DEFAULT_CHAR_CLASS,\n DEFAULT_VISIBLE_CLASS,\n} from \"./incremental-dom-styles\";\nimport type { IncrementalMarkdownDomAnimationOptions } from \"./incremental-dom-types\";\n\nexport interface ResolvedAnimationOptions {\n mode: \"none\" | \"character\";\n durationMs: number;\n staggerMs: number;\n committed: boolean;\n pending: boolean;\n charClassName: string;\n visibleClassName: string;\n atomClassName: string;\n}\n\nexport function resolveAnimationOptions(\n animation: boolean | IncrementalMarkdownDomAnimationOptions | undefined,\n): ResolvedAnimationOptions {\n if (!animation) {\n return {\n mode: \"none\",\n durationMs: 0,\n staggerMs: 0,\n committed: false,\n pending: false,\n charClassName: DEFAULT_CHAR_CLASS,\n visibleClassName: DEFAULT_VISIBLE_CLASS,\n atomClassName: DEFAULT_ATOM_CLASS,\n };\n }\n\n const options = animation === true ? {} : animation;\n return {\n mode: options.mode ?? \"character\",\n durationMs: options.durationMs ?? 170,\n staggerMs: options.staggerMs ?? 2,\n committed: options.committed ?? true,\n pending: options.pending ?? true,\n charClassName: options.charClassName ?? DEFAULT_CHAR_CLASS,\n visibleClassName: options.visibleClassName ?? DEFAULT_VISIBLE_CLASS,\n atomClassName: options.atomClassName ?? DEFAULT_ATOM_CLASS,\n };\n}\n\nexport function prepareCharacterFade(\n document: Document,\n root: ParentNode,\n animation: ResolvedAnimationOptions,\n visibleTextPrefix: number,\n): void {\n if (animation.mode === \"none\") {\n return;\n }\n\n const textNodes = collectTextNodes(document, root);\n let index = 0;\n let textOffset = 0;\n\n for (const textNode of textNodes) {\n const value = textNode.nodeValue ?? \"\";\n const parent = textNode.parentElement;\n const preserveWhitespace = Boolean(parent?.closest(\"pre, code\"));\n\n if (!value || (!preserveWhitespace && !value.trim())) {\n continue;\n }\n\n const fragment = document.createDocumentFragment();\n for (const char of [...value]) {\n const span = document.createElement(\"span\");\n if (textOffset < visibleTextPrefix) {\n span.className = `${animation.charClassName} ${animation.visibleClassName}`;\n } else {\n span.className = animation.charClassName;\n span.style.setProperty(\"--ox-incremental-delay\", `${index * animation.staggerMs}ms`);\n span.style.setProperty(\"--ox-incremental-duration\", `${animation.durationMs}ms`);\n index += 1;\n }\n span.textContent = char;\n fragment.append(span);\n textOffset += 1;\n }\n textNode.replaceWith(fragment);\n }\n\n for (const atom of root.querySelectorAll(\"input, img, hr, br, iframe, svg\")) {\n if (textOffset < visibleTextPrefix) {\n continue;\n }\n const element = atom as HTMLElement;\n atom.classList.add(animation.atomClassName);\n element.style.setProperty(\"--ox-incremental-delay\", `${index * animation.staggerMs}ms`);\n element.style.setProperty(\"--ox-incremental-duration\", `${animation.durationMs}ms`);\n index += 1;\n }\n}\n\nfunction collectTextNodes(document: Document, root: ParentNode): Text[] {\n const textNodes: Text[] = [];\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n\n while (walker.nextNode()) {\n textNodes.push(walker.currentNode as Text);\n }\n\n return textNodes;\n}\n","/// <reference lib=\"dom\" />\n\nimport { prepareCharacterFade, resolveAnimationOptions } from \"./incremental-dom-animation\";\nimport { DEFAULT_COMMITTED_CLASS, DEFAULT_PENDING_CLASS } from \"./incremental-dom-styles\";\nimport type {\n IncrementalMarkdownDomApplyOptions,\n IncrementalMarkdownDomOptions,\n IncrementalMarkdownDomRenderer,\n IncrementalMarkdownRenderResultLike,\n} from \"./incremental-dom-types\";\n\nexport function createIncrementalMarkdownDomRenderer(\n options: IncrementalMarkdownDomOptions,\n): IncrementalMarkdownDomRenderer {\n const document = options.preview.ownerDocument;\n const animation = resolveAnimationOptions(options.animation);\n const committedRoot = document.createElement(\"div\");\n const pendingRoot = document.createElement(\"div\");\n const committedClassName = options.committedClassName ?? DEFAULT_COMMITTED_CLASS;\n const pendingClassName = options.pendingClassName ?? DEFAULT_PENDING_CLASS;\n let markdown = \"\";\n\n committedRoot.className = committedClassName;\n pendingRoot.className = pendingClassName;\n options.preview.replaceChildren(committedRoot, pendingRoot);\n\n function apply(\n result: IncrementalMarkdownRenderResultLike,\n applyOptions: IncrementalMarkdownDomApplyOptions = {},\n ): void {\n const previousPendingText = pendingRoot.textContent ?? \"\";\n\n if (applyOptions.chunk !== undefined && options.source) {\n markdown += applyOptions.chunk;\n options.source.textContent = markdown;\n }\n\n if (result.deltaHtml) {\n appendCommittedHtml(result.deltaHtml, previousPendingText);\n }\n\n setPendingHtml(result.pendingHtml);\n }\n\n function reset(): void {\n markdown = \"\";\n if (options.source) {\n options.source.textContent = \"\";\n }\n committedRoot.replaceChildren();\n pendingRoot.replaceChildren();\n }\n\n function appendCommittedHtml(html: string, previousPendingText: string): void {\n const fragment = parseHtml(html);\n const committedText = fragment.textContent ?? \"\";\n const visiblePrefix = commonPrefixLength(previousPendingText, committedText);\n prepareCharacterFade(\n document,\n fragment,\n animation,\n animation.committed ? visiblePrefix : Infinity,\n );\n committedRoot.append(fragment);\n }\n\n function setPendingHtml(html: string): void {\n const previousText = pendingRoot.textContent ?? \"\";\n const fragment = parseHtml(html);\n const nextText = fragment.textContent ?? \"\";\n const visiblePrefix = animation.pending ? commonPrefixLength(previousText, nextText) : Infinity;\n prepareCharacterFade(document, fragment, animation, visiblePrefix);\n pendingRoot.replaceChildren(fragment);\n }\n\n function parseHtml(html: string): DocumentFragment {\n const template = document.createElement(\"template\");\n template.innerHTML = html;\n return template.content;\n }\n\n return { committedRoot, pendingRoot, apply, reset };\n}\n\nfunction commonPrefixLength(left: string, right: string): number {\n const max = Math.min(left.length, right.length);\n let index = 0;\n\n while (index < max && left[index] === right[index]) {\n index += 1;\n }\n\n return index;\n}\n"],"mappings":"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"}
|