@linloir/limr 0.1.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.
Files changed (97) hide show
  1. package/README.en.md +151 -0
  2. package/README.md +80 -127
  3. package/benchmarks/results/layout.json +2593 -0
  4. package/benchmarks/results/markstream-code.json +1823 -0
  5. package/benchmarks/results/markstream-reading-repeat.json +1152 -0
  6. package/benchmarks/results/markstream.json +12486 -0
  7. package/benchmarks/results/streaming-browser.json +77 -0
  8. package/benchmarks/results/streaming.json +357 -0
  9. package/dist/base.css +93 -10
  10. package/dist/{chunk-7JF5HHVF.js → chunk-BG5QUQFR.js} +340 -72
  11. package/dist/chunk-BG5QUQFR.js.map +1 -0
  12. package/dist/chunk-BVHHOVMT.js +179 -0
  13. package/dist/chunk-BVHHOVMT.js.map +1 -0
  14. package/dist/chunk-FJZCQY2S.js +155 -0
  15. package/dist/chunk-FJZCQY2S.js.map +1 -0
  16. package/dist/chunk-FSI5OTBW.js +1 -0
  17. package/dist/{chunk-ETHLPBKQ.js → chunk-GU2RPESF.js} +238 -131
  18. package/dist/chunk-GU2RPESF.js.map +1 -0
  19. package/dist/{chunk-65V5OZ4G.js → chunk-SUAAUGAX.js} +1350 -511
  20. package/dist/chunk-SUAAUGAX.js.map +1 -0
  21. package/dist/core/index.d.ts +6 -3
  22. package/dist/core/index.js +15 -5
  23. package/dist/extensions/index.d.ts +30 -5
  24. package/dist/extensions/index.js +15 -3
  25. package/dist/index.d.ts +4 -4
  26. package/dist/index.js +31 -8
  27. package/dist/{engine-43u8B4yt.d.ts → knuth-plass-C8mgFm7W.d.ts} +67 -1
  28. package/dist/knuth-plass-layout-CHQCWKB5.js +449 -0
  29. package/dist/knuth-plass-layout-CHQCWKB5.js.map +1 -0
  30. package/dist/react/index.d.ts +7 -5
  31. package/dist/react/index.js +7 -3
  32. package/dist/styles.css +93 -10
  33. package/dist/{translations-BliabrPd.d.ts → translations-BXzSwLBJ.d.ts} +49 -4
  34. package/docs/README.md +13 -0
  35. package/docs/api.md +5 -158
  36. package/docs/assets/rendered.svg +9 -0
  37. package/docs/assets/source.svg +9 -0
  38. package/docs/en/README.md +28 -0
  39. package/docs/en/ai-skills.md +57 -0
  40. package/docs/en/annotations.md +86 -0
  41. package/docs/en/api.md +115 -0
  42. package/docs/en/architecture.md +41 -0
  43. package/docs/en/extensions.md +208 -0
  44. package/docs/en/getting-started.md +69 -0
  45. package/docs/en/integration.md +154 -0
  46. package/docs/en/modules.md +84 -0
  47. package/docs/en/performance.md +93 -0
  48. package/docs/en/plugin-packages.md +68 -0
  49. package/docs/en/styles.md +99 -0
  50. package/docs/en/syntax.md +455 -0
  51. package/docs/extensions.md +5 -306
  52. package/docs/implementation.md +5 -76
  53. package/docs/performance.md +5 -81
  54. package/docs/screenshots/blocks.png +0 -0
  55. package/docs/screenshots/dark.png +0 -0
  56. package/docs/screenshots/desktop.png +0 -0
  57. package/docs/screenshots/plugin-mobile.png +0 -0
  58. package/docs/styles.md +5 -100
  59. package/docs/visual-upgrade.md +5 -145
  60. package/docs/zh-CN/README.md +28 -0
  61. package/docs/zh-CN/ai-skills.md +57 -0
  62. package/docs/zh-CN/annotations.md +86 -0
  63. package/docs/zh-CN/api.md +115 -0
  64. package/docs/zh-CN/architecture.md +41 -0
  65. package/docs/zh-CN/extensions.md +210 -0
  66. package/docs/zh-CN/getting-started.md +69 -0
  67. package/docs/zh-CN/integration.md +154 -0
  68. package/docs/zh-CN/modules.md +84 -0
  69. package/docs/zh-CN/performance.md +93 -0
  70. package/docs/zh-CN/plugin-packages.md +68 -0
  71. package/docs/zh-CN/styles.md +99 -0
  72. package/docs/zh-CN/syntax.md +457 -0
  73. package/examples/notes.tsx +18 -11
  74. package/examples/packages/paper-theme/index.css +25 -0
  75. package/examples/packages/paper-theme/package.json +7 -0
  76. package/examples/packages/reading-tools/index.d.ts +2 -0
  77. package/examples/packages/reading-tools/index.js +25 -0
  78. package/examples/packages/reading-tools/package.json +16 -0
  79. package/package.json +17 -5
  80. package/skills/limr-plugin-development/SKILL.md +22 -0
  81. package/skills/limr-plugin-development/agents/openai.yaml +4 -0
  82. package/skills/limr-plugin-development/assets/plugin-template/README.md +30 -0
  83. package/skills/limr-plugin-development/assets/plugin-template/package.json +36 -0
  84. package/skills/limr-plugin-development/assets/plugin-template/src/index.tsx +50 -0
  85. package/skills/limr-plugin-development/assets/plugin-template/src/styles.css +9 -0
  86. package/skills/limr-plugin-development/assets/plugin-template/tsconfig.json +20 -0
  87. package/skills/limr-plugin-development/assets/plugin-template/tsup.config.ts +8 -0
  88. package/skills/limr-plugin-development/references/contract.md +51 -0
  89. package/skills/limr-use/SKILL.md +23 -0
  90. package/skills/limr-use/agents/openai.yaml +4 -0
  91. package/skills/limr-use/references/integration.md +49 -0
  92. package/skills/limr-use/references/syntax.md +20 -0
  93. package/dist/chunk-65V5OZ4G.js.map +0 -1
  94. package/dist/chunk-7JF5HHVF.js.map +0 -1
  95. package/dist/chunk-ETHLPBKQ.js.map +0 -1
  96. package/dist/chunk-V2OG4Y3F.js +0 -1
  97. /package/dist/{chunk-V2OG4Y3F.js.map → chunk-FSI5OTBW.js.map} +0 -0
package/docs/styles.md CHANGED
@@ -1,103 +1,8 @@
1
- # 样式与交互外观
1
+ # 样式与字体 / Styles and fonts
2
2
 
3
- `@linloir/limr/styles.css` 提供默认 classic 样式和代码字体。所有默认规则位于 `@layer limr`;应用或样式包的普通 CSS 可以直接覆盖,无须提高选择器优先级。`appearance="paper"` 会传播到正文、目录、侧栏、选区工具栏和 portal 浮层,适合同页存在多个阅读器的场景。
3
+ 文档已整理到语言目录。This guide now lives in the language directories.
4
4
 
5
- ```tsx
6
- import '@linloir/limr/styles.css';
7
- import '@your-scope/limr-theme-paper';
8
- <Reader source={markdown} appearance="paper" theme="dark" />
9
- ```
5
+ - [简体中文](zh-CN/styles.md)
6
+ - [English](en/styles.md)
10
7
 
