@linloir/limr 1.0.0 → 1.0.1
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/README.en.md +36 -8
- package/README.md +36 -8
- package/benchmarks/results/layout.json +2593 -0
- package/benchmarks/results/markstream-code.json +1823 -0
- package/benchmarks/results/markstream-reading-repeat.json +1152 -0
- package/benchmarks/results/markstream.json +12486 -0
- package/benchmarks/results/streaming-browser.json +77 -0
- package/benchmarks/results/streaming.json +357 -0
- package/dist/base.css +83 -3
- package/dist/{chunk-TTISGBST.js → chunk-BG5QUQFR.js} +327 -72
- package/dist/chunk-BG5QUQFR.js.map +1 -0
- package/dist/chunk-BVHHOVMT.js +179 -0
- package/dist/chunk-BVHHOVMT.js.map +1 -0
- package/dist/chunk-FJZCQY2S.js +155 -0
- package/dist/chunk-FJZCQY2S.js.map +1 -0
- package/dist/chunk-FSI5OTBW.js +1 -0
- package/dist/{chunk-N77VD2YR.js → chunk-GU2RPESF.js} +145 -83
- package/dist/chunk-GU2RPESF.js.map +1 -0
- package/dist/{chunk-3ILUZKDB.js → chunk-SUAAUGAX.js} +1280 -501
- package/dist/chunk-SUAAUGAX.js.map +1 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +13 -5
- package/dist/extensions/index.d.ts +30 -5
- package/dist/extensions/index.js +15 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +27 -8
- package/dist/{engine-43u8B4yt.d.ts → knuth-plass-C8mgFm7W.d.ts} +67 -1
- package/dist/knuth-plass-layout-CHQCWKB5.js +449 -0
- package/dist/knuth-plass-layout-CHQCWKB5.js.map +1 -0
- package/dist/react/index.d.ts +5 -4
- package/dist/react/index.js +5 -3
- package/dist/styles.css +83 -3
- package/dist/{translations-DHnYMg4h.d.ts → translations-BXzSwLBJ.d.ts} +39 -2
- package/docs/en/README.md +8 -6
- package/docs/en/annotations.md +3 -1
- package/docs/en/api.md +9 -1
- package/docs/en/architecture.md +11 -3
- package/docs/en/extensions.md +53 -4
- package/docs/en/getting-started.md +2 -0
- package/docs/en/integration.md +26 -2
- package/docs/en/modules.md +9 -5
- package/docs/en/performance.md +42 -2
- package/docs/en/styles.md +21 -2
- package/docs/en/syntax.md +118 -15
- package/docs/zh-CN/README.md +8 -6
- package/docs/zh-CN/annotations.md +3 -1
- package/docs/zh-CN/api.md +9 -1
- package/docs/zh-CN/architecture.md +11 -3
- package/docs/zh-CN/extensions.md +55 -4
- package/docs/zh-CN/getting-started.md +2 -0
- package/docs/zh-CN/integration.md +26 -2
- package/docs/zh-CN/modules.md +9 -5
- package/docs/zh-CN/performance.md +42 -2
- package/docs/zh-CN/styles.md +21 -2
- package/docs/zh-CN/syntax.md +120 -15
- package/package.json +9 -1
- package/skills/limr-plugin-development/references/contract.md +9 -3
- package/skills/limr-use/references/integration.md +11 -3
- package/skills/limr-use/references/syntax.md +8 -5
- package/dist/chunk-3ILUZKDB.js.map +0 -1
- package/dist/chunk-N77VD2YR.js.map +0 -1
- package/dist/chunk-TTISGBST.js.map +0 -1
- package/dist/chunk-V2OG4Y3F.js +0 -1
- /package/dist/{chunk-V2OG4Y3F.js.map → chunk-FSI5OTBW.js.map} +0 -0
package/docs/zh-CN/styles.md
CHANGED
|
@@ -39,7 +39,8 @@ appearance 会传给 portal 中的浮层/工具栏;不要只用 `.limr-reader
|
|
|
39
39
|
| --- | --- |
|
|
40
40
|
| --limr-font-text / --limr-font-code | 正文 / 代码字体 |
|
|
41
41
|
| --limr-font-size / --limr-line-height | 基础排版 |
|
|
42
|
-
| --limr-font-features | 正文默认 'palt' 1
|
|
42
|
+
| --limr-font-features | 正文默认 normal,保留中文全角标点;可显式设置 'palt' 1 启用比例标点 |
|
|
43
|
+
| --limr-punctuation-spacing | 默认 space-all,保留连续中文标点的全角空白 |
|
|
43
44
|
| --limr-emphasis-spacing / --limr-list-item-gap | 斜体末尾 / 列表间距 |
|
|
44
45
|
| --limr-text / --limr-heading / --limr-secondary / --limr-muted | 文字层次 |
|
|
45
46
|
| --limr-background / --limr-surface / --limr-border | 背景和边框 |
|
|
@@ -54,6 +55,8 @@ appearance 会传给 portal 中的浮层/工具栏;不要只用 `.limr-reader
|
|
|
54
55
|
| --limr-overflow-fade-size | 溢出渐隐,默认 24px,0px 关闭 |
|
|
55
56
|
| --limr-toolbar-panel-max-height | 工具栏面板高度上限 |
|
|
56
57
|
| --limr-tool-icon-size / --limr-mark-size | 工具图标 / 正文角标尺寸 |
|
|
58
|
+
| --limr-mermaid-max-height | 图表视口最大高度;默认 min(70vh, 36rem) |
|
|
59
|
+
| --limr-mermaid-scrollbar | 图表细滚动条颜色;默认 #87837866 |
|
|
57
60
|
|
|
58
61
|
runtime 测量的 --limr-toolbar-available-height、--limr-toolbar-panel-height、--limr-toc-available-height 是布局输出,不应由主题覆盖。sidebar 的局部颜色通常由 AnnotationType.sidebar 配置提供,见[扩展开发](extensions.md)。
|
|
59
62
|
|
|
@@ -71,10 +74,26 @@ Maple Mono NF CN v7.9 的本地 WOFF2 子集随包分发,衍生字体名为 Li
|
|
|
71
74
|
|
|
72
75
|
密集的文末引用在静止时向上借用空余空间。悬浮或激活时优先对齐当前条目,允许邻项在边缘裁切;角标悬浮时可压缩可选摘要,为关联区和标题留出空间。展开内容受可见阅读区域高度限制,并可在卡片内滚动。侧栏条目即使被向上收拢,也会反向对齐正文。取消激活后按当前卡片高度平滑回位,使用 `--limr-motion-slow` 和 `--limr-ease`,保持卡片间距与页面高度。
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
选区保留原生浏览器范围与键盘行为,绘制层只计算可见片段。代码支持局部高亮,公式整体选择,图片高亮使用边框。单个整块选区的工具栏定位在块下方。打印隐藏绘制层并保留正文。移动端自动化检查不等于 iOS/Android 原生拖动手柄和真机验收。
|
|
78
|
+
|
|
79
|
+
选区工具栏的复制反馈使用淡入淡出与轻微缩放。按钮文字宽度随当前状态增长或收缩,均通过 `--limr-ease` 非线性过渡;减少动态效果设置会关闭这些过渡。
|
|
80
|
+
|
|
81
|
+
Mermaid 图像支持拖拽平移、触摸和触控板滚动、方向键、Page Up/Down、Home/End,以及 Shift+滚轮横向移动;单击或 Enter 整块选择,拖动不会选中内部文字。缩放仅改变有限高度视口内的内容。共享磨砂工具栏在悬浮或获得焦点时显示,触屏常显;按钮只做背景淡入,不缩放。源码模式保留正常顶部内边距。主题和插件可在 Reader 或图表块上覆盖最大高度与滚动条变量。
|
|
75
82
|
|
|
76
83
|
## 仅 CSS 的独立主题
|
|
77
84
|
|
|
78
85
|
包可导出 CSS,files 包含 CSS,sideEffects 为 `["**/*.css"]`;不需要 React 或解析器运行时依赖。规则用独立 appearance 名隔离,覆盖浅色、深色、auto 和 portal,并在同页两个不同主题 Reader 中检查。
|
|
79
86
|
|
|
80
87
|
展开工具栏面板使用工具栏的全部可用宽度。宽度由当前操作按钮行与可用视口决定,展开内容不参与工具栏的固有宽度计算,不会反向撑大工具栏。高亮样式按钮按文字自然宽度排列,空间不足时整项换行并左对齐。多行下划线需要保持内部 span 为 inline,不把它直接作为 flex 子项。
|
|
88
|
+
|
|
89
|
+
## 段落排版与流式效果
|
|
90
|
+
|
|
91
|
+
`typography="standard"` 为默认模式;`justify` 使用浏览器两端对齐;`knuth-plass` 使用 TeX 的 box/glue/penalty 动态规划:四种适配类别、整数 badness、独立平方惩罚、连续与末行断词惩罚,以及 pretolerance、tolerance、emergency 多轮求解。整段求最优解,不使用 beam search 或段落长度截断。默认英文断词采用 Knuth–Liang 模式,Unicode 断行规则同时处理中文标点。字形由浏览器测量,因此不承诺与 TeX PDF 逐像素相同。
|
|
92
|
+
|
|
93
|
+
`knuthPlass` 可配置 `pretolerance`、`tolerance`、`linePenalty`、`hyphenPenalty`、`adjacentDemerits`、`doubleHyphenDemerits`、`finalHyphenDemerits`、`emergencyStretch`(CSS 像素)、`looseness` 和 `hyphenate`(`false` 或返回单词分段的函数)。核心段落参数沿用 TeX 常用默认值,额外提供 16px 应急伸展量;浏览器适配器默认按字号换算为 3em,仅参与断行评估,可用 `knuthPlass.emergencyStretch` 显式覆盖。`pretty` / `normal` 保留为可选的旧版 CSS 模式。
|
|
94
|
+
|
|
95
|
+
KP 按需加载,对视口附近的稳定段落排版;离开视口后保留 DOM,宽度变化时复用测量结果与前缀和,更新前保护原生选区。窗口缩小时,屏外缓存行暂时裁切横向溢出,进入视口后完成精确排版;仍被选中的段落暂时允许换行并保留原生选区。流式尾段稳定后再排版,不改变源码、标注位置或复制内容。滚动和缩放对照见[性能](performance.md),算法依据见 [TeX 源码](https://github.com/TeX-Live/texlive-source/blob/trunk/texk/web2c/tex.web)。测量准备与断行分离的设计也参考了 [Typst 的增量排版实现](https://github.com/typst/typst/tree/main/crates/typst-layout/src/inline)。
|
|
96
|
+
|
|
97
|
+
默认 loading 使用固定 32×32 viewBox、22px 显示尺寸、粗轨道和伸缩弧线;旋转、增长、收缩均为非线性缓动,围绕固定圆心运动,颜色跟随 `--limr-secondary`。新增文字与特殊块只做透明度淡入,不增加背景色,段落结束时不再次播放出现动画。插件可用 `streaming.effect` 替换共享动画,Reader 可用 `streamEffect` 单独覆盖。
|
|
98
|
+
|
|
99
|
+
源码高亮的默认蓝色由 `--limr-inline-highlight` 控制,也可通过 `inlineHighlights({ color })` 替换模块。默认只读工具栏的说明可用 `locale.inlineHighlightHint` 本地化。
|
package/docs/zh-CN/syntax.md
CHANGED
|
@@ -6,22 +6,26 @@
|
|
|
6
6
|
|
|
7
7
|
**模块**是为 LiMR 增加一组能力的配置对象,例如公式、视频或引用。下面的“创建函数”在应用代码中调用,返回模块对象;“模块名”是对象的 `name` 字段,用于替换和移除;“标签 / 指令”才是写在 Markdown 正文中的语法。完整概念和配置方式见[内置模块](modules.md)。
|
|
8
8
|
|
|
9
|
-
`@linloir/limr`
|
|
9
|
+
`@linloir/limr` 随包提供以下默认模块。`Reader`、独立 `Markdown` 和 `DocumentProvider` 默认通过 `standard()` 全部启用;纯核心 `createDocument()` 默认只有 CommonMark。下面每节给出源码和实际效果,交互示例由 LiMR 自己渲染。
|
|
10
10
|
|
|
11
11
|
## 模块清单
|
|
12
12
|
|
|
13
13
|
| 创建函数(应用代码) | 模块名(name) | 默认能力 | 注册的特殊标签 / 指令 |
|
|
14
14
|
| --- | --- | --- | --- |
|
|
15
|
-
| `gfm()` | `gfm` | 表格、删除线、任务列表、自动链接、标准脚注 |
|
|
16
|
-
| `math()` | `math` | 行内与块级公式 |
|
|
17
|
-
| `codeHighlight()` | `code-highlight` | Shiki 围栏代码高亮 |
|
|
18
|
-
| `definition()` | `definition` | 释义 | 标签 `definition`、`title`、`content
|
|
19
|
-
| `question()` | `question` | 练习题与答案 | 标签
|
|
20
|
-
| `extras()` | `extras` | 拓展阅读 | 标签 `extras`、`extra
|
|
21
|
-
| `video()` | `video` | 原生视频、YouTube、Bilibili | 标签 `video`、`md-video
|
|
22
|
-
| `figures()` | `figures` | 图组与图注 | 标签 `figures`、`figure`、`figcaption`、`caption`、`img
|
|
23
|
-
| `citation()` | `citation` | 引用定义与角标 | 标签 `citation`、`ref
|
|
15
|
+
| `gfm()` | `gfm` | 表格、删除线、任务列表、自动链接、标准脚注 | `::gfm` |
|
|
16
|
+
| `math()` | `math` | 行内与块级公式 | `$…$`、`$$…$$`、`::math` |
|
|
17
|
+
| `codeHighlight()` | `code-highlight` | Shiki 围栏代码高亮 | 标准代码围栏、`::code` / `::code-highlight` |
|
|
18
|
+
| `definition()` | `definition` | 释义 | 标签 / 指令 `definition`、`title`、`content` |
|
|
19
|
+
| `question()` | `question` | 练习题与答案 | 标签 / 指令 `question` 及下文子标签 |
|
|
20
|
+
| `extras()` | `extras` | 拓展阅读 | 标签 / 指令 `extras`、`extra` |
|
|
21
|
+
| `video()` | `video` | 原生视频、YouTube、Bilibili | 标签 / 指令 `video`、`md-video` |
|
|
22
|
+
| `figures()` | `figures` | 图组与图注 | 标签 / 指令 `figures`、`figure`、`figcaption`、`caption`、`img` |
|
|
23
|
+
| `citation()` | `citation` | 引用定义与角标 | 标签 / 指令 `citation`、`ref` |
|
|
24
24
|
| `translations()` | `translations` | 原文、译文与对照 | 标签及指令 `translations`、`origin`、`translation` |
|
|
25
|
+
| `mermaid()` | `mermaid` | 流程图等 Mermaid 图表 | Mermaid 围栏、`::mermaid` |
|
|
26
|
+
| `callout()` | `callout` | 有类型、标题、折叠状态的注释块 | `> [!type]`、`::callout` |
|
|
27
|
+
| `inlineHighlights()` | `inline-highlights` | 源码内嵌高亮 | `==文字==`、`::highlight` |
|
|
28
|
+
| `footnotes()` | `footnotes` | 评论角标和脚注卡片 | `[^id]`、`^[正文]`、`::footnote`、`::footnote-ref` |
|
|
25
29
|
|
|
26
30
|
这些是 Markdown 中允许的静态标签,不是任意 MDX/HTML 执行环境。使用字符串属性,如 `multi="true"`、`answer="[0,2]"`;不要使用 `answer={[0,2]}`、事件函数或展开属性。未注册 HTML 按文本显示;表达式不执行并可能产生诊断。嵌套块的标签和正文之间保留空行。
|
|
27
31
|
|
|
@@ -48,7 +52,7 @@ const value = 42;
|
|
|
48
52
|
|
|
49
53
|
标准脚注[^note]。
|
|
50
54
|
|
|
51
|
-
[^note]:
|
|
55
|
+
[^note]: 以角标和侧栏 / 窄屏卡片显示的脚注内容。
|
|
52
56
|
````
|
|
53
57
|
|
|
54
58
|
实际效果(可交互):
|
|
@@ -73,9 +77,9 @@ const value = 42;
|
|
|
73
77
|
|
|
74
78
|
标准脚注[^syntax-note]。
|
|
75
79
|
|
|
76
|
-
[^syntax-note]:
|
|
80
|
+
[^syntax-note]: 以角标和侧栏 / 窄屏卡片显示的脚注内容。
|
|
77
81
|
|
|
78
|
-
|
|
82
|
+
默认 `[^note]` 显示脚注角标和卡片;移除 `footnotes` 模块后,GFM 仍可渲染传统文末脚注。图片 `` 由普通 Markdown 支持。原始 HTML 不透传到 DOM;需要自定义外观时注册扩展或覆盖 `components`。
|
|
79
83
|
|
|
80
84
|
## 公式与代码
|
|
81
85
|
|
|
@@ -95,7 +99,7 @@ $$
|
|
|
95
99
|
\int_0^1 x^2\,dx = \frac{1}{3}
|
|
96
100
|
$$
|
|
97
101
|
|
|
98
|
-
公式需要导入 `@linloir/limr/math.css`;支持通过 `math({ macros, strict })` 配置。代码围栏语言用于 Shiki
|
|
102
|
+
公式需要导入 `@linloir/limr/math.css`;支持通过 `math({ macros, strict })` 配置。代码围栏语言用于 Shiki 高亮。默认接近视口才加载高亮,流式代码等待语法闭合,且原生选区离开代码后再应用高亮;超过默认 100,000 字符、未支持或未在允许列表中的语言保留可读源码。`codeHighlight({ languages, lightTheme, darkTheme, eager, maxLength })` 可配置。
|
|
99
103
|
|
|
100
104
|
## 释义
|
|
101
105
|
|
|
@@ -349,4 +353,105 @@ Original **Markdown**.
|
|
|
349
353
|
|
|
350
354
|
## 选择与替换
|
|
351
355
|
|
|
352
|
-
|
|
356
|
+
工具栏创建的高亮存为 annotation;`==高亮==` 由源码定义,只提供复制工具栏。默认模块的全部已注册标签都支持同名 `::` 指令。自定义标签需注册插件。使用完整清单配置或替换默认模块,见[扩展开发](extensions.md)。
|
|
357
|
+
|
|
358
|
+
## 双冒号组件写法
|
|
359
|
+
|
|
360
|
+
所有默认模块都支持 [CoMark 的组件写法](https://comark.dev/syntax/components),包括嵌套、标量属性和 Markdown 正文:
|
|
361
|
+
|
|
362
|
+
```md
|
|
363
|
+
::definition{title="定义"}
|
|
364
|
+
支持 **富文本** 的正文。
|
|
365
|
+
::
|
|
366
|
+
|
|
367
|
+
::question{title="一道题"}
|
|
368
|
+
::question-content
|
|
369
|
+
题目内容。
|
|
370
|
+
::
|
|
371
|
+
::question-answer
|
|
372
|
+
答案内容。
|
|
373
|
+
::
|
|
374
|
+
::
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
可用名称包括 `gfm`、`definition`、`title`、`content`、`question` 及其已有子标签、`extras`、`extra`、`video`、`md-video`、`figures`、`figure`、`figcaption`、`caption`、`img`、`citation`、`ref`、`translations`、`origin`、`translation`、`code`(别名 `code-highlight`)、`math`、`mermaid`、`callout`、`highlight`、`footnote`、`footnote-ref`。`::code{lang="typescript"}` 与 `::math` 的正文保持字面量。
|
|
378
|
+
|
|
379
|
+
标准 Markdown 围栏、JSX、单冒号行内指令和原有三冒号容器继续可用。最终文档中没有配对闭合的双冒号行,保留原有 leaf directive 语义。这里兼容的是组件语法,不包含 CoMark 的 YAML 属性、命名插槽和 frontmatter。
|
|
380
|
+
|
|
381
|
+
流式过程中,半截头部、链接、行内代码/强调/公式符号和表头会暂缓显示;已识别但未闭合的组件携带 `incomplete`,由模块选择 loading 或渐进内容。代码围栏和块公式可在闭合前展示。结束时设置 `streaming={false}` 或调用 `finish()`,恢复普通 Markdown 的最终解释。所有范围始终对应未改写的原始输入。
|
|
382
|
+
|
|
383
|
+
## Mermaid 图表
|
|
384
|
+
|
|
385
|
+
````markdown
|
|
386
|
+
```mermaid
|
|
387
|
+
flowchart LR
|
|
388
|
+
A[开始] --> B{准备好了吗}
|
|
389
|
+
B --> C[继续阅读]
|
|
390
|
+
```
|
|
391
|
+
````
|
|
392
|
+
|
|
393
|
+
也可使用 `::mermaid`。流式闭合前显示 loading,完成后异步加载 Mermaid 并淡入图像。背景与公式块一致,右上角共用圆角工具栏提供复制源码、放大、缩小、源码 / 图像切换。选区、高亮和角标以整张图为单位;源码视图不改变这个原子选择约定。图表使用 Mermaid strict 模式,不执行图中的交互回调。
|
|
394
|
+
|
|
395
|
+
实际效果:
|
|
396
|
+
|
|
397
|
+
```mermaid
|
|
398
|
+
flowchart LR
|
|
399
|
+
A[开始] --> B{准备好了吗}
|
|
400
|
+
B --> C[继续阅读]
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
图像模式支持拖动平移、方向键、Page Up/Down、Home/End 和滚轮,Shift + 滚轮横向移动;点击或 Enter 整块选择,选区工具栏位于块下方。放大后的内容在最大高度内滚动,`--limr-mermaid-max-height` 默认 `min(70vh, 36rem)`。操作栏“复制”获取图表正文,选区工具栏及浏览器复制保留完整围栏或指令。详见[样式与字体](styles.md)和[整体复制](annotations.md)。
|
|
404
|
+
|
|
405
|
+
## Callout 与嵌套注释
|
|
406
|
+
|
|
407
|
+
```markdown
|
|
408
|
+
> [!tip]+ 自定义标题
|
|
409
|
+
> 提示正文。
|
|
410
|
+
>
|
|
411
|
+
> > 普通的嵌套注释。
|
|
412
|
+
> >
|
|
413
|
+
> > > [!warning]- 可折叠的提醒
|
|
414
|
+
> > > 支持 **Markdown**。
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
默认类型为 `note`、`abstract`、`info`、`todo`、`tip`、`success`、`question`、`warning`、`failure`、`danger`、`bug`、`example`、`quote`,别名对齐 Obsidian:summary/tldr、hint/important、check/done、help/faq、caution/attention、fail/missing、error、cite。大小写不敏感,未知类型沿用 note 外观。`+` 初始展开,`-` 初始折叠;不写符号时为普通块。另支持 `::callout{type="tip" title="标题" fold="-"}`。
|
|
418
|
+
|
|
419
|
+
实际效果,可展开内部的提醒:
|
|
420
|
+
|
|
421
|
+
> [!tip]+ 自定义标题
|
|
422
|
+
> 提示正文。
|
|
423
|
+
>
|
|
424
|
+
> > 普通的嵌套注释。
|
|
425
|
+
> >
|
|
426
|
+
> > > [!warning]- 可折叠的提醒
|
|
427
|
+
> > > 支持 **Markdown**。
|
|
428
|
+
|
|
429
|
+
## 源码高亮与脚注
|
|
430
|
+
|
|
431
|
+
```markdown
|
|
432
|
+
==默认蓝色高亮==,点击后只能复制。
|
|
433
|
+
|
|
434
|
+
==有脚注的高亮==[^note]
|
|
435
|
+
|
|
436
|
+
==内联脚注==^[这里可以写 **Markdown**。]
|
|
437
|
+
|
|
438
|
+
[^note]: 脚注正文。
|
|
439
|
+
|
|
440
|
+
脚注的第二段。
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
高亮支持内部富文本,转义字符、代码和公式中的 `==` 保持字面量。高亮颜色可由 CSS `--limr-inline-highlight` 或 `inlineHighlights({ color })` 覆盖。工具栏只提供复制按钮和单行提示“Markdown 内嵌高亮,不支持编辑”。
|
|
444
|
+
|
|
445
|
+
脚注显示圆润评论角标;宽屏为侧栏 item,窄屏为悬浮卡片,标题是“脚注”。紧邻高亮的脚注引用这段高亮,独立脚注引用所在段落;命名脚注可重复引用。`::highlight`、`::footnote{id="note"}` 和 `::footnote-ref{id="note"}` 可表达相同模块的容器形式。移除 `footnotes` 模块可恢复 GFM 的上标和文末脚注。
|
|
446
|
+
|
|
447
|
+
实际效果,点击高亮或评论角标:
|
|
448
|
+
|
|
449
|
+
==默认蓝色高亮==,点击后只能复制。
|
|
450
|
+
|
|
451
|
+
==有脚注的高亮==[^syntax-source-highlight]
|
|
452
|
+
|
|
453
|
+
==内联脚注==^[这里可以写 **Markdown**。]
|
|
454
|
+
|
|
455
|
+
[^syntax-source-highlight]: 脚注正文。
|
|
456
|
+
|
|
457
|
+
脚注的第二段。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linloir/limr",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Linloir's limr Is a Markdown Renderer — extensible reading and streaming components for React",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -64,12 +64,16 @@
|
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@floating-ui/react": "^0.27.20",
|
|
67
|
+
"hyphenation.en-us": "^0.2.1",
|
|
68
|
+
"hypher": "^0.2.5",
|
|
67
69
|
"katex": "^0.19.0",
|
|
70
|
+
"linebreak": "^1.1.0",
|
|
68
71
|
"mdast-util-directive": "^3.1.1",
|
|
69
72
|
"mdast-util-from-markdown": "^2.1.0",
|
|
70
73
|
"mdast-util-gfm": "^3.1.0",
|
|
71
74
|
"mdast-util-math": "^3.0.0",
|
|
72
75
|
"mdast-util-mdx-jsx": "^3.2.0",
|
|
76
|
+
"mermaid": "^12.2.0",
|
|
73
77
|
"micromark-extension-directive": "^4.0.0",
|
|
74
78
|
"micromark-extension-gfm": "^3.0.0",
|
|
75
79
|
"micromark-extension-math": "^3.1.0",
|
|
@@ -86,12 +90,14 @@
|
|
|
86
90
|
"@types/react": "^19.3.0",
|
|
87
91
|
"@types/react-dom": "^19.3.0",
|
|
88
92
|
"@vitejs/plugin-react": "^5.2.0",
|
|
93
|
+
"markstream-react": "2.0.19",
|
|
89
94
|
"react": "^19",
|
|
90
95
|
"react-dom": "^19",
|
|
91
96
|
"react-markdown": "^10.1.0",
|
|
92
97
|
"rehype-katex": "^7.0.1",
|
|
93
98
|
"remark-gfm": "^4.0.1",
|
|
94
99
|
"remark-math": "^6.0.0",
|
|
100
|
+
"stream-diffs": "0.0.2",
|
|
95
101
|
"tsup": "^8.5.1",
|
|
96
102
|
"tsx": "^4.23.15",
|
|
97
103
|
"typescript": "^5.9.3",
|
|
@@ -110,8 +116,10 @@
|
|
|
110
116
|
"test:docs": "node scripts/check-docs.mjs",
|
|
111
117
|
"pack:skills": "python3 scripts/package-skills.py",
|
|
112
118
|
"bench": "tsx benchmarks/run.ts",
|
|
119
|
+
"bench:streaming": "tsx benchmarks/streaming.ts",
|
|
113
120
|
"bench:browser": "tsx benchmarks/browser.ts",
|
|
114
121
|
"bench:selection": "tsx benchmarks/selection.ts",
|
|
122
|
+
"bench:markstream": "tsx benchmarks/markstream/run.ts",
|
|
115
123
|
"check": "pnpm typecheck && pnpm test && pnpm build"
|
|
116
124
|
}
|
|
117
125
|
}
|
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Syntax and rendering
|
|
4
4
|
|
|
5
|
-
RendererExtension extends SyntaxExtension with components, annotationTypes, actions, and parameters. SyntaxExtension has name, micromark, mdast, tags, directives, transform(root, context), display, selection, and
|
|
5
|
+
RendererExtension extends SyntaxExtension with components, rendererOverrides, streaming, annotationTypes, actions, and parameters. SyntaxExtension has name, micromark, mdast, tags, directives, transform(root, context), display, selection, scope, and literal. Extension/tag/directive names are validated independently; registered tags also accept matching component directives. Check the installed package's exports before depending on repository additions.
|
|
6
6
|
|
|
7
|
-
defineBlock({ name, component, tags?, directives?, selection? }) registers a block with default tag/directive [name], content selection, and local scope. defineAnnotation<T>(type) returns an extension named annotation:<type>. defineExtension returns the supplied RendererExtension.
|
|
7
|
+
defineBlock({ name, component, tags?, directives?, selection?, streaming? }) registers a block with default tag/directive [name], content selection, and local scope. Paired ::name components support nesting, as do existing ::: containers. defineAnnotation<T>(type) returns an extension named annotation:<type>. defineExtension returns the supplied RendererExtension.
|
|
8
8
|
|
|
9
|
-
NodeRendererProps contains node, children, pending, source (node slice), renderChildren(nodes, {trailing?}), renderValue(tokens?), and renderAttribute(name). Do not reparse children or replace the original source. Token offsets and node positions are UTF-16. Use atomic selection for widgets without character correspondence. A custom visual boundary can use data-limr-selection-surface. InlineMarker inserts action-only markers; it is not an annotation.
|
|
9
|
+
NodeRendererProps contains node, children, pending, incomplete, source (node slice), renderChildren(nodes, {trailing?}), renderValue(tokens?), and renderAttribute(name). pending describes a growing top-level block; incomplete identifies this particular open node. Do not reparse children or replace the original source. Token offsets and node positions are UTF-16. Use atomic selection for widgets without character correspondence. A custom visual boundary can use data-limr-selection-surface. InlineMarker inserts action-only markers; it is not an annotation.
|
|
10
|
+
|
|
11
|
+
streaming.Loading renders a module-owned intermediate view; omit it to render progressive content using incomplete. streaming.effect supplies className, keyframes, and timing for new text/blocks. The last configured extension effect wins; Reader.streamEffect overrides it and false disables it. Default motion uses opacity alone and respects reduced motion. Reuse children/renderValue/renderChildren to retain text selection and control identity. literal keeps directive bodies from being interpreted as Markdown/JSX; parse original source without changing its public offsets.
|
|
12
|
+
|
|
13
|
+
rendererOverrides rules contain type, component, and optional when(node,{pending,incomplete,ancestors}). The last matching rule wins, with host rules taking final precedence over extensions and components. Explicit replacements own intermediate rendering and keep LiMR's mapping/error boundaries. These are scoped matching rules, not a sandbox for third-party code.
|
|
10
14
|
|
|
11
15
|
Unknown tags are inert literal source, unknown directives under standard() render child Markdown, and malformed JSX can fall back with diagnostics. A document-scoped transform disables tail-only parsing. Declaring local means no dependence on prior/future blocks and no mutation of retained prefixes.
|
|
12
16
|
|
|
@@ -28,6 +32,8 @@ SelectionAction requires id, label, icon, and may provide run/visible/disabled/o
|
|
|
28
32
|
|
|
29
33
|
ActionContext includes selection, document, annotations, highlight, locale, clearSelection, signal, and document commands. The signal aborts on reader disposal, not menu close. selection.raw/syntax/blocks contain ranges and sourceText; quality is exact/atomic/unmapped, settled is false during adjustment. Keep all selected ranges and use original source slices as quote, not rendered text.
|
|
30
34
|
|
|
35
|
+
For atomic widgets, selection.text and default/native copy preserve the entire original range, including delimiters, mapped attributes, and nested content. Outermost atomic ownership takes precedence. Ordinary text adjacent to an atom keeps rendered spelling. Partial code selections remain supported. A single atomic block anchors the toolbar below the block; custom block-local copy actions define their own copied value. Default copy feedback measures changing button width and uses eased width/opacity/scale transitions with reduced-motion support.
|
|
36
|
+
|
|
31
37
|
Commands: addAnnotation(annotation,{highlight?,edit?}), updateAnnotation(id,partial), removeAnnotation(id), removeAnnotationsAt(ranges), editAnnotation(id|null), activateAnnotation(id|null). Updates shallow-merge annotation fields and replace data. Preserve immutable data and fields such as the initial question during answer streaming. Controlled hosts must return onAnnotationsChange results.
|
|
32
38
|
|
|
33
39
|
Unknown types still produce generic/unavailable UI. Never delete hidden records to simulate plugin uninstallation. A plugin-only action should not create data for a type it fails to register.
|
|
@@ -22,20 +22,28 @@ Reader supports annotations/onAnnotationsChange. Supplying annotations makes it
|
|
|
22
22
|
|
|
23
23
|
Annotation is { id, type, data?, range?, anchors? }. Anchors are { range, documentId?, revision?, quote?, id? }. All offsets use the unmodified source's UTF-16 indices with an exclusive end. A quote relocates only when it matches uniquely; ambiguous or mismatched anchors can be omitted.
|
|
24
24
|
|
|
25
|
-
Selection exposes text, quality, settled, and raw/syntax/blocks (each with ranges and sourceText). Preserve all selected ranges and quote each original slice. Syntax absorbs adjacent standard delimiters, not unselected words or custom outer tags. Code can be selected partially; math/images
|
|
25
|
+
Selection exposes text, quality, settled, and raw/syntax/blocks (each with ranges and sourceText). Preserve all selected ranges and quote each original slice. Syntax absorbs adjacent standard delimiters, not unselected words or custom outer tags. Code can be selected partially; math/images/Mermaid and selection:atomic widgets select as a whole. Toolbar/native copying serializes each atom's complete original source, including $ delimiters, fences, or custom tags; surrounding ordinary text remains rendered text. A single atomic block anchors its toolbar below the block. Block-local copy buttons may deliberately copy only code, a URL, or another module-specific value.
|
|
26
26
|
|
|
27
27
|
useLiMR() exposes addAnnotation, updateAnnotation, removeAnnotation, removeAnnotationsAt, editAnnotation, activateAnnotation, clearSelection, invalidateAnnotation, and the engine. data updates replace the entire data object. addAnnotation normally adds a shared persistent highlight; highlight:false disables that. highlight:'hover' types skip automatic persistent highlights unless an explicit appearance is supplied. highlight annotations need no plugin and support background/underline/dotted/wavy plus hidden.
|
|
28
28
|
|
|
29
29
|
## Streaming and resources
|
|
30
30
|
|
|
31
|
-
Pass the complete accumulated text to source and set streaming=false at completion. followOutput is opt-in and pauses after upward scrolling. Keep extensions/plugins stable; full-document transforms, changed definitions, middle edits
|
|
31
|
+
Pass the complete accumulated text to source and set streaming=false at completion. followOutput is opt-in and pauses after upward scrolling. Keep extensions/plugins stable. Appends and eligible finalization reuse stable prefixes; full-document transforms, changed definitions, and middle edits may require complete parsing. Growing code fences have a literal fast path.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
New text and special blocks fade in without a background tint. streamEffect overrides animation keyframes/timing/className; false disables it. Extensions can provide streaming.effect and streaming.Loading. Incomplete code/math may render progressively while Mermaid waits for closure. Existing control state and selected text are retained; honor reduced motion in custom components.
|
|
34
|
+
|
|
35
|
+
typography defaults to standard; choose justify for browser justification or knuth-plass for TeX paragraph optimization with English Knuth–Liang hyphenation. The client adapter caches preparation, retains offscreen DOM, and protects active selections on width changes. knuthPlass configures tolerances, penalties, emergencyStretch, looseness, and hyphenate. Browser font shaping is not pixel-identical to TeX PDF; compare workloads using the repository performance report rather than promising universal timing parity.
|
|
36
|
+
|
|
37
|
+
SSR renders code text without client Shiki and a loading view for Mermaid; KP begins with standard layout and runs on the client. Await preloadMath() before synchronous SSR when complete formula HTML is needed. Framework client boundaries still apply to interactive components. Annotation loaders start when content is shown on the client; Preview only uses local data. Do not infer physical-device acceptance from Chromium mobile emulation.
|
|
34
38
|
|
|
35
39
|
## Importing a plugin
|
|
36
40
|
|
|
37
41
|
Read the actual installed package exports/peer dependencies. Import its factory, create a stable array, pass plugins, and import its CSS if required. Plugins add to defaults; extensions replaces them. Duplicate extension/tag/directive names throw. Parameter overrides belong in parameters and do not reparse source.
|
|
38
42
|
|
|
43
|
+
rendererOverrides replaces views without changing syntax: each rule has type, component, and optional when(node,{pending,incomplete,ancestors}). Last matching rules win; host rules override extension rules. This restricts where a renderer applies, not what third-party JavaScript can execute.
|
|
44
|
+
|
|
39
45
|
Missing plugin annotations retain data but show generic markers/unavailable cards. The Playground's plugin switches disable action entries while leaving renderers installed. If an application wants to hide unsupported types, merge untouched hidden records back into persistence on edits.
|
|
40
46
|
|
|
41
47
|
Use docs shipped under node_modules/@linloir/limr/docs when available. Public source: https://github.com/Linloir/LiMR . Do not rely on internal src/dist imports.
|
|
48
|
+
|
|
49
|
+
The Playground always refreshes to its default document and standard typography. Edits are stored only through explicit Save, then opened manually from the saved-draft menu; locale preference persists separately. Reader itself supplies no persistence.
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
# Built-in syntax
|
|
2
2
|
|
|
3
|
-
React defaults install gfm, math, code-highlight, definition, question, extras, video, figures, citation, and
|
|
3
|
+
React defaults install gfm, math, code-highlight, mermaid, callout, definition, question, extras, video, figures, citation, translations, inline-highlights, and footnotes. Core createDocument defaults to basic CommonMark. Check the installed package's exports and version before using new APIs; these references describe the repository implementation.
|
|
4
4
|
|
|
5
|
-
- Standard Markdown: headings, emphasis, lists, links, images, fenced/inline code, blockquotes. GFM adds tables, tasks, strikethrough, autolinks, and
|
|
5
|
+
- Standard Markdown: headings, emphasis, lists, links, images, fenced/inline code, blockquotes. GFM adds tables, tasks, strikethrough, autolinks, and named footnote parsing; the default footnotes module presents notes as comment markers and sidebar/floating cards instead of superscripts/endnotes.
|
|
6
6
|
- Math uses $…$ and $$ fences; import math.css.
|
|
7
|
+
- Mermaid uses mermaid code fences or a paired ::mermaid component. Open streaming diagrams show loading; completed diagrams render on the client and fade in. One shared toolbar copies the diagram body, zooms, and switches source/image views. Drag to pan; arrow keys and wheel scroll, Shift+wheel scrolls horizontally. Selection is atomic in both views, and selection-toolbar/native copying retains the entire original fence/component. Override --limr-mermaid-max-height and --limr-mermaid-scrollbar through CSS.
|
|
8
|
+
- Obsidian callouts use > [!type] Title. Types: note, abstract, info, todo, tip, success, question, warning, failure, danger, bug, example, quote; common Obsidian aliases work. A + suffix starts expanded, - starts collapsed. Blockquotes and callouts can nest. ::callout{type="tip" title="Title" fold="-"} is the component form.
|
|
9
|
+
- ==highlight== creates a read-only blue source highlight; its toolbar offers copy plus a localized hint. Override --limr-inline-highlight or replace inlineHighlights({ color }). Named [^id] definitions and inline ^[Markdown content] create footnote cards. ==highlight==[^id] and ==highlight==^[note] attach the footnote to the highlight. Removing footnotes() restores GFM superscripts/endnotes.
|
|
7
10
|
- <definition title="Term"> supports Markdown body. <title> and <content> child tags support richer content.
|
|
8
11
|
- <question> supports question-content, question-hint, question-answer, question-sel-grp and question-sel. Use string attributes multi="true" and answer="[0,2]"; indices start at zero. This is an exercise, not an AI annotation.
|
|
9
12
|
- <extras> contains <extra title="Title" url="https://example.com" desc="Description" />.
|
|
10
13
|
- <citation id="a" title="Source" url="https://example.com" description="Markdown body" summary="Short preview" /> defines data; <ref id="a" /> or <ref ids='["a","b"]' /> inserts a marker. Legacy cite-id, cite-from-ids, and desc work. Standard [^footnote] syntax is a separate feature.
|
|
11
|
-
- <figure src="/a.png" alt="A" caption="Caption" /> works alone or inside <figures columns="2">. Use figcaption children for Markdown. Limits: min-width/min-height 220/120, max-width/max-height 560/480; none/false removes maxima. Columns/rows, responsive, and gap control grouping.
|
|
14
|
+
- <figure src="/a.png" alt="A" caption="Caption" /> works alone or inside <figures columns="2">. Use figcaption children for Markdown. Limits: min-width/min-height 220/120, max-width/max-height 560/480; none/false removes maxima. Columns/rows, responsive, and gap control grouping. Media-local copy buttons copy image URLs or group Markdown; selection copying follows the selected atomic source range, including Markdown image syntax when present.
|
|
12
15
|
- <video src="/clip.mp4" provider="native" /> and <md-video url="…" /> support native, YouTube, and Bilibili. loading defaults to visible (200px proximity), not click. Use loading="click" to defer until interaction. Remote playback is not guaranteed by local iframe tests.
|
|
13
16
|
- <translations default="both"> contains <origin> and <translation>. Modes: origin/translation/both; both shows translation first. It displays supplied content, not an automatic translation service. Global parameters.translationMode overrides local mode; onTranslationModeChange accepts switch requests.
|
|
14
17
|
|
|
15
|
-
Use static string/boolean attributes, never JavaScript expressions or spread props. Separate block tags and Markdown with blank lines. Only registered tags execute React renderers. Unknown tags show the full original text; unknown directives under standard() render children without their outer marker.
|
|
18
|
+
Use static string/boolean attributes, never JavaScript expressions or spread props. Separate block tags and Markdown with blank lines. Only registered tags execute React renderers. Unknown tags show the full original text; unknown directives under standard() render children without their outer marker. Streaming defers partial headers and inline delimiters; recognized unclosed components carry incomplete and use module-owned loading/progressive rendering. Finish with streaming=false to apply final Markdown interpretation.
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
Every registered tag also supports its matching directive, including child tags and citation/ref. Paired ::name{key="value"} and a closing :: support nested Markdown components; ::: containers and single-colon inline directives remain supported. Code/math/Mermaid directive bodies are literal. An unpaired two-colon line in a finalized document keeps its legacy leaf-directive meaning. This compatibility covers scalar attributes and nesting, not CoMark YAML properties, named slots, or frontmatter.
|