remons-render-markdown 2.0.1-beta.2 → 2.0.1-beta.4
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/components/ImagePreview/index.d.ts +15 -6
- package/dist/components/MermaidRenderer/index.d.ts +27 -3
- package/dist/components/MermaidRenderer/mermaidRootRegistry.d.ts +25 -0
- package/dist/components/MermaidRenderer/renderMermaidWithControls.d.ts +22 -6
- package/dist/components/MermaidRenderer/useMermaidRender.d.ts +13 -4
- package/dist/components/MermaidRenderer/usePanzoom.d.ts +17 -3
- package/dist/components/RenderMarkdown/index.d.ts +60 -15
- package/dist/components/RenderMarkdown/utils/render-markdown/empty-task-lists.d.ts +2 -0
- package/dist/components/RenderMarkdown/utils/render-markdown/fence-state.d.ts +16 -0
- package/dist/components/RenderMarkdown/utils/render-markdown/index.d.ts +23 -2
- package/dist/components/RenderMarkdown/utils/render-markdown/render-tab.d.ts +2 -1
- package/dist/components/RenderMarkdown/utils/render-markdown/validate-link.d.ts +16 -0
- package/dist/components/TocSidebar/index.d.ts +15 -0
- package/dist/hooks/useIncrementalRender.d.ts +64 -0
- package/dist/hooks/useTheme.d.ts +8 -2
- package/dist/index.css +1 -1
- package/dist/index.d.ts +9 -4
- package/dist/index.mjs +19 -14
- package/dist/utils/cdn.d.ts +8 -1
- package/dist/utils/dom-contract.d.ts +24 -0
- package/dist/utils/driver.d.ts +3 -0
- package/dist/utils/preload.d.ts +1 -1
- package/package.json +93 -95
- package/readme.md +288 -70
- package/dist/components/ImagePreview/ImageToolbar.d.ts +0 -9
- package/dist/main.d.ts +0 -2
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* 向图片预览全局排除名单中添加选择器
|
|
3
|
+
* 外部自定义渲染器若包含图片,需调用此方法避免与本库预览冲突
|
|
4
4
|
* @param selectors - CSS 选择器或选择器数组,如 '.copy-password-container' 或 ['.a', '.b']
|
|
5
5
|
*/
|
|
6
6
|
export declare function addExcludedSelector(selectors: string | string[]): void;
|
|
7
|
+
/** 从全局排除名单移除选择器(与 addExcludedSelector 配对,支持撤销) */
|
|
8
|
+
export declare function removeExcludedSelector(selectors: string | string[]): void;
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
10
|
+
* 初始化图片预览:绑定容器内的图片点击委托,并刷新可预览列表
|
|
11
|
+
* @param container - 渲染容器(.markdown-html),只处理其内部图片
|
|
12
|
+
* @param options.instanceSelectors - 实例级排除名单(excludedSelectors prop)
|
|
13
|
+
* @param options.isPrintPreview - 打印模式:跳过交互,仅展开图片样式
|
|
9
14
|
*/
|
|
10
|
-
export declare function initImageToolbars(
|
|
15
|
+
export declare function initImageToolbars(container: HTMLDivElement | null, options?: {
|
|
16
|
+
instanceSelectors?: string[];
|
|
17
|
+
isPrintPreview?: boolean;
|
|
18
|
+
}): void;
|
|
11
19
|
/**
|
|
12
|
-
*
|
|
20
|
+
* 销毁指定容器的预览状态(容器卸载/隐藏前调用)
|
|
21
|
+
* 遮罩是挂在 body 上的独立节点,不属于容器子树,必须显式关掉
|
|
13
22
|
*/
|
|
14
|
-
export declare function cleanupImageToolbars(): void;
|
|
23
|
+
export declare function cleanupImageToolbars(container?: HTMLElement | null): void;
|
|
@@ -45,16 +45,40 @@ interface MermaidRendererProps {
|
|
|
45
45
|
*/
|
|
46
46
|
isPrintPreview?: boolean;
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
49
|
-
|
|
48
|
+
* 渲染前对图表源码进行改写(初始化语义:仅首次传入生效)
|
|
49
|
+
*/
|
|
50
|
+
transformSource?: (text: string) => string;
|
|
51
|
+
/**
|
|
52
|
+
* @deprecated 旧名,等价于 transformSource
|
|
50
53
|
*/
|
|
51
54
|
chartConfig?: (text: string) => string;
|
|
52
55
|
/**
|
|
53
|
-
*
|
|
56
|
+
* mermaid 安全级别,默认 'strict'(禁用图内点击事件/原始 HTML)。
|
|
57
|
+
* 仅当完全信任图表来源时才设为 'loose'。
|
|
58
|
+
*/
|
|
59
|
+
securityLevel?: 'strict' | 'loose';
|
|
60
|
+
/**
|
|
61
|
+
* 自定义 CDN 配置,如 { mermaid: 'https://...' }(初始化语义:全局仅加载一次)
|
|
54
62
|
*/
|
|
55
63
|
cdn?: Record<string, string>;
|
|
64
|
+
/**
|
|
65
|
+
* 新手引导是否每个元素只触发一次(默认 true)。
|
|
66
|
+
* 流式重渲染场景下设为 false 会反复弹引导。
|
|
67
|
+
*/
|
|
68
|
+
driverGuideOnce?: boolean;
|
|
56
69
|
}
|
|
57
70
|
declare const MermaidRenderer: import('react').ForwardRefExoticComponent<MermaidRendererProps & import('react').RefAttributes<null>>;
|
|
58
71
|
export default MermaidRenderer;
|
|
72
|
+
/**
|
|
73
|
+
* 带主题容器的图表组件(推荐直接使用):
|
|
74
|
+
* 作为 JSX 元素类型稳定,父组件重渲染不会导致子树卸载重建;自带 ThemeProvider,
|
|
75
|
+
* 应用未包主题上下文时也能直接渲染。
|
|
76
|
+
* 旧用法 renderMermaid({...}) 返回 JSX 的方式每次调用都生成新元素类型,
|
|
77
|
+
* 会造成重渲染时完整卸载重建,已标废。
|
|
78
|
+
*/
|
|
79
|
+
export declare const MermaidChart: React.FC<MermaidRendererProps>;
|
|
80
|
+
/**
|
|
81
|
+
* @deprecated 请改用组件形式 <MermaidChart {...} />;函数调用返回 JSX 会在父组件重渲染时重置子树状态
|
|
82
|
+
*/
|
|
59
83
|
declare const renderMermaid: (props: MermaidRendererProps) => import("react").JSX.Element;
|
|
60
84
|
export { renderMermaidWithControls, renderMermaid };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Root } from 'react-dom/client';
|
|
2
|
+
/** 注册一个挂载点与其 React Root */
|
|
3
|
+
export declare function registerMermaidRoot(el: Element, root: Root): void;
|
|
4
|
+
/** 卸载并清空指定元素上挂载过的图表 root */
|
|
5
|
+
export declare function unmountMermaidRootsAt(el: Element): void;
|
|
6
|
+
/** 取挂载点上的 React Root:源码变化时用它原地更新 props,避免卸载重建 */
|
|
7
|
+
export declare function getMermaidRoot(el: Element): Root | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* 回收已脱离文档的挂载点。
|
|
10
|
+
* 非增量模式整块重建、内容为空时 React 直接移除子树,这些节点
|
|
11
|
+
* 不在任何作用域内、扫描再也找不到,不主动回收就是永久泄漏的 Root。
|
|
12
|
+
*/
|
|
13
|
+
export declare function pruneDetachedMermaidRoots(): void;
|
|
14
|
+
/**
|
|
15
|
+
* 源码指纹(FNV-1a 32 位 + 长度):用于判断图表源码是否真的变了。
|
|
16
|
+
* 长度入摘要以降低碰撞概率;只用于“是否相等”判定,不用于还原源码。
|
|
17
|
+
*/
|
|
18
|
+
export declare function hashMermaidSource(text: string): string;
|
|
19
|
+
/** 是否由扫描挂载的图表节点(兼作锚点定位与孤儿回收的判据) */
|
|
20
|
+
export declare function isMermaidChartRoot(el: Element | null | undefined): el is HTMLElement;
|
|
21
|
+
/**
|
|
22
|
+
* 回收某棵子树内所有图表 root 并移除挂载点节点。
|
|
23
|
+
* 组件卸载 / 增量 diff 丢弃节点时调用,防止 React Root 泄漏。
|
|
24
|
+
*/
|
|
25
|
+
export declare function cleanupMermaidRoots(scope: ParentNode | null): void;
|
|
@@ -1,11 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*/
|
|
5
|
-
export default function renderMermaidWithControls(props: {
|
|
1
|
+
import { cleanupMermaidRoots } from './mermaidRootRegistry';
|
|
2
|
+
export { cleanupMermaidRoots };
|
|
3
|
+
interface ScanProps {
|
|
6
4
|
showDriverGuide?: boolean;
|
|
7
5
|
isPrintPreview?: boolean;
|
|
6
|
+
transformSource?: (text: string) => string;
|
|
7
|
+
/** @deprecated 旧名,等价于 transformSource(初始化语义) */
|
|
8
8
|
chartConfig?: (text: string) => string;
|
|
9
9
|
defaultCollapsed?: boolean;
|
|
10
10
|
cdn?: Record<string, string>;
|
|
11
|
-
|
|
11
|
+
/** 扫描作用域,默认为 document;传入容器可实现多实例隔离 */
|
|
12
|
+
rootElement?: ParentNode;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* DOM 扫描入口(文档页使用)
|
|
16
|
+
* 扫描容器内所有已闭合的 code.language-mermaid 代码块,在其**后面**插入图表挂载点。
|
|
17
|
+
*
|
|
18
|
+
* 关键约定:`<pre>` 保留在 DOM 中(由 CSS 隐藏源码),图表作为它的兄弟节点存在。
|
|
19
|
+
* 这样增量渲染时 morphdom 仍能按 <pre> 自身的语义 key 匹配到原节点、原地无变化,
|
|
20
|
+
* 而挂载点靠 MD_PERSIST_ATTR 免于被移除;两边都不会被销毁重建。
|
|
21
|
+
* 早先的 `pre.replaceWith(container)` 写法会让每次 patch 都命中"签名不匹配",
|
|
22
|
+
* 图表被移除→重挂→整图重新 mermaid.render,表现为流式中反复闪白并丢失交互状态。
|
|
23
|
+
*
|
|
24
|
+
* 可重复调用:源码未变的块直接复用现有挂载点(不重渲染);源码变了走 props 更新;
|
|
25
|
+
* 块被删除/围栏重开的挂载点会被卸载移除,不会累积泄漏。
|
|
26
|
+
*/
|
|
27
|
+
export default function renderMermaidWithControls(props?: ScanProps): Promise<void>;
|
|
@@ -10,16 +10,25 @@ interface UseMermaidRenderParams {
|
|
|
10
10
|
debounceMs?: number;
|
|
11
11
|
isDark: boolean;
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* 渲染前对图表源码进行改写(初始化语义:仅首次传入时确定,后续变更不生效,
|
|
14
|
+
* 避免内联函数引用变化导致每轮重渲染重置防抖)
|
|
15
|
+
*/
|
|
16
|
+
transformSource?: (text: string) => string;
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated 旧名,等价于 transformSource(初始化语义)
|
|
15
19
|
*/
|
|
16
20
|
chartConfig?: (text: string) => string;
|
|
17
21
|
/**
|
|
18
|
-
* 自定义 CDN 配置,如 { mermaid: 'https://...' }
|
|
22
|
+
* 自定义 CDN 配置,如 { mermaid: 'https://...' }(初始化语义:全局仅加载一次,以首次调用为准)
|
|
19
23
|
*/
|
|
20
24
|
cdn?: Record<string, string>;
|
|
25
|
+
/**
|
|
26
|
+
* mermaid 安全级别,默认 'strict'(禁用图内点击事件/原始 HTML)。
|
|
27
|
+
* 仅当完全信任图表来源时才设为 'loose'。
|
|
28
|
+
*/
|
|
29
|
+
securityLevel?: 'strict' | 'loose';
|
|
21
30
|
}
|
|
22
|
-
export default function useMermaidRender({ source, debounceMs, isDark, chartConfig, cdn }: UseMermaidRenderParams): {
|
|
31
|
+
export default function useMermaidRender({ source, debounceMs, isDark, transformSource, chartConfig, cdn, securityLevel, }: UseMermaidRenderParams): {
|
|
23
32
|
svg: string;
|
|
24
33
|
error: string;
|
|
25
34
|
loading: boolean;
|
|
@@ -9,9 +9,23 @@ interface PanzoomRefType {
|
|
|
9
9
|
interface UsePanzoomParams {
|
|
10
10
|
contentRef: RefObject<HTMLElement | null>;
|
|
11
11
|
wrapperRef: RefObject<HTMLElement | null>;
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* 是否具备缩放能力(图表已渲染且开启 enablePanzoom)。
|
|
14
|
+
* 实例只跟随它创建/销毁,因此图表重渲染不会重置用户的缩放/平移位姿。
|
|
15
|
+
*/
|
|
16
|
+
canUse: boolean;
|
|
17
|
+
/** 是否响应交互(拖拽、滚轮缩放)。关闭时只解绑事件,保留已有 transform */
|
|
18
|
+
active: boolean;
|
|
19
|
+
/** 全屏切换会大幅改变可视区域,需要重建实例以重新计算边界 */
|
|
14
20
|
isFullscreen: boolean;
|
|
15
21
|
}
|
|
16
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Panzoom 实例管理。
|
|
24
|
+
*
|
|
25
|
+
* 修复前:依赖里含 svg 字符串,每次重渲染(流式输出、主题切换)都 destroy + 重建,
|
|
26
|
+
* 用户刚缩放/平移好的视图被反复清零;折叠再展开同样清零。
|
|
27
|
+
* 现在:实例只由 canUse 决定生死(承载 transform 的容器节点始终不变,替换其内部 <svg> 不影响它),
|
|
28
|
+
* 交互开关用 bind/destroy 解绑事件实现,位姿得以保留。
|
|
29
|
+
*/
|
|
30
|
+
export default function usePanzoom({ contentRef, wrapperRef, canUse, active, isFullscreen }: UsePanzoomParams): import('react').MutableRefObject<PanzoomRefType | null>;
|
|
17
31
|
export {};
|
|
@@ -10,11 +10,19 @@ export interface RenderMarkdownProps {
|
|
|
10
10
|
*/
|
|
11
11
|
showBackTop?: boolean;
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* 是否将 mermaid 代码块渲染为图表
|
|
14
|
+
*/
|
|
15
|
+
enableMermaid?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated 旧名,等价于 enableMermaid
|
|
14
18
|
*/
|
|
15
19
|
isSlotMermaid?: boolean;
|
|
16
20
|
/**
|
|
17
|
-
*
|
|
21
|
+
* 是否显示代码折叠按钮
|
|
22
|
+
*/
|
|
23
|
+
showCollapseButton?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* @deprecated 旧名,等价于 showCollapseButton
|
|
18
26
|
*/
|
|
19
27
|
isShowCollapsed?: boolean;
|
|
20
28
|
/**
|
|
@@ -26,10 +34,9 @@ export interface RenderMarkdownProps {
|
|
|
26
34
|
*/
|
|
27
35
|
footer?: React.ReactNode;
|
|
28
36
|
/**
|
|
29
|
-
*
|
|
30
|
-
* HTMLElement
|
|
37
|
+
* 返回顶部所依赖的容器,默认 document.body(仅在首次渲染时读取)
|
|
31
38
|
*/
|
|
32
|
-
backTopTarget?: HTMLElement;
|
|
39
|
+
backTopTarget?: HTMLElement | null;
|
|
33
40
|
/**
|
|
34
41
|
* 是否显示新手引导
|
|
35
42
|
*/
|
|
@@ -39,30 +46,68 @@ export interface RenderMarkdownProps {
|
|
|
39
46
|
*/
|
|
40
47
|
isPrintPreview?: boolean;
|
|
41
48
|
/**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
* 渲染前对 mermaid 源码进行改写(初始化语义:仅首次传入生效)
|
|
50
|
+
*/
|
|
51
|
+
transformSource?: (text: string) => string;
|
|
52
|
+
/**
|
|
53
|
+
* @deprecated 旧名,等价于 transformSource
|
|
54
|
+
*/
|
|
45
55
|
chartConfig?: (text: string) => string;
|
|
46
56
|
/**
|
|
47
|
-
*
|
|
57
|
+
* 代码块默认是否折叠
|
|
48
58
|
*/
|
|
49
59
|
defaultCollapsed?: boolean;
|
|
50
60
|
/**
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
* content 变化后工具栏/mermaid 扫描的防抖延迟(ms),默认 100(初始化语义)
|
|
62
|
+
*/
|
|
63
|
+
toolbarDebounceMs?: number;
|
|
64
|
+
/**
|
|
65
|
+
* @deprecated 旧名,等价于 toolbarDebounceMs
|
|
66
|
+
*/
|
|
53
67
|
mermaidDebounce?: number;
|
|
54
68
|
/**
|
|
55
|
-
* 自定义 CDN 配置,如 { mermaid: 'https://...' }
|
|
69
|
+
* 自定义 CDN 配置,如 { mermaid: 'https://...' }(初始化语义:mermaid 库全局仅加载一次)
|
|
56
70
|
*/
|
|
57
71
|
cdn?: Record<string, string>;
|
|
58
72
|
/**
|
|
59
|
-
* 自定义 markdown-it
|
|
73
|
+
* 自定义 markdown-it 渲染器插件列表,在内部渲染器之后按序执行(初始化语义)
|
|
60
74
|
*/
|
|
61
75
|
customRenderers?: MarkdownPlugin[];
|
|
62
76
|
/**
|
|
63
|
-
*
|
|
64
|
-
* 如:['.copy-password-container']
|
|
77
|
+
* 图片预览排除名单(实例级):位于这些容器内的图片不会进入预览列表,
|
|
78
|
+
* 如:['.copy-password-container']。全局名单请用 addExcludedSelector/removeExcludedSelector
|
|
65
79
|
*/
|
|
66
80
|
excludedSelectors?: string[];
|
|
81
|
+
/**
|
|
82
|
+
* 是否显示目录(TOC)按钮和侧边栏
|
|
83
|
+
*/
|
|
84
|
+
showToc?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* 是否启用增量渲染(使用 morphdom 进行 DOM 差异化更新)
|
|
87
|
+
* 适用于流式输出或编辑器场景,避免全量重绘导致的状态丢失。
|
|
88
|
+
* 初始化语义:渲染途中变更不生效
|
|
89
|
+
*/
|
|
90
|
+
incremental?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* @deprecated 旧名,等价于 incremental
|
|
93
|
+
*/
|
|
94
|
+
useIncremental?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* 增量渲染节流时间(ms),默认 16(初始化语义)
|
|
97
|
+
*/
|
|
98
|
+
incrementalThrottleMs?: number;
|
|
99
|
+
/**
|
|
100
|
+
* 是否渲染源码中的原生 HTML。默认 true(历史行为);
|
|
101
|
+
* 渲染不可信内容(AI 输出/用户上传)时建议设为 false
|
|
102
|
+
*/
|
|
103
|
+
html?: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* 覆盖链接校验(初始化语义)。不传则用本库默认 `defaultValidateLink`:
|
|
106
|
+
* markdown-it 原生名单(拒 javascript:/vbscript:/file: 与绝大多数 data: URI,仅放行
|
|
107
|
+
* `data:image/(gif|png|jpeg|webp);`)+ 额外放行无脚本特征的 `data:image/svg+xml` 内联图。
|
|
108
|
+
* 传入则整体接管,要保留库默认可写
|
|
109
|
+
* `validateLink={(url) => myRule(url) || defaultValidateLink(url)}`
|
|
110
|
+
*/
|
|
111
|
+
validateLink?: (url: string) => boolean;
|
|
67
112
|
}
|
|
68
113
|
export default function RenderMarkdown(props: RenderMarkdownProps): React.JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Token } from 'markdown-it';
|
|
2
|
+
/** 未闭合围栏的 <code> 上追加的标记 class(无样式,仅供上层判断"这段还没写完") */
|
|
3
|
+
export declare const FENCE_OPEN_CLASS = "md-fence-open";
|
|
4
|
+
/**
|
|
5
|
+
* 给「源码末尾尚未闭合」的围栏代码块打标记。
|
|
6
|
+
*
|
|
7
|
+
* 为什么需要:流式(打字机/SSE)输出时,最后一个 ``` 围栏常常只有开头没有结尾,
|
|
8
|
+
* 而 markdown-it 的 fence 规则在找不到闭合行时会吞到输入末尾、照常产出一个 code token
|
|
9
|
+
* (见其源码:haveEndMarker 只用于推进 state.line,**不会记录到 token 上**)。
|
|
10
|
+
* 于是残缺的 Mermaid 源码被当成完整图表送去 mermaid.render(),
|
|
11
|
+
* 每个增量片段都必然抛 Parse error(实测 67 个前缀里 31 个失败),表现为控制台刷屏 + 红框闪现。
|
|
12
|
+
*
|
|
13
|
+
* 判定规则按 CommonMark:只有最后一个 fence token 可能未闭合(未闭合围栏会吞掉其后全部内容),
|
|
14
|
+
* 闭合行需与起始行同种标记、长度不小于起始行、且该行之后只有空白。
|
|
15
|
+
*/
|
|
16
|
+
export declare function markUnclosedFence(tokens: Token[], src: string): void;
|
|
@@ -5,14 +5,35 @@ export type AnchorItem = {
|
|
|
5
5
|
nodeName: string;
|
|
6
6
|
children: AnchorItem[];
|
|
7
7
|
};
|
|
8
|
+
export interface RenderMarkdownOptions {
|
|
9
|
+
/**
|
|
10
|
+
* 是否渲染源码中的原生 HTML 标签。
|
|
11
|
+
* 默认 true(历史行为)。渲染不可信内容(AI 输出、用户上传)时建议设为 false。
|
|
12
|
+
*/
|
|
13
|
+
html?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* 覆盖链接校验。
|
|
16
|
+
* 缺省用本库默认(`defaultValidateLink`):markdown-it 原生名单 + 额外放行无脚本特征的
|
|
17
|
+
* `data:image/svg+xml` 内联图(原生不认 svg,`` 会退化成源码)。
|
|
18
|
+
* 传入本项则**整体接管**:要保留库默认可用
|
|
19
|
+
* `validateLink={(url) => myRule(url) || defaultValidateLink(url)}`。
|
|
20
|
+
* 不要把“方便”写成 `() => true` —— 那会连带放行 javascript:/vbscript:/file: 等危险协议。
|
|
21
|
+
* 初始化语义:随本次渲染调用生效,不保留上一例的覆盖。
|
|
22
|
+
*/
|
|
23
|
+
validateLink?: (url: string) => boolean;
|
|
24
|
+
}
|
|
8
25
|
/** markdown-it 插件函数类型 */
|
|
9
26
|
export type MarkdownPlugin = (md: any) => void;
|
|
10
|
-
|
|
27
|
+
/**
|
|
28
|
+
* 渲染 Markdown 为 HTML,并返回自动采集的标题锚点树。
|
|
29
|
+
* KaTeX 为 CDN 懒加载:加载失败不抛错,公式降级为原文并 console.warn。
|
|
30
|
+
*/
|
|
31
|
+
declare function renderMarkdown(content: string, customPlugins?: MarkdownPlugin[], options?: RenderMarkdownOptions): Promise<{
|
|
11
32
|
anchor: AnchorItem[];
|
|
12
33
|
info: string;
|
|
13
34
|
}>;
|
|
14
35
|
/**
|
|
15
|
-
*
|
|
36
|
+
* 初始化高亮语言包(hljs 为 external 依赖,需由使用方注册语言后才会高亮)
|
|
16
37
|
* @param {Object} languages - 语言包对象,如 { javascript: javascriptModule, css: cssModule }
|
|
17
38
|
*/
|
|
18
39
|
export declare function initHighlighter(languages: Record<string, any> | null | undefined): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 本库默认的链接校验(覆盖 markdown-it 的 validateLink)
|
|
3
|
+
*
|
|
4
|
+
* markdown-it 原生只放行 `data:image/(gif|png|jpeg|webp);`,`data:image/svg+xml` 会被判为不安全链接,
|
|
5
|
+
* 结果是 `` 整行退化成源码文本 —— 图标、图表、AI 产出的内联 svg 全中招。
|
|
6
|
+
* 这里在原生名单之上**只额外**放行内联 svg,其余协议(javascript:/vbscript:/file: 与其它 data:)
|
|
7
|
+
* 一律照旧拒绝。
|
|
8
|
+
*
|
|
9
|
+
* 为什么放行 svg 还需要额外过滤:validateLink 同时作用于图片语法和链接语法,
|
|
10
|
+
* `<img src="data:image/svg+xml,...">` 本身是惰性的(规范里 SVG 作为图片不执行脚本、不加载外部资源),
|
|
11
|
+
* 但 `<a href="data:image/svg+xml,...">` 被导航时 SVG 会作为**文档**渲染,脚本可执行。
|
|
12
|
+
* 因此对 svg 载荷做一次可执行特征检查,命中就拒。这是纵深防御的启发式过滤,不是沙箱;
|
|
13
|
+
* 渲染真正不可信的内容仍应把 `html={false}` 打开,必要时传入更严的 validateLink。
|
|
14
|
+
*/
|
|
15
|
+
/** 本库默认链接校验:markdown-it 名单 + 无脚本特征的内联 svg */
|
|
16
|
+
export declare function defaultValidateLink(url: string): boolean;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface AnchorItem {
|
|
2
|
+
href: string;
|
|
3
|
+
title: string;
|
|
4
|
+
children: AnchorItem[];
|
|
5
|
+
nodeName: string;
|
|
6
|
+
nodeTitle: string;
|
|
7
|
+
}
|
|
8
|
+
interface TocSidebarProps {
|
|
9
|
+
anchors: AnchorItem[];
|
|
10
|
+
activeId: string;
|
|
11
|
+
visible: boolean;
|
|
12
|
+
onClose: () => void;
|
|
13
|
+
}
|
|
14
|
+
declare function TocSidebar({ anchors, activeId, visible, onClose }: TocSidebarProps): import("react").JSX.Element | null;
|
|
15
|
+
export default TocSidebar;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { MarkdownPlugin, AnchorItem, RenderMarkdownOptions } from '../components/RenderMarkdown/utils/render-markdown';
|
|
2
|
+
import { MD_PERSIST_ATTR } from '../utils/dom-contract';
|
|
3
|
+
export { MD_PERSIST_ATTR };
|
|
4
|
+
interface UseIncrementalRenderOptions {
|
|
5
|
+
/** Markdown 内容 */
|
|
6
|
+
content: string;
|
|
7
|
+
/**
|
|
8
|
+
* 代码类型包装
|
|
9
|
+
* 初始化语义:仅在挂载时读取,渲染途中变更不生效
|
|
10
|
+
*/
|
|
11
|
+
codeType?: string;
|
|
12
|
+
/**
|
|
13
|
+
* 自定义 markdown-it 插件
|
|
14
|
+
* 初始化语义:仅在挂载时读取,渲染途中变更不生效
|
|
15
|
+
*/
|
|
16
|
+
customRenderers?: MarkdownPlugin[];
|
|
17
|
+
/**
|
|
18
|
+
* 增量渲染节流时间(ms),默认 16(~60fps)
|
|
19
|
+
* 初始化语义:仅在挂载时读取
|
|
20
|
+
* 真节流语义:首个内容变化立即渲染,期间的新变化最多每 throttleMs 渲染一次(含收尾)
|
|
21
|
+
*/
|
|
22
|
+
throttleMs?: number;
|
|
23
|
+
/**
|
|
24
|
+
* 是否渲染源码中的原生 HTML(安全开关)。
|
|
25
|
+
* 初始化语义:仅在挂载时读取;缺省 true。
|
|
26
|
+
* 修复前增量模式没把该开关透传给 renderMarkdown,导致 html=false 只在非增量模式下生效。
|
|
27
|
+
*/
|
|
28
|
+
html?: RenderMarkdownOptions['html'];
|
|
29
|
+
/**
|
|
30
|
+
* 覆盖链接校验(缺省不传则用本库默认 defaultValidateLink:markdown-it 名单 + 放行内联 svg 图)。
|
|
31
|
+
* 初始化语义:仅在挂载时读取;传入则整体接管,只对可信内容放宽
|
|
32
|
+
*/
|
|
33
|
+
validateLink?: RenderMarkdownOptions['validateLink'];
|
|
34
|
+
/**
|
|
35
|
+
* 节点被 morphdom diff 移除后触发(含被移除子树的递归子节点)。
|
|
36
|
+
* 用于清理挂在被移除节点上的 React Root、监听器等状态。
|
|
37
|
+
*/
|
|
38
|
+
onNodeDiscarded?: (el: HTMLElement) => void;
|
|
39
|
+
/**
|
|
40
|
+
* 每次 DOM patch 完成后同步触发(浏览器绘制前)。
|
|
41
|
+
* 用于恢复被 diff 丢弃的运行时标记(如代码块工具栏的动态 class / 语言标签)。
|
|
42
|
+
*/
|
|
43
|
+
onPatched?: () => void;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 增量渲染 hook,使用 morphdom 进行部分 DOM 更新。
|
|
47
|
+
*
|
|
48
|
+
* - 首次渲染:使用 innerHTML 设置初始内容
|
|
49
|
+
* - 后续渲染:渲染为字符串,然后通过 morphdom patch 容器
|
|
50
|
+
* - 节流 patch 调用(真节流:首次立即执行 + 周期收尾),避免流式输出期间过多 DOM 操作
|
|
51
|
+
* - 渲染序号保证内容变化后,飞行中的渲染结果不会污染新状态
|
|
52
|
+
* - 按"标签 + className"语义 key 匹配节点,保护 customRenderers(插件)产出的容器状态
|
|
53
|
+
* - 保留节点上 JS 添加的 data-* 属性(初始化守卫位),避免 patch 后被重复初始化
|
|
54
|
+
* - 返回 inner 内容 <div> 的 ref 回调
|
|
55
|
+
*
|
|
56
|
+
* 注意:除 content 外的所有选项均为**初始化语义**——仅在挂载时读取一次,
|
|
57
|
+
* 渲染途中变更不生效(customRenderers / codeType / throttleMs 等)。
|
|
58
|
+
*/
|
|
59
|
+
export declare function useIncrementalRender({ content, codeType, customRenderers, throttleMs, html, validateLink, onNodeDiscarded, onPatched, }: UseIncrementalRenderOptions): {
|
|
60
|
+
anchors: AnchorItem[];
|
|
61
|
+
hasContent: boolean;
|
|
62
|
+
setInnerRef: (node: HTMLDivElement | null) => void;
|
|
63
|
+
};
|
|
64
|
+
export default useIncrementalRender;
|
package/dist/hooks/useTheme.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
+
export type ThemeMode = "light" | "dark" | "system";
|
|
2
3
|
export interface UseThemeReturn {
|
|
3
4
|
theme: string;
|
|
4
|
-
mode:
|
|
5
|
+
mode: ThemeMode;
|
|
5
6
|
isDark: boolean;
|
|
6
|
-
setMode: (mode:
|
|
7
|
+
setMode: (mode: ThemeMode) => void;
|
|
7
8
|
}
|
|
8
9
|
export interface ThemeProviderProps {
|
|
9
10
|
children: React.ReactNode;
|
|
@@ -11,6 +12,11 @@ export interface ThemeProviderProps {
|
|
|
11
12
|
declare const THEME_LIGHT = "light";
|
|
12
13
|
declare const THEME_DARK = "dark";
|
|
13
14
|
declare const THEME_SYSTEM = "system";
|
|
15
|
+
/**
|
|
16
|
+
* 同步应用已存储的主题(防 FOUC)。
|
|
17
|
+
* 库不再在 import 时产生全局副作用;使用方需在应用入口(或 index.html 内联脚本)主动调用。
|
|
18
|
+
*/
|
|
19
|
+
export declare function initTheme(): void;
|
|
14
20
|
export declare function ThemeProvider({ children }: ThemeProviderProps): React.FunctionComponentElement<React.ProviderProps<UseThemeReturn | null>>;
|
|
15
21
|
export declare function useTheme(): UseThemeReturn;
|
|
16
22
|
export { THEME_LIGHT, THEME_DARK, THEME_SYSTEM };
|