@typefm/react-markdown-viewer 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.
- package/LICENSE +21 -0
- package/README.md +217 -0
- package/dist/ErrorBoundary.d.ts +25 -0
- package/dist/ErrorBoundary.d.ts.map +1 -0
- package/dist/ErrorBoundary.js +29 -0
- package/dist/ErrorBoundary.js.map +1 -0
- package/dist/MarkdownViewer.d.ts +41 -0
- package/dist/MarkdownViewer.d.ts.map +1 -0
- package/dist/MarkdownViewer.js +69 -0
- package/dist/MarkdownViewer.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cache-manager.d.ts +59 -0
- package/dist/lib/cache-manager.d.ts.map +1 -0
- package/dist/lib/cache-manager.js +160 -0
- package/dist/lib/cache-manager.js.map +1 -0
- package/dist/lib/cursor-controller.d.ts +13 -0
- package/dist/lib/cursor-controller.d.ts.map +1 -0
- package/dist/lib/cursor-controller.js +93 -0
- package/dist/lib/cursor-controller.js.map +1 -0
- package/dist/lib/defaults/code-block.d.ts +71 -0
- package/dist/lib/defaults/code-block.d.ts.map +1 -0
- package/dist/lib/defaults/code-block.js +104 -0
- package/dist/lib/defaults/code-block.js.map +1 -0
- package/dist/lib/defaults/image.d.ts +41 -0
- package/dist/lib/defaults/image.d.ts.map +1 -0
- package/dist/lib/defaults/image.js +45 -0
- package/dist/lib/defaults/image.js.map +1 -0
- package/dist/lib/defaults/link.d.ts +45 -0
- package/dist/lib/defaults/link.d.ts.map +1 -0
- package/dist/lib/defaults/link.js +76 -0
- package/dist/lib/defaults/link.js.map +1 -0
- package/dist/lib/defaults/math.d.ts +51 -0
- package/dist/lib/defaults/math.d.ts.map +1 -0
- package/dist/lib/defaults/math.js +119 -0
- package/dist/lib/defaults/math.js.map +1 -0
- package/dist/lib/defaults/table.d.ts +18 -0
- package/dist/lib/defaults/table.d.ts.map +1 -0
- package/dist/lib/defaults/table.js +19 -0
- package/dist/lib/defaults/table.js.map +1 -0
- package/dist/lib/highlighter.d.ts +81 -0
- package/dist/lib/highlighter.d.ts.map +1 -0
- package/dist/lib/highlighter.js +421 -0
- package/dist/lib/highlighter.js.map +1 -0
- package/dist/lib/hook-utils.d.ts +32 -0
- package/dist/lib/hook-utils.d.ts.map +1 -0
- package/dist/lib/hook-utils.js +42 -0
- package/dist/lib/hook-utils.js.map +1 -0
- package/dist/lib/html.d.ts +2 -0
- package/dist/lib/html.d.ts.map +1 -0
- package/dist/lib/html.js +12 -0
- package/dist/lib/html.js.map +1 -0
- package/dist/lib/morph.d.ts +57 -0
- package/dist/lib/morph.d.ts.map +1 -0
- package/dist/lib/morph.js +204 -0
- package/dist/lib/morph.js.map +1 -0
- package/dist/lib/parser.d.ts +32 -0
- package/dist/lib/parser.d.ts.map +1 -0
- package/dist/lib/parser.js +645 -0
- package/dist/lib/parser.js.map +1 -0
- package/dist/lib/wasm-init.d.ts +33 -0
- package/dist/lib/wasm-init.d.ts.map +1 -0
- package/dist/lib/wasm-init.js +69 -0
- package/dist/lib/wasm-init.js.map +1 -0
- package/dist/styles/alerts.css +294 -0
- package/dist/styles/dotted.svg +3 -0
- package/dist/styles/hljs.css +332 -0
- package/dist/styles/index.css +17 -0
- package/dist/styles/katex.css +74 -0
- package/dist/styles/viewer.css +975 -0
- package/dist/types/hooks.d.ts +207 -0
- package/dist/types/hooks.d.ts.map +1 -0
- package/dist/types/hooks.js +7 -0
- package/dist/types/hooks.js.map +1 -0
- package/dist/useMarkdownViewer.d.ts +18 -0
- package/dist/useMarkdownViewer.d.ts.map +1 -0
- package/dist/useMarkdownViewer.js +403 -0
- package/dist/useMarkdownViewer.js.map +1 -0
- package/dist/utils.d.ts +20 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +18 -0
- package/dist/utils.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Syntax highlighter using highlight.js with dynamic language loading
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Minimal core bundle (~8KB gzipped)
|
|
6
|
+
* - Dynamic language loading on demand with code-splitting
|
|
7
|
+
* - Event system for re-highlighting when languages load
|
|
8
|
+
* - LRU caching for performance
|
|
9
|
+
*
|
|
10
|
+
* @see https://highlightjs.org/
|
|
11
|
+
*/
|
|
12
|
+
import hljs from 'highlight.js/lib/core';
|
|
13
|
+
import { cacheManager } from './cache-manager';
|
|
14
|
+
// --------------------------------------------------------------------------
|
|
15
|
+
// Bundled Languages (minimal set, always available)
|
|
16
|
+
// --------------------------------------------------------------------------
|
|
17
|
+
import plaintext from 'highlight.js/lib/languages/plaintext';
|
|
18
|
+
hljs.registerLanguage('plaintext', plaintext);
|
|
19
|
+
// --------------------------------------------------------------------------
|
|
20
|
+
// Dynamic Language Import Map
|
|
21
|
+
// Explicit imports enable bundler code-splitting and tree-shaking
|
|
22
|
+
// --------------------------------------------------------------------------
|
|
23
|
+
const LANGUAGE_LOADERS = {
|
|
24
|
+
// Web essentials
|
|
25
|
+
javascript: () => import('highlight.js/lib/languages/javascript'),
|
|
26
|
+
typescript: () => import('highlight.js/lib/languages/typescript'),
|
|
27
|
+
json: () => import('highlight.js/lib/languages/json'),
|
|
28
|
+
css: () => import('highlight.js/lib/languages/css'),
|
|
29
|
+
scss: () => import('highlight.js/lib/languages/scss'),
|
|
30
|
+
less: () => import('highlight.js/lib/languages/less'),
|
|
31
|
+
xml: () => import('highlight.js/lib/languages/xml'), // includes HTML
|
|
32
|
+
markdown: () => import('highlight.js/lib/languages/markdown'),
|
|
33
|
+
// Shell & config
|
|
34
|
+
bash: () => import('highlight.js/lib/languages/bash'),
|
|
35
|
+
shell: () => import('highlight.js/lib/languages/shell'),
|
|
36
|
+
yaml: () => import('highlight.js/lib/languages/yaml'),
|
|
37
|
+
ini: () => import('highlight.js/lib/languages/ini'),
|
|
38
|
+
dockerfile: () => import('highlight.js/lib/languages/dockerfile'),
|
|
39
|
+
nginx: () => import('highlight.js/lib/languages/nginx'),
|
|
40
|
+
makefile: () => import('highlight.js/lib/languages/makefile'),
|
|
41
|
+
// Data & query
|
|
42
|
+
sql: () => import('highlight.js/lib/languages/sql'),
|
|
43
|
+
graphql: () => import('highlight.js/lib/languages/graphql'),
|
|
44
|
+
// Systems programming
|
|
45
|
+
c: () => import('highlight.js/lib/languages/c'),
|
|
46
|
+
cpp: () => import('highlight.js/lib/languages/cpp'),
|
|
47
|
+
rust: () => import('highlight.js/lib/languages/rust'),
|
|
48
|
+
go: () => import('highlight.js/lib/languages/go'),
|
|
49
|
+
// JVM languages
|
|
50
|
+
java: () => import('highlight.js/lib/languages/java'),
|
|
51
|
+
kotlin: () => import('highlight.js/lib/languages/kotlin'),
|
|
52
|
+
scala: () => import('highlight.js/lib/languages/scala'),
|
|
53
|
+
// .NET
|
|
54
|
+
csharp: () => import('highlight.js/lib/languages/csharp'),
|
|
55
|
+
// Scripting languages
|
|
56
|
+
python: () => import('highlight.js/lib/languages/python'),
|
|
57
|
+
ruby: () => import('highlight.js/lib/languages/ruby'),
|
|
58
|
+
php: () => import('highlight.js/lib/languages/php'),
|
|
59
|
+
perl: () => import('highlight.js/lib/languages/perl'),
|
|
60
|
+
lua: () => import('highlight.js/lib/languages/lua'),
|
|
61
|
+
r: () => import('highlight.js/lib/languages/r'),
|
|
62
|
+
// Mobile
|
|
63
|
+
swift: () => import('highlight.js/lib/languages/swift'),
|
|
64
|
+
objectivec: () => import('highlight.js/lib/languages/objectivec'),
|
|
65
|
+
// Other
|
|
66
|
+
diff: () => import('highlight.js/lib/languages/diff'),
|
|
67
|
+
wasm: () => import('highlight.js/lib/languages/wasm'),
|
|
68
|
+
latex: () => import('highlight.js/lib/languages/latex'),
|
|
69
|
+
haskell: () => import('highlight.js/lib/languages/haskell'),
|
|
70
|
+
elixir: () => import('highlight.js/lib/languages/elixir'),
|
|
71
|
+
erlang: () => import('highlight.js/lib/languages/erlang'),
|
|
72
|
+
clojure: () => import('highlight.js/lib/languages/clojure'),
|
|
73
|
+
lisp: () => import('highlight.js/lib/languages/lisp'),
|
|
74
|
+
scheme: () => import('highlight.js/lib/languages/scheme'),
|
|
75
|
+
ocaml: () => import('highlight.js/lib/languages/ocaml'),
|
|
76
|
+
fsharp: () => import('highlight.js/lib/languages/fsharp'),
|
|
77
|
+
powershell: () => import('highlight.js/lib/languages/powershell'),
|
|
78
|
+
vim: () => import('highlight.js/lib/languages/vim'),
|
|
79
|
+
toml: () => import('highlight.js/lib/languages/ini'), // TOML uses ini grammar
|
|
80
|
+
delphi: () => import('highlight.js/lib/languages/delphi'), // Pascal/Delphi
|
|
81
|
+
};
|
|
82
|
+
// --------------------------------------------------------------------------
|
|
83
|
+
// Language Aliases
|
|
84
|
+
// --------------------------------------------------------------------------
|
|
85
|
+
const LANGUAGE_ALIASES = {
|
|
86
|
+
// JavaScript
|
|
87
|
+
js: 'javascript',
|
|
88
|
+
jsx: 'javascript',
|
|
89
|
+
mjs: 'javascript',
|
|
90
|
+
cjs: 'javascript',
|
|
91
|
+
// TypeScript
|
|
92
|
+
ts: 'typescript',
|
|
93
|
+
tsx: 'typescript',
|
|
94
|
+
mts: 'typescript',
|
|
95
|
+
cts: 'typescript',
|
|
96
|
+
// Shell
|
|
97
|
+
sh: 'bash',
|
|
98
|
+
zsh: 'bash',
|
|
99
|
+
// Python
|
|
100
|
+
py: 'python',
|
|
101
|
+
py3: 'python',
|
|
102
|
+
python3: 'python',
|
|
103
|
+
// Ruby
|
|
104
|
+
rb: 'ruby',
|
|
105
|
+
// YAML
|
|
106
|
+
yml: 'yaml',
|
|
107
|
+
// Markup
|
|
108
|
+
htm: 'xml',
|
|
109
|
+
html: 'xml',
|
|
110
|
+
xhtml: 'xml',
|
|
111
|
+
svg: 'xml',
|
|
112
|
+
vue: 'xml',
|
|
113
|
+
// Config
|
|
114
|
+
jsonc: 'json',
|
|
115
|
+
json5: 'json',
|
|
116
|
+
// C family
|
|
117
|
+
h: 'c',
|
|
118
|
+
hpp: 'cpp',
|
|
119
|
+
cc: 'cpp',
|
|
120
|
+
cxx: 'cpp',
|
|
121
|
+
'c++': 'cpp',
|
|
122
|
+
// C#
|
|
123
|
+
cs: 'csharp',
|
|
124
|
+
// Dockerfile
|
|
125
|
+
docker: 'dockerfile',
|
|
126
|
+
// Makefile
|
|
127
|
+
mk: 'makefile',
|
|
128
|
+
// Objective-C
|
|
129
|
+
objc: 'objectivec',
|
|
130
|
+
'm': 'objectivec',
|
|
131
|
+
// F#
|
|
132
|
+
fs: 'fsharp',
|
|
133
|
+
// Pascal/Delphi
|
|
134
|
+
pascal: 'delphi',
|
|
135
|
+
pas: 'delphi',
|
|
136
|
+
// Text
|
|
137
|
+
text: 'plaintext',
|
|
138
|
+
txt: 'plaintext',
|
|
139
|
+
plain: 'plaintext',
|
|
140
|
+
};
|
|
141
|
+
function normalizeLanguage(lang) {
|
|
142
|
+
const lower = lang.toLowerCase();
|
|
143
|
+
return LANGUAGE_ALIASES[lower] ?? lower;
|
|
144
|
+
}
|
|
145
|
+
// --------------------------------------------------------------------------
|
|
146
|
+
// State
|
|
147
|
+
// --------------------------------------------------------------------------
|
|
148
|
+
const registeredLanguages = new Set(['plaintext']);
|
|
149
|
+
const loadingLanguages = new Map();
|
|
150
|
+
const failedLanguages = new Set();
|
|
151
|
+
const languageLoadListeners = new Set();
|
|
152
|
+
// Batched notification state (avoids multiple re-renders when several languages load)
|
|
153
|
+
let pendingNotifications = new Set();
|
|
154
|
+
let notificationScheduled = false;
|
|
155
|
+
// --------------------------------------------------------------------------
|
|
156
|
+
// Dynamic Language Loading
|
|
157
|
+
// --------------------------------------------------------------------------
|
|
158
|
+
// Dev-only logging helper
|
|
159
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
160
|
+
function devLog(message, ...args) {
|
|
161
|
+
if (isDev) {
|
|
162
|
+
console.log(`[hljs] ${message}`, ...args);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function devWarn(message, ...args) {
|
|
166
|
+
if (isDev) {
|
|
167
|
+
console.warn(`[hljs] ${message}`, ...args);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Load a language dynamically
|
|
172
|
+
* Returns a promise that resolves when the language is ready
|
|
173
|
+
*/
|
|
174
|
+
export async function loadLanguage(language) {
|
|
175
|
+
const normalized = normalizeLanguage(language);
|
|
176
|
+
// Already registered
|
|
177
|
+
if (registeredLanguages.has(normalized)) {
|
|
178
|
+
devLog(`✓ "${normalized}" already loaded`);
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
// Already failed
|
|
182
|
+
if (failedLanguages.has(normalized)) {
|
|
183
|
+
devLog(`✗ "${normalized}" previously failed, skipping`);
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
// Already loading - wait for it
|
|
187
|
+
const existing = loadingLanguages.get(normalized);
|
|
188
|
+
if (existing) {
|
|
189
|
+
devLog(`⏳ "${normalized}" already loading, waiting...`);
|
|
190
|
+
await existing;
|
|
191
|
+
return registeredLanguages.has(normalized);
|
|
192
|
+
}
|
|
193
|
+
// Check if we have a loader for this language
|
|
194
|
+
const loader = LANGUAGE_LOADERS[normalized];
|
|
195
|
+
if (!loader) {
|
|
196
|
+
devWarn(`✗ "${normalized}" not supported (no loader available)`);
|
|
197
|
+
failedLanguages.add(normalized);
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
// Start loading
|
|
201
|
+
devLog(`⏳ "${normalized}" loading...`);
|
|
202
|
+
const startTime = performance.now();
|
|
203
|
+
const loadPromise = (async () => {
|
|
204
|
+
try {
|
|
205
|
+
const module = await loader();
|
|
206
|
+
hljs.registerLanguage(normalized, module.default);
|
|
207
|
+
registeredLanguages.add(normalized);
|
|
208
|
+
const duration = (performance.now() - startTime).toFixed(1);
|
|
209
|
+
devLog(`✓ "${normalized}" loaded in ${duration}ms`);
|
|
210
|
+
// Notify listeners
|
|
211
|
+
notifyLanguageLoaded(normalized);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
failedLanguages.add(normalized);
|
|
215
|
+
devWarn(`✗ "${normalized}" failed to load:`, error);
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
loadingLanguages.delete(normalized);
|
|
219
|
+
}
|
|
220
|
+
})();
|
|
221
|
+
loadingLanguages.set(normalized, loadPromise);
|
|
222
|
+
await loadPromise;
|
|
223
|
+
return registeredLanguages.has(normalized);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Load multiple languages in parallel
|
|
227
|
+
*/
|
|
228
|
+
export async function loadLanguages(languages) {
|
|
229
|
+
const unique = [...new Set(languages.map(normalizeLanguage))];
|
|
230
|
+
const toLoad = unique.filter(lang => !registeredLanguages.has(lang) &&
|
|
231
|
+
!failedLanguages.has(lang) &&
|
|
232
|
+
LANGUAGE_LOADERS[lang]);
|
|
233
|
+
if (toLoad.length > 0) {
|
|
234
|
+
devLog(`⏳ Loading ${toLoad.length} languages in parallel: [${toLoad.join(', ')}]`);
|
|
235
|
+
const startTime = performance.now();
|
|
236
|
+
await Promise.all(toLoad.map(loadLanguage));
|
|
237
|
+
const duration = (performance.now() - startTime).toFixed(1);
|
|
238
|
+
devLog(`✓ Parallel load complete in ${duration}ms`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Highlight code synchronously if language is available
|
|
243
|
+
* Triggers async language load if not available
|
|
244
|
+
*
|
|
245
|
+
* @param code - Source code to highlight
|
|
246
|
+
* @param language - Language identifier
|
|
247
|
+
* @returns Highlighted HTML and status
|
|
248
|
+
*/
|
|
249
|
+
export function highlightCode(code, language) {
|
|
250
|
+
if (!code) {
|
|
251
|
+
return { html: '', language: 'plaintext', isHighlighted: false };
|
|
252
|
+
}
|
|
253
|
+
if (!language) {
|
|
254
|
+
return { html: escapeHtml(code), language: 'plaintext', isHighlighted: false };
|
|
255
|
+
}
|
|
256
|
+
const normalized = normalizeLanguage(language);
|
|
257
|
+
if (normalized === 'plaintext') {
|
|
258
|
+
return { html: escapeHtml(code), language: 'plaintext', isHighlighted: true };
|
|
259
|
+
}
|
|
260
|
+
// Check cache
|
|
261
|
+
const cacheKey = `${normalized}:${code}`;
|
|
262
|
+
const cached = cacheManager.highlightCache.get(cacheKey);
|
|
263
|
+
if (cached !== undefined) {
|
|
264
|
+
return { html: cached, language: normalized, isHighlighted: true };
|
|
265
|
+
}
|
|
266
|
+
// Check if language is registered
|
|
267
|
+
if (!registeredLanguages.has(normalized)) {
|
|
268
|
+
// Trigger async load (non-blocking)
|
|
269
|
+
if (LANGUAGE_LOADERS[normalized] && !failedLanguages.has(normalized)) {
|
|
270
|
+
loadLanguage(normalized); // Fire and forget
|
|
271
|
+
}
|
|
272
|
+
else if (!failedLanguages.has(normalized)) {
|
|
273
|
+
// Unknown language - log warning and mark as failed
|
|
274
|
+
devWarn(`✗ "${normalized}" not supported (no loader available)`);
|
|
275
|
+
failedLanguages.add(normalized);
|
|
276
|
+
}
|
|
277
|
+
return { html: escapeHtml(code), language: normalized, isHighlighted: false };
|
|
278
|
+
}
|
|
279
|
+
// Highlight synchronously
|
|
280
|
+
try {
|
|
281
|
+
const result = hljs.highlight(code, {
|
|
282
|
+
language: normalized,
|
|
283
|
+
ignoreIllegals: true,
|
|
284
|
+
});
|
|
285
|
+
cacheManager.highlightCache.set(cacheKey, result.value);
|
|
286
|
+
return { html: result.value, language: normalized, isHighlighted: true };
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return { html: escapeHtml(code), language: normalized, isHighlighted: false };
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Simple highlight that returns just the HTML string
|
|
294
|
+
* For use in parser where we don't need status info
|
|
295
|
+
*/
|
|
296
|
+
export function highlight(code, language) {
|
|
297
|
+
return highlightCode(code, language).html;
|
|
298
|
+
}
|
|
299
|
+
// --------------------------------------------------------------------------
|
|
300
|
+
// Event System
|
|
301
|
+
// --------------------------------------------------------------------------
|
|
302
|
+
/**
|
|
303
|
+
* Subscribe to language load events
|
|
304
|
+
*/
|
|
305
|
+
export function onLanguageLoaded(listener) {
|
|
306
|
+
languageLoadListeners.add(listener);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Unsubscribe from language load events
|
|
310
|
+
*/
|
|
311
|
+
export function offLanguageLoaded(listener) {
|
|
312
|
+
languageLoadListeners.delete(listener);
|
|
313
|
+
}
|
|
314
|
+
// Track the last notification generation so late subscribers can detect missed notifications
|
|
315
|
+
let notificationGeneration = 0;
|
|
316
|
+
function notifyLanguageLoaded(language) {
|
|
317
|
+
// Collect language and its aliases for notification
|
|
318
|
+
pendingNotifications.add(language);
|
|
319
|
+
for (const [alias, target] of Object.entries(LANGUAGE_ALIASES)) {
|
|
320
|
+
if (target === language) {
|
|
321
|
+
pendingNotifications.add(alias);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// Batch notifications using microtask to avoid multiple re-renders
|
|
325
|
+
// when several languages load in parallel
|
|
326
|
+
if (!notificationScheduled) {
|
|
327
|
+
notificationScheduled = true;
|
|
328
|
+
queueMicrotask(() => {
|
|
329
|
+
const languages = [...pendingNotifications];
|
|
330
|
+
pendingNotifications.clear();
|
|
331
|
+
notificationScheduled = false;
|
|
332
|
+
notificationGeneration++;
|
|
333
|
+
const listenerCount = languageLoadListeners.size;
|
|
334
|
+
if (listenerCount > 0) {
|
|
335
|
+
devLog(`📢 Notifying ${listenerCount} listener(s) for [${languages.join(', ')}]`);
|
|
336
|
+
}
|
|
337
|
+
// Notify once per listener (not per language)
|
|
338
|
+
// Listener receives first language but all are now available
|
|
339
|
+
languageLoadListeners.forEach(listener => {
|
|
340
|
+
try {
|
|
341
|
+
listener(languages[0]);
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
console.error('[hljs] Error in language load listener:', error);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Get the current notification generation.
|
|
352
|
+
* Used by late subscribers to detect if they missed a notification
|
|
353
|
+
* (e.g., useEffect subscribes after paint, but languages loaded before paint).
|
|
354
|
+
*/
|
|
355
|
+
export function getNotificationGeneration() {
|
|
356
|
+
return notificationGeneration;
|
|
357
|
+
}
|
|
358
|
+
// --------------------------------------------------------------------------
|
|
359
|
+
// Registration API
|
|
360
|
+
// --------------------------------------------------------------------------
|
|
361
|
+
/**
|
|
362
|
+
* Register a custom language not in the dynamic loader map
|
|
363
|
+
*/
|
|
364
|
+
export function registerLanguage(name, languageFn) {
|
|
365
|
+
const normalized = normalizeLanguage(name);
|
|
366
|
+
if (registeredLanguages.has(normalized)) {
|
|
367
|
+
devLog(`✓ "${normalized}" already registered`);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
hljs.registerLanguage(normalized, languageFn);
|
|
371
|
+
registeredLanguages.add(normalized);
|
|
372
|
+
failedLanguages.delete(normalized);
|
|
373
|
+
devLog(`✓ "${normalized}" registered (custom)`);
|
|
374
|
+
notifyLanguageLoaded(normalized);
|
|
375
|
+
}
|
|
376
|
+
// --------------------------------------------------------------------------
|
|
377
|
+
// Utilities
|
|
378
|
+
// --------------------------------------------------------------------------
|
|
379
|
+
const HTML_ESCAPE_MAP = {
|
|
380
|
+
'&': '&',
|
|
381
|
+
'<': '<',
|
|
382
|
+
'>': '>',
|
|
383
|
+
'"': '"',
|
|
384
|
+
"'": ''',
|
|
385
|
+
};
|
|
386
|
+
const HTML_ESCAPE_RE = /[&<>"']/g;
|
|
387
|
+
function escapeHtml(text) {
|
|
388
|
+
return text.replace(HTML_ESCAPE_RE, char => HTML_ESCAPE_MAP[char]);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Check if a language is available (registered)
|
|
392
|
+
*/
|
|
393
|
+
export function isLanguageReady(language) {
|
|
394
|
+
return registeredLanguages.has(normalizeLanguage(language));
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Check if a language can be loaded dynamically
|
|
398
|
+
*/
|
|
399
|
+
export function isLanguageSupported(language) {
|
|
400
|
+
const normalized = normalizeLanguage(language);
|
|
401
|
+
return registeredLanguages.has(normalized) || normalized in LANGUAGE_LOADERS;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Get all registered languages
|
|
405
|
+
*/
|
|
406
|
+
export function getRegisteredLanguages() {
|
|
407
|
+
return Array.from(registeredLanguages);
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Get all supported languages (registered + loadable)
|
|
411
|
+
*/
|
|
412
|
+
export function getSupportedLanguages() {
|
|
413
|
+
return [...new Set([...registeredLanguages, ...Object.keys(LANGUAGE_LOADERS)])];
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Clear highlight cache
|
|
417
|
+
*/
|
|
418
|
+
export function clearHighlightCache() {
|
|
419
|
+
cacheManager.highlightCache.clear();
|
|
420
|
+
}
|
|
421
|
+
//# sourceMappingURL=highlighter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highlighter.js","sourceRoot":"","sources":["../../src/lib/highlighter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for processing hook results.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/hook-utils
|
|
5
|
+
*/
|
|
6
|
+
import type { HookResult } from "../types/hooks";
|
|
7
|
+
/**
|
|
8
|
+
* Escape HTML special characters to prevent XSS.
|
|
9
|
+
*
|
|
10
|
+
* Use this when inserting user content into HTML strings in hooks.
|
|
11
|
+
*
|
|
12
|
+
* @param str - String to escape
|
|
13
|
+
* @returns Escaped string safe for HTML insertion
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import { escapeHtml } from '@typefm/react-markdown-viewer';
|
|
17
|
+
*
|
|
18
|
+
* const hooks: RenderHooks = {
|
|
19
|
+
* onCodeBlock: ({ code, language }) =>
|
|
20
|
+
* `<pre data-lang="${escapeHtml(language || '')}">${escapeHtml(code)}</pre>`,
|
|
21
|
+
* };
|
|
22
|
+
*/
|
|
23
|
+
export declare function escapeHtml(str: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a hook result to a string or null.
|
|
26
|
+
*
|
|
27
|
+
* Hooks return `string | null`:
|
|
28
|
+
* - `string` → HTML to insert (direct, fast)
|
|
29
|
+
* - `null` → Use the default processor
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveHookResult(result: HookResult): string | null;
|
|
32
|
+
//# sourceMappingURL=hook-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-utils.d.ts","sourceRoot":"","sources":["../../src/lib/hook-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAGnE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for processing hook results.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/hook-utils
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Escape HTML special characters to prevent XSS.
|
|
8
|
+
*
|
|
9
|
+
* Use this when inserting user content into HTML strings in hooks.
|
|
10
|
+
*
|
|
11
|
+
* @param str - String to escape
|
|
12
|
+
* @returns Escaped string safe for HTML insertion
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* import { escapeHtml } from '@typefm/react-markdown-viewer';
|
|
16
|
+
*
|
|
17
|
+
* const hooks: RenderHooks = {
|
|
18
|
+
* onCodeBlock: ({ code, language }) =>
|
|
19
|
+
* `<pre data-lang="${escapeHtml(language || '')}">${escapeHtml(code)}</pre>`,
|
|
20
|
+
* };
|
|
21
|
+
*/
|
|
22
|
+
export function escapeHtml(str) {
|
|
23
|
+
return str
|
|
24
|
+
.replace(/&/g, "&")
|
|
25
|
+
.replace(/</g, "<")
|
|
26
|
+
.replace(/>/g, ">")
|
|
27
|
+
.replace(/"/g, """)
|
|
28
|
+
.replace(/'/g, "'");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolve a hook result to a string or null.
|
|
32
|
+
*
|
|
33
|
+
* Hooks return `string | null`:
|
|
34
|
+
* - `string` → HTML to insert (direct, fast)
|
|
35
|
+
* - `null` → Use the default processor
|
|
36
|
+
*/
|
|
37
|
+
export function resolveHookResult(result) {
|
|
38
|
+
if (typeof result === "string")
|
|
39
|
+
return result;
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=hook-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-utils.js","sourceRoot":"","sources":["../../src/lib/hook-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACrC,OAAO,GAAG;SACR,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAkB;IACnD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,OAAO,IAAI,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/lib/html.ts"],"names":[],"mappings":"AASA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C"}
|
package/dist/lib/html.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const HTML_ENTITY_MAP = {
|
|
2
|
+
'<': '<',
|
|
3
|
+
'>': '>',
|
|
4
|
+
'"': '"',
|
|
5
|
+
''': "'",
|
|
6
|
+
'&': '&'
|
|
7
|
+
};
|
|
8
|
+
const HTML_ENTITY_RE = /<|>|"|'|&/g;
|
|
9
|
+
export function decodeHtml(html) {
|
|
10
|
+
return html.replace(HTML_ENTITY_RE, (match) => HTML_ENTITY_MAP[match]);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/lib/html.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAA2B;IAC9C,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,GAAG;IACX,QAAQ,EAAE,GAAG;IACb,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,GAAG;CACb,CAAC;AACF,MAAM,cAAc,GAAG,+BAA+B,CAAC;AAEvD,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
interface MorphStats {
|
|
2
|
+
updated: number;
|
|
3
|
+
skipped: number;
|
|
4
|
+
added: number;
|
|
5
|
+
removed: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Morph the content of an element using Idiomorph
|
|
9
|
+
* Uses requestAnimationFrame to batch updates and prevent jank
|
|
10
|
+
*
|
|
11
|
+
* @param element The container element to morph
|
|
12
|
+
* @param newHtml The new HTML content
|
|
13
|
+
*/
|
|
14
|
+
export declare function morphContent(element: Element, newHtml: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* Morph content synchronously (for testing or immediate updates)
|
|
17
|
+
*
|
|
18
|
+
* @param element The container element to morph
|
|
19
|
+
* @param newHtml The new HTML content
|
|
20
|
+
*/
|
|
21
|
+
export declare function morphContentSync(element: Element, newHtml: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Reset morph state for a specific container, or clear all pending operations
|
|
24
|
+
*
|
|
25
|
+
* @param container Optional container to reset state for
|
|
26
|
+
*/
|
|
27
|
+
export declare function resetMorphCache(container?: Element): void;
|
|
28
|
+
/**
|
|
29
|
+
* Get morph stats for a specific container
|
|
30
|
+
*
|
|
31
|
+
* @param container The container to get stats for
|
|
32
|
+
* @returns Stats from the last morph operation on this container
|
|
33
|
+
*/
|
|
34
|
+
export declare function getMorphStats(container?: Element): MorphStats;
|
|
35
|
+
/**
|
|
36
|
+
* Optimized morph that skips unchanged elements
|
|
37
|
+
*
|
|
38
|
+
* Strategy:
|
|
39
|
+
* 1. Parse new HTML into temp container
|
|
40
|
+
* 2. Hash each top-level element
|
|
41
|
+
* 3. Compare with previous hashes for this container
|
|
42
|
+
* 4. Only morph elements that changed
|
|
43
|
+
*
|
|
44
|
+
* @param container The container element to morph
|
|
45
|
+
* @param newHtml The new HTML content
|
|
46
|
+
* @returns true if any elements were updated
|
|
47
|
+
*/
|
|
48
|
+
export declare function morphContentOptimized(container: Element, newHtml: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Reset element-level morph state for a container
|
|
51
|
+
* Note: Usually not needed since WeakMap auto-cleans when element is GC'd
|
|
52
|
+
*
|
|
53
|
+
* @param container Optional container to reset (if omitted, does nothing - use resetMorphCache)
|
|
54
|
+
*/
|
|
55
|
+
export declare function resetElementMorphState(container?: Element): void;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=morph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"morph.d.ts","sourceRoot":"","sources":["../../src/lib/morph.ts"],"names":[],"mappings":"AAoBA,UAAU,UAAU;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAsDD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CA2BpE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CASxE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAazD;AAMD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU,CAM7D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAyDlF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAIhE"}
|