@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/en/styles.md
CHANGED
|
@@ -39,7 +39,8 @@ appearance propagates to portalled controls. Do not rely only on .limr-reader an
|
|
|
39
39
|
| --- | --- |
|
|
40
40
|
| --limr-font-text / --limr-font-code | Body / code fonts |
|
|
41
41
|
| --limr-font-size / --limr-line-height | Base typography |
|
|
42
|
-
| --limr-font-features | Defaults to 'palt' 1 for proportional
|
|
42
|
+
| --limr-font-features | Defaults to normal, preserving full-width Chinese punctuation; opt into 'palt' 1 for proportional spacing |
|
|
43
|
+
| --limr-punctuation-spacing | Defaults to space-all, preserving full-width spacing between CJK punctuation |
|
|
43
44
|
| --limr-emphasis-spacing / --limr-list-item-gap | Trailing emphasis / list spacing |
|
|
44
45
|
| --limr-text / --limr-heading / --limr-secondary / --limr-muted | Text hierarchy |
|
|
45
46
|
| --limr-background / --limr-surface / --limr-border | Backgrounds and borders |
|
|
@@ -54,6 +55,8 @@ appearance propagates to portalled controls. Do not rely only on .limr-reader an
|
|
|
54
55
|
| --limr-overflow-fade-size | Overflow fade, default 24px; 0px disables |
|
|
55
56
|
| --limr-toolbar-panel-max-height | Maximum toolbar panel height |
|
|
56
57
|
| --limr-tool-icon-size / --limr-mark-size | Toolbar icons / inline markers |
|
|
58
|
+
| --limr-mermaid-max-height | Diagram viewport maximum height; default min(70vh, 36rem) |
|
|
59
|
+
| --limr-mermaid-scrollbar | Thin diagram scrollbar color; default #87837866 |
|
|
57
60
|
|
|
58
61
|
--limr-toolbar-available-height, --limr-toolbar-panel-height, and --limr-toc-available-height are runtime measurements, not theme inputs. AnnotationType.sidebar usually supplies local card colors; see [extensions](extensions.md).
|
|
59
62
|
|
|
@@ -71,10 +74,26 @@ The reading region determines synchronized sidebar height; do not size the page
|
|
|
71
74
|
|
|
72
75
|
Dense footer references borrow spare space above them at rest. Hovered or active items take alignment priority, allowing neighboring items to clip at the edges. Marker hover can compress the optional summary to leave room for the reference and heading. Expanded content is bounded by the visible reading region and scrolls within its card. Packed sidebar items still align the prose on hover. Deactivation smoothly restores the resting layout using current card heights, `--limr-motion-slow`, and `--limr-ease`, preserving gaps and page height.
|
|
73
76
|
|
|
74
|
-
Selection retains native browser ranges and keyboard behavior. Paint layers calculate visible fragments only. Code allows partial highlights, math is atomic, and image highlights use borders. Printing hides paint layers while keeping document content. Mobile automation does not certify native iOS/Android handles or physical-device behavior.
|
|
77
|
+
Selection retains native browser ranges and keyboard behavior. Paint layers calculate visible fragments only. Code allows partial highlights, math is atomic, and image highlights use borders. A single atomic block anchors its toolbar below the block. Printing hides paint layers while keeping document content. Mobile automation does not certify native iOS/Android handles or physical-device behavior.
|
|
78
|
+
|
|
79
|
+
Selection-toolbar copy feedback crossfades with a small scale change. Its label width grows and shrinks to the active face with nonlinear easing through `--limr-ease`; reduced-motion preferences remove these transitions.
|
|
80
|
+
|
|
81
|
+
Mermaid diagrams support drag panning, native touch/trackpad scrolling, arrow keys, Page Up/Down, Home/End, and Shift+wheel for horizontal movement. Click or Enter selects the whole block; dragging never selects its internal labels. Zoom scrolls inside the bounded viewport. The shared glass toolbar appears on hover/focus (always on touch screens); button feedback fades its background without scaling. Source mode keeps ordinary top padding. Themes and plugins can override the diagram height and scrollbar variables on the Reader or block.
|
|
75
82
|
|
|
76
83
|
## CSS-only themes
|
|
77
84
|
|
|
78
85
|
Export CSS, include it in files, and mark sideEffects as ["**/*.css"]. A theme does not need React or parser runtime dependencies. Scope rules to an appearance name and check light, dark, auto, portals, and two differently themed readers on the same page.
|
|
79
86
|
|
|
80
87
|
Expanded toolbar panels use the full available toolbar width. The action row and available viewport determine its width; expanded content does not contribute intrinsic width or enlarge the toolbar. Highlight options use intrinsic text widths and wrap as whole items, aligned to the start. Multiline underlines need an inner inline span rather than a direct flex child.
|
|
88
|
+
|
|
89
|
+
## Paragraph layout and streaming
|
|
90
|
+
|
|
91
|
+
`typography="standard"` is the default. `justify` uses browser justification. `knuth-plass` uses TeX's box/glue/penalty dynamic program: four fitness classes, integer badness, squared penalties, consecutive/final hyphen demerits, pretolerance, tolerance and emergency passes. It optimizes the whole paragraph without a beam or paragraph-length cutoff. Default English hyphenation uses Knuth–Liang patterns; Unicode break opportunities also support Chinese punctuation. Browser font shaping remains authoritative, so this does not promise pixel-identical TeX PDF output.
|
|
92
|
+
|
|
93
|
+
`knuthPlass` accepts `pretolerance`, `tolerance`, `linePenalty`, `hyphenPenalty`, `adjacentDemerits`, `doubleHyphenDemerits`, `finalHyphenDemerits`, `emergencyStretch` (CSS pixels), `looseness`, and `hyphenate` (`false` or a function returning the word's parts). Core defaults follow TeX's usual paragraph parameters, with 16px of emergency stretch. The browser adapter instead derives 3em from the font size for break scoring only; an explicit `knuthPlass.emergencyStretch` overrides it. `pretty` and `normal` remain optional legacy CSS modes.
|
|
94
|
+
|
|
95
|
+
KP loads lazily and typesets stable paragraphs near the viewport. It retains their DOM when they leave the viewport, reuses measured items and prefix sums for width changes, and preserves native selections before updating text. During shrink, offscreen cached lines clip horizontal overflow until their queued exact layout is ready; an actively selected paragraph temporarily wraps while keeping its native range. Active streaming tails use normal wrapping until stable. Layout never changes original source text, annotations or copy output. See [performance](performance.md) for measured scroll/resize comparisons and [TeX's source](https://github.com/TeX-Live/texlive-source/blob/trunk/texk/web2c/tex.web) for the underlying paragraph model. The separation of preparation and layout also follows the incremental approach used by [Typst](https://github.com/typst/typst/tree/main/crates/typst-layout/src/inline).
|
|
96
|
+
|
|
97
|
+
Default loading rings use a fixed 32×32 view box, 22px display size, a thick track and an animated arc. Rotation and arc growth/shrink use nonlinear easing around one fixed center; color follows `--limr-secondary`. Streaming text and blocks fade from transparent to opaque, without a background tint or a second paragraph-completion entrance. Plugins can replace the shared effect through `streaming.effect`, and each Reader can override it through `streamEffect`.
|
|
98
|
+
|
|
99
|
+
Source-authored highlight blue is controlled by `--limr-inline-highlight`, or replace the module using `inlineHighlights({ color })`. Localize the read-only toolbar hint with `locale.inlineHighlightHint`.
|
package/docs/en/syntax.md
CHANGED
|
@@ -6,22 +6,26 @@
|
|
|
6
6
|
|
|
7
7
|
**Modules** are configuration objects that add capabilities such as formulas, videos, or citations. A factory is called in application code to return an object; the module name is its `name` property, used for replacement and removal; tags and directives are the syntax written in Markdown. See [built-in modules](modules.md) for concepts and configuration.
|
|
8
8
|
|
|
9
|
-
The
|
|
9
|
+
The default modules below ship with `@linloir/limr`. `Reader`, standalone `Markdown`, and `DocumentProvider` enable all of them through `standard()` by default; core-only `createDocument()` starts with CommonMark. The following sections include source and rendered examples, using LiMR itself.
|
|
10
10
|
|
|
11
11
|
## Module catalog
|
|
12
12
|
|
|
13
13
|
| Factory (application code) | Module name (name) | Capability | Registered tags / directives |
|
|
14
14
|
| --- | --- | --- | --- |
|
|
15
|
-
| `gfm()` | `gfm` | Tables, strikethrough, tasks, autolinks, standard footnotes |
|
|
16
|
-
| `math()` | `math` | Inline and display math | `$…$`,
|
|
17
|
-
| `codeHighlight()` | `code-highlight` | Shiki fenced-code highlighting | Standard code fences |
|
|
18
|
-
| `definition()` | `definition` | Definitions | Tags: definition, title, content
|
|
19
|
-
| `question()` | `question` | Exercises and answers | question and child
|
|
20
|
-
| `extras()` | `extras` | Further reading | Tags: extras, extra
|
|
21
|
-
| `video()` | `video` | Native video, YouTube, Bilibili | Tags: video, md-video
|
|
22
|
-
| `figures()` | `figures` | Figure groups and captions | Tags: figures, figure, figcaption, caption, img
|
|
23
|
-
| `citation()` | `citation` | Reference definitions and markers | Tags: citation, ref
|
|
15
|
+
| `gfm()` | `gfm` | Tables, strikethrough, tasks, autolinks, standard footnotes | `::gfm` |
|
|
16
|
+
| `math()` | `math` | Inline and display math | `$…$`, `$$…$$`, `::math` |
|
|
17
|
+
| `codeHighlight()` | `code-highlight` | Shiki fenced-code highlighting | Standard code fences, `::code` / `::code-highlight` |
|
|
18
|
+
| `definition()` | `definition` | Definitions | Tags / directives: definition, title, content |
|
|
19
|
+
| `question()` | `question` | Exercises and answers | Tags / directives: question and child names below |
|
|
20
|
+
| `extras()` | `extras` | Further reading | Tags / directives: extras, extra |
|
|
21
|
+
| `video()` | `video` | Native video, YouTube, Bilibili | Tags / directives: video, md-video |
|
|
22
|
+
| `figures()` | `figures` | Figure groups and captions | Tags / directives: figures, figure, figcaption, caption, img |
|
|
23
|
+
| `citation()` | `citation` | Reference definitions and markers | Tags / directives: citation, ref |
|
|
24
24
|
| `translations()` | `translations` | Original, translated, and parallel text | Tags and directives: translations, origin, translation |
|
|
25
|
+
| `mermaid()` | `mermaid` | Mermaid diagrams | Mermaid fences, `::mermaid` |
|
|
26
|
+
| `callout()` | `callout` | Typed, titled and collapsible quotes | `> [!type]`, `::callout` |
|
|
27
|
+
| `inlineHighlights()` | `inline-highlights` | Source-authored highlights | `==text==`, `::highlight` |
|
|
28
|
+
| `footnotes()` | `footnotes` | Comment markers and footnote cards | `[^id]`, `^[body]`, `::footnote`, `::footnote-ref` |
|
|
25
29
|
|
|
26
30
|
These are registered static tags in Markdown, not an arbitrary MDX/HTML execution environment. Use string attributes such as `multi="true"` and `answer="[0,2]"`. Do not use `answer={[0,2]}`, event functions, or spread attributes. Unregistered HTML is displayed as text; expressions are not executed and may produce diagnostics. Keep blank lines between block tags and their Markdown content.
|
|
27
31
|
|
|
@@ -48,7 +52,7 @@ const value = 42;
|
|
|
48
52
|
|
|
49
53
|
A standard footnote[^note].
|
|
50
54
|
|
|
51
|
-
[^note]:
|
|
55
|
+
[^note]: Footnote content in a sidebar or floating card.
|
|
52
56
|
````
|
|
53
57
|
|
|
54
58
|
Rendered result (interactive where applicable):
|
|
@@ -73,9 +77,9 @@ const value = 42;
|
|
|
73
77
|
|
|
74
78
|
A standard footnote[^syntax-note].
|
|
75
79
|
|
|
76
|
-
[^syntax-note]:
|
|
80
|
+
[^syntax-note]: Footnote content in a sidebar or floating card.
|
|
77
81
|
|
|
78
|
-
|
|
82
|
+
Default `[^note]` footnotes use markers and cards. Remove the `footnotes` module to restore traditional GFM endnotes. Ordinary Markdown supports ``. Raw HTML is not passed through to the DOM. Register an extension or override `components` to customize rendering.
|
|
79
83
|
|
|
80
84
|
## Math and code
|
|
81
85
|
|
|
@@ -95,7 +99,7 @@ $$
|
|
|
95
99
|
\int_0^1 x^2\,dx = \frac{1}{3}
|
|
96
100
|
$$
|
|
97
101
|
|
|
98
|
-
Import `@linloir/limr/math.css`. Configure formulas with `math({ macros, strict })`. Fenced language names select Shiki highlighting. Highlighting loads near the viewport; streaming code waits for
|
|
102
|
+
Import `@linloir/limr/math.css`. Configure formulas with `math({ macros, strict })`. Fenced language names select Shiki highlighting. Highlighting loads near the viewport; streaming code waits for closure and for native selections to leave before applying colors. Code over the default 100,000-character limit, unsupported languages, and languages outside the configured list retain readable source. Configure `codeHighlight({ languages, lightTheme, darkTheme, eager, maxLength })`.
|
|
99
103
|
|
|
100
104
|
## Definitions
|
|
101
105
|
|
|
@@ -349,4 +353,103 @@ Global `parameters.translationMode` overrides individual blocks. Pass onTranslat
|
|
|
349
353
|
|
|
350
354
|
## Selection and replacement
|
|
351
355
|
|
|
352
|
-
|
|
356
|
+
Toolbar-authored highlights are annotations; source-authored `==highlights==` offer copying without editing. All registered default tags also support their matching `::` directive. Register plugins for custom tags. See [extension development](extensions.md) to select or replace default modules.
|
|
357
|
+
|
|
358
|
+
## Two-colon components
|
|
359
|
+
|
|
360
|
+
All default modules accept the [CoMark component form](https://comark.dev/syntax/components), including nesting, scalar attributes, and Markdown children:
|
|
361
|
+
|
|
362
|
+
```md
|
|
363
|
+
::definition{title="A definition"}
|
|
364
|
+
**Rich** Markdown content.
|
|
365
|
+
::
|
|
366
|
+
|
|
367
|
+
::question{title="A question"}
|
|
368
|
+
::question-content
|
|
369
|
+
The prompt.
|
|
370
|
+
::
|
|
371
|
+
::question-answer
|
|
372
|
+
The answer.
|
|
373
|
+
::
|
|
374
|
+
::
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Names: `gfm`, `definition`, `title`, `content`, `question` and its existing child tags, `extras`, `extra`, `video`, `md-video`, `figures`, `figure`, `figcaption`, `caption`, `img`, `citation`, `ref`, `translations`, `origin`, `translation`, `code` (alias `code-highlight`), `math`, `mermaid`, `callout`, `highlight`, `footnote`, and `footnote-ref`. `::code{lang="typescript"}` and `::math` preserve their bodies literally. Standard Markdown fences, JSX, single-colon inline directives and existing triple-colon containers remain supported. An unpaired two-colon line in a finished document keeps its legacy leaf-directive meaning. This is component-syntax compatibility, not support for CoMark's YAML props, named slots or frontmatter.
|
|
378
|
+
|
|
379
|
+
During streaming, partial headers, links, inline code/emphasis/math delimiters and table headers are withheld until usable. Registered open components carry `incomplete`; the module chooses a loading view or progressive content. Code fences and display math can render before their closing delimiter. Set `streaming={false}` or call `finish()` to restore normal final Markdown interpretation. Source ranges always refer to the unmodified original input.
|
|
380
|
+
|
|
381
|
+
## Mermaid diagrams
|
|
382
|
+
|
|
383
|
+
````markdown
|
|
384
|
+
```mermaid
|
|
385
|
+
flowchart LR
|
|
386
|
+
A[Start] --> B{Ready}
|
|
387
|
+
B --> C[Read on]
|
|
388
|
+
```
|
|
389
|
+
````
|
|
390
|
+
|
|
391
|
+
`::mermaid` is also supported. Open streaming blocks show a loading ring; completed diagrams load asynchronously and fade into view. The math-style surface has one rounded toolbar for copying source, zooming in/out, and switching source/image views. Selection, highlights and markers treat the whole diagram atomically in both views. Mermaid uses strict mode without diagram interaction callbacks.
|
|
392
|
+
|
|
393
|
+
Rendered result:
|
|
394
|
+
|
|
395
|
+
```mermaid
|
|
396
|
+
flowchart LR
|
|
397
|
+
A[Start] --> B{Ready}
|
|
398
|
+
B --> C[Read on]
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Drag to pan, or use arrow keys, Page Up/Down, Home/End and the wheel; Shift+wheel moves horizontally. Click or Enter selects the whole block with its selection toolbar below. Zoomed content scrolls within `--limr-mermaid-max-height`, defaulting to `min(70vh, 36rem)`. The diagram's own copy button copies its body; selection-toolbar and browser copying preserve the full fence or directive. See [styles](styles.md) and [atomic copying](annotations.md).
|
|
402
|
+
|
|
403
|
+
## Callouts and nested quotes
|
|
404
|
+
|
|
405
|
+
```markdown
|
|
406
|
+
> [!tip]+ Custom title
|
|
407
|
+
> A useful hint.
|
|
408
|
+
>
|
|
409
|
+
> > An ordinary nested quote.
|
|
410
|
+
> >
|
|
411
|
+
> > > [!warning]- Collapsible reminder
|
|
412
|
+
> > > With **Markdown** content.
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Default types are `note`, `abstract`, `info`, `todo`, `tip`, `success`, `question`, `warning`, `failure`, `danger`, `bug`, `example`, and `quote`. Obsidian aliases are supported: summary/tldr, hint/important, check/done, help/faq, caution/attention, fail/missing, error, and cite. Types are case-insensitive; unknown names use note styling. `+` starts expanded, `-` starts collapsed, and no sign creates a regular block. The equivalent component is `::callout{type="tip" title="Title" fold="-"}`.
|
|
416
|
+
|
|
417
|
+
Rendered result; expand the nested reminder:
|
|
418
|
+
|
|
419
|
+
> [!tip]+ Custom title
|
|
420
|
+
> A useful hint.
|
|
421
|
+
>
|
|
422
|
+
> > An ordinary nested quote.
|
|
423
|
+
> >
|
|
424
|
+
> > > [!warning]- Collapsible reminder
|
|
425
|
+
> > > With **Markdown** content.
|
|
426
|
+
|
|
427
|
+
## Source highlights and footnotes
|
|
428
|
+
|
|
429
|
+
```markdown
|
|
430
|
+
==A blue highlight== offers copying without editing.
|
|
431
|
+
|
|
432
|
+
==A named note==[^note]
|
|
433
|
+
|
|
434
|
+
==An inline note==^[With **Markdown** content.]
|
|
435
|
+
|
|
436
|
+
[^note]: Footnote content.
|
|
437
|
+
|
|
438
|
+
A second paragraph.
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
Highlights preserve rich inline formatting. Escaped punctuation, code and math do not create highlights. Override the blue through `--limr-inline-highlight` or `inlineHighlights({ color })`. Their toolbar contains only a copy button and a single-line, left-aligned read-only hint.
|
|
442
|
+
|
|
443
|
+
Footnotes use rounded comment markers, sidebar items on wide readers, and floating cards on narrow readers. Adjacent footnotes reference precisely the highlighted text; standalone markers reference their paragraph. Named definitions can be reused. `::highlight`, `::footnote{id="note"}`, and `::footnote-ref{id="note"}` provide component forms. Removing the `footnotes` module restores GFM superscripts and endnotes.
|
|
444
|
+
|
|
445
|
+
Rendered result; click a highlight or comment marker:
|
|
446
|
+
|
|
447
|
+
==A blue highlight== offers copying without editing.
|
|
448
|
+
|
|
449
|
+
==A named note==[^syntax-source-highlight]
|
|
450
|
+
|
|
451
|
+
==An inline note==^[With **Markdown** content.]
|
|
452
|
+
|
|
453
|
+
[^syntax-source-highlight]: Footnote content.
|
|
454
|
+
|
|
455
|
+
A second paragraph.
|
package/docs/zh-CN/README.md
CHANGED
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
[文档目录](README.md) · [English](../en/README.md)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
这套文档对应当前仓库实现,包含本次新增的流式、排版与模块能力;使用 npm 包时请核对安装版本的导出与类型。默认入口为中文,英文页面与本目录一一对应。
|
|
8
8
|
|
|
9
9
|
| 你要做什么 | 阅读文档 |
|
|
10
10
|
| --- | --- |
|
|
11
11
|
| 安装并显示第一篇文档 | [快速开始](getting-started.md) |
|
|
12
12
|
| 了解模块、默认包含的能力与配置方式 | [内置模块](modules.md) |
|
|
13
|
-
| 编写 Markdown
|
|
14
|
-
| 集成到 React
|
|
15
|
-
|
|
|
16
|
-
|
|
|
13
|
+
| 编写 Markdown、Mermaid、callout、高亮、脚注与双冒号组件 | [默认语法](syntax.md) |
|
|
14
|
+
| 集成到 React、选择排版模式、接收流式输出、自定义布局或 SSR | [项目集成](integration.md) |
|
|
15
|
+
| 保存选区、高亮、引用和自定义标注,理解整体复制 | [标注与选区](annotations.md) |
|
|
16
|
+
| 新增语法、卡片、选区动作、流式效果或按条件替换组件 | [扩展开发](extensions.md) |
|
|
17
17
|
| 开发独立 npm 插件并在应用中引入 | [插件模块包](plugin-packages.md) |
|
|
18
|
-
|
|
|
18
|
+
| 调整主题、字体、KP 排版、动画与图表样式 | [样式与字体](styles.md) |
|
|
19
19
|
| 查询组件 props、hooks 和核心 API | [API 参考](api.md) |
|
|
20
20
|
| 理解解析、状态和资源边界 | [架构与行为](architecture.md) |
|
|
21
21
|
| 了解性能数据和验证范围 | [性能与限制](performance.md) |
|
|
@@ -23,4 +23,6 @@
|
|
|
23
23
|
|
|
24
24
|
先接入 `Reader`,需要定制布局时再拆分组件;需要应用功能时优先添加插件。Playground 中的本地保存、导入导出和模拟问答是演示应用功能,不是 Reader 自带的服务。
|
|
25
25
|
|
|
26
|
+
Playground 默认使用标准排版,可从菜单切换 Knuth–Plass 或两端对齐;流式演示已放慢。刷新会重新打开默认文档,不自动恢复上次的文章或编辑;显式保存的草稿可手动加载,语言偏好独立保留。Docs 链接支持直接打开指定页面,页内切换 Docs / Playground 保留本次会话中的编辑。
|
|
27
|
+
|
|
26
28
|
[返回 README](../../README.md) · [在线 Playground](https://linloir.github.io/LiMR/)
|
|
@@ -36,7 +36,7 @@ export const annotations: readonly Annotation[] = [{
|
|
|
36
36
|
|
|
37
37
|
| 字段 | 含义 |
|
|
38
38
|
| --- | --- |
|
|
39
|
-
| `text` |
|
|
39
|
+
| `text` | 可读的选中文本;选区稳定后,原子内容使用完整原始源码 |
|
|
40
40
|
| `raw` | 映射得到的原始范围和源码 |
|
|
41
41
|
| `syntax` | 仅吸收两端紧邻的标准 Markdown 标记,不扩选未选文字或特殊块外层标签 |
|
|
42
42
|
| `blocks` | 选区触及的块范围与源码 |
|
|
@@ -46,6 +46,8 @@ export const annotations: readonly Annotation[] = [{
|
|
|
46
46
|
|
|
47
47
|
每种结果包含 ranges 和 sourceText。一般笔记使用 syntax.ranges,并为**每个范围**保存 `document.source.slice(start, end)` 作为 quote。代码支持部分选择;公式和图片作为原子内容。不要用 DOM textContent 长度倒推原文范围,实体、转义和 emoji 会让两者不同。
|
|
48
48
|
|
|
49
|
+
默认选区工具栏与浏览器复制会完整序列化原子内容,保留原来的 `$…$`、`$$…$$`、图片语法、Mermaid 围栏/指令及插件块标签;周围普通文字保留渲染后的文本与显式换行。重新点击已有高亮后复制也遵循这一规则。插件的 `selection: 'atomic'` 覆盖其映射属性、子内容及嵌套原子块;模块内部的复制按钮可以提供专用格式。
|
|
50
|
+
|
|
49
51
|
## 高亮和命令
|
|
50
52
|
|
|
51
53
|
`highlight` 不需要安装额外的 AnnotationType,data 支持 color、style(background / underline / dotted / wavy)、hidden。删除内容标注与隐藏高亮是不同操作。
|
package/docs/zh-CN/api.md
CHANGED
|
@@ -37,6 +37,10 @@ Reader、Markdown 与 DocumentProvider 接受:
|
|
|
37
37
|
| appearance | classic,传播到 portal 的样式作用域 |
|
|
38
38
|
| locale | english,可传 chinese 或 Partial<LiMRLocale> |
|
|
39
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 关闭 |
|
|
40
44
|
| scrollRoot | null / 未指定表示窗口 |
|
|
41
45
|
| scrollOffset | 24px |
|
|
42
46
|
| onDocumentChange | 文档更新后的 DocumentSnapshot |
|
|
@@ -63,7 +67,7 @@ Reader、Markdown 与 DocumentProvider 接受:
|
|
|
63
67
|
| AnnotationGroup | occurrence、presentation、expanded=true、enabled=true |
|
|
64
68
|
| AnnotationMarkdown | MarkdownProps,source 必填;默认 interactive=false |
|
|
65
69
|
| InlineMarker | label 必填,color、children 和 button 属性/ref |
|
|
66
|
-
| ToolIcon | name 与 SVG 属性;如 note、copy、
|
|
70
|
+
| ToolIcon | name 与 SVG 属性;如 note、copy、highlight、comment、zoom-in、zoom-out、source、image |
|
|
67
71
|
|
|
68
72
|
除独立 Markdown 和 Reader 外,共享组件/hooks 应位于 Provider 内。AnnotationCard 是浮层内容模板,不负责自建 portal。sidebar.renderCard 接收 `{ occurrence, active, activate }`;toolbar.render 接收 `{ context, actions, run }`。
|
|
69
73
|
|
|
@@ -105,3 +109,7 @@ createDocument(source?, { id?, extensions?, streaming? }) 返回 DocumentEngine
|
|
|
105
109
|
DocumentSnapshot 包含 id、revision、source、streaming、blocks、headings、definitions、footnotes、footnoteOrder、annotations、occurrences、diagnostics、metrics。这里 annotations 是**源内解析得到的数据**;外部受控数据使用 useAnnotations,不要混淆两个集合。
|
|
106
110
|
|
|
107
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` 及对应类型。准备后的函数可按不同宽度求解同一段落,复用前缀和。
|
|
@@ -14,15 +14,23 @@ Doc 页面导航和 Playground 的保存、加载、语言菜单属于演示应
|
|
|
14
14
|
|
|
15
15
|
## 追加解析
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
流式追加从末尾尚未稳定的顶层块回退,复用稳定前缀、行号索引和节点语义索引。持续增长的代码围栏可走字面量快速路径;收尾也可只重新解析尾部,不再一律全文解析。后到的 Markdown 引用/脚注定义、中间编辑、全文 transform 或更换扩展仍可能要求全文解析。长段落、列表和复杂未闭合标签仍有尾部重解析成本。
|
|
18
18
|
|
|
19
|
-
|
|
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
|
+
原子内容的选区文本以完整源码序列化;同一选区里的普通文字保留渲染文本和显式换行。插件原子块的属性、子内容和嵌套原子节点服从外层整体选择契约。
|
|
20
28
|
|
|
21
29
|
## 状态与资源
|
|
22
30
|
|
|
23
31
|
配置数组/对象按不可变数据更新,静态配置保持引用稳定。滚动和 parameter 变化不需要重解析。一个 Provider 管理一个主正文;不同 Provider 的文档和标注请求隔离。
|
|
24
32
|
|
|
25
|
-
标注异步资源使用阅读器内有限缓存,消费者释放后可以取消无用请求。Shiki 的纯 token
|
|
33
|
+
标注异步资源使用阅读器内有限缓存,消费者释放后可以取消无用请求。Shiki 的纯 token 结果使用模块级有限缓存;不应将其与用户标注数据缓存混为一谈。Mermaid 结果使用有限缓存,串行处理全局初始化与绘图,防止不同主题的阅读器相互干扰。库不提供模型服务、账号认证、数据库或自动保存。
|
|
26
34
|
|
|
27
35
|
## 退化行为
|
|
28
36
|
|
package/docs/zh-CN/extensions.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
| 一个带 Markdown 正文的新区块 | defineBlock |
|
|
14
14
|
| 一种独立标注类型 | defineAnnotation |
|
|
15
15
|
| 组合语法、标注、动作和参数 | defineExtension / RendererExtension |
|
|
16
|
-
|
|
|
16
|
+
| 改写已有节点外观或只替换满足条件的节点 | components / rendererOverrides |
|
|
17
17
|
| 新的解析规则 | micromark + mdast 扩展,必要时 transform |
|
|
18
18
|
| 仅修改视觉 | CSS 主题包 + appearance |
|
|
19
19
|
|
|
@@ -51,7 +51,7 @@ export const notice = defineBlock({
|
|
|
51
51
|
});
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
支持 `<notice title="提示">…</notice
|
|
54
|
+
支持 `<notice title="提示">…</notice>`、配对的 `::notice{title="提示"}` / `::`,以及 `:::` 容器。name 默认同时成为标签名和指令名,可通过 tags / directives 自定义。defineBlock 默认 display: block、selection: content、scope: local。
|
|
55
55
|
|
|
56
56
|
| NodeRendererProps | 用法 |
|
|
57
57
|
| --- | --- |
|
|
@@ -59,6 +59,7 @@ export const notice = defineBlock({
|
|
|
59
59
|
| children | 已经渲染好的子树;优先复用 |
|
|
60
60
|
| source | **当前节点**对应的源码片段,不是全文 |
|
|
61
61
|
| pending | 所属尾块是否仍在流式生成 |
|
|
62
|
+
| incomplete | 当前语法节点是否尚未闭合 |
|
|
62
63
|
| renderChildren(nodes, { trailing? }) | 重排已有子树,可在末尾注入纯操作角标 |
|
|
63
64
|
| renderValue(tokens?) | 渲染字面量及高亮 token,保留原文选择和标注插入 |
|
|
64
65
|
| renderAttribute(name) | 显示属性文本并保留原文坐标 |
|
|
@@ -148,12 +149,62 @@ export const glossary = defineExtension({
|
|
|
148
149
|
|
|
149
150
|
## 解析与流式约束
|
|
150
151
|
|
|
151
|
-
SyntaxExtension 支持 micromark、mdast、tags、directives、display、selection、transform 和 scope。transform 默认全文作用域;仅依赖当前局部子树、不会回写前文或读取全局文档语义时才声明 scope: local。context.source 仍是原始全文,position 必须保持原始 UTF-16
|
|
152
|
+
SyntaxExtension 支持 micromark、mdast、tags、directives、display、selection、literal、transform 和 scope。transform 默认全文作用域;仅依赖当前局部子树、不会回写前文或读取全局文档语义时才声明 scope: local。context.source 仍是原始全文,position 必须保持原始 UTF-16 坐标。插件不要先用正则替换 source 再解析。
|
|
152
153
|
|
|
153
|
-
未知特殊标签安全显示整段原文,内部 Markdown 也作为原文显示。默认配置的未知指令则渲染内部 Markdown,丢弃指令外层标记;未安装任何指令扩展时按基础 Markdown
|
|
154
|
+
未知特殊标签安全显示整段原文,内部 Markdown 也作为原文显示。默认配置的未知指令则渲染内部 Markdown,丢弃指令外层标记;未安装任何指令扩展时按基础 Markdown 解析。已注册的未闭合标签和容器携带 node.incomplete,之后追加继续恢复;半截头部暂缓显示或交由模块展示 loading;无效 JSX 仍可能回退并记录 diagnostics;结束必须 finish 或 streaming=false。扩展 transform 的异常记录为 diagnostic;客户端渲染边界可回退源码,但 React 错误边界不负责捕获服务端渲染异常。
|
|
154
155
|
|
|
155
156
|
验证应覆盖标签/指令、中文与 emoji、源坐标、流式结束与一次性解析等价、SSR,以及新增交互的浏览器行为。独立分发还需验证真实打包消费,见[插件模块包](plugin-packages.md)。
|
|
156
157
|
|
|
157
158
|
## 插件本地化
|
|
158
159
|
|
|
159
160
|
1.0.0 起,组件可用 useLocale() 读取合并后的 locale,以 locale.language 选择自己的文案。AnnotationType.label 接受字符串或 `(locale) => string`;选区动作使用 context.locale。Citation 默认标题随语言切换为 Citation / 引用。保持插件实例稳定即可更新文案,无需重写源文;用户保存的笔记不会被翻译。
|
|
161
|
+
|
|
162
|
+
## 流式中间态与增量动画
|
|
163
|
+
|
|
164
|
+
`pending` 表示顶层块还在增长;`incomplete` 表示当前语法节点尚未闭合。注册的标签自动支持组件指令写法。`defineBlock` 可提供 `streaming.Loading`,不提供时由原组件渐进渲染,并通过 `incomplete` 判断状态。后续内容到来时保持组件身份和内部状态。
|
|
165
|
+
|
|
166
|
+
默认的定义、题目、拓展阅读、视频、图片和 callout 指令使用小圆环等待完整内容;Mermaid 等待闭合后异步绘图;代码、公式、GFM 和翻译模块直接展示可用中间态。callout 的引用块写法可在头部完整后渐进展示正文。未闭合的引用定义不会提前注册不完整数据。第三方模块完全拥有自己的中间态样式。
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
import { defineBlock, defineExtension } from '@linloir/limr';
|
|
170
|
+
|
|
171
|
+
export const chart = defineBlock({
|
|
172
|
+
name: 'chart',
|
|
173
|
+
component: ({ children }) => <section>{children}</section>,
|
|
174
|
+
streaming: { Loading: () => <span role="status">正在准备图表…</span> },
|
|
175
|
+
});
|
|
176
|
+
export const streamMotion = defineExtension({
|
|
177
|
+
name: 'example:stream-motion',
|
|
178
|
+
streaming: {
|
|
179
|
+
effect: {
|
|
180
|
+
className: 'my-stream-increment',
|
|
181
|
+
keyframes: [{ opacity: 0.25 }, { opacity: 1 }],
|
|
182
|
+
timing: { duration: 320, easing: 'ease-out' },
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
后注册的 `streaming.effect` 优先,阅读器的 `streamEffect` 拥有最终覆盖权,`false` 关闭效果。关键帧和时间选项使用 Web Animations API;减少动态效果的系统偏好会阻止新动画。默认动画仅改变新增文字和特殊块的透明度,不添加背景色;文字动画结束后在原生选区离开时合并临时包装节点。使用 `children`、`renderChildren` 和 `renderValue` 可保留这些行为;插件自行替换 DOM 时,需要自行维护选区和动画。
|
|
189
|
+
|
|
190
|
+
`SyntaxExtension.literal` 让指令正文保持字面量,避免内部代码被解释为 Markdown 或 JSX。模块可读取原始 `source` 或变换组件节点;它不会执行属性表达式、YAML 或 JavaScript。
|
|
191
|
+
|
|
192
|
+
## 按条件替换渲染组件
|
|
193
|
+
|
|
194
|
+
模块可通过 `rendererOverrides` 限制替换的节点类型、语言、祖先或流式状态;规则只作用于使用该模块的 Reader。后注册且满足条件的规则优先;宿主 Reader 的规则优先于模块和 `components` 映射。未匹配的节点继续使用原组件。
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import { defineExtension, type NodeRenderer } from '@linloir/limr';
|
|
198
|
+
|
|
199
|
+
const JavaScriptCode: NodeRenderer = ({ renderValue }) => <pre>{renderValue()}</pre>;
|
|
200
|
+
export const customCode = defineExtension({
|
|
201
|
+
name: 'example:javascript-code',
|
|
202
|
+
rendererOverrides: [{
|
|
203
|
+
type: 'code',
|
|
204
|
+
when: (node, context) => node.lang === 'js' && !context.incomplete,
|
|
205
|
+
component: JavaScriptCode,
|
|
206
|
+
}],
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`when` 也能读取 `pending` 和 `ancestors`。显式替换组件拥有自己的中间态渲染,仍处于 LiMR 的源范围、原子选择和异常边界之内。使用 `renderValue`、`renderAttribute`、`renderChildren` 维持精确映射。这里的限制是渲染规则作用域,不是对第三方 JavaScript 的安全沙箱。
|
|
@@ -36,6 +36,8 @@ export function Article() {
|
|
|
36
36
|
|
|
37
37
|
宽屏提供目录、正文和侧栏;容器宽度小于 `sidebarBreakpoint`(默认 1120px)时标注改用浮层。目录在窄屏以可折叠列表展示。
|
|
38
38
|
|
|
39
|
+
默认排版为 `standard`;可选 `knuth-plass` 或 `justify`,见[项目集成](integration.md)。默认模块还提供 Mermaid、嵌套 callout、`==高亮==` 和脚注卡片,不需要再追加同名插件;完整列表见[内置模块](modules.md)。
|
|
40
|
+
|
|
39
41
|
## 只需要正文
|
|
40
42
|
|
|
41
43
|
```tsx
|
|
@@ -21,7 +21,31 @@ export function StreamingAnswer({ answer, generating }: {
|
|
|
21
21
|
}
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
应用负责传输层,把每个片段追加到完整 `answer`;不要只把最后一个片段传给 source。最后一次更新必须传 `streaming={false}
|
|
24
|
+
应用负责传输层,把每个片段追加到完整 `answer`;不要只把最后一个片段传给 source。最后一次更新必须传 `streaming={false}`,完成尾部语法与语义校正。收尾可以复用稳定前缀;引用定义变化等情况仍可能触发全文解析。followOutput 只在仍靠近底部时跟随,不会强行拉回正在阅读上文的用户。纯核心支持 `append(chunk)` / `finish()`,React props 使用累计字符串。
|
|
25
|
+
|
|
26
|
+
默认新增文字和特殊块使用透明度淡入,段落结束时不重播动画。`streamEffect={false}` 可关闭,传入 `className`、`keyframes` 和 `timing` 可自定义;系统的减少动态效果偏好优先。未闭合模块可显示 loading,代码/公式渐进显示;复用 `children`、`renderChildren`、`renderValue` 有助于保留控件状态与选区。插件接口见[扩展开发](extensions.md)。
|
|
27
|
+
|
|
28
|
+
## 段落排版
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { useState } from 'react';
|
|
32
|
+
import { Reader, type TypographyMode } from '@linloir/limr';
|
|
33
|
+
|
|
34
|
+
export function TypographyReader({ source }: { source: string }) {
|
|
35
|
+
const [mode, setMode] = useState<TypographyMode>('standard');
|
|
36
|
+
return <>
|
|
37
|
+
<select aria-label="排版模式" value={mode}
|
|
38
|
+
onChange={event => setMode(event.target.value as TypographyMode)}>
|
|
39
|
+
<option value="standard">标准</option>
|
|
40
|
+
<option value="knuth-plass">Knuth–Plass</option>
|
|
41
|
+
<option value="justify">两端对齐</option>
|
|
42
|
+
</select>
|
|
43
|
+
<Reader source={source} typography={mode} />
|
|
44
|
+
</>;
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`standard` 为默认值;`justify` 使用浏览器两端对齐;`knuth-plass` 启用真正的段落优化算法。`knuthPlass` 可调整 TeX 参数与断词;流式尾段稳定后再参与 KP 排版。详细行为及性能边界见[样式](styles.md)和[性能](performance.md)。
|
|
25
49
|
|
|
26
50
|
## 内部滚动容器
|
|
27
51
|
|
|
@@ -111,7 +135,7 @@ export async function renderArticle(source: string) {
|
|
|
111
135
|
}
|
|
112
136
|
```
|
|
113
137
|
|
|
114
|
-
也可以使用 React 流式 SSR 处理 Suspense。Shiki 在客户端补充高亮,SSR HTML
|
|
138
|
+
也可以使用 React 流式 SSR 处理 Suspense。Shiki 在客户端补充高亮,SSR HTML 仍包含代码文本。Mermaid 在服务器输出 loading,客户端完成绘图后淡入;KP 在客户端测量字体并排版,SSR 保留普通文本布局。`load` 标注请求在客户端显示卡片时发起;如需服务端已有内容,可预先放进 annotation.data。宿主仍需把 CSS 和字体资源放到页面能访问的位置。
|
|
115
139
|
|
|
116
140
|
## 已有插件与主题
|
|
117
141
|
|
package/docs/zh-CN/modules.md
CHANGED
|
@@ -40,13 +40,13 @@ export function Article() {
|
|
|
40
40
|
|
|
41
41
|
`video({ loading: 'click' })` 的参数设置这个 Reader 中视频模块的默认行为;正文的 `<video loading="eager" … />` 则可以覆盖某一个视频的设置。不同模块支持不同参数,见[默认语法](syntax.md)。
|
|
42
42
|
|
|
43
|
-
## 随 LiMR
|
|
43
|
+
## 随 LiMR 提供的默认模块
|
|
44
44
|
|
|
45
|
-
这些模块都随 `@linloir/limr`
|
|
45
|
+
这些模块都随 `@linloir/limr` 安装,不需要分别安装 npm 包。`standard()` 返回下面的模块对象数组,使用各自的默认配置。
|
|
46
46
|
|
|
47
47
|
| 创建模块的函数 | 对象的 `name` | 增加的能力与正文写法 |
|
|
48
48
|
| --- | --- | --- |
|
|
49
|
-
| `gfm()` | `gfm` | 表格、`~~删除线~~`、任务列表、自动链接、`[^id]`
|
|
49
|
+
| `gfm()` | `gfm` | 表格、`~~删除线~~`、任务列表、自动链接、`[^id]` 脚注解析 |
|
|
50
50
|
| `math()` | `math` | `$…$` 行内公式、`$$…$$` 块级公式,需要额外导入 math.css |
|
|
51
51
|
| `codeHighlight()` | `code-highlight` | 使用 Shiki 为带语言标记的代码围栏着色 |
|
|
52
52
|
| `definition()` | `definition` | `<definition>` 释义卡片,可带标题与 Markdown 正文 |
|
|
@@ -56,12 +56,16 @@ export function Article() {
|
|
|
56
56
|
| `figures()` | `figures` | `<figures>` / `<figure>` 响应式图组、单图和图注 |
|
|
57
57
|
| `citation()` | `citation` | `<citation>` 定义来源,`<ref>` 插入引用角标和卡片 |
|
|
58
58
|
| `translations()` | `translations` | `<translations>` 包含原文与译文,切换原文、译文、对照 |
|
|
59
|
+
| `mermaid()` | `mermaid` | Mermaid 围栏 / `::mermaid`,图像、源码、缩放和复制 |
|
|
60
|
+
| `callout()` | `callout` | Obsidian callout 类型、别名和嵌套注释 / `::callout` |
|
|
61
|
+
| `inlineHighlights()` | `inline-highlights` | `==文字==` 和 `::highlight`,默认蓝色只读高亮 |
|
|
62
|
+
| `footnotes()` | `footnotes` | `[^id]`、`^[正文]`,评论角标与脚注卡片;`::footnote` / `::footnote-ref` |
|
|
59
63
|
|
|
60
|
-
所有函数都可以从 `@linloir/limr` 或 `@linloir/limr/extensions` 导入。`standard()`
|
|
64
|
+
所有函数都可以从 `@linloir/limr` 或 `@linloir/limr/extensions` 导入。`standard()` 是便捷组合函数,自身不是额外的模块;它的返回值是数组。
|
|
61
65
|
|
|
62
66
|
`Reader`、独立使用的 `Markdown`、`DocumentProvider` 在未传 `extensions` 时自动使用 `standard()`,因此最初的 `<Reader source={source} />` 就支持这些能力。共享 Provider 内的组件使用 Provider 的配置。纯核心 `createDocument()` 默认只启用 CommonMark;需要时显式传入扩展,它不负责显示 React UI。
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
高亮、复制、删除选区标注是工具栏自带动作。`==文字==` 和 Markdown 脚注由默认模块自动识别;源码中的高亮只可复制,不能通过工具栏编辑。Playground 的可编辑旁注、笔记、提问、脚注和模拟 AI 问答来自示例插件,**没有自动装进每个 Reader**。`question()` 的练习题与“提问”标注也不是同一功能。
|
|
65
69
|
|
|
66
70
|
## 按需要组合
|
|
67
71
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[文档目录](README.md) · [English](../en/performance.md)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
前几节保留仓库 **2026-10-12** 的历史基准,便于对照。文末 **2026-10-13** 一节记录本次优化实测。两组数据都不是性能保证。
|
|
8
8
|
|
|
9
9
|
环境:Intel Core i7-13700、WSL2/Linux、Node 20.19.5、Chromium 156.0.8078.4、React 19 production。对照为 react-markdown 10.1.0 + remark-gfm 4.0.1。
|
|
10
10
|
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
保留全部 DOM 支持搜索、选择和打印,因此首次完整长文渲染仍有成本。增量解析复用稳定前缀;长尾块、全文 transform、定义变化、中间编辑和收尾仍可昂贵。保持 extensions/plugins 引用稳定,按需要限制高亮语言和长度。
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
上面的历史测量未覆盖完整 Reader 布局;下方新增的 KP 对照包含一个完整 Reader 场景。两组数据都未覆盖大量公式、Shiki 冷启动、任意密集标注或插件组合、实体移动设备。字体安装体积与浏览器请求量也不同,见[样式与字体](styles.md)。
|
|
41
41
|
|
|
42
42
|
## 在仓库复现
|
|
43
43
|
|
|
@@ -51,3 +51,43 @@ pnpm bench:selection
|
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
运行时避免同时构建或跑其他基准;脚本写入 benchmarks/results。每次使用自己的硬件、内容和已构建版本重新判断,不把历史测量当作最新包验收结果。
|
|
54
|
+
|
|
55
|
+
## 2026-10-13:流式与排版优化实测
|
|
56
|
+
|
|
57
|
+
以下为本次工作区实现与修改前提交 `ebab991` 的同进程对比,使用同一依赖、原始 UTF-16 输入、分块大小和五次交错顺序采样,按总耗时取中位样本。数据只包含核心追加和收尾,不包含 React、浏览器布局、异步高亮或网络。机器和运行时见 [streaming.json](../../benchmarks/results/streaming.json)。
|
|
58
|
+
|
|
59
|
+
| 场景 | 字符数 | 修改前总耗时 | 修改后总耗时 |
|
|
60
|
+
| --- | ---: | ---: | ---: |
|
|
61
|
+
| GFM | 34,860 | 139.22ms | 89.07ms |
|
|
62
|
+
| 默认模块 | 34,860 | 141.40ms | 94.63ms |
|
|
63
|
+
| 增长的代码围栏 | 43,209 | 1335.87ms | 29.05ms |
|
|
64
|
+
| 单个长段落 | 7,840 | 72.43ms | 74.32ms |
|
|
65
|
+
|
|
66
|
+
优化包含:追加时增量维护行号、缓存已完成节点的语义索引、局部收尾、持续增长代码的词法快速路径,以及按需创建代码字符映射。仍在增长的复杂段落要重新解析;单个长段落的差异较小且受运行波动影响,不能据此声称所有内容都同比加速。
|
|
67
|
+
|
|
68
|
+
运行 `pnpm bench:streaming` 测量当前核心。需要交错对照时,将 `LIMR_BENCH_BASELINE` 指向未修改的 `ebab991` 独立检出目录,并确保那里可访问相同依赖。脚本写入 `benchmarks/results/streaming.json`;复跑不意味着能复现历史硬件与耗时。
|
|
69
|
+
|
|
70
|
+
生产 Chromium 156 的完整同步更新(React 提交加布局、默认排版和增量动画)中,默认模块的 34,860 字符流式文档 P95 为 **3.9ms**、最大 7.3ms;43,211 字符代码 P95 为 **2.6ms**、最大 12.4ms。每种场景三次隔离页面采样、字体预热、256 字符一块,rAF 等待和异步高亮不计入。这里没有浏览器旧版本对照,也不代表物理设备上的端到端帧率。原始数据:[streaming-browser.json](../../benchmarks/results/streaming-browser.json)。
|
|
71
|
+
|
|
72
|
+
KP 提供独立生产基准:在完整 scikit-learn Playground 中保留目录、侧栏和标注,每种模式使用三个独立页面,各进行三轮向下/向上滚动,再进行 32 次 1100–1420px 的窗口宽度变化。第一轮包含新进入视口的段落排版,后续轮次复用结果。以下合并每种模式的 1,080 个滚动样本和 96 个缩放样本,没有 CPU 降速。
|
|
73
|
+
|
|
74
|
+
| 测量 | 标准模式 | Knuth–Plass |
|
|
75
|
+
| --- | ---: | ---: |
|
|
76
|
+
| 滚动中位数 / P95 / 最大值 | 16.6 / 17.0 / 18.5ms | 16.6 / 19.8 / 46.5ms |
|
|
77
|
+
| 缩放中位数 / P95 / 最大值 | 11.2 / 24.1 / 31.9ms | 17.7 / 41.6 / 49.9ms |
|
|
78
|
+
| 超过 50ms 的滚动样本 | 0 / 1,080 | 0 / 1,080 |
|
|
79
|
+
| 超过 50ms 的缩放样本 | 0 / 96 | 0 / 96 |
|
|
80
|
+
|
|
81
|
+
侧栏起点定位按源码范围跳过无关绑定,找到首个可见字符即停止,不再为每条批注遍历全部 KP 行节点。
|
|
82
|
+
|
|
83
|
+
滚动计时从 `scrollTo` 到下一次 rAF;缩放计时包含窗口宽度更新、协议开销和下一次 rAF。KP 在缩放时仍有额外成本,但本轮未复现此前的长时间卡顿。这是本机 Chromium 的结果,不代表物理设备输入延迟或任意插件下的性能保证。原始样本和精确测量边界见 [layout.json](../../benchmarks/results/layout.json)。
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
pnpm build:playground
|
|
87
|
+
pnpm preview:playground --port 4174
|
|
88
|
+
# 在另一个终端执行,避免同时构建或测试:
|
|
89
|
+
pnpm exec tsx benchmarks/layout.ts
|
|
90
|
+
BENCH_URL=http://127.0.0.1:4174/LiMR pnpm exec tsx benchmarks/streaming-browser.ts
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
准备阶段将字形测量、断词、合法断点与前缀和独立于行宽缓存。渲染使用每行的词间距片段,减少逐空格 DOM;宽度变化时,断点不变则原位调整间距,断点变化则复用文本容器。同步测量共用一个 Range,避免后续 DOM 修改维护大量尚未回收的活动 Range。高亮几何缓存为段落局部坐标,KP 的相邻绘制片段按行合并,集中读写避免每个矩形强制布局。视口蒙层坐标不向正文继承。滚动保留已排版节点,不重复求解段落。
|