@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,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified LRU Cache Manager
|
|
3
|
+
* Coordinates memory usage across all caches in the markdown-viewer
|
|
4
|
+
*/
|
|
5
|
+
class LRUCache {
|
|
6
|
+
cache = new Map();
|
|
7
|
+
sizeEstimates = new Map();
|
|
8
|
+
totalBytes = 0;
|
|
9
|
+
maxEntries;
|
|
10
|
+
maxBytes;
|
|
11
|
+
constructor(maxEntries, maxBytes = Infinity) {
|
|
12
|
+
this.maxEntries = maxEntries;
|
|
13
|
+
this.maxBytes = maxBytes;
|
|
14
|
+
}
|
|
15
|
+
get(key) {
|
|
16
|
+
const value = this.cache.get(key);
|
|
17
|
+
if (value !== undefined) {
|
|
18
|
+
// Move to end (most recently used)
|
|
19
|
+
this.cache.delete(key);
|
|
20
|
+
this.cache.set(key, value);
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
set(key, value, sizeBytes) {
|
|
25
|
+
// If key exists, remove old size
|
|
26
|
+
if (this.cache.has(key)) {
|
|
27
|
+
this.totalBytes -= this.sizeEstimates.get(key) ?? 0;
|
|
28
|
+
this.cache.delete(key);
|
|
29
|
+
this.sizeEstimates.delete(key);
|
|
30
|
+
}
|
|
31
|
+
// Estimate size if not provided
|
|
32
|
+
const size = sizeBytes ?? this.estimateSize(value);
|
|
33
|
+
// Evict if needed
|
|
34
|
+
while ((this.cache.size >= this.maxEntries || this.totalBytes + size > this.maxBytes) &&
|
|
35
|
+
this.cache.size > 0) {
|
|
36
|
+
const firstKey = this.cache.keys().next().value;
|
|
37
|
+
if (firstKey) {
|
|
38
|
+
this.totalBytes -= this.sizeEstimates.get(firstKey) ?? 0;
|
|
39
|
+
this.cache.delete(firstKey);
|
|
40
|
+
this.sizeEstimates.delete(firstKey);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
this.cache.set(key, value);
|
|
44
|
+
this.sizeEstimates.set(key, size);
|
|
45
|
+
this.totalBytes += size;
|
|
46
|
+
}
|
|
47
|
+
has(key) {
|
|
48
|
+
return this.cache.has(key);
|
|
49
|
+
}
|
|
50
|
+
clear() {
|
|
51
|
+
this.cache.clear();
|
|
52
|
+
this.sizeEstimates.clear();
|
|
53
|
+
this.totalBytes = 0;
|
|
54
|
+
}
|
|
55
|
+
evictOldest(count) {
|
|
56
|
+
const keys = this.cache.keys();
|
|
57
|
+
for (let i = 0; i < count; i++) {
|
|
58
|
+
const { value: key, done } = keys.next();
|
|
59
|
+
if (done || !key)
|
|
60
|
+
break;
|
|
61
|
+
this.totalBytes -= this.sizeEstimates.get(key) ?? 0;
|
|
62
|
+
this.cache.delete(key);
|
|
63
|
+
this.sizeEstimates.delete(key);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
get stats() {
|
|
67
|
+
return {
|
|
68
|
+
entries: this.cache.size,
|
|
69
|
+
estimatedBytes: this.totalBytes
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
estimateSize(value) {
|
|
73
|
+
if (typeof value === 'string') {
|
|
74
|
+
return value.length * 2; // UTF-16
|
|
75
|
+
}
|
|
76
|
+
return 100; // Default estimate for objects
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Total memory budget: ~10MB default
|
|
80
|
+
const DEFAULT_MEMORY_BUDGET = 10 * 1024 * 1024;
|
|
81
|
+
/**
|
|
82
|
+
* Global cache manager instance
|
|
83
|
+
* Coordinates memory across render cache, katex cache, and morph cache
|
|
84
|
+
*/
|
|
85
|
+
class CacheManager {
|
|
86
|
+
memoryBudget;
|
|
87
|
+
// Individual caches with allocated budgets
|
|
88
|
+
// Separate render caches for sync/async strategies (avoids key concatenation)
|
|
89
|
+
renderCacheSync;
|
|
90
|
+
renderCacheAsync;
|
|
91
|
+
// Separate KaTeX caches for display/inline modes (avoids key concatenation)
|
|
92
|
+
katexCacheDisplay;
|
|
93
|
+
katexCacheInline;
|
|
94
|
+
// Highlight.js cache (key: "language:code", value: highlighted HTML)
|
|
95
|
+
highlightCache;
|
|
96
|
+
constructor(memoryBudget = DEFAULT_MEMORY_BUDGET) {
|
|
97
|
+
this.memoryBudget = memoryBudget;
|
|
98
|
+
// Allocate budget: 20% each for render sync/async, katex display/inline, highlight
|
|
99
|
+
// Note: morph state moved to WeakMap in morph.ts for per-instance isolation
|
|
100
|
+
this.renderCacheSync = new LRUCache(100, memoryBudget * 0.2);
|
|
101
|
+
this.renderCacheAsync = new LRUCache(100, memoryBudget * 0.2);
|
|
102
|
+
this.katexCacheDisplay = new LRUCache(250, memoryBudget * 0.2);
|
|
103
|
+
this.katexCacheInline = new LRUCache(250, memoryBudget * 0.2);
|
|
104
|
+
this.highlightCache = new LRUCache(200, memoryBudget * 0.2);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get combined stats for all caches
|
|
108
|
+
*/
|
|
109
|
+
get stats() {
|
|
110
|
+
const renderSync = this.renderCacheSync.stats;
|
|
111
|
+
const renderAsync = this.renderCacheAsync.stats;
|
|
112
|
+
const katexDisplay = this.katexCacheDisplay.stats;
|
|
113
|
+
const katexInline = this.katexCacheInline.stats;
|
|
114
|
+
const highlight = this.highlightCache.stats;
|
|
115
|
+
return {
|
|
116
|
+
renderSync,
|
|
117
|
+
renderAsync,
|
|
118
|
+
katexDisplay,
|
|
119
|
+
katexInline,
|
|
120
|
+
highlight,
|
|
121
|
+
total: {
|
|
122
|
+
entries: renderSync.entries + renderAsync.entries + katexDisplay.entries + katexInline.entries + highlight.entries,
|
|
123
|
+
estimatedBytes: renderSync.estimatedBytes + renderAsync.estimatedBytes + katexDisplay.estimatedBytes + katexInline.estimatedBytes + highlight.estimatedBytes
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Clear all caches
|
|
129
|
+
*/
|
|
130
|
+
clearAll() {
|
|
131
|
+
this.renderCacheSync.clear();
|
|
132
|
+
this.renderCacheAsync.clear();
|
|
133
|
+
this.katexCacheDisplay.clear();
|
|
134
|
+
this.katexCacheInline.clear();
|
|
135
|
+
this.highlightCache.clear();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Trim caches if under memory pressure
|
|
139
|
+
* Evicts ~25% of entries from each cache when budget exceeded
|
|
140
|
+
*/
|
|
141
|
+
trimIfNeeded() {
|
|
142
|
+
const { total } = this.stats;
|
|
143
|
+
if (total.estimatedBytes > this.memoryBudget * 0.9) {
|
|
144
|
+
const caches = [
|
|
145
|
+
this.renderCacheSync,
|
|
146
|
+
this.renderCacheAsync,
|
|
147
|
+
this.katexCacheDisplay,
|
|
148
|
+
this.katexCacheInline,
|
|
149
|
+
this.highlightCache,
|
|
150
|
+
];
|
|
151
|
+
for (const cache of caches) {
|
|
152
|
+
const targetEvictions = Math.ceil(cache.stats.entries * 0.25);
|
|
153
|
+
cache.evictOldest(targetEvictions);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Singleton instance
|
|
159
|
+
export const cacheManager = new CacheManager();
|
|
160
|
+
//# sourceMappingURL=cache-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-manager.js","sourceRoot":"","sources":["../../src/lib/cache-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface CursorBlinkOptions {
|
|
2
|
+
blinkEnabled?: boolean;
|
|
3
|
+
blinkSpeed?: number;
|
|
4
|
+
blinkDelay?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function createCursorController(options?: CursorBlinkOptions): {
|
|
7
|
+
update: (container: HTMLElement) => void;
|
|
8
|
+
setBlinking: (container: HTMLElement, blinking: boolean) => void;
|
|
9
|
+
reset: () => void;
|
|
10
|
+
destroy: () => void;
|
|
11
|
+
};
|
|
12
|
+
export type CursorController = ReturnType<typeof createCursorController>;
|
|
13
|
+
//# sourceMappingURL=cursor-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-controller.d.ts","sourceRoot":"","sources":["../../src/lib/cursor-controller.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAQD,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,kBAAuB;wBAkD1C,WAAW,KAAG,IAAI;6BA0Bb,WAAW,YAAY,OAAO,KAAG,IAAI;iBAoBnD,IAAI;mBAUF,IAAI;EAWzB;AAED,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const DEFAULT_OPTIONS = {
|
|
2
|
+
blinkEnabled: true,
|
|
3
|
+
blinkSpeed: 1.0,
|
|
4
|
+
blinkDelay: 0.5,
|
|
5
|
+
};
|
|
6
|
+
export function createCursorController(options = {}) {
|
|
7
|
+
const config = { ...DEFAULT_OPTIONS, ...options };
|
|
8
|
+
// Time to wait after typing stops before blinking resumes.
|
|
9
|
+
const IDLE_TIMEOUT_MS = 500;
|
|
10
|
+
let activeTimer = null;
|
|
11
|
+
let isBlinkAlt = false;
|
|
12
|
+
let currentContainer = null;
|
|
13
|
+
// Initialize CSS variables on container
|
|
14
|
+
const initConfig = (el) => {
|
|
15
|
+
el.style.setProperty("--cursor-blink-name", "cursor-blink");
|
|
16
|
+
el.style.setProperty("--cursor-blink-duration", config.blinkEnabled ? `${config.blinkSpeed.toFixed(2)}s` : "0s");
|
|
17
|
+
el.style.setProperty("--cursor-blink-delay", `${config.blinkDelay.toFixed(2)}s`);
|
|
18
|
+
};
|
|
19
|
+
// Ensure container is initialized, returns cursor element if found
|
|
20
|
+
const ensureInit = (container) => {
|
|
21
|
+
if (container !== currentContainer) {
|
|
22
|
+
currentContainer = container;
|
|
23
|
+
initConfig(container);
|
|
24
|
+
}
|
|
25
|
+
return container.querySelector("[data-cursor]");
|
|
26
|
+
};
|
|
27
|
+
// Clear active timer if exists
|
|
28
|
+
const clearTimer = () => {
|
|
29
|
+
if (activeTimer) {
|
|
30
|
+
clearTimeout(activeTimer);
|
|
31
|
+
activeTimer = null;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
// Toggle animation name to restart CSS animation at 0%
|
|
35
|
+
const resetBlinkAnimation = (el) => {
|
|
36
|
+
isBlinkAlt = !isBlinkAlt;
|
|
37
|
+
el.style.setProperty("--cursor-blink-name", isBlinkAlt ? "cursor-blink-" : "cursor-blink");
|
|
38
|
+
};
|
|
39
|
+
// Called on each content update during streaming
|
|
40
|
+
const update = (container) => {
|
|
41
|
+
const cursor = ensureInit(container);
|
|
42
|
+
if (!cursor)
|
|
43
|
+
return;
|
|
44
|
+
clearTimer();
|
|
45
|
+
resetBlinkAnimation(container);
|
|
46
|
+
// Restore configured blink delay (may have been set to 0 by setBlinking)
|
|
47
|
+
container.style.setProperty("--cursor-blink-delay", `${config.blinkDelay.toFixed(2)}s`);
|
|
48
|
+
// Make cursor solid while receiving updates
|
|
49
|
+
cursor.classList.add("cursor-active");
|
|
50
|
+
// Resume blinking after idle timeout
|
|
51
|
+
activeTimer = window.setTimeout(() => {
|
|
52
|
+
if (cursor.isConnected) {
|
|
53
|
+
cursor.classList.remove("cursor-active");
|
|
54
|
+
}
|
|
55
|
+
activeTimer = null;
|
|
56
|
+
}, IDLE_TIMEOUT_MS);
|
|
57
|
+
};
|
|
58
|
+
// Directly set blinking state (for empty content waiting state)
|
|
59
|
+
const setBlinking = (container, blinking) => {
|
|
60
|
+
const cursor = ensureInit(container);
|
|
61
|
+
if (!cursor)
|
|
62
|
+
return;
|
|
63
|
+
clearTimer();
|
|
64
|
+
if (blinking) {
|
|
65
|
+
// Set delay to 0 for immediate blinking (waiting state)
|
|
66
|
+
container.style.setProperty("--cursor-blink-delay", "0s");
|
|
67
|
+
cursor.classList.remove("cursor-active");
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// Restore configured delay
|
|
71
|
+
container.style.setProperty("--cursor-blink-delay", `${config.blinkDelay.toFixed(2)}s`);
|
|
72
|
+
cursor.classList.add("cursor-active");
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const reset = () => {
|
|
76
|
+
clearTimer();
|
|
77
|
+
if (currentContainer) {
|
|
78
|
+
const cursor = currentContainer.querySelector("[data-cursor]");
|
|
79
|
+
cursor?.classList.remove("cursor-active");
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const destroy = () => {
|
|
83
|
+
reset();
|
|
84
|
+
if (currentContainer) {
|
|
85
|
+
currentContainer.style.removeProperty("--cursor-blink-name");
|
|
86
|
+
currentContainer.style.removeProperty("--cursor-blink-duration");
|
|
87
|
+
currentContainer.style.removeProperty("--cursor-blink-delay");
|
|
88
|
+
}
|
|
89
|
+
currentContainer = null;
|
|
90
|
+
};
|
|
91
|
+
return { update, setBlinking, reset, destroy };
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=cursor-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-controller.js","sourceRoot":"","sources":["../../src/lib/cursor-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default code block processor with syntax highlighting and copy button.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/defaults/code-block
|
|
5
|
+
*/
|
|
6
|
+
import type { CodeBlockData, InlineCodeData } from '../../types/hooks';
|
|
7
|
+
/** SVG icon for copy button */
|
|
8
|
+
export declare const COPY_ICON = "<svg class=\"copy-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"></rect><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"></path></svg>";
|
|
9
|
+
/** SVG icon for copied state */
|
|
10
|
+
export declare const CHECK_ICON = "<svg class=\"check-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M20 6 9 17l-5-5\"></path></svg>";
|
|
11
|
+
/**
|
|
12
|
+
* Matches hex, rgb, rgba, hsl, hsla colors.
|
|
13
|
+
* Negative lookbehind prevents matching HTML entities like | or &#124;
|
|
14
|
+
*/
|
|
15
|
+
export declare const COLOR_RE: RegExp;
|
|
16
|
+
export interface CodeBlockOptions {
|
|
17
|
+
/** Enable color preview injection (default: true) */
|
|
18
|
+
colorPreviews?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Wrap lines in `<span class="code-line">` for streaming stability (default: false).
|
|
21
|
+
*
|
|
22
|
+
* Note: The default parser wraps lines automatically during streaming.
|
|
23
|
+
* Set this to `true` if you override `onCodeBlock` and want similar behavior.
|
|
24
|
+
*/
|
|
25
|
+
wrapLines?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface InlineCodeOptions {
|
|
28
|
+
/** Enable color preview injection (default: true) */
|
|
29
|
+
colorPreviews?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Inject color preview boxes into content containing color codes.
|
|
33
|
+
*
|
|
34
|
+
* @param content - Content to process
|
|
35
|
+
* @returns Content with color preview boxes injected
|
|
36
|
+
*/
|
|
37
|
+
export declare function injectColorPreviews(content: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Default code block processor.
|
|
40
|
+
*
|
|
41
|
+
* Applies syntax highlighting, optional color previews, and wraps in a
|
|
42
|
+
* container with a copy button.
|
|
43
|
+
*
|
|
44
|
+
* @param data - Code block data with code and language
|
|
45
|
+
* @param options - Processing options
|
|
46
|
+
* @returns HTML string for the code block
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const html = processCodeBlock(
|
|
50
|
+
* { code: 'const x = 1;', language: 'javascript' },
|
|
51
|
+
* { colorPreviews: true, wrapLines: false }
|
|
52
|
+
* );
|
|
53
|
+
*/
|
|
54
|
+
export declare function processCodeBlock(data: CodeBlockData, options?: CodeBlockOptions): string;
|
|
55
|
+
/**
|
|
56
|
+
* Default inline code processor.
|
|
57
|
+
*
|
|
58
|
+
* Optionally injects color preview boxes for color codes.
|
|
59
|
+
*
|
|
60
|
+
* @param data - Inline code data
|
|
61
|
+
* @param options - Processing options
|
|
62
|
+
* @returns HTML string for the inline code
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* const html = processInlineCode(
|
|
66
|
+
* { code: '#ff0000' },
|
|
67
|
+
* { colorPreviews: true }
|
|
68
|
+
* );
|
|
69
|
+
*/
|
|
70
|
+
export declare function processInlineCode(data: InlineCodeData, options?: InlineCodeOptions): string;
|
|
71
|
+
//# sourceMappingURL=code-block.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-block.d.ts","sourceRoot":"","sources":["../../../src/lib/defaults/code-block.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAMvE,+BAA+B;AAC/B,eAAO,MAAM,SAAS,2XAAyV,CAAC;AAEhX,gCAAgC;AAChC,eAAO,MAAM,UAAU,0QAAoP,CAAC;AAE5Q;;;GAGG;AACH,eAAO,MAAM,QAAQ,QAAsE,CAAC;AAM5F,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAMD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAe3D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE,gBAAqB,GAC7B,MAAM,CAwBR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE,iBAAsB,GAC9B,MAAM,CAYR"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default code block processor with syntax highlighting and copy button.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/defaults/code-block
|
|
5
|
+
*/
|
|
6
|
+
import { highlight } from '../highlighter';
|
|
7
|
+
// --------------------------------------------------------------------------
|
|
8
|
+
// Constants (hoisted for performance)
|
|
9
|
+
// --------------------------------------------------------------------------
|
|
10
|
+
/** SVG icon for copy button */
|
|
11
|
+
export const COPY_ICON = `<svg class="copy-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>`;
|
|
12
|
+
/** SVG icon for copied state */
|
|
13
|
+
export const CHECK_ICON = `<svg class="check-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>`;
|
|
14
|
+
/**
|
|
15
|
+
* Matches hex, rgb, rgba, hsl, hsla colors.
|
|
16
|
+
* Negative lookbehind prevents matching HTML entities like | or &#124;
|
|
17
|
+
*/
|
|
18
|
+
export const COLOR_RE = /(?<!&)(?<!;)#([0-9a-fA-F]{3,8})\b|(?:rgba?|hsla?)\([\d\s,.%]+\)/gi;
|
|
19
|
+
// --------------------------------------------------------------------------
|
|
20
|
+
// Processors
|
|
21
|
+
// --------------------------------------------------------------------------
|
|
22
|
+
/**
|
|
23
|
+
* Inject color preview boxes into content containing color codes.
|
|
24
|
+
*
|
|
25
|
+
* @param content - Content to process
|
|
26
|
+
* @returns Content with color preview boxes injected
|
|
27
|
+
*/
|
|
28
|
+
export function injectColorPreviews(content) {
|
|
29
|
+
if (!content.includes('#') && !content.includes('rgb') && !content.includes('hsl')) {
|
|
30
|
+
return content;
|
|
31
|
+
}
|
|
32
|
+
return content.replace(COLOR_RE, (colorMatch) => {
|
|
33
|
+
// Validate hex colors
|
|
34
|
+
if (colorMatch.startsWith('#')) {
|
|
35
|
+
const hex = colorMatch.slice(1);
|
|
36
|
+
if (![3, 4, 6, 8].includes(hex.length)) {
|
|
37
|
+
return colorMatch;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return `<span style="white-space: nowrap;"><span class="color-box" style="background-color: ${colorMatch};"></span>${colorMatch}</span>`;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Default code block processor.
|
|
45
|
+
*
|
|
46
|
+
* Applies syntax highlighting, optional color previews, and wraps in a
|
|
47
|
+
* container with a copy button.
|
|
48
|
+
*
|
|
49
|
+
* @param data - Code block data with code and language
|
|
50
|
+
* @param options - Processing options
|
|
51
|
+
* @returns HTML string for the code block
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const html = processCodeBlock(
|
|
55
|
+
* { code: 'const x = 1;', language: 'javascript' },
|
|
56
|
+
* { colorPreviews: true, wrapLines: false }
|
|
57
|
+
* );
|
|
58
|
+
*/
|
|
59
|
+
export function processCodeBlock(data, options = {}) {
|
|
60
|
+
const { code, language } = data;
|
|
61
|
+
const { colorPreviews = true, wrapLines = false } = options;
|
|
62
|
+
// 1. Apply syntax highlighting
|
|
63
|
+
let content = highlight(code, language);
|
|
64
|
+
// 2. Apply color previews if enabled
|
|
65
|
+
if (colorPreviews) {
|
|
66
|
+
content = injectColorPreviews(content);
|
|
67
|
+
}
|
|
68
|
+
// 3. Wrap lines for streaming stability
|
|
69
|
+
if (wrapLines && content) {
|
|
70
|
+
content = content.replace(/^(.*)$/gm, '<span class="code-line">$1</span>');
|
|
71
|
+
}
|
|
72
|
+
// 4. Build the code block with wrapper and copy button
|
|
73
|
+
const langClass = language ? `language-${language}` : '';
|
|
74
|
+
const codeTag = langClass
|
|
75
|
+
? `<code class="${langClass}">${content}</code>`
|
|
76
|
+
: `<code>${content}</code>`;
|
|
77
|
+
return `<div class="code-block-wrapper"><button type="button" class="copy-btn" aria-label="Copy code">${COPY_ICON}${CHECK_ICON}</button><pre>${codeTag}</pre></div>`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Default inline code processor.
|
|
81
|
+
*
|
|
82
|
+
* Optionally injects color preview boxes for color codes.
|
|
83
|
+
*
|
|
84
|
+
* @param data - Inline code data
|
|
85
|
+
* @param options - Processing options
|
|
86
|
+
* @returns HTML string for the inline code
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* const html = processInlineCode(
|
|
90
|
+
* { code: '#ff0000' },
|
|
91
|
+
* { colorPreviews: true }
|
|
92
|
+
* );
|
|
93
|
+
*/
|
|
94
|
+
export function processInlineCode(data, options = {}) {
|
|
95
|
+
const { code } = data;
|
|
96
|
+
const { colorPreviews = true } = options;
|
|
97
|
+
let content = code;
|
|
98
|
+
// Apply color previews if enabled
|
|
99
|
+
if (colorPreviews) {
|
|
100
|
+
content = injectColorPreviews(content);
|
|
101
|
+
}
|
|
102
|
+
return `<code>${content}</code>`;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=code-block.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-block.js","sourceRoot":"","sources":["../../../src/lib/defaults/code-block.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,6EAA6E;AAC7E,sCAAsC;AACtC,6EAA6E;AAE7E,+BAA+B;AAC/B,MAAM,CAAC,MAAM,SAAS,GAAG,sVAAsV,CAAC;AAEhX,gCAAgC;AAChC,MAAM,CAAC,MAAM,UAAU,GAAG,iPAAiP,CAAC;AAE5Q;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,mEAAmE,CAAC;AAuB5F,6EAA6E;AAC7E,aAAa;AACb,6EAA6E;AAE7E;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACnF,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,UAAkB,EAAE,EAAE;QACtD,sBAAsB;QACtB,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBACvC,OAAO,UAAU,CAAC;YACpB,CAAC;QACH,CAAC;QACD,OAAO,uFAAuF,UAAU,aAAa,UAAU,SAAS,CAAC;IAC3I,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAmB,EACnB,UAA4B,EAAE;IAE9B,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,aAAa,GAAG,IAAI,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAE5D,+BAA+B;IAC/B,IAAI,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAExC,qCAAqC;IACrC,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,wCAAwC;IACxC,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;QACzB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,mCAAmC,CAAC,CAAC;IAC7E,CAAC;IAED,uDAAuD;IACvD,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,YAAY,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,MAAM,OAAO,GAAG,SAAS;QACvB,CAAC,CAAC,gBAAgB,SAAS,KAAK,OAAO,SAAS;QAChD,CAAC,CAAC,SAAS,OAAO,SAAS,CAAC;IAE9B,OAAO,iGAAiG,SAAS,GAAG,UAAU,iBAAiB,OAAO,cAAc,CAAC;AACvK,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAoB,EACpB,UAA6B,EAAE;IAE/B,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,aAAa,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAEzC,IAAI,OAAO,GAAG,IAAI,CAAC;IAEnB,kCAAkC;IAClC,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,SAAS,OAAO,SAAS,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default image processor with lazy loading and lightbox support.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/defaults/image
|
|
5
|
+
*/
|
|
6
|
+
import type { ImageData } from '../../types/hooks';
|
|
7
|
+
/**
|
|
8
|
+
* Options for image processing.
|
|
9
|
+
*/
|
|
10
|
+
export interface ImageOptions {
|
|
11
|
+
/** Add loading="lazy" attribute (default: true) */
|
|
12
|
+
lazyLoad?: boolean;
|
|
13
|
+
/** Wrap in anchor for lightbox integration (default: false) */
|
|
14
|
+
linkWrapper?: boolean;
|
|
15
|
+
/** Custom class for the image (default: none) */
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Process an image with optional lazy loading and lightbox wrapper.
|
|
20
|
+
*
|
|
21
|
+
* @param data - Image data from the hook
|
|
22
|
+
* @param options - Processing options
|
|
23
|
+
* @returns HTML string for the image
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Basic usage with lazy loading (default)
|
|
27
|
+
* processImage({ src: 'photo.jpg', alt: 'A photo' })
|
|
28
|
+
* // => <img src="photo.jpg" alt="A photo" loading="lazy">
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // With lightbox wrapper
|
|
32
|
+
* processImage({ src: 'photo.jpg', alt: 'A photo' }, { linkWrapper: true })
|
|
33
|
+
* // => <a href="photo.jpg" data-lightbox><img src="photo.jpg" alt="A photo" loading="lazy"></a>
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // Custom class
|
|
37
|
+
* processImage({ src: 'photo.jpg', alt: 'A photo' }, { className: 'rounded shadow' })
|
|
38
|
+
* // => <img src="photo.jpg" alt="A photo" loading="lazy" class="rounded shadow">
|
|
39
|
+
*/
|
|
40
|
+
export declare function processImage(data: ImageData, options?: ImageOptions): string;
|
|
41
|
+
//# sourceMappingURL=image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/lib/defaults/image.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,CAmB5E"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default image processor with lazy loading and lightbox support.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/defaults/image
|
|
5
|
+
*/
|
|
6
|
+
import { escapeHtml } from '../hook-utils';
|
|
7
|
+
/**
|
|
8
|
+
* Process an image with optional lazy loading and lightbox wrapper.
|
|
9
|
+
*
|
|
10
|
+
* @param data - Image data from the hook
|
|
11
|
+
* @param options - Processing options
|
|
12
|
+
* @returns HTML string for the image
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Basic usage with lazy loading (default)
|
|
16
|
+
* processImage({ src: 'photo.jpg', alt: 'A photo' })
|
|
17
|
+
* // => <img src="photo.jpg" alt="A photo" loading="lazy">
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // With lightbox wrapper
|
|
21
|
+
* processImage({ src: 'photo.jpg', alt: 'A photo' }, { linkWrapper: true })
|
|
22
|
+
* // => <a href="photo.jpg" data-lightbox><img src="photo.jpg" alt="A photo" loading="lazy"></a>
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Custom class
|
|
26
|
+
* processImage({ src: 'photo.jpg', alt: 'A photo' }, { className: 'rounded shadow' })
|
|
27
|
+
* // => <img src="photo.jpg" alt="A photo" loading="lazy" class="rounded shadow">
|
|
28
|
+
*/
|
|
29
|
+
export function processImage(data, options) {
|
|
30
|
+
const { lazyLoad = true, linkWrapper = false, className } = options || {};
|
|
31
|
+
const { src, alt, title } = data;
|
|
32
|
+
const attrs = [
|
|
33
|
+
`src="${escapeHtml(src)}"`,
|
|
34
|
+
`alt="${escapeHtml(alt)}"`,
|
|
35
|
+
title ? `title="${escapeHtml(title)}"` : '',
|
|
36
|
+
lazyLoad ? 'loading="lazy"' : '',
|
|
37
|
+
className ? `class="${escapeHtml(className)}"` : '',
|
|
38
|
+
].filter(Boolean).join(' ');
|
|
39
|
+
const img = `<img ${attrs}>`;
|
|
40
|
+
if (linkWrapper) {
|
|
41
|
+
return `<a href="${escapeHtml(src)}" data-lightbox>${img}</a>`;
|
|
42
|
+
}
|
|
43
|
+
return img;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../../src/lib/defaults/image.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAc3C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,YAAY,CAAC,IAAe,EAAE,OAAsB;IAClE,MAAM,EAAE,QAAQ,GAAG,IAAI,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;IAC1E,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IAEjC,MAAM,KAAK,GAAG;QACZ,QAAQ,UAAU,CAAC,GAAG,CAAC,GAAG;QAC1B,QAAQ,UAAU,CAAC,GAAG,CAAC,GAAG;QAC1B,KAAK,CAAC,CAAC,CAAC,UAAU,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QAC3C,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE;QAChC,SAAS,CAAC,CAAC,CAAC,UAAU,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;KACpD,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE5B,MAAM,GAAG,GAAG,QAAQ,KAAK,GAAG,CAAC;IAE7B,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,YAAY,UAAU,CAAC,GAAG,CAAC,mBAAmB,GAAG,MAAM,CAAC;IACjE,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default link processor with security hardening.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/defaults/link
|
|
5
|
+
*/
|
|
6
|
+
import type { LinkData } from '../../types/hooks';
|
|
7
|
+
/**
|
|
8
|
+
* Check if a URL is potentially dangerous.
|
|
9
|
+
*
|
|
10
|
+
* @param href - URL to check
|
|
11
|
+
* @returns true if the URL should be sanitized
|
|
12
|
+
*/
|
|
13
|
+
export declare function isDangerousUrl(href: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Check if a URL is external (not anchor or relative).
|
|
16
|
+
*
|
|
17
|
+
* @param href - URL to check
|
|
18
|
+
* @returns true if the URL is external
|
|
19
|
+
*/
|
|
20
|
+
export declare function isExternalUrl(href: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Default link processor - sanitizes and adds security attributes.
|
|
23
|
+
*
|
|
24
|
+
* Security measures:
|
|
25
|
+
* - Sanitizes javascript:, vbscript:, and dangerous data: URLs
|
|
26
|
+
* - Adds target="_blank" and rel="noopener noreferrer" to external links
|
|
27
|
+
*
|
|
28
|
+
* @param data - Link data with href, text, and optional title
|
|
29
|
+
* @returns HTML string for the anchor tag
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // Internal link
|
|
33
|
+
* processLink({ href: '/about', text: 'About' });
|
|
34
|
+
* // Returns: '<a href="/about">About</a>'
|
|
35
|
+
*
|
|
36
|
+
* // External link
|
|
37
|
+
* processLink({ href: 'https://example.com', text: 'Example' });
|
|
38
|
+
* // Returns: '<a href="https://example.com" target="_blank" rel="noopener noreferrer">Example</a>'
|
|
39
|
+
*
|
|
40
|
+
* // Dangerous link (sanitized)
|
|
41
|
+
* processLink({ href: 'javascript:alert(1)', text: 'Click' });
|
|
42
|
+
* // Returns: '<a href="#">Click</a>'
|
|
43
|
+
*/
|
|
44
|
+
export declare function processLink(data: LinkData): string;
|
|
45
|
+
//# sourceMappingURL=link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/lib/defaults/link.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAWlD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMpD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAsBlD"}
|