11
- 主题包可只包含 CSS,并将 `exports["."]` 指向该文件、`sideEffects` 设为 `["**/*.css"]`。用 `[data-limr-appearance='paper']` 包裹 token 和规则,不依赖 `.limr-reader` 作为 portal 的祖先。自定义组件使用稳定的 `.limr-*` 类,状态由 `data-active`、`data-expanded`、`data-open`、`data-status` 等属性表示。
12
-
13
- | CSS 变量 | 用途 |
14
- | --- | --- |
15
- | `--limr-font-text`, `--limr-font-code` | 正文与代码字体栈 |
16
- | `--limr-font-size`, `--limr-line-height` | 正文字号和行高 |
17
- | `--limr-font-features` | 正文 OpenType 特性,默认 `'palt' 1`,使中文字体的弯引号等标点采用比例宽度;`normal` 可恢复字体原有宽度 |
18
- | `--limr-emphasis-spacing` | 斜体末尾的光学留白,默认 `.08em`;不改变左侧间距 |
19
- | `--limr-list-item-gap` | 列表项和嵌套层级前后的统一间距,默认 `.375rem` |
20
- | `--limr-text`, `--limr-heading`, `--limr-secondary`, `--limr-muted` | 文本层次 |
21
- | `--limr-background`, `--limr-surface`, `--limr-border` | 背景与边框 |
22
- | `--limr-link`, `--limr-accent`, `--limr-selection` | 链接、激活与选区颜色 |
23
- | `--limr-code-bg`, `--limr-code-header`, `--limr-inline-code` | 两种主题下的代码颜色 |
24
- | `--limr-mark-size` | 角标方形边长,默认 `.92em`,统一使用正文基准字号 |
25
- | `--limr-motion-fast`, `--limr-motion`, `--limr-motion-slow`, `--limr-ease` | 动画时长与曲线 |
26
- | `--limr-overlay-duration` | 悬浮预览展开/收回共用时长(560ms);兼容旧变量 `--limr-overlay-enter-duration` |
27
- | `--limr-overlay-morph-duration`, `--limr-overlay-ease` | 预览与大卡片变换时长(480ms),浮层曲线(`cubic-bezier(.22,1,.36,1)`) |
28
- | `--limr-video-width`, `--limr-definition-math-bg` | 视频最大宽度与释义块内公式背景 |
29
- | `--limr-content-width`, `--limr-reader-width`, `--limr-sticky-top` | 布局上限及吸顶位置 |
30
- | `--limr-toc-width`, `--limr-sidebar-width`, `--limr-column-gap` | 三栏宽度与间隔;默认侧栏随容器增宽 |
31
- | `--limr-reader-min-height`, `--limr-reader-bottom-space` | 短正文的最小高度与视口底部预留空间;默认自动填充并预留 24px |
32
- | `--limr-annotation-color`, `--limr-annotation-border`, `--limr-annotation-title`, `--limr-annotation-text`, `--limr-annotation-excerpt` | 模块通过 `color` / `sidebar` 配置提供的卡片局部色值 |
33
- | `--limr-sidebar-padding-block` | 通用侧栏卡片顶部留白,默认 `.65rem`;底部额外补足 `2px`,Citation 使用独立规则 |
34
- | `--limr-sidebar-padding-inline` | 关联区与内容区共用的水平留白,默认 `10px`;标题、预览、正文的文字起点一致 |
35
- | `--limr-sidebar-reference-gap` | 灰色关联区与下方内容区之间的分隔,默认 `1px` |
36
- | `--limr-toolbar-background`, `--limr-toolbar-border`, `--limr-toolbar-shadow`, `--limr-toolbar-radius` | 工具栏浮层背景、边框、阴影、圆角(默认 `6px`) |
37
- | `--limr-toolbar-font-size`, `--limr-tool-icon-size`, `--limr-toolbar-accent` | 工具栏文字(默认 `.75rem`)、图标(`18px`)、选择框颜色(沿用 `--limr-accent`) |
38
- | `--limr-toolbar-panel-width`, `--limr-toolbar-panel-max-height` | 展开内容宽度(默认 `246px`,不含内边距)与高度上限(默认 `260px`) |
39
- | `--limr-toolbar-panel-height`, `--limr-toolbar-available-height` | 骨架测量得到的面板高度上限与所选方向空间;插件可读取,不应覆盖 |
40
-
41
- 系统 `prefers-reduced-motion: reduce` 会关闭位移、展开与滚动动画。工具栏文字按钮使用 `.limr-underline` 从左向右展开下划线,不添加悬浮背景;复制成功原位淡出淡入为绿色“已复制”,2.4 秒后恢复。代码块内的图标复制按钮保留独立的背景与图标过渡。默认 `>` 引用块使用“注释 / Note”标题;可用 `components.blockquote` 完全替换其外观。它与插件注册的注记角注类型相互独立。
42
-
43
- 图片外框使用 `.limr-figure` / `.limr-figures`,继承代码/公式区域的背景和边框色;`.limr-figures-grid` 使用实际测量得出的列数,图片保持长宽比。同一行图片居中对齐、caption 共用行轨道,单图与整组 caption 均居中。图组与单图分别有源码和图片 URL 复制按钮,按钮位于外框内部。`.limr-translations` 内的两个 `.limr-translation-panel` 复用可逆的高度与透明度动画,默认 480ms;隐藏侧设置 `inert`。`.limr-action-mark` 复用普通角标的图标槽与尺寸,原文、译文、对照使用不同的圆润图标,并保留状态提示及无障碍标签。
44
-
45
- 宽屏参考 infilearn 的正文尺度:阅读器默认最大 `1800px`,正文最大 `900px`,目录和注释栏随容器宽度渐增,列间距默认 `36px`。容器不足 `1120px` 时仍切换为注释浮层,不依赖浏览器窗口宽度。宿主可用上述变量覆盖尺寸。
46
-
47
- 同步注释侧栏由所在网格行决定高度,并使用 size/layout containment 与 `overflow: clip` 隔离内部位移。短正文自动补足可用阅读高度,注释数量不会撑大页面。悬浮角标驱动侧栏,悬浮卡片则锁定卡片命中区域并平滑移动正文;正文容器裁切位移,不改变页面滚动范围。不要把所有卡片底部的最大值赋给外层 `height` / `min-height`,也不要给这个同步列表添加 `overflow: auto`。卡片正文的长内容滚动与列表定位相互独立。
48
-
49
- 模块颜色、边距、`sidebar.Preview` 和 Citation 单条/多条补偿的约定见[扩展指南](extensions.md)。可以通过 `.limr-sidebar-card[data-type='assistant']` 定位模块;默认卡片的有色装饰条、背景和 padding 在它的 `.limr-sidebar-card-body` 上,灰色关联区是独立的 `.limr-sidebar-reference`,两者之间留出分隔。`.limr-sidebar-preview` 使用模块配置的预览颜色和行数,展开后隐藏。浮层使用 `.limr-annotation-overlay[data-type='assistant']`,无需依赖阅读器作为 portal 的祖先。
50
-
51
- 悬浮预览先按最终位置和尺寸排版,再从角标横坐标对应的位置裁切展开,内容不会随动画反复换行。预览在角标上方时从底部展开,在下方时从顶部展开;切换角标会等待新角标的定位结果。视口较矮时,预览高度受对应方向的剩余空间限制。允许展开的模块从预览的位置和尺寸放大至目标布局,关闭时缩回预览位置和尺寸并淡出;触摸、工具栏直接打开也采用同一几何起点。
52
-
53
- 动画从实时画面重新取样,移开、重入和快速展开/收起均可中途反转。悬浮预览进入和退出共用 560ms,内容和外壳同时结束;鼠标移开后的跨越间隙宽限为 90ms,明确关闭时立即开始动画。组件在退场完成后才卸载,保留请求与组件状态。外壳背景与阴影由 `.limr-overlay-surface` 绘制并独立变形,`.limr-overlay-card` 内的文字、按钮与输入框不缩放。打开时聚焦对话框容器,不自动高亮“收起”按钮,Tab 导航仍保留焦点提示。
54
-
55
- 窄屏目录使用整行 hover 背景和圆角折线箭头,内容高度、透明度、位移和箭头旋转连续过渡。内容持续挂载、隐藏时 inert,快速点击直接从当前帧反转,没有延迟卸载定时器。
56
-
57
- 宽屏目录通过不占高度的 sticky 定位容器固定顶部,内部目录按实际可见高度单独限制尺寸,正文末尾不会把目录整体向上推出视口。`--limr-sticky-top` 控制吸顶距离,`--limr-toc-available-height` 由 Reader 测量,不应覆盖。目录标题不参与渐隐;`.limr-toc-scroll` 与正文、注释栏共用 `--limr-overflow-fade-size`(默认 `24px`),仅在对应方向有溢出时淡出,列表自身滚动也会更新渐隐边界。
58
-
59
- 角标的鼠标命中区域保持固定,hover/按下缩放只作用于内部图形,避免边缘反复触发进入/离开。侧栏展开/收起使用纯文字和下划线渐变,仅悬浮“展开 / 收起”文字或键盘聚焦时触发;切换展开状态时保留卡片 hover。提问选项菱形按第一行文字基线对齐,公布答案时正确选项填充绿色;扩展阅读标题使用正文标题色,副标题字号更小、间距更紧凑。
60
-
61
- 浮层隐藏原生滚动条,使用不占内容宽度的 3px 覆盖式滚动条(`.limr-overlay-scroll-thumb`)。展开/收起动画期间不显示;实际滚动时淡入,停止 800ms 后淡出,支持拖动滑块。滚轮、触摸和键盘滚动仍由原生滚动容器处理。
62
-
63
- ## 字体资源和缓存
64
-
65
- 爱丽丝样例中的撇号是 Unicode 弯引号 `’`(U+2019),不是全角 ASCII 撇号。默认启用字体的比例标点特性以缩小其宽度,不替换源文本,因此复制、选区和 annotation 偏移保持一致。样式包可覆盖 `--limr-font-features`,或通过 `--limr-font-text` 换用自己的字体;特性是否可用取决于字体。代码仍使用独立的等宽字体特性。
66
-
67
- 两端对齐由渲染器的 `justify` 属性控制,默认关闭。开启时段落和列表使用 `text-align: justify`,末行和显式换行前的行保持起始侧对齐,标题、代码块及表格保持原有排版。选区与高亮使用排版后的实际文字位置测量,包含斜体末尾留白。
68
-
69
- 默认代码字体来自 [Maple Mono v7.9 的 NF CN 版本](https://github.com/subframe7536/maple-font/releases/tag/v7.9),保留原版连字、中文、日文、Nerd 图标及原版支持的其他字形。不能把“多语言”理解为所有文字均有字形;缺失字符仍使用系统回退。四个字重/样式文件切分为 unicode-range WOFF2 子集,浏览器只按实际字符请求所需子集,`font-display: swap` 使代码先用系统等宽字体显示。Latin/Greek/Cyrillic 常规子集约 47 KB;完整字体资产约 31 MB,不会在页面初始全部下载。
70
-
71
- `src/fonts/manifest.json` 记录来源、原始包摘要、字形覆盖和各文件大小,OFL 许可证随包分发。子集字体使用新名称 `LiMR Maple Mono NF CN`。`scripts/subset-fonts.py` 可从官方 unhinted ZIP 重建资源。WOFF2 文件名包含版本与内容摘要,构建工具可进一步生成哈希资源 URL。
72
-
73
- 组件无法设置服务器的 HTTP 缓存头。生产部署应对带内容哈希的字体资源返回 `Cache-Control: public, max-age=31536000, immutable`;浏览器是否复用仍取决于 URL、缓存头和用户缓存状态,不应由组件重复 fetch 字体。
74
-
75
- 本地生产预览的中英混排/希腊/西里尔/Nerd 图标夹具实际请求 4 个 Maple 子集,共 341,440 字节;刷新后没有重新传输字体正文。这是该夹具和预览服务器的观测结果,不能代替宿主应用的缓存配置。
76
-
77
- 完全使用自己的字体时:
78
-
79
- ```tsx
80
- import '@linloir/limr/styles/base.css'; // 默认排版/交互样式,不引入 Maple
81
- // 可单独 import '@linloir/limr/fonts.css',或载入应用自己的字体。
82
- ```
83
-
84
- ## 选区、高亮与移动端
85
-
86
- 浏览器仍管理原生文本范围、键盘选择、复制与辅助技术;覆盖层统一文本、行内代码、公式及角标的选中高度,不用替换正文或铺设透明文字副本。覆盖层只绘制视口中的片段,并在字体、内容、尺寸和滚动变化后重新计算。全文 DOM 保留,浏览器搜索和打印不受虚拟列表影响。
87
-
88
- 代码可部分选中;公式按整体选中,块公式继承背景边界与圆角。角标仅在两侧都有文本且范围跨过两侧文本时着色,按钮本身的背景和交互独立。自定义原子组件可给内部实际背景元素添加 `data-limr-selection-surface`,指定覆盖边界和圆角。
89
-
90
- 图片的选区和背景高亮使用边框,避免遮住图像;下划线样式仍可使用。图片与块公式的角标直接覆盖原有右下角,不增加块高度。图片角标的按钮使用不透明的浅主题底色,不附加白色底板。文字角标与前一个字符共同换行,不单独留在新行;连接字符通过 CSS 生成,不改变源文或复制文本。译文状态图标可用 `--limr-translation-accent` 改色。
91
-
92
- 侧栏布局优先利用上方留白,把末尾卡片收进可用高度;边界处悬浮不会强行移动正文来追齐角标。正文和侧栏在实际发生上下裁切时使用透明渐隐,跟随窗口、嵌套滚动容器及动画中的真实边界;内容完整时不会淡化边缘,打印时也不保留屏幕蒙版。`--limr-overflow-fade-size` 控制渐隐高度,默认 `24px`,设置为 `0px` 可关闭渐变。
93
-
94
- 移动视口、触摸点击浮层和 Selection API 的程序化选择有浏览器回归检查。iOS/Android 的系统拖动手柄、放大镜和原生菜单并不能通过网页 CSS 一致接管;保留这些平台控件,不伪装成已在真机上实现了完全自定义触摸选区。实体设备的手指拖动仍需单独验收。
95
-
96
-
97
- 工具栏外层 `.limr-selection-toolbar` 只负责定位,`.limr-toolbar-surface` 与各 `.limr-toolbar-item` 分别执行非线性位移和延后淡入。上方工具栏从下向上浮入,下方工具栏从上向下浮入;组件按序延迟 22ms,淡入再稍晚开始。`prefers-reduced-motion` 关闭这些移动和延迟。工具栏优先位于选区下方,为展开内容预留同一份空间预算;展开后按钮行保持靠近选区,面板向外生长。分隔线覆盖整个工具栏宽度,面板内容居左并受宽度约束。
98
-
99
- `.limr-tool-icon` 默认 18px,可用 `--limr-tool-icon-size` 覆盖。图标槽约束 SVG、图片及嵌套包装的大小和溢出。文字行高为 1.5,以 1px 底部留白校正视觉中心;内置图标在自身 viewBox 内校正,不对整行施加额外位移。自绘整个 action 的 `render` 槽位需自己复用图标槽或提供等价约束。
100
-
101
- 面板由骨架的 `OverlayScrollArea` 负责滚动:内容不足预算时自然收缩,溢出时使用 3px 覆盖式滚动条,不挤占内容布局。插件通常不需要设置高度或再提供滚动条;复杂模块可读取上述可用高度变量。外部样式包示例见 [`paper-theme/index.css`](../examples/packages/paper-theme/index.css)。
102
-
103
- 持久高亮使用 `.limr-highlight-layer`,在各段落、代码或公式背景上方、文字下方绘制;临时选区保留独立的 `.limr-paint-layer`。两个层都只维护视口内的几何,且不拦截指针。高亮悬浮通过正文的坐标命中判断,按叠放顺序选择一个高亮,应用 `data-hovered` / `data-active` 到该高亮的全部可见片段。悬浮侧栏条目、角标或激活 annotation 时,其他片段添加 `data-muted` 暂时隐藏;离开后恢复原本的可见性。打印时隐藏绘制层,恢复语义 mark 的原生装饰。
8
+ [文档目录 / Documentation](README.md)
@@ -1,148 +1,8 @@
1
- # Visual and extension refinement
1
+ # 样式与交互 / Styles and interaction
2
2
 
3
- This checklist records the requested acceptance scope. An item is complete only
4
- after its implementation and relevant browser/package evidence are recorded.
3
+ 文档已整理到语言目录。This guide now lives in the language directories.
5
4
 
6
- - [x] Third-party pnpm plugins add to defaults with a small public API; a real
7
- separate package consumer verifies syntax, actions and annotation content.
8
- - [x] CSS packages override the default skin, including portals and multiple
9
- readers. Document stable tokens, layers, selectors and packaging.
10
- - [x] Local Maple Mono NF CN with ligatures, CJK/Nerd/multilingual glyphs, small
11
- on-demand font subsets, swap fallback, versioned cacheable URLs and licenses.
12
- - [x] Rounded copy/check icons: frosted math button, transparent code button,
13
- background hover/press and nonlinear success/reset; code header/body same
14
- font, both themes. Hover/press translation was removed after review.
15
- - [x] Compact symmetric block spacing, question type label, animated diamond
16
- choices, multiline underline, color feedback, single submit/retry, expandable
17
- hint/answer sections with animated result and answer reveal.
18
- - [x] Reusable nonlinear multiline underline on TOC, extras, options and links.
19
- - [x] Nonlinear TOC/sidebar alignment, card expansion/collapse; reduced motion.
20
- - [x] Anchored overlay enter/exit and continuous preview-to-expanded transition,
21
- animated content reveal, no remount/repeated request, focus/viewport handling.
22
- - [x] Square centered markers with independent hover/press animations.
23
- - [x] Unified line geometry for selection and highlights: text, partial inline
24
- code, atomic inline/display math, partial fenced code with inline markers,
25
- special blocks. Marker paint only when text on both sides is spanned; preserve
26
- marker background/motion. No adjacent-code-line overlap.
27
- - [x] Mobile selection visual parity where browser APIs permit; document native
28
- handles/platform limitations with evidence rather than removing accessibility.
29
- - [x] Playground common navigation and plugin styling, live two-column editor
30
- and bidirectional source-aware scroll matching, responsive narrow layout.
31
- - [x] Unit/browser/package tests, visual evidence in light/dark/mobile, updated
32
- performance checks for long documents and streams without unbounded repaint.
5
+ - [简体中文](zh-CN/styles.md)
6
+ - [English](en/styles.md)
33
7
 
34
- Additional review requirements:
35
-
36
- - [x] Continuous drag regression: publish and paint during the gesture; measure
37
- an 878k-character document, select-all/scroll, and 1,000 tokenized code lines.
38
- The three browser regressions passed with one worker on 2026-10-12.
39
- - [x] All annotation buttons use the same fixed slot at 80% of the previous
40
- citation size; active state must not persistently enlarge plugin markers;
41
- oversized SVG/image/nested plugin content stays inside the slot.
42
- - [x] Whole collapsed sidebar card is clickable, localized expand/collapse text
43
- and hover/state motion, balanced bottom spacing in nested Markdown.
44
- - [x] Standard blockquotes use a Note/注释 title and special-block background.
45
- - [x] Definition/extras have more bottom breathing room; question disclosures
46
- sit farther below submit, with symmetric collapsed/expanded bottom spacing.
47
- - [x] Original pointed diamond paths and center-fill animation, now 15px;
48
- first-line center alignment; empty space beside choices has no hover effect.
49
- - [x] Math/code copy buttons never translate on hover/press; code button is
50
- smaller with visually balanced header insets.
51
- - [x] Atomic formula selection/highlights retain the painted surface's corners.
52
-
53
- Initial refinement validation on 2026-10-12:
54
-
55
- - `pnpm check`: TypeScript, 40 unit/SSR tests and library build passed.
56
- - `pnpm test:browser`: 23 Chromium tests passed, including continuous long
57
- document/code drag, select-all/scroll, formula corners, adversarial plugin
58
- icon sizes, question/sidebar controls, copy transitions, footnote selection,
59
- overlay continuity, mobile viewport and bidirectional editor scrolling.
60
- - `pnpm test:package`: actual LiMR, syntax/action/annotation plugin and CSS
61
- package tarballs install and work in independent React 18.3.1 and React 19
62
- applications, including TypeScript, SSR, portals and theme isolation. Core
63
- also imports when React imports are deliberately denied.
64
- - Production browser, selection and Node measurements are retained in
65
- `benchmarks/results/`; see [performance.md](performance.md) for measured
66
- budgets, slower cases and limits. Do not infer equal selection-processing
67
- cost or a long-document SSR advantage from the browser frame statistics.
68
- - Inspected production screenshots are saved locally in `artifacts/visual/`:
69
- `light.png`, `dark.png`, `question-collapsed.png`, `question-expanded.png`,
70
- `sidebar-expanded.png`, `markers.png`, `math-selected.png`,
71
- `math-highlighted.png`, `mobile.png` and `mobile-overlay.png`.
72
- `evidence.json` records measured 15px diamonds, six equal 14.71875px marker
73
- buttons, 4px formula selection corners, code themes and font requests.
74
-
75
- Physical iOS/Android selection handles and finger dragging were not tested.
76
- The mobile evidence covers Chromium touch emulation and programmatic Selection
77
- API geometry; platform controls remain native. Font cache headers belong to the
78
- host application; see [styles.md](styles.md). Plugin slots contain oversized
79
- elements but cannot repair an incorrectly centered intrinsic SVG drawing.
80
-
81
- Narrow-overlay follow-up on 2026-10-12:
82
-
83
- - The final card bounds and text width stay stable during a clip reveal. The
84
- horizontal origin follows the current marker; vertical reveal follows the
85
- resolved top/bottom placement. Positioning no longer measures animated widths
86
- or heights, and a changed marker cannot reuse the previous positioning result.
87
- Preview height is capped to available space on the resolved side; this cap is
88
- released when switching to the expanded dialog.
89
- - Native scrollbars are hidden. A 3px overlaid thumb appears only while scrolling,
90
- fades after 800ms of inactivity, supports dragging, and stays hidden throughout
91
- card motion. It never reserves text width.
92
- - `pnpm check` passed (40 tests, TypeScript and build). The 16 tests in
93
- `motion-playground.spec.ts` and `reader.spec.ts` passed, including motion frame
94
- geometry, right/bottom edge placement, rapid reference changes, interrupted
95
- exit/reopening, scrollbar behavior, touch viewport, focus restoration and
96
- annotation request reuse.
97
-
98
- References reviewed: the previous renderer's Extras/Question/Citation styles,
99
- selection and highlight hooks, the web app's QuestionnaireView multiline
100
- gradient underline and diamond control, and UniDevice's rounded copy control. The new
101
- implementation keeps LiMR independent of those applications.
102
-
103
- Module-controlled cards and follow-up refinements on 2026-10-12:
104
-
105
- - Annotation modules opt into anchored content-height expansion or a centered
106
- size such as 80dvh. Citation stays a pinnable preview; conversation and reading
107
- plugin examples opt into their own expansion. Sidebar content-click collapse
108
- is also opt-in; Citation items instead underline and follow their links.
109
- - Preview reveal/content animations sample their live frame on each direction
110
- change, including repeated interruption. Retained overlays remeasure on reopening;
111
- Floating UI's closed positioning state otherwise stranded the retained card.
112
- Exit completion, rather than a fixed unmount timer, releases the subtree.
113
- The painted shell connects preview and expanded bounds independently of text
114
- and controls. Direct opening measures the module's preview first; closing
115
- returns to that preview geometry while fading out. Preview entry/exit both
116
- take 560ms, and preview/dialog transformations both take 480ms.
117
- - Modules own the full floating UI through `overlay.Card`, optionally reusing
118
- `AnnotationCard`. Centered dialogs use the page viewport and module-specified
119
- widths. Initial focus lands on the dialog container, with visible focus cues
120
- retained for keyboard navigation. Mobile TOC toggles animate continuously.
121
- - Sidebar hover applies across the whole card and survives header collapse.
122
- Close controls have background feedback. Attribute titles support source
123
- selection/highlights. Question correct diamonds are filled green; the submit
124
- label is shorter. Nested definition formula backgrounds have stronger contrast.
125
- - Citation spacing now follows the supplied screenshots: the preview item gap
126
- is 6px smaller and trailing space 2px smaller; collapsed sidebar trailing
127
- space grows 2px. Expanded sidebar heading space shrinks 2px, separator spacing
128
- moves 2px from above to below, and trailing space shrinks 3px. The final
129
- Markdown paragraph no longer overrides these gaps through margin collapse.
130
- - Video providers mount near the viewport, normalize watch/short/embed and BV/av
131
- links, retain click-loading as an option, and share the math copy primitive.
132
- YouTube uses the previous renderer's youtube.com/embed address with origin
133
- referrer information. In the local real-network comparison, dQw4w9WgXcQ failed
134
- with an auth player error even in the previous renderer's bare iframe setup;
135
- M7lc1UVf-VE loaded its player. This is not evidence that the user's specific
136
- video now plays. Automated provider tests intercept network responses.
137
- - Validation: TypeScript, all 50 unit/SSR cases, and all 33 browser cases passed.
138
- After the final animation fix, the 20 motion/reader cases were rerun; the other
139
- 13 cases include video, visual selection and the three selection performance
140
- checks. React 18.3.1 and React 19 tarball consumers passed types, SSR and browser
141
- plugin/theme checks. The local tarball and production demo were rebuilt.
142
- - Production screenshots inspected: question-refined.png,
143
- definition-math-refined-light.png, definition-math-refined-dark.png,
144
- citation-overlay-refined.png, video-provider-refined.png in artifacts/visual/.
145
- refinement-evidence.json records the compact retry button, filled correct
146
- diamond, nested formula colors and the real official YouTube player's loaded
147
- title/isPlayable state. Loading that player does not prove the reported Rick
148
- Astley video plays in the user's browser.
8
+ [文档目录 / Documentation](README.md)
@@ -0,0 +1,28 @@
1
+ # 中文文档
2
+
3
+ > 阅读提示:本文包含 LiMR 扩展语法和交互示例。部分内容在 GitHub 等普通 Markdown 阅读器中无法完整展示;前往 [GitHub Pages 文档](https://linloir.github.io/LiMR/#/docs/zh-CN/README) 可获得最佳阅读体验。
4
+
5
+ [文档目录](README.md) · [English](../en/README.md)
6
+
7
+ 这套文档对应当前仓库实现,包含本次新增的流式、排版与模块能力;使用 npm 包时请核对安装版本的导出与类型。默认入口为中文,英文页面与本目录一一对应。
8
+
9
+ | 你要做什么 | 阅读文档 |
10
+ | --- | --- |
11
+ | 安装并显示第一篇文档 | [快速开始](getting-started.md) |
12
+ | 了解模块、默认包含的能力与配置方式 | [内置模块](modules.md) |
13
+ | 编写 Markdown、Mermaid、callout、高亮、脚注与双冒号组件 | [默认语法](syntax.md) |
14
+ | 集成到 React、选择排版模式、接收流式输出、自定义布局或 SSR | [项目集成](integration.md) |
15
+ | 保存选区、高亮、引用和自定义标注,理解整体复制 | [标注与选区](annotations.md) |
16
+ | 新增语法、卡片、选区动作、流式效果或按条件替换组件 | [扩展开发](extensions.md) |
17
+ | 开发独立 npm 插件并在应用中引入 | [插件模块包](plugin-packages.md) |
18
+ | 调整主题、字体、KP 排版、动画与图表样式 | [样式与字体](styles.md) |
19
+ | 查询组件 props、hooks 和核心 API | [API 参考](api.md) |
20
+ | 理解解析、状态和资源边界 | [架构与行为](architecture.md) |
21
+ | 了解性能数据和验证范围 | [性能与限制](performance.md) |
22
+ | 让 AI 使用 LiMR 或开发插件 | [AI Skills](ai-skills.md) |
23
+
24
+ 先接入 `Reader`,需要定制布局时再拆分组件;需要应用功能时优先添加插件。Playground 中的本地保存、导入导出和模拟问答是演示应用功能,不是 Reader 自带的服务。
25
+
26
+ Playground 默认使用标准排版,可从菜单切换 Knuth–Plass 或两端对齐;流式演示已放慢。刷新会重新打开默认文档,不自动恢复上次的文章或编辑;显式保存的草稿可手动加载,语言偏好独立保留。Docs 链接支持直接打开指定页面,页内切换 Docs / Playground 保留本次会话中的编辑。
27
+
28
+ [返回 README](../../README.md) · [在线 Playground](https://linloir.github.io/LiMR/)
@@ -0,0 +1,57 @@
1
+ # AI Skills:下载、导入与使用
2
+
3
+ > 阅读提示:本文包含 LiMR 扩展语法和交互示例。部分内容在 GitHub 等普通 Markdown 阅读器中无法完整展示;前往 [GitHub Pages 文档](https://linloir.github.io/LiMR/#/docs/zh-CN/ai-skills) 可获得最佳阅读体验。
4
+
5
+ [文档目录](README.md) · [English](../en/ai-skills.md)
6
+
7
+ Skills 是指导 AI 工作的文件包,不是运行在 Reader 中的 RendererExtension,也不是模型服务。安装 Skill 不会自动修改项目、安装插件或连接 AI API。
8
+
9
+ | Skill | 适用任务 |
10
+ | --- | --- |
11
+ | [limr-use](../../skills/limr-use/SKILL.md) | 接入 LiMR、选择组件、编写语法、配置标注/流式/主题、引入已有插件 |
12
+ | [limr-plugin-development](../../skills/limr-plugin-development/SKILL.md) | 开发新插件模块包,扩展卡片/语法/动作/参数,构建并验证消费者 |
13
+
14
+ 两份 Skill 的指令使用英文以便复用,支持中文任务输入;给使用者的说明同时提供中英文。插件 Skill 包含独立模板,两个 Skill 都包含本地 references,无需把整个 LiMR 仓库放进 AI 上下文。
15
+
16
+ ## 从 npm 包导入
17
+
18
+ 先安装包含 Skills 的 LiMR 版本,在**你的应用项目**中运行:
19
+
20
+ ```sh
21
+ npm install @linloir/limr
22
+ mkdir -p .agents/skills
23
+ cp -R node_modules/@linloir/limr/skills/limr-use .agents/skills/
24
+ cp -R node_modules/@linloir/limr/skills/limr-plugin-development .agents/skills/
25
+ ```
26
+
27
+ 以上为新安装示例;已有同名目录时先检查本地定制,再更新整个目录,避免旧模板残留。导入是快照,npm 升级不会自动同步副本。升级 LiMR 后应同时检查 Skill 版本适配。
28
+
29
+ ## 从仓库或 ZIP 导入
30
+
31
+ 可以从仓库的 skills 目录复制,也可以在本地生成 ZIP(需要 Python 3):
32
+
33
+ ```sh
34
+ pnpm pack:skills
35
+ ```
36
+
37
+ 输出在 artifacts/skills,并同步到 Playground 的 public/downloads 供 Docs 页面下载。每个 ZIP 的根目录是完整 skill 文件夹,不只包含 SKILL.md;另有包含两份 Skill 的版本化总包。构建 Docs 站点时自动生成下载文件。
38
+
39
+ 对应版本网站部署后可直接下载:[limr-use.zip](https://linloir.github.io/LiMR/downloads/limr-use.zip)、[limr-plugin-development.zip](https://linloir.github.io/LiMR/downloads/limr-plugin-development.zip)。本地 Docs 的 AI Skills 页面也有下载按钮。ZIP 是便于下载的归档,不代表所有 AI 客户端都支持一键 ZIP 导入;不支持时解压并复制完整目录。
40
+
41
+ ## Codex 的位置与调用
42
+
43
+ Codex 的项目级目录是 `.agents/skills/`,用户级目录是 `~/.agents/skills/`。选择一个作用域,避免重复安装同名 Skill。客户端仍使用旧目录时,按该版本支持的路径导入。Codex 通常自动发现变化,未显示时重启;可通过 `/skills` 或 `$skill-name` 调用。依据:[OpenAI 官方 Skills 文档](https://developers.openai.com/codex/skills/)。
44
+
45
+ ```text
46
+ $limr-use 在这个 React 项目中接入 LiMR,使用中文界面、流式回答和受控标注。
47
+ ```
48
+
49
+ ```text
50
+ $limr-plugin-development 创建术语解释插件包,包含术语块、选区动作、可展开卡片和侧栏摘要,再引入当前应用。
51
+ ```
52
+
53
+ 其他支持 SKILL.md 的 AI 工具,使用其实际支持的项目/用户目录;没有 Skill 自动发现能力时,可以要求 AI 阅读 SKILL.md,并按其中链接加载 references 和 assets。无需假定某个客户端专属命令可在所有工具上工作。
54
+
55
+ ## 期望产物
56
+
57
+ 使用 Skill 应交付可运行的集成、稳定配置和验证结果;开发 Skill 应交付模块源码、包导出/类型/CSS、宿主引入示例及真实包消费验证。它们都要求以当前安装版本为准,不虚构解析能力,不删除未知标注的持久化数据,也不在未获指示时发布 npm 或修改外部服务。
@@ -0,0 +1,86 @@
1
+ # 标注与选区
2
+
3
+ > 阅读提示:本文包含 LiMR 扩展语法和交互示例。部分内容在 GitHub 等普通 Markdown 阅读器中无法完整展示;前往 [GitHub Pages 文档](https://linloir.github.io/LiMR/#/docs/zh-CN/annotations) 可获得最佳阅读体验。
4
+
5
+ [文档目录](README.md) · [English](../en/annotations.md)
6
+
7
+ ## 数据模型
8
+
9
+ `Annotation` 是数据,`AnnotationType` 是插件注册的呈现和加载逻辑,`AnnotationOccurrence` 是一次出现位置。一个标注可以通过 anchors 出现在多处;一个引用角标可以关联多条标注。
10
+
11
+ ```ts
12
+ import type { Annotation } from '@linloir/limr';
13
+
14
+ export const annotations: readonly Annotation[] = [{
15
+ id: 'paper-reference',
16
+ type: 'citation',
17
+ data: { title: 'Paper', url: 'https://example.com/paper' },
18
+ anchors: [{
19
+ range: { start: 0, end: 4 },
20
+ documentId: 'article',
21
+ quote: 'LiMR',
22
+ }],
23
+ }, {
24
+ id: 'highlight-1',
25
+ type: 'highlight',
26
+ range: { start: 0, end: 4 },
27
+ data: { color: '#F2C744', style: 'background' },
28
+ }];
29
+ ```
30
+
31
+ 这个示例要求 source 的前四个 UTF-16 单元为 `LiMR`,documentId 为 article。range 是单次锚点的简写;传 anchors 后以 anchors 为准。范围均指向**未经改写的输入**,采用 UTF-16、右端不包含,不是 UTF-8 字节或 Unicode 码点。
32
+
33
+ 持久化时保存原始 source、稳定 documentId、annotation.id、type、data、anchors,并在有需要时记录应用文档版本。anchor.revision 对应当前引擎修订号,不是跨会话持久 ID。quote 与原范围不符时,只在全文有唯一匹配时迁移;无匹配、多个匹配或 documentId 不一致会跳过该锚点。没有 quote 且 revision 不匹配的锚点也会跳过。这不是协同编辑的自动位置转换系统。
34
+
35
+ ## 三种选区
36
+
37
+ | 字段 | 含义 |
38
+ | --- | --- |
39
+ | `text` | 可读的选中文本;选区稳定后,原子内容使用完整原始源码 |
40
+ | `raw` | 映射得到的原始范围和源码 |
41
+ | `syntax` | 仅吸收两端紧邻的标准 Markdown 标记,不扩选未选文字或特殊块外层标签 |
42
+ | `blocks` | 选区触及的块范围与源码 |
43
+ | `quality` | exact、atomic 或 unmapped |
44
+ | `settled` | 指针仍在拖选时为 false |
45
+ | `documentId` / `revision` | 选区所属文档快照 |
46
+
47
+ 每种结果包含 ranges 和 sourceText。一般笔记使用 syntax.ranges,并为**每个范围**保存 `document.source.slice(start, end)` 作为 quote。代码支持部分选择;公式和图片作为原子内容。不要用 DOM textContent 长度倒推原文范围,实体、转义和 emoji 会让两者不同。
48
+
49
+ 默认选区工具栏与浏览器复制会完整序列化原子内容,保留原来的 `$…$`、`$$…$$`、图片语法、Mermaid 围栏/指令及插件块标签;周围普通文字保留渲染后的文本与显式换行。重新点击已有高亮后复制也遵循这一规则。插件的 `selection: 'atomic'` 覆盖其映射属性、子内容及嵌套原子块;模块内部的复制按钮可以提供专用格式。
50
+
51
+ ## 高亮和命令
52
+
53
+ `highlight` 不需要安装额外的 AnnotationType,data 支持 color、style(background / underline / dotted / wavy)、hidden。删除内容标注与隐藏高亮是不同操作。
54
+
55
+ | 命令 | 行为 |
56
+ | --- | --- |
57
+ | `addAnnotation(annotation, options?)` | 添加/替换同 ID 数据;普通内容标注默认同时补充共享高亮 |
58
+ | `updateAnnotation(id, partial)` | 浅合并标注字段;data 是整体替换,更新时保留需要的字段 |
59
+ | `removeAnnotation(id)` | 移除这一条标注,其他标注和共享高亮保留 |
60
+ | `removeAnnotationsAt(ranges)` | 移除精确匹配片段上的标注及高亮;保留它们其他位置的锚点 |
61
+ | `editAnnotation(id / null)` | 切换共享编辑状态;设置 ID 时也激活卡片 |
62
+ | `activateAnnotation(id / null)` | 激活标注的首个 occurrence,也接受 occurrence ID |
63
+
64
+ `addAnnotation` 的 `{ highlight: false }` 关闭自动持久高亮,显式 HighlightData 指定样式;`{ edit: true }` 进入编辑。类型配置 `highlight: 'hover'` 时默认不创建持久高亮,但显式传入高亮样式仍可创建。默认选区工具栏为调色板、添加/隐藏高亮、复制、删除;actions 覆盖内置列表,插件动作仍会合并进去。
65
+
66
+ ## Citation 的临时高亮
67
+
68
+ Citation 默认 `highlight: 'hover'`。角标或侧栏条目悬浮、或引用处于 activate 状态时,用类型 color 的 18% 底色高亮关联文本。底色绘制在文字下方;点击激活后,移开鼠标仍保留,取消激活且不再悬浮后才隐藏。同一段落的激活与悬浮引用不会叠加加深颜色。该效果不更新 annotations,也不改变已保存高亮的 hidden 设置。嵌入 ref 使用最近的段落、标题、列表项或表格单元格;外部范围引用使用自身范围,并以该范围首行对齐侧栏。
69
+
70
+ 侧栏联动使用正文位移动画,不改变页面滚动范围。绘制层在动画过程中及结束、取消时更新可见片段,因此从视口外移入的文本也会同步获得当前悬浮或激活高亮。
71
+
72
+ 使用 `replaceExtension(standard(), citation({ highlight: false }))` 关闭该效果。其他类型也可显式启用 highlight: 'hover'。
73
+
74
+ ## 缺少插件时
75
+
76
+ 当前实现**不会静默忽略未知 annotation 类型**。数据和范围仍保留,可能显示通用圆点角标;没有 Content 时卡片显示本地化的“不可用”及类型名称。缺失 citation 定义也可能显示不可用提示。要保证呈现,应安装对应插件,或由应用决定暂时隐藏哪些标注。
77
+
78
+ 若应用过滤不支持的类型,保留完整的持久化原始数组,并在写回时合并仍隐藏的数据,避免卸载插件导致数据丢失。Playground 的插件勾选目前只启用/关闭动作入口,仍保留卡片渲染器,因此不会模拟完整卸载插件。
79
+
80
+ ## 卡片与异步资源
81
+
82
+ 卡片 UI 由模块注册:Content 渲染内容,overlay.Card 负责完整浮层内部,sidebar.Preview 负责收起时的本地摘要。`AnnotationMarkdown` 在隔离选区作用域内复用 Markdown 配置。
83
+
84
+ `load(annotation, { signal })` 在内容显示时才调用,同一阅读器内复用请求和有限缓存,不在不同 Reader 间共享。Preview 不调用 load。Content 接收 data、loading、error、retry、editing、presentation、expanded;处理加载和错误 UI 是模块的职责。可通过 useLiMR().invalidateAnnotation(id) 刷新。
85
+
86
+ 动作的 signal 在阅读器销毁时取消,关闭菜单不会取消动作。调用 updateAnnotation 更新流式答案时同时保留问题字段;“停止生成”、重试、认证、会话和保存由应用 adapter 管理。参考[助手示例](../../examples/assistant.tsx)和[扩展开发](extensions.md)。
@@ -0,0 +1,115 @@
1
+ # API 参考
2
+
3
+ > 阅读提示:本文包含 LiMR 扩展语法和交互示例。部分内容在 GitHub 等普通 Markdown 阅读器中无法完整展示;前往 [GitHub Pages 文档](https://linloir.github.io/LiMR/#/docs/zh-CN/api) 可获得最佳阅读体验。
4
+
5
+ [文档目录](README.md) · [English](../en/api.md)
6
+
7
+ ## 导出入口
8
+
9
+ | 入口 | 内容 |
10
+ | --- | --- |
11
+ | @linloir/limr | 全部公开 core、React 和扩展接口 |
12
+ | @linloir/limr/core | 无 React/DOM 的文档引擎、选区计算、树工具、缓存、数据类型 |
13
+ | @linloir/limr/react | 组件、hooks、locale、React 类型 |
14
+ | @linloir/limr/extensions | 模块工厂、扩展定义、选区动作、AnnotationMarkdown |
15
+ | styles.css / styles/base.css / fonts.css / math.css | 公开样式资源,前面加包名 |
16
+ | @linloir/limr/package.json | 包元数据 |
17
+
18
+ 以下是使用入口;精确 TypeScript 签名随包导出,插件应以已安装版本的声明为准。
19
+
20
+ ## 共享文档配置
21
+
22
+ Reader、Markdown 与 DocumentProvider 接受:
23
+
24
+ | 属性 | 默认 / 说明 |
25
+ | --- | --- |
26
+ | source | 空字符串,原始 Markdown |
27
+ | streaming | false |
28
+ | documentId | 自动生成;显式值应稳定且页面内唯一 |
29
+ | extensions | standard(),完整扩展清单 |
30
+ | plugins | 追加到默认或显式清单 |
31
+ | parameters | 文档级模块参数覆盖 |
32
+ | components | 按 AST 类型/特殊标签覆盖 NodeRenderer |
33
+ | annotationTypes | 按 type 追加/覆盖标注呈现 |
34
+ | annotations | 不传则内部管理;传入则受控 |
35
+ | onAnnotationsChange | 下一份外部标注数组,包含 highlight;受控编辑必须回传 |
36
+ | theme | light,可选 dark / auto |
37
+ | appearance | classic,传播到 portal 的样式作用域 |
38
+ | locale | english,可传 chinese 或 Partial&lt;LiMRLocale&gt; |
39
+ | justify | false,段落/列表两端对齐 |
40
+ | typography | standard(默认)、knuth-plass 或 justify;保留旧 CSS 模式 pretty / normal |
41
+ | knuthPlass | TeX 段落参数,见[样式](styles.md) |
42
+ | rendererOverrides | 按顺序匹配的渲染规则:type、component 和可选 when 条件,仅作用于当前 Reader |
43
+ | streamEffect | 覆盖流式增量动画;false 关闭 |
44
+ | scrollRoot | null / 未指定表示窗口 |
45
+ | scrollOffset | 24px |
46
+ | onDocumentChange | 文档更新后的 DocumentSnapshot |
47
+ | onSelectionChange | SelectionSnapshot 或 null |
48
+ | onAnnotationClick | 激活的 AnnotationOccurrence |
49
+ | onAnnotationHover | occurrence 或 null |
50
+ | onHighlightClick / onHighlightHover | 高亮 Annotation;hover 离开为 null |
51
+
52
+ 默认 locale 是 english,Partial 未指定键回退到英文。locale 影响采用 LiMRLocale 的内置控件,不翻译正文;第三方插件通过 useLocale 自行提供文案。当前部分辅助文字(例如公式 Copy LaTeX、译文切换提示)仍是模块固定文案。Playground 的界面语言按钮可试用中文/英文切换,选择会独立保存到浏览器。
53
+
54
+ ## 组件
55
+
56
+ | 组件 | 额外属性及默认值 |
57
+ | --- | --- |
58
+ | Reader | toc=true、sidebar=true、fillHeight=true、sidebarBreakpoint=1120、actions、followOutput=false、className/style |
59
+ | Markdown | interactive=true、followOutput=false、className/style |
60
+ | DocumentProvider | children;为下方组件提供上下文 |
61
+ | TableOfContents | title、maxDepth=6、followActive=true、topInset=24、updateHash=false、className/style |
62
+ | AnnotationSidebar | sync='document' / 'none'、gap=14、positioner=alignSidebar、renderCard、className/style |
63
+ | AnnotationOverlay | disabled=false、portalRoot、previewWidth=340、maxHeight='80dvh' |
64
+ | SelectionToolbar | actions、portalRoot、maxPanelHeight=260、render、className/style |
65
+ | AnnotationCard | AnnotationOverlayCardProps 加必填 title 和可选 bodyLabel |
66
+ | AnnotationContent | annotationId、presentation、expanded=true、enabled=true |
67
+ | AnnotationGroup | occurrence、presentation、expanded=true、enabled=true |
68
+ | AnnotationMarkdown | MarkdownProps,source 必填;默认 interactive=false |
69
+ | InlineMarker | label 必填,color、children 和 button 属性/ref |
70
+ | ToolIcon | name 与 SVG 属性;如 note、copy、highlight、comment、zoom-in、zoom-out、source、image |
71
+
72
+ 除独立 Markdown 和 Reader 外,共享组件/hooks 应位于 Provider 内。AnnotationCard 是浮层内容模板,不负责自建 portal。sidebar.renderCard 接收 `{ occurrence, active, activate }`;toolbar.render 接收 `{ context, actions, run }`。
73
+
74
+ `SidebarPositioner` 接收 `{ id, anchorTop, height }[]` 与 `{ activeId, gap, height?, prioritizeActive? }`,返回 ID 到 top 的映射。anchorTop 是关联文本首行的位置;prioritizeActive 区分悬浮/激活条目与随阅读位置选择的条目。默认 alignSidebar 在静止时收拢文末卡片,交互时优先保留当前条目的对齐。
75
+
76
+ ## Hooks
77
+
78
+ | Hook | 返回 |
79
+ | --- | --- |
80
+ | useDocument() | 完整快照 |
81
+ | useDocumentSelector(select) | 选中值;返回值引用不变时不重渲染 |
82
+ | useLocale() | 当前合并后的 locale;内置 language 为 en / zh-CN,供插件选择自己的词典 |
83
+ | useSelection() | 选区或 null |
84
+ | useAnnotation(id) | 数据或 undefined |
85
+ | useAnnotations() | annotations Map 与 occurrences 数组,含源内引用及外部数据 |
86
+ | useAnnotationState() | active / hovered occurrence ID 与 activate / hover |
87
+ | useAnchor(occurrenceId) | element、视口 rect、contentRect,未挂载时为 null |
88
+ | useRendererParameter(name) | 宿主参数覆盖或最后注册的默认值 |
89
+ | useLiMR() | 文档引擎、命令、signal、clearSelection、scrollToHeading、scrollToAnnotation、invalidateAnnotation |
90
+
91
+ 不要将 useRuntime、useTheme 当作公开 API。useLocale、locale.language 和可本地化的标注 label 从 1.0.0 起提供。命令语义见[标注与选区](annotations.md),渲染和动作契约见[扩展开发](extensions.md)。
92
+
93
+ ## 核心引擎
94
+
95
+ ```ts
96
+ import { createDocument, selectionFromRange } from '@linloir/limr/core';
97
+
98
+ const engine = createDocument('# Hello\n\nText', { id: 'core-doc', streaming: true });
99
+ engine.append('\n\nMore text.');
100
+ const document = engine.finish();
101
+ const selection = selectionFromRange(document, { start: 9, end: 13 });
102
+ console.log(document.headings, selection.syntax.sourceText);
103
+ ```
104
+
105
+ createDocument(source?, { id?, extensions?, streaming? }) 返回 DocumentEngine。getSnapshot() 读取;subscribe(listener) 返回取消订阅函数;update(source, { streaming? }) 替换完整输入;append(chunk) 追加并设流式;finish() 收尾;setExtensions(list) 切换解析配置。
106
+
107
+ 核心默认 extensions=[]。纯核心使用带 micromark/mdast 的 SyntaxExtension;从 React 扩展入口导入 standard 不再是严格的无 React 依赖路径。
108
+
109
+ DocumentSnapshot 包含 id、revision、source、streaming、blocks、headings、definitions、footnotes、footnoteOrder、annotations、occurrences、diagnostics、metrics。这里 annotations 是**源内解析得到的数据**;外部受控数据使用 useAnnotations,不要混淆两个集合。
110
+
111
+ 其他核心导出包括 walk、textContent、rangeOf、intersects、safeUrl、mapText、selectionFromRange、replaceExtension、resolveAnnotationAnchors、annotationReferenceRange、sameRange、defaultHighlight、LruCache、ResourceCache。ResourceCache.acquire 返回 promise/release;invalidate 可按 key 或全部失效。
112
+
113
+ `inlineHighlights({ color?, component? })` 与 `footnotes(annotationTypeOptions?)` 都在 `standard()` 中。`HighlightData.readOnly` 限制默认高亮工具栏为复制与提示;`AnnotationOccurrence.referenceRange` 可将角标的源位置与它引用的文字范围分开。
114
+
115
+ 核心还导出 `knuthPlass(items, lengths, options?)`、`prepareKnuthPlass(items)`、`texBadness` 及对应类型。准备后的函数可按不同宽度求解同一段落,复用前缀和。
@@ -0,0 +1,41 @@
1
+ # 架构与行为
2
+
3
+ > 阅读提示:本文包含 LiMR 扩展语法和交互示例。部分内容在 GitHub 等普通 Markdown 阅读器中无法完整展示;前往 [GitHub Pages 文档](https://linloir.github.io/LiMR/#/docs/zh-CN/architecture) 可获得最佳阅读体验。
4
+
5
+ [文档目录](README.md) · [English](../en/architecture.md)
6
+
7
+ ## 三层公开边界
8
+
9
+ 1. core 管理原始 source、AST、块、标题、源内引用、诊断和选区坐标,无 React/DOM 运行时依赖。
10
+ 2. React 层将文档、交互、布局、外部标注和资源状态连接到组件。
11
+ 3. extensions 层使用同一套公开接口提供默认语法和交互;应用可以追加、替换或移除。
12
+
13
+ Doc 页面导航和 Playground 的保存、加载、语言菜单属于演示应用,不进入 LiMR 核心架构。
14
+
15
+ ## 追加解析
16
+
17
+ 流式追加从末尾尚未稳定的顶层块回退,复用稳定前缀、行号索引和节点语义索引。持续增长的代码围栏可走字面量快速路径;收尾也可只重新解析尾部,不再一律全文解析。后到的 Markdown 引用/脚注定义、中间编辑、全文 transform 或更换扩展仍可能要求全文解析。长段落、列表和复杂未闭合标签仍有尾部重解析成本。
18
+
19
+ 未闭合节点用 `incomplete` 标识,与所属顶层块仍在增长的 `pending` 区分。模块可渐进渲染或提供 `streaming.Loading`;不完整的语法头部与行内标记暂缓显示。增量动画只作用于新内容,临时包装节点在动画结束且原生选区离开后合并。代码在流式追加时保留已有文本节点,最终高亮也避开正在使用的选区。
20
+
21
+ 公开的 source 始终保留原始输入。解析器内部为双冒号组件和未闭合语法补充解析标记,再通过稀疏偏移映射还原到原始 UTF-16 坐标;这些内部标记不会进入复制、标注或持久化数据。自定义 transform 必须维护坐标和局部性约定。源码中引用数据与应用 annotations 分开输入,在 React 视图层合并。
22
+
23
+ ## 排版与源映射
24
+
25
+ 标准模式默认使用浏览器排版。KP 在客户端按需加载:准备阶段缓存字形测量、断词、合法断点和前缀和,求解阶段运行 TeX 段落动态规划。视口附近的稳定段落优先排版,滚动离开后保留 DOM;宽度变化复用准备结果与文本容器。用户仍在选择的段落保留原生 Range,等待选区释放后再排版。源码坐标与标注保持不变,详细策略和测量见[样式](styles.md)与[性能](performance.md)。
26
+
27
+ 原子内容的选区文本以完整源码序列化;同一选区里的普通文字保留渲染文本和显式换行。插件原子块的属性、子内容和嵌套原子节点服从外层整体选择契约。
28
+
29
+ ## 状态与资源
30
+
31
+ 配置数组/对象按不可变数据更新,静态配置保持引用稳定。滚动和 parameter 变化不需要重解析。一个 Provider 管理一个主正文;不同 Provider 的文档和标注请求隔离。
32
+
33
+ 标注异步资源使用阅读器内有限缓存,消费者释放后可以取消无用请求。Shiki 的纯 token 结果使用模块级有限缓存;不应将其与用户标注数据缓存混为一谈。Mermaid 结果使用有限缓存,串行处理全局初始化与绘图,防止不同主题的阅读器相互干扰。库不提供模型服务、账号认证、数据库或自动保存。
34
+
35
+ ## 退化行为
36
+
37
+ 未知 HTML/自定义标签是惰性的原文;默认配置下未知指令仅渲染子内容。未知标注类型保留数据并显示通用角标/不可用提示,并非静默跳过。不完整语法恢复、transform diagnostics 和客户端渲染错误边界各有自己的适用范围,见[扩展开发](extensions.md)。
38
+
39
+ ## 验证边界
40
+
41
+ 仓库包含解析/坐标/SSR 单元测试、真实 Chromium 交互回归和 React 18/19 独立 npm 消费验证。浏览器测试中的远程媒体拦截、移动视口模拟和性能夹具不等于真实平台播放、移动设备验收或通用性能承诺。