@linloir/limr 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +123 -0
- package/README.md +63 -138
- package/dist/base.css +10 -7
- package/dist/{chunk-65V5OZ4G.js → chunk-3ILUZKDB.js} +77 -17
- package/dist/chunk-3ILUZKDB.js.map +1 -0
- package/dist/{chunk-ETHLPBKQ.js → chunk-N77VD2YR.js} +96 -51
- package/dist/chunk-N77VD2YR.js.map +1 -0
- package/dist/{chunk-7JF5HHVF.js → chunk-TTISGBST.js} +14 -1
- package/dist/{chunk-7JF5HHVF.js.map → chunk-TTISGBST.js.map} +1 -1
- package/dist/core/index.d.ts +6 -3
- package/dist/core/index.js +3 -1
- package/dist/extensions/index.d.ts +2 -2
- package/dist/extensions/index.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -3
- package/dist/react/index.d.ts +4 -3
- package/dist/react/index.js +5 -3
- package/dist/styles.css +10 -7
- package/dist/{translations-BliabrPd.d.ts → translations-DHnYMg4h.d.ts} +11 -3
- package/docs/README.md +13 -0
- package/docs/api.md +5 -158
- package/docs/assets/rendered.svg +9 -0
- package/docs/assets/source.svg +9 -0
- package/docs/en/README.md +26 -0
- package/docs/en/ai-skills.md +57 -0
- package/docs/en/annotations.md +84 -0
- package/docs/en/api.md +107 -0
- package/docs/en/architecture.md +33 -0
- package/docs/en/extensions.md +159 -0
- package/docs/en/getting-started.md +67 -0
- package/docs/en/integration.md +130 -0
- package/docs/en/modules.md +80 -0
- package/docs/en/performance.md +53 -0
- package/docs/en/plugin-packages.md +68 -0
- package/docs/en/styles.md +80 -0
- package/docs/en/syntax.md +352 -0
- package/docs/extensions.md +5 -306
- package/docs/implementation.md +5 -76
- package/docs/performance.md +5 -81
- package/docs/screenshots/blocks.png +0 -0
- package/docs/screenshots/dark.png +0 -0
- package/docs/screenshots/desktop.png +0 -0
- package/docs/screenshots/plugin-mobile.png +0 -0
- package/docs/styles.md +5 -100
- package/docs/visual-upgrade.md +5 -145
- package/docs/zh-CN/README.md +26 -0
- package/docs/zh-CN/ai-skills.md +57 -0
- package/docs/zh-CN/annotations.md +84 -0
- package/docs/zh-CN/api.md +107 -0
- package/docs/zh-CN/architecture.md +33 -0
- package/docs/zh-CN/extensions.md +159 -0
- package/docs/zh-CN/getting-started.md +67 -0
- package/docs/zh-CN/integration.md +130 -0
- package/docs/zh-CN/modules.md +80 -0
- package/docs/zh-CN/performance.md +53 -0
- package/docs/zh-CN/plugin-packages.md +68 -0
- package/docs/zh-CN/styles.md +80 -0
- package/docs/zh-CN/syntax.md +352 -0
- package/examples/notes.tsx +18 -11
- package/examples/packages/paper-theme/index.css +25 -0
- package/examples/packages/paper-theme/package.json +7 -0
- package/examples/packages/reading-tools/index.d.ts +2 -0
- package/examples/packages/reading-tools/index.js +25 -0
- package/examples/packages/reading-tools/package.json +16 -0
- package/package.json +9 -5
- package/skills/limr-plugin-development/SKILL.md +22 -0
- package/skills/limr-plugin-development/agents/openai.yaml +4 -0
- package/skills/limr-plugin-development/assets/plugin-template/README.md +30 -0
- package/skills/limr-plugin-development/assets/plugin-template/package.json +36 -0
- package/skills/limr-plugin-development/assets/plugin-template/src/index.tsx +50 -0
- package/skills/limr-plugin-development/assets/plugin-template/src/styles.css +9 -0
- package/skills/limr-plugin-development/assets/plugin-template/tsconfig.json +20 -0
- package/skills/limr-plugin-development/assets/plugin-template/tsup.config.ts +8 -0
- package/skills/limr-plugin-development/references/contract.md +45 -0
- package/skills/limr-use/SKILL.md +23 -0
- package/skills/limr-use/agents/openai.yaml +4 -0
- package/skills/limr-use/references/integration.md +41 -0
- package/skills/limr-use/references/syntax.md +17 -0
- package/dist/chunk-65V5OZ4G.js.map +0 -1
- package/dist/chunk-ETHLPBKQ.js.map +0 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { AnnotationCard, AnnotationMarkdown, defineBlock, defineExtension, ToolIcon, useLocale,
|
|
2
|
+
type AnnotationContentProps, type AnnotationOverlayCardProps, type AnnotationSidebarPreviewProps,
|
|
3
|
+
type AnnotationType, type LiMRLocale, type RendererExtension } from '@linloir/limr';
|
|
4
|
+
|
|
5
|
+
export interface ReadingNoteData { text: string }
|
|
6
|
+
export interface ReadingToolsOptions { label?: string }
|
|
7
|
+
const isChinese = (locale: LiMRLocale) => locale.language?.startsWith('zh') ?? false;
|
|
8
|
+
|
|
9
|
+
export function readingTools(options: ReadingToolsOptions = {}): RendererExtension {
|
|
10
|
+
const label = (locale: LiMRLocale) => options.label ?? (isChinese(locale) ? '阅读笔记' : 'Reading note');
|
|
11
|
+
function Content({ data }: AnnotationContentProps<ReadingNoteData>) {
|
|
12
|
+
return <AnnotationMarkdown source={data?.text ?? ''} />;
|
|
13
|
+
}
|
|
14
|
+
function Card(props: AnnotationOverlayCardProps<ReadingNoteData>) {
|
|
15
|
+
return <AnnotationCard {...props} title={label(useLocale())} />;
|
|
16
|
+
}
|
|
17
|
+
function Preview({ data }: AnnotationSidebarPreviewProps<ReadingNoteData>) {
|
|
18
|
+
return data?.text ? <span>{data.text}</span> : null;
|
|
19
|
+
}
|
|
20
|
+
const note: AnnotationType<ReadingNoteData> = {
|
|
21
|
+
type: 'example:note', label, icon: <ToolIcon name="note" />, color: '#548b74', Content,
|
|
22
|
+
sidebar: { Preview },
|
|
23
|
+
overlay: { Card, previewWidth: 320, expand: { placement: 'center', width: 600, maxHeight: '80dvh' } },
|
|
24
|
+
};
|
|
25
|
+
const tip = defineBlock({
|
|
26
|
+
name: 'reading-tip',
|
|
27
|
+
component: ({ children, renderAttribute, node }) => <aside className="example-reading-tip">
|
|
28
|
+
{node.attributes?.title && <header>{renderAttribute('title')}</header>}
|
|
29
|
+
{children}
|
|
30
|
+
</aside>,
|
|
31
|
+
});
|
|
32
|
+
return defineExtension({
|
|
33
|
+
...tip, name: 'example:reading-tools', annotationTypes: [note],
|
|
34
|
+
actions: [{
|
|
35
|
+
id: 'example:save-passage', label: context => label(context.locale), icon: <ToolIcon name="note" />,
|
|
36
|
+
visible: ({ selection }) => selection.settled && selection.quality !== 'unmapped'
|
|
37
|
+
&& selection.syntax.ranges.some(range => range.end > range.start),
|
|
38
|
+
run(context) {
|
|
39
|
+
const id = `example-note-${crypto.randomUUID()}`;
|
|
40
|
+
context.addAnnotation({ id, type: note.type, data: { text: context.selection.text } satisfies ReadingNoteData,
|
|
41
|
+
anchors: context.selection.syntax.ranges.map(range => ({
|
|
42
|
+
range, documentId: context.document.id, quote: context.document.source.slice(range.start, range.end),
|
|
43
|
+
})),
|
|
44
|
+
});
|
|
45
|
+
context.activateAnnotation(id);
|
|
46
|
+
context.clearSelection();
|
|
47
|
+
},
|
|
48
|
+
}],
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
.example-reading-tip {
|
|
2
|
+
padding: 1rem;
|
|
3
|
+
border-inline-start: 3px solid var(--limr-accent, #548b74);
|
|
4
|
+
background: var(--limr-surface, #f3f1ee);
|
|
5
|
+
color: var(--limr-text, #3d3a36);
|
|
6
|
+
}
|
|
7
|
+
.example-reading-tip > header { font-weight: 600; }
|
|
8
|
+
.example-reading-tip > :first-child { margin-block-start: 0; }
|
|
9
|
+
.example-reading-tip > :last-child { margin-block-end: 0; }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": [
|
|
5
|
+
"ES2022",
|
|
6
|
+
"DOM"
|
|
7
|
+
],
|
|
8
|
+
"module": "ESNext",
|
|
9
|
+
"moduleResolution": "Bundler",
|
|
10
|
+
"jsx": "react-jsx",
|
|
11
|
+
"strict": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"declaration": true
|
|
15
|
+
},
|
|
16
|
+
"include": [
|
|
17
|
+
"src",
|
|
18
|
+
"tsup.config.ts"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { cp } from 'node:fs/promises';
|
|
2
|
+
import { defineConfig } from 'tsup';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
entry: ['src/index.tsx'], format: ['esm'], target: 'es2022', dts: true, clean: true,
|
|
6
|
+
external: ['@linloir/limr', 'react', 'react/jsx-runtime', 'react-dom'],
|
|
7
|
+
onSuccess: async () => { await cp('src/styles.css', 'dist/styles.css'); },
|
|
8
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Public plugin contract
|
|
2
|
+
|
|
3
|
+
## Syntax and rendering
|
|
4
|
+
|
|
5
|
+
RendererExtension extends SyntaxExtension with components, annotationTypes, actions, and parameters. SyntaxExtension has name, micromark, mdast, tags, directives, transform(root, context), display, selection, and scope. Extension/tag/directive names are validated independently.
|
|
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.
|
|
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.
|
|
10
|
+
|
|
11
|
+
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
|
+
|
|
13
|
+
## Annotation UI
|
|
14
|
+
|
|
15
|
+
AnnotationType<T> has type, label, optional icon/color/highlight, Content, Marker, overlay, sidebar, and load. highlight:'hover' paints temporary referenced-text feedback and suppresses the automatic persistent highlight unless explicitly requested. In 1.0.0 label can be a string or (locale: LiMRLocale) => string; stable factory instances can switch names without reparsing.
|
|
16
|
+
|
|
17
|
+
Content receives annotation, data, loading, error, retry, presentation ('preview'|'expanded'|'sidebar'), expanded, and editing. It renders the resource/loading/error/editor states. AnnotationMarkdown renders nested Markdown with an isolated selection scope.
|
|
18
|
+
|
|
19
|
+
overlay.Card receives annotation, occurrence, presentation, expanded, pinned, canExpand, expand, collapse, close, and children. It owns the full interior; children contains shared Content. AnnotationCard is an optional layout requiring title. Expansion is opt-in: {placement:'anchor'|'center',width?,height?,maxHeight?}, false, or an annotation resolver. previewWidth is independent. Preserve keyboard-accessible controls when drawing a custom card.
|
|
20
|
+
|
|
21
|
+
sidebar.Preview receives local annotation/data, occurrence, all annotations in the group, and referenceText. It must not trigger load. Return null or set Preview:false to omit it. previewLines defaults to 2. Color fields include previewColor, color, borderColor, titleColor, textColor, excerptColor. collapseOnContentClick defaults to false. The first annotation type owns grouped preview/presentation. Do not duplicate shell padding; use shared CSS variables.
|
|
22
|
+
|
|
23
|
+
load(annotation,{signal}) returns Promise<T> on visible content. The reader deduplicates requests and cancels when unused. Data changes/invalidation refresh resources. Do not put credentials in source, Markdown, or shipped templates. Implement service adapters in the host.
|
|
24
|
+
|
|
25
|
+
## Selection actions and storage
|
|
26
|
+
|
|
27
|
+
SelectionAction requires id, label, icon, and may provide run/visible/disabled/onHover/renderExpanded/render. label can resolve from ActionContext; icon can resolve from context. Custom panel operations use ToolbarActionContext.run for shared busy/error state. Expanded panels inherit the current action-row width; they cannot enlarge the toolbar. Use min-width: 0 and wrapping layouts for controls, with left-aligned whole-item wrapping.
|
|
28
|
+
|
|
29
|
+
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
|
+
|
|
31
|
+
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
|
+
|
|
33
|
+
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.
|
|
34
|
+
|
|
35
|
+
## Parameters, locales, and styles
|
|
36
|
+
|
|
37
|
+
Augment RendererParameters through declare module '@linloir/limr', register defaults in extension.parameters, and read useRendererParameter. Host parameters override defaults without reparsing. Export augmentation in .d.ts.
|
|
38
|
+
|
|
39
|
+
On 1.0.0 useLocale() exposes the merged locale. language is an optional BCP-47-style tag, with en and zh-CN in built-ins. Use it to select plugin-owned dictionaries, with a sensible fallback. Existing string labels remain valid. Plugins are responsible for translating their own editor buttons, placeholders, summaries, prompts, and status text; do not translate saved data.
|
|
40
|
+
|
|
41
|
+
CSS is explicitly imported. For themes use [data-limr-appearance='your-theme']; reader ancestor selectors miss portals. Keep annotation IDs and CSS names unique. Use the provided .limr-underline on an inline span inside a layout wrapper: a direct flex child becomes a block and cannot paint an underline per text line. Labels that must remain on one line need intrinsic-width buttons; allow button groups to wrap on narrow screens.
|
|
42
|
+
|
|
43
|
+
## Consumer verification
|
|
44
|
+
|
|
45
|
+
Build ESM and .d.ts, pack, install into a temporary React consumer without source aliases, and exercise exported CSS. Test supported React versions rather than claiming compatibility from one host. Check final streaming vs one-shot parse equivalence for syntax changes, source offsets for entities/emoji, and actual browser states for card/toolbar/portal behavior. Test loader cancellation and isolation if adding remote data. No real network service is required by the starter.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: limr-use
|
|
3
|
+
description: Integrate @linloir/limr into React applications, author its supported Markdown, configure streaming, annotations, locales and themes, or import existing LiMR plugins. Use for LiMR consumers; new reusable plugin packages belong to limr-plugin-development.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Use LiMR
|
|
7
|
+
|
|
8
|
+
Deliver a working integration using the host application's installed LiMR API. These references cover the 1.0.0 contract; inspect package.json and exported declarations before assuming a newer or older version behaves identically.
|
|
9
|
+
|
|
10
|
+
- Read [integration.md](references/integration.md) for components, styles, state, streaming, and installed plugin imports.
|
|
11
|
+
- Read [syntax.md](references/syntax.md) when authoring or converting content. Preserve original source and do not invent tag/attribute support.
|
|
12
|
+
|
|
13
|
+
Choose Reader for the complete UI, Markdown for body-only rendering, or one DocumentProvider with one primary Markdown for a custom layout. Inside a provider, omit Markdown.source to share the document.
|
|
14
|
+
|
|
15
|
+
Append third-party factories through a stable plugins array. extensions replaces the entire list; use standard() and replaceExtension() to change defaults. Verify package existence and public exports before suggesting an npm install. Repository @limr-example packages are unpublished examples.
|
|
16
|
+
|
|
17
|
+
Persist controlled annotations immutably and return every onAnnotationsChange value. Keep unknown types in storage even if the host filters them from a view. Unknown annotation types currently show generic/unavailable UI, not silent omission. Use original UTF-16 ranges, stable document IDs, and quotes; avoid DOM-derived offsets.
|
|
18
|
+
|
|
19
|
+
Use locale={chinese} or english for built-in labels. locale does not translate source. In 1.0.0, plugins can use the public useLocale() hook and locale.language, and AnnotationType.label may resolve from the locale. Confirm these exports before using them against 0.1.0.
|
|
20
|
+
|
|
21
|
+
For streaming, pass the accumulated source and finalize with streaming=false. Transport, authentication, storage, and stopping generation belong to the app. No AI provider is installed by this skill.
|
|
22
|
+
|
|
23
|
+
Follow the existing project layout and stylesheet conventions. Validate a real rendered page, relevant interactions, and type/build checks. When changing portals or responsive layouts, inspect desktop and narrow containers. Report what was verified locally and what still needs the host environment; do not publish or deploy unless requested.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Consumer contract
|
|
2
|
+
|
|
3
|
+
## Minimal integration
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Reader, chinese } from '@linloir/limr';
|
|
7
|
+
import '@linloir/limr/styles.css';
|
|
8
|
+
import '@linloir/limr/math.css';
|
|
9
|
+
|
|
10
|
+
export function Article({ source }: { source: string }) {
|
|
11
|
+
return <Reader source={source} locale={chinese} theme="auto" />;
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
React/React DOM 18.3 or 19, Node 20+, ESM. Choose styles.css or styles/base.css; the latter avoids browser requests for Maple but leaves fonts in the installed package. math.css is separate. CSS themes are imported separately and selected with appearance; that scope reaches portals.
|
|
16
|
+
|
|
17
|
+
Markdown is body-only, with no automatic toolbar. A composed DocumentProvider contains one primary <Markdown /> plus TableOfContents, AnnotationSidebar or AnnotationOverlay, and SelectionToolbar. A Markdown with source creates another document. Synchronized body/sidebar share one scroll container and unscaled coordinates; the host/grid supplies sidebar height. Use sync="none" for a separately scrolling annotation list.
|
|
18
|
+
|
|
19
|
+
## State and commands
|
|
20
|
+
|
|
21
|
+
Reader supports annotations/onAnnotationsChange. Supplying annotations makes it controlled; updates require a callback and a new array. Store data per article and supply a stable documentId. Changing Reader.key resets its internal state, not host state.
|
|
22
|
+
|
|
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
|
+
|
|
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 are atomic.
|
|
26
|
+
|
|
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
|
+
|
|
29
|
+
## Streaming and resources
|
|
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, and finalization require complete parsing.
|
|
32
|
+
|
|
33
|
+
SSR renders code text without client Shiki. 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
|
+
|
|
35
|
+
## Importing a plugin
|
|
36
|
+
|
|
37
|
+
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
|
+
|
|
39
|
+
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
|
+
|
|
41
|
+
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.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Built-in syntax
|
|
2
|
+
|
|
3
|
+
React defaults install gfm, math, code-highlight, definition, question, extras, video, figures, citation, and translations. Core createDocument defaults to basic CommonMark.
|
|
4
|
+
|
|
5
|
+
- Standard Markdown: headings, emphasis, lists, links, images, fenced/inline code, blockquotes. GFM adds tables, tasks, strikethrough, autolinks, and document-end footnotes.
|
|
6
|
+
- Math uses $…$ and $$ fences; import math.css.
|
|
7
|
+
- <definition title="Term"> supports Markdown body. <title> and <content> child tags support richer content.
|
|
8
|
+
- <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
|
+
- <extras> contains <extra title="Title" url="https://example.com" desc="Description" />.
|
|
10
|
+
- <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. Images copy URLs, groups copy Markdown.
|
|
12
|
+
- <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
|
+
- <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
|
+
|
|
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. Incomplete JSX falls back and retries during streaming.
|
|
16
|
+
|
|
17
|
+
Directives are registered separately: definition/question/extras/video have their main directive; figures has figures/figure/figcaption; translations has translations/origin/translation. Citation/ref do not register directives. Do not invent directives for every child tag. There is no built-in ==highlight== syntax.
|