@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
|
@@ -2,16 +2,24 @@ import {
|
|
|
2
2
|
annotationReferenceRange,
|
|
3
3
|
createDocument,
|
|
4
4
|
defaultHighlight,
|
|
5
|
-
intersects,
|
|
6
5
|
mapText,
|
|
7
|
-
rangeOf,
|
|
8
6
|
resolveAnnotationAnchors,
|
|
9
|
-
safeUrl,
|
|
10
7
|
sameRange,
|
|
11
|
-
selectionFromRange
|
|
8
|
+
selectionFromRange
|
|
9
|
+
} from "./chunk-BG5QUQFR.js";
|
|
10
|
+
import {
|
|
11
|
+
atomicSelectionText,
|
|
12
|
+
leavesIn,
|
|
13
|
+
measurementRange,
|
|
14
|
+
textRange
|
|
15
|
+
} from "./chunk-BVHHOVMT.js";
|
|
16
|
+
import {
|
|
17
|
+
intersects,
|
|
18
|
+
rangeOf,
|
|
19
|
+
safeUrl,
|
|
12
20
|
textContent,
|
|
13
21
|
walk
|
|
14
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-FJZCQY2S.js";
|
|
15
23
|
import {
|
|
16
24
|
ResourceCache
|
|
17
25
|
} from "./chunk-6N6TFHEN.js";
|
|
@@ -94,6 +102,7 @@ var english = {
|
|
|
94
102
|
highlightWavy: "Wavy",
|
|
95
103
|
hideHighlight: "Hide highlight",
|
|
96
104
|
showHighlight: "Show highlight",
|
|
105
|
+
inlineHighlightHint: "Markdown inline highlight, editing unavailable",
|
|
97
106
|
deleteAnnotations: "Delete",
|
|
98
107
|
deleteAnnotationsHint: "Deletes {count} annotations on this text and any highlight."
|
|
99
108
|
};
|
|
@@ -135,6 +144,7 @@ var chinese = {
|
|
|
135
144
|
highlightWavy: "\u6CE2\u6D6A\u7EBF",
|
|
136
145
|
hideHighlight: "\u9690\u85CF\u9AD8\u4EAE",
|
|
137
146
|
showHighlight: "\u663E\u793A\u9AD8\u4EAE",
|
|
147
|
+
inlineHighlightHint: "Markdown \u5185\u5D4C\u9AD8\u4EAE\uFF0C\u4E0D\u652F\u6301\u7F16\u8F91",
|
|
138
148
|
deleteAnnotations: "\u5220\u9664",
|
|
139
149
|
deleteAnnotationsHint: "\u5C06\u5220\u9664\u8FD9\u6BB5\u6587\u5B57\u5173\u8054\u7684 {count} \u4E2A\u6CE8\u91CA\u53CA\u9AD8\u4EAE\u3002"
|
|
140
150
|
};
|
|
@@ -175,6 +185,7 @@ var ReaderRuntime = class {
|
|
|
175
185
|
bindings = /* @__PURE__ */ new WeakMap();
|
|
176
186
|
textBinders = /* @__PURE__ */ new WeakMap();
|
|
177
187
|
components = {};
|
|
188
|
+
rendererOverrides = /* @__PURE__ */ new Map();
|
|
178
189
|
annotationTypes = /* @__PURE__ */ new Map();
|
|
179
190
|
resolvedTypes = /* @__PURE__ */ new WeakMap();
|
|
180
191
|
locale = english;
|
|
@@ -278,6 +289,13 @@ var ReaderRuntime = class {
|
|
|
278
289
|
installConfiguration(config) {
|
|
279
290
|
this.locale = { ...english, ...config.locale };
|
|
280
291
|
this.components = Object.assign({}, ...(config.extensions ?? []).map((ext) => ext.components), config.components);
|
|
292
|
+
this.rendererOverrides = /* @__PURE__ */ new Map();
|
|
293
|
+
const rules = [
|
|
294
|
+
...(config.extensions ?? []).flatMap((ext) => ext.rendererOverrides ?? []),
|
|
295
|
+
...Object.entries(config.components ?? {}).map(([type, component]) => ({ type, component })),
|
|
296
|
+
...config.rendererOverrides ?? []
|
|
297
|
+
];
|
|
298
|
+
for (const rule of rules) this.rendererOverrides.set(rule.type, [...this.rendererOverrides.get(rule.type) ?? [], rule]);
|
|
281
299
|
const annotationTypes = [...(config.extensions ?? []).flatMap((ext) => [...ext.annotationTypes ?? []]), ...config.annotationTypes ?? []];
|
|
282
300
|
this.annotationTypes = new Map(annotationTypes.map((type) => {
|
|
283
301
|
if (typeof type.label === "string") return [type.type, type];
|
|
@@ -352,13 +370,13 @@ var ReaderRuntime = class {
|
|
|
352
370
|
if ([...versions.keys()].some((id) => !annotations.has(id))) this.resourceVersions.set(new Map([...versions].filter(([id]) => annotations.has(id))));
|
|
353
371
|
const occurrences = [...doc.occurrences];
|
|
354
372
|
const allHighlights = [];
|
|
355
|
-
for (const annotation of
|
|
373
|
+
for (const annotation of annotations.values()) {
|
|
356
374
|
resolveAnnotationAnchors(annotation, doc).forEach((anchor, index) => {
|
|
357
375
|
if (annotation.type === "highlight") {
|
|
358
376
|
const id = index ? `${annotation.id}:${index}` : annotation.id;
|
|
359
377
|
const value = { ...annotation.data, id, annotationId: annotation.id, range: anchor.range };
|
|
360
378
|
const old = previous.highlights.get(id);
|
|
361
|
-
allHighlights.push(old && !old.occurrenceId && sameRange(old.range, value.range) && old.color === value.color && old.style === value.style && old.hidden === value.hidden ? old : value);
|
|
379
|
+
allHighlights.push(old && !old.occurrenceId && sameRange(old.range, value.range) && old.color === value.color && old.style === value.style && old.hidden === value.hidden && old.readOnly === value.readOnly ? old : value);
|
|
362
380
|
} else occurrences.push({ ...anchor, id: anchor.id ?? `${doc.id}-${annotation.id}-${index}`, annotationIds: [annotation.id] });
|
|
363
381
|
});
|
|
364
382
|
}
|
|
@@ -539,7 +557,7 @@ var emptyList = EMPTY;
|
|
|
539
557
|
import { gfm as syntax } from "micromark-extension-gfm";
|
|
540
558
|
import { gfmFromMarkdown } from "mdast-util-gfm";
|
|
541
559
|
function gfm() {
|
|
542
|
-
return { name: "gfm", micromark: [syntax()], mdast: gfmFromMarkdown(), scope: "local" };
|
|
560
|
+
return { name: "gfm", directives: ["gfm"], micromark: [syntax()], mdast: gfmFromMarkdown(), scope: "local", components: { gfm: ({ children }) => children } };
|
|
543
561
|
}
|
|
544
562
|
|
|
545
563
|
// src/extensions/math.tsx
|
|
@@ -548,10 +566,10 @@ import { math as syntax2 } from "micromark-extension-math";
|
|
|
548
566
|
import { mathFromMarkdown } from "mdast-util-math";
|
|
549
567
|
|
|
550
568
|
// src/components/CopyButton.tsx
|
|
551
|
-
import { useEffect as
|
|
569
|
+
import { useEffect as useEffect10, useRef as useRef15, useState as useState10 } from "react";
|
|
552
570
|
|
|
553
571
|
// src/react/context.tsx
|
|
554
|
-
import { createContext as createContext2, useCallback as
|
|
572
|
+
import { createContext as createContext2, useCallback as useCallback3, useContext as useContext3, useEffect as useEffect9, useId, useLayoutEffect, useMemo as useMemo5, useRef as useRef14, useState as useState9, useSyncExternalStore } from "react";
|
|
555
573
|
|
|
556
574
|
// src/extensions/code.tsx
|
|
557
575
|
import { useEffect, useRef, useState } from "react";
|
|
@@ -563,6 +581,16 @@ function literalValue(node) {
|
|
|
563
581
|
function mapLiteral(source, node) {
|
|
564
582
|
const range = rangeOf(node), raw = source.slice(range.start, range.end), value = literalValue(node);
|
|
565
583
|
const starts = [], ends = [];
|
|
584
|
+
if (node.valueRange) {
|
|
585
|
+
const payload = node.valueRange;
|
|
586
|
+
for (let at = payload.start; at < payload.end && starts.length < value.length; at++) {
|
|
587
|
+
const size = source[at] === "\r" && source[at + 1] === "\n" ? 2 : 1;
|
|
588
|
+
starts.push(at);
|
|
589
|
+
ends.push(at + size);
|
|
590
|
+
at += size - 1;
|
|
591
|
+
}
|
|
592
|
+
return { starts, ends, exact: starts.length === value.length };
|
|
593
|
+
}
|
|
566
594
|
if (node.type === "inlineCode") {
|
|
567
595
|
const fence = /^`+/.exec(raw)?.[0].length ?? 0;
|
|
568
596
|
let from = fence, until = raw.length - fence;
|
|
@@ -602,6 +630,24 @@ function mapLiteral(source, node) {
|
|
|
602
630
|
return { starts, ends, exact };
|
|
603
631
|
}
|
|
604
632
|
|
|
633
|
+
// src/extensions/literal-directive.ts
|
|
634
|
+
function literalDirective(root, source, name, aliases3 = [name]) {
|
|
635
|
+
walk(root, (node) => {
|
|
636
|
+
if (node.type !== "component" || !aliases3.includes(node.name ?? "") || !node.position) return;
|
|
637
|
+
const start = node.position.start.offset, end = node.position.end.offset;
|
|
638
|
+
const raw = source.slice(start, end);
|
|
639
|
+
const header = /^[^\r\n]*(?:\r\n|\r|\n)/.exec(raw);
|
|
640
|
+
const closing = /(?:\r\n|\r|\n)[ \t]*:{2,}[ \t]*$/.exec(raw);
|
|
641
|
+
const from = start + (header?.[0].length ?? raw.length);
|
|
642
|
+
const until = closing ? start + closing.index : end;
|
|
643
|
+
node.type = name;
|
|
644
|
+
node.value = source.slice(from, until).replace(/\r\n?/g, "\n").replace(node.incomplete ? /\n$/ : /$^/, "");
|
|
645
|
+
node.valueRange = { start: from, end: until };
|
|
646
|
+
if (name === "code") node.lang = String(node.attributes?.lang ?? node.attributes?.language ?? "text");
|
|
647
|
+
node.children = void 0;
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
|
|
605
651
|
// src/extensions/code.tsx
|
|
606
652
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
607
653
|
var cache = new ResourceCache(96);
|
|
@@ -631,9 +677,10 @@ function codeHighlight(options = {}) {
|
|
|
631
677
|
return () => observer.disconnect();
|
|
632
678
|
}, [visible, runtime]);
|
|
633
679
|
useEffect(() => {
|
|
634
|
-
if (!visible || code.length > (options.maxLength ?? 1e5)) return;
|
|
680
|
+
if (!visible || pending || code.length > (options.maxLength ?? 1e5)) return;
|
|
635
681
|
let disposed = false;
|
|
636
682
|
let release;
|
|
683
|
+
let waiting;
|
|
637
684
|
const timer = setTimeout(() => {
|
|
638
685
|
if (normalized === "text" || options.languages && !options.languages.includes(normalized)) return;
|
|
639
686
|
const request = cache.acquire(JSON.stringify([code, normalized, options.lightTheme, options.darkTheme]), async () => {
|
|
@@ -655,14 +702,31 @@ function codeHighlight(options = {}) {
|
|
|
655
702
|
});
|
|
656
703
|
release = request.release;
|
|
657
704
|
request.promise.then((tokens2) => {
|
|
658
|
-
|
|
705
|
+
const apply = () => {
|
|
706
|
+
if (disposed) return;
|
|
707
|
+
const selection = ref.current?.ownerDocument.getSelection();
|
|
708
|
+
if (selection && !selection.isCollapsed && selection.rangeCount && ref.current && selection.getRangeAt(0).intersectsNode(ref.current)) {
|
|
709
|
+
if (!waiting) {
|
|
710
|
+
waiting = apply;
|
|
711
|
+
document.addEventListener("selectionchange", waiting);
|
|
712
|
+
}
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
if (waiting) {
|
|
716
|
+
document.removeEventListener("selectionchange", waiting);
|
|
717
|
+
waiting = void 0;
|
|
718
|
+
}
|
|
719
|
+
setResult({ code, tokens: tokens2 });
|
|
720
|
+
};
|
|
721
|
+
apply();
|
|
659
722
|
}).catch(() => {
|
|
660
723
|
});
|
|
661
|
-
},
|
|
724
|
+
}, 0);
|
|
662
725
|
return () => {
|
|
663
726
|
disposed = true;
|
|
664
727
|
clearTimeout(timer);
|
|
665
728
|
release?.();
|
|
729
|
+
if (waiting) document.removeEventListener("selectionchange", waiting);
|
|
666
730
|
};
|
|
667
731
|
}, [code, normalized, pending, visible]);
|
|
668
732
|
const tokens = result?.code === code ? result.tokens : void 0;
|
|
@@ -674,29 +738,29 @@ function codeHighlight(options = {}) {
|
|
|
674
738
|
/* @__PURE__ */ jsx("pre", { className: tokens?.length ? "shiki" : void 0, children: /* @__PURE__ */ jsx("code", { children: renderValue(tokens) }) })
|
|
675
739
|
] });
|
|
676
740
|
}
|
|
677
|
-
return { name: "code-highlight", scope: "local", components: { code: CodeNode } };
|
|
741
|
+
return { name: "code-highlight", directives: ["code", "code-highlight"], literal: true, scope: "local", components: { code: CodeNode }, transform: (root, context) => literalDirective(root, context.source, "code", ["code", "code-highlight"]) };
|
|
678
742
|
}
|
|
679
743
|
|
|
680
744
|
// src/extensions/annotations.tsx
|
|
681
|
-
import { useMemo as useMemo2, useRef as
|
|
745
|
+
import { useMemo as useMemo2, useRef as useRef8 } from "react";
|
|
682
746
|
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
683
747
|
|
|
684
748
|
// src/react/Markdown.tsx
|
|
685
|
-
import { useContext, useEffect as
|
|
749
|
+
import { useContext, useEffect as useEffect5, useRef as useRef6 } from "react";
|
|
686
750
|
|
|
687
751
|
// src/react/render.tsx
|
|
688
|
-
import { cloneElement, Component, createElement, Fragment, isValidElement, memo, useCallback, useMemo, useRef as
|
|
752
|
+
import { cloneElement, Component as Component2, createElement, Fragment, isValidElement, memo, useCallback as useCallback2, useMemo, useRef as useRef4 } from "react";
|
|
689
753
|
|
|
690
754
|
// src/react/text-binding.ts
|
|
691
755
|
var atomic = /* @__PURE__ */ new Set(["inlineCode", "code", "math", "inlineMath", "image", "imageReference", "html"]);
|
|
692
756
|
var hidden = /* @__PURE__ */ new Set(["definition", "footnoteDefinition", "annotationDefinition", "footnoteReference"]);
|
|
693
757
|
var ordinary = /* @__PURE__ */ new Set(["text", "paragraph", "heading", "strong", "emphasis", "delete", "blockquote", "list", "listItem", "link", "linkReference", "table", "tableRow", "tableCell", "thematicBreak", "break", "annotationReference"]);
|
|
694
|
-
function compactTextNodes(node, components) {
|
|
758
|
+
function compactTextNodes(node, components, overrides) {
|
|
695
759
|
const texts = [];
|
|
696
760
|
let supported = true;
|
|
697
761
|
const visit = (node2) => {
|
|
698
762
|
if (node2.selection === "atomic" || atomic.has(node2.type) || hidden.has(node2.type)) return;
|
|
699
|
-
if (!ordinary.has(node2.type) || components[node2.type]) {
|
|
763
|
+
if (!ordinary.has(node2.type) || components[node2.type] || overrides?.has(node2.type)) {
|
|
700
764
|
supported = false;
|
|
701
765
|
return;
|
|
702
766
|
}
|
|
@@ -778,8 +842,182 @@ function bindCompactText(element, nodes, runtime) {
|
|
|
778
842
|
return clear;
|
|
779
843
|
}
|
|
780
844
|
|
|
845
|
+
// src/react/stream-text.tsx
|
|
846
|
+
import { useCallback, useEffect as useEffect2, useRef as useRef3 } from "react";
|
|
847
|
+
|
|
848
|
+
// src/react/stream-effect.tsx
|
|
849
|
+
import { useRef as useRef2 } from "react";
|
|
850
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
851
|
+
var defaultStreamEffect = {
|
|
852
|
+
keyframes: [{ opacity: 0 }, { opacity: 1 }],
|
|
853
|
+
timing: { duration: 420, easing: "cubic-bezier(.16,1,.3,1)" }
|
|
854
|
+
};
|
|
855
|
+
function streamEffect(runtime) {
|
|
856
|
+
const config = runtime.configuration.get();
|
|
857
|
+
if (config.streamEffect !== void 0) return config.streamEffect;
|
|
858
|
+
let effect = defaultStreamEffect;
|
|
859
|
+
for (const extension of config.extensions ?? []) if (extension.streaming?.effect !== void 0) effect = extension.streaming.effect;
|
|
860
|
+
return effect;
|
|
861
|
+
}
|
|
862
|
+
function animateStream(element, effect) {
|
|
863
|
+
if (effect === false || !element.animate || matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
864
|
+
return element.animate(effect.keyframes ?? defaultStreamEffect.keyframes, { ...defaultStreamEffect.timing, ...effect.timing });
|
|
865
|
+
}
|
|
866
|
+
function useStreamEntrance(ref, enabled, state = true, contents = false) {
|
|
867
|
+
const runtime = useRuntime();
|
|
868
|
+
useIsomorphicLayoutEffect(() => {
|
|
869
|
+
const host = ref.current;
|
|
870
|
+
const target = contents ? host?.firstElementChild : host;
|
|
871
|
+
if (!enabled || !target) return;
|
|
872
|
+
const effect = streamEffect(runtime);
|
|
873
|
+
const classes = effect && effect.className?.split(/\s+/).filter(Boolean);
|
|
874
|
+
if (classes) target.classList.add(...classes);
|
|
875
|
+
target.dataset.limrEntrance = "";
|
|
876
|
+
const animation = animateStream(target, effect);
|
|
877
|
+
return () => {
|
|
878
|
+
animation?.cancel();
|
|
879
|
+
if (classes) target.classList.remove(...classes);
|
|
880
|
+
};
|
|
881
|
+
}, [runtime, enabled, state]);
|
|
882
|
+
}
|
|
883
|
+
function StreamEntrance({ children, state }) {
|
|
884
|
+
const ref = useRef2(null);
|
|
885
|
+
useStreamEntrance(ref, true, state, true);
|
|
886
|
+
return /* @__PURE__ */ jsx2("div", { ref, className: "limr-stream-block", children });
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
// src/react/stream-text.tsx
|
|
890
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
891
|
+
function StreamText({ value, animateInitial = true }) {
|
|
892
|
+
const runtime = useRuntime();
|
|
893
|
+
const initial = useRef3(value), previous = useRef3(value);
|
|
894
|
+
const element = useRef3(null);
|
|
895
|
+
const animations = useRef3(/* @__PURE__ */ new Set());
|
|
896
|
+
const waiting = useRef3(false);
|
|
897
|
+
const mounted = useRef3(false);
|
|
898
|
+
const compact = useCallback(() => {
|
|
899
|
+
const host = element.current;
|
|
900
|
+
if (!host) return;
|
|
901
|
+
const selection = host.ownerDocument.getSelection();
|
|
902
|
+
if (selection && !selection.isCollapsed && selection.rangeCount && selection.getRangeAt(0).intersectsNode(host)) {
|
|
903
|
+
if (!waiting.current) {
|
|
904
|
+
host.ownerDocument.addEventListener("selectionchange", compact);
|
|
905
|
+
waiting.current = true;
|
|
906
|
+
}
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
if (waiting.current) {
|
|
910
|
+
host.ownerDocument.removeEventListener("selectionchange", compact);
|
|
911
|
+
waiting.current = false;
|
|
912
|
+
}
|
|
913
|
+
for (const span of host.querySelectorAll("[data-limr-increment-done]")) span.replaceWith(...span.childNodes);
|
|
914
|
+
host.normalize();
|
|
915
|
+
}, []);
|
|
916
|
+
useIsomorphicLayoutEffect(() => {
|
|
917
|
+
const host = element.current;
|
|
918
|
+
if (!host) return;
|
|
919
|
+
const effect = streamEffect(runtime);
|
|
920
|
+
const animate = (element2) => {
|
|
921
|
+
const animation = animateStream(element2, effect);
|
|
922
|
+
if (!animation) return;
|
|
923
|
+
animations.current.add(animation);
|
|
924
|
+
void animation.finished.then(() => {
|
|
925
|
+
animations.current.delete(animation);
|
|
926
|
+
if (element2.hasAttribute("data-limr-increment")) element2.dataset.limrIncrementDone = "";
|
|
927
|
+
compact();
|
|
928
|
+
}, () => animations.current.delete(animation));
|
|
929
|
+
};
|
|
930
|
+
if (!mounted.current) {
|
|
931
|
+
mounted.current = true;
|
|
932
|
+
if (animateInitial && value && runtime.document.getSnapshot().streaming) animate(host);
|
|
933
|
+
}
|
|
934
|
+
if (value === previous.current) return;
|
|
935
|
+
let from = previous.current.length;
|
|
936
|
+
if (!value.startsWith(previous.current)) {
|
|
937
|
+
for (const animation of animations.current) animation.cancel();
|
|
938
|
+
animations.current.clear();
|
|
939
|
+
for (const span of host.querySelectorAll("[data-limr-increment]")) span.dataset.limrIncrementDone = "";
|
|
940
|
+
from = 0;
|
|
941
|
+
while (from < Math.min(previous.current.length, value.length) && previous.current[from] === value[from]) from++;
|
|
942
|
+
const walker = host.ownerDocument.createTreeWalker(host, NodeFilter.SHOW_TEXT);
|
|
943
|
+
const texts = [];
|
|
944
|
+
for (let node = walker.nextNode(); node; node = walker.nextNode()) texts.push(node);
|
|
945
|
+
let at = 0;
|
|
946
|
+
for (const text of texts) {
|
|
947
|
+
const size = text.length;
|
|
948
|
+
if (at >= from) text.remove();
|
|
949
|
+
else if (at + size > from) text.deleteData(from - at, size);
|
|
950
|
+
at += size;
|
|
951
|
+
}
|
|
952
|
+
for (const span of host.querySelectorAll("[data-limr-increment]")) if (!span.textContent) span.remove();
|
|
953
|
+
}
|
|
954
|
+
const addition = value.slice(from);
|
|
955
|
+
if (addition) {
|
|
956
|
+
if (effect === false || !host.animate || matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
957
|
+
const tail = host.lastChild;
|
|
958
|
+
if (tail?.nodeType === Node.TEXT_NODE) tail.appendData(addition);
|
|
959
|
+
else host.append(host.ownerDocument.createTextNode(addition));
|
|
960
|
+
} else {
|
|
961
|
+
const span = host.ownerDocument.createElement("span");
|
|
962
|
+
span.dataset.limrIncrement = "";
|
|
963
|
+
span.className = `limr-stream-increment ${effect.className ?? ""}`;
|
|
964
|
+
span.textContent = addition;
|
|
965
|
+
host.append(span);
|
|
966
|
+
animate(span);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
previous.current = value;
|
|
970
|
+
}, [value, runtime]);
|
|
971
|
+
useEffect2(() => {
|
|
972
|
+
const document2 = element.current?.ownerDocument;
|
|
973
|
+
return () => {
|
|
974
|
+
document2?.removeEventListener("selectionchange", compact);
|
|
975
|
+
for (const animation of animations.current) animation.cancel();
|
|
976
|
+
animations.current.clear();
|
|
977
|
+
};
|
|
978
|
+
}, []);
|
|
979
|
+
return /* @__PURE__ */ jsx3("span", { ref: element, "data-limr-stream-text": "", children: initial.current });
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// src/react/knuth-plass-boundary.tsx
|
|
983
|
+
import { Component } from "react";
|
|
984
|
+
var implementation;
|
|
985
|
+
var KnuthPlassBoundary = class extends Component {
|
|
986
|
+
release;
|
|
987
|
+
version = 0;
|
|
988
|
+
start() {
|
|
989
|
+
const version = ++this.version;
|
|
990
|
+
if (!this.props.enabled || this.props.pending) return;
|
|
991
|
+
implementation ??= import("./knuth-plass-layout-CHQCWKB5.js");
|
|
992
|
+
void implementation.then((module) => {
|
|
993
|
+
if (version !== this.version) return;
|
|
994
|
+
const root = this.props.element();
|
|
995
|
+
if (root) this.release = module.typeset(root, this.props.runtime, this.props.options);
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
componentDidMount() {
|
|
999
|
+
this.start();
|
|
1000
|
+
}
|
|
1001
|
+
getSnapshotBeforeUpdate() {
|
|
1002
|
+
this.version++;
|
|
1003
|
+
this.release?.();
|
|
1004
|
+
this.release = void 0;
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
componentDidUpdate() {
|
|
1008
|
+
this.start();
|
|
1009
|
+
}
|
|
1010
|
+
componentWillUnmount() {
|
|
1011
|
+
this.version++;
|
|
1012
|
+
this.release?.();
|
|
1013
|
+
}
|
|
1014
|
+
render() {
|
|
1015
|
+
return this.props.children;
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
|
|
781
1019
|
// src/react/render.tsx
|
|
782
|
-
import { Fragment as Fragment2, jsx as
|
|
1020
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
783
1021
|
var blockAttributes = (block) => block ? { "data-limr-block": block.id, "data-source-start": block.range.start, "data-source-end": block.range.end, "data-pending": block.pending || void 0 } : {};
|
|
784
1022
|
function AnnotationMarker({ occurrence }) {
|
|
785
1023
|
const runtime = useRuntime();
|
|
@@ -787,10 +1025,10 @@ function AnnotationMarker({ occurrence }) {
|
|
|
787
1025
|
const active = useStoreSelector(runtime.interaction, (state) => state.active === occurrence.id);
|
|
788
1026
|
const hovered = useStoreSelector(runtime.interaction, (state) => state.hovered === occurrence.id);
|
|
789
1027
|
const definition2 = useStoreSelector(runtime.configuration, () => runtime.annotationTypes.get(annotation?.type ?? "citation"));
|
|
790
|
-
const
|
|
1028
|
+
const Icon2 = definition2?.icon;
|
|
791
1029
|
const Custom = definition2?.Marker;
|
|
792
|
-
const icon = typeof
|
|
793
|
-
return /* @__PURE__ */
|
|
1030
|
+
const icon = typeof Icon2 === "function" || Icon2 && typeof Icon2 === "object" && !isValidElement(Icon2) && "$$typeof" in Icon2 ? createElement(Icon2) : Icon2;
|
|
1031
|
+
return /* @__PURE__ */ jsx4("span", { className: "limr-mark-wrap", "data-limr-ignore": "true", "data-limr-marker": occurrence.id, "data-source-start": occurrence.range.start, "data-source-end": occurrence.range.end, children: /* @__PURE__ */ jsxs2(
|
|
794
1032
|
"button",
|
|
795
1033
|
{
|
|
796
1034
|
type: "button",
|
|
@@ -820,8 +1058,8 @@ function AnnotationMarker({ occurrence }) {
|
|
|
820
1058
|
if (hovering) runtime.hover(occurrence.id);
|
|
821
1059
|
},
|
|
822
1060
|
children: [
|
|
823
|
-
/* @__PURE__ */
|
|
824
|
-
occurrence.annotationIds.length > 1 && /* @__PURE__ */
|
|
1061
|
+
/* @__PURE__ */ jsx4("span", { className: "limr-mark-icon", children: Custom && annotation ? /* @__PURE__ */ jsx4(Custom, { annotation, active }) : icon ?? "\u2022" }),
|
|
1062
|
+
occurrence.annotationIds.length > 1 && /* @__PURE__ */ jsx4("span", { className: "limr-mark-count", children: occurrence.annotationIds.length })
|
|
825
1063
|
]
|
|
826
1064
|
}
|
|
827
1065
|
) });
|
|
@@ -835,7 +1073,7 @@ function Text({ node, context, mapping: literalMapping, marks: literalMarks, sty
|
|
|
835
1073
|
let mapping2;
|
|
836
1074
|
const raw = source.slice(range.start, range.end);
|
|
837
1075
|
return () => {
|
|
838
|
-
if (literalMapping) return literalMapping;
|
|
1076
|
+
if (literalMapping) return typeof literalMapping === "function" ? literalMapping() : literalMapping;
|
|
839
1077
|
if (!mapping2) {
|
|
840
1078
|
const relative = mapText(raw, value, { start: 0, end: raw.length }, { escapes: node.verbatimEscapes !== true });
|
|
841
1079
|
mapping2 = { starts: relative.starts.map((offset) => offset + range.start), ends: relative.ends.map((offset) => offset + range.start), exact: relative.exact };
|
|
@@ -847,7 +1085,7 @@ function Text({ node, context, mapping: literalMapping, marks: literalMarks, sty
|
|
|
847
1085
|
const highlights = context.highlights.filter((highlight) => intersects(highlight.range, range));
|
|
848
1086
|
if (!marks.length && !highlights.length) {
|
|
849
1087
|
const direct = !literalMapping && source.slice(range.start, range.end) === value;
|
|
850
|
-
return /* @__PURE__ */
|
|
1088
|
+
return /* @__PURE__ */ jsx4("span", { style, className, "data-limr-text": "", "data-source-start": range.start, "data-source-end": range.end, ref: (element) => {
|
|
851
1089
|
if (element) runtime.bindings.set(element, {
|
|
852
1090
|
range,
|
|
853
1091
|
atomic: false,
|
|
@@ -856,7 +1094,7 @@ function Text({ node, context, mapping: literalMapping, marks: literalMarks, sty
|
|
|
856
1094
|
},
|
|
857
1095
|
resolve: (offset, edge) => direct ? Math.max(range.start, Math.min(range.end, range.start + offset)) : edge === "start" ? mapped().starts[offset] ?? range.end : mapped().ends[offset - 1] ?? range.start
|
|
858
1096
|
});
|
|
859
|
-
}, children: value });
|
|
1097
|
+
}, children: context.live ? /* @__PURE__ */ jsx4(StreamText, { value, animateInitial: range.end > context.revealFrom }) : value });
|
|
860
1098
|
}
|
|
861
1099
|
const mapping = mapped();
|
|
862
1100
|
const markerAt = /* @__PURE__ */ new Map();
|
|
@@ -874,12 +1112,12 @@ function Text({ node, context, mapping: literalMapping, marks: literalMarks, sty
|
|
|
874
1112
|
boundaries.add(end < 0 ? value.length : end);
|
|
875
1113
|
}
|
|
876
1114
|
const points = [...boundaries].sort((a, b) => a - b);
|
|
877
|
-
return /* @__PURE__ */
|
|
1115
|
+
return /* @__PURE__ */ jsx4(Fragment2, { children: points.slice(1).map((end, index) => {
|
|
878
1116
|
const start = points[index];
|
|
879
1117
|
const segmentRange = { start: mapping.starts[start] ?? range.start, end: mapping.ends[end - 1] ?? range.end };
|
|
880
1118
|
const styles = highlights.filter((highlight) => intersects(highlight.range, segmentRange));
|
|
881
|
-
let text = value.slice(start, end);
|
|
882
|
-
for (const highlight of styles) text = /* @__PURE__ */
|
|
1119
|
+
let text = context.live ? /* @__PURE__ */ jsx4(StreamText, { value: value.slice(start, end), animateInitial: segmentRange.end > context.revealFrom }) : value.slice(start, end);
|
|
1120
|
+
for (const highlight of styles) text = /* @__PURE__ */ jsx4("mark", { "data-limr-highlight": highlight.id, "data-hidden": highlight.hidden || void 0, className: `limr-highlight limr-highlight-${highlight.style ?? "background"}`, style: { "--limr-highlight": highlight.color ?? "#f3ce7380" }, children: text }, highlight.id);
|
|
883
1121
|
return /* @__PURE__ */ jsxs2("span", { style, className, ref: (element) => {
|
|
884
1122
|
if (element) runtime.bindings.set(element, { range: segmentRange, atomic: false, exact: mapping.exact, resolve: (offset, edge) => {
|
|
885
1123
|
const at = Math.max(start, Math.min(end, start + offset));
|
|
@@ -887,22 +1125,27 @@ function Text({ node, context, mapping: literalMapping, marks: literalMarks, sty
|
|
|
887
1125
|
} });
|
|
888
1126
|
}, "data-limr-text": "", "data-source-start": segmentRange.start, "data-source-end": segmentRange.end, children: [
|
|
889
1127
|
text,
|
|
890
|
-
markerAt.get(end)?.map((occurrence) => /* @__PURE__ */
|
|
1128
|
+
markerAt.get(end)?.map((occurrence) => /* @__PURE__ */ jsx4(AnnotationMarker, { occurrence }, occurrence.id))
|
|
891
1129
|
] }, start);
|
|
892
1130
|
}) });
|
|
893
1131
|
}
|
|
894
1132
|
function LiteralValue({ node, context, tokens }) {
|
|
895
1133
|
const source = context.runtime.document.getSnapshot().source;
|
|
896
|
-
const
|
|
1134
|
+
const mapped = useMemo(() => {
|
|
1135
|
+
let value2;
|
|
1136
|
+
return () => value2 ??= mapLiteral(source, node);
|
|
1137
|
+
}, [node]);
|
|
897
1138
|
const value = literalValue(node);
|
|
898
1139
|
const marks = context.marks.get(node) ?? emptyList;
|
|
1140
|
+
if (!tokens?.length) return /* @__PURE__ */ jsx4(Text, { node: { ...node, type: "text", value }, context, mapping: mapped, marks }, 0);
|
|
1141
|
+
const mapping = mapped();
|
|
899
1142
|
const segments = tokens?.length ? tokens : [{ content: value, offset: 0 }];
|
|
900
|
-
return /* @__PURE__ */
|
|
1143
|
+
return /* @__PURE__ */ jsx4(Fragment2, { children: segments.map((token, index) => {
|
|
901
1144
|
const start = token.offset, end = start + token.content.length;
|
|
902
|
-
const
|
|
903
|
-
const range = { start:
|
|
1145
|
+
const mapped2 = { starts: mapping.starts.slice(start, end), ends: mapping.ends.slice(start, end), exact: mapping.exact };
|
|
1146
|
+
const range = { start: mapped2.starts[0] ?? rangeOf(node).start, end: mapped2.ends.at(-1) ?? rangeOf(node).end };
|
|
904
1147
|
const leaf = { type: "text", value: token.content, position: { start: { offset: range.start, line: 0, column: 0 }, end: { offset: range.end, line: 0, column: 0 } } };
|
|
905
|
-
return /* @__PURE__ */
|
|
1148
|
+
return /* @__PURE__ */ jsx4(Text, { className: token.style ? "limr-code-token" : void 0, style: token.style, node: leaf, context, mapping: mapped2, marks: marks.filter((mark) => mark.range.end > range.start && mark.range.end <= range.end) }, index);
|
|
906
1149
|
}) });
|
|
907
1150
|
}
|
|
908
1151
|
function Atomic({ node, context, children, inline, blockElement }) {
|
|
@@ -913,7 +1156,7 @@ function Atomic({ node, context, children, inline, blockElement }) {
|
|
|
913
1156
|
const image = ["image", "imageReference"].includes(node.type) || node.type === "component" && node.name === "img";
|
|
914
1157
|
const corner = image || !inline;
|
|
915
1158
|
const marks = [...context.marks.get(node) ?? [], ...corner ? context.afterMarks.get(node) ?? [] : []];
|
|
916
|
-
const markers = marks.map((occurrence) => /* @__PURE__ */
|
|
1159
|
+
const markers = marks.map((occurrence) => /* @__PURE__ */ jsx4(AnnotationMarker, { occurrence }, occurrence.id));
|
|
917
1160
|
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
918
1161
|
/* @__PURE__ */ jsxs2(
|
|
919
1162
|
Tag,
|
|
@@ -932,7 +1175,7 @@ function Atomic({ node, context, children, inline, blockElement }) {
|
|
|
932
1175
|
},
|
|
933
1176
|
children: [
|
|
934
1177
|
children,
|
|
935
|
-
corner && !!marks.length && /* @__PURE__ */
|
|
1178
|
+
corner && !!marks.length && /* @__PURE__ */ jsx4("span", { className: "limr-corner-marks", "data-limr-ignore": "true", children: markers })
|
|
936
1179
|
]
|
|
937
1180
|
}
|
|
938
1181
|
),
|
|
@@ -958,16 +1201,16 @@ function HeadingNode({ node, children, runtime, blockElement }) {
|
|
|
958
1201
|
}
|
|
959
1202
|
function Reference({ node, children, image }) {
|
|
960
1203
|
const definition2 = useDocumentSelector((doc) => doc.definitions.get(String(node.identifier)));
|
|
961
|
-
if (!definition2) return /* @__PURE__ */
|
|
962
|
-
return image ? /* @__PURE__ */
|
|
1204
|
+
if (!definition2) return /* @__PURE__ */ jsx4(Fragment2, { children: children || String(node.alt ?? node.label ?? "") });
|
|
1205
|
+
return image ? /* @__PURE__ */ jsx4("img", { src: safeUrl(definition2.url, true), alt: String(node.alt ?? ""), title: definition2.title ? String(definition2.title) : void 0, loading: "lazy", decoding: "async" }) : /* @__PURE__ */ jsx4("a", { href: safeUrl(definition2.url), title: definition2.title ? String(definition2.title) : void 0, children });
|
|
963
1206
|
}
|
|
964
1207
|
function FootnoteReference({ node }) {
|
|
965
1208
|
const runtime = useRuntime();
|
|
966
1209
|
const identifier2 = String(node.identifier);
|
|
967
1210
|
const number = useDocumentSelector((doc) => doc.footnoteOrder.indexOf(identifier2) + 1);
|
|
968
|
-
return /* @__PURE__ */
|
|
1211
|
+
return /* @__PURE__ */ jsx4("sup", { "data-limr-ignore": "true", children: /* @__PURE__ */ jsx4("a", { href: `#${runtime.document.id}-fn-${encodeURIComponent(identifier2)}`, id: `${runtime.document.id}-fnref-${rangeOf(node).start}`, "aria-label": `Footnote ${number}`, children: number }) });
|
|
969
1212
|
}
|
|
970
|
-
var ExtensionBoundary = class extends
|
|
1213
|
+
var ExtensionBoundary = class extends Component2 {
|
|
971
1214
|
state = { failed: false };
|
|
972
1215
|
static getDerivedStateFromError() {
|
|
973
1216
|
return { failed: true };
|
|
@@ -978,7 +1221,7 @@ var ExtensionBoundary = class extends Component {
|
|
|
978
1221
|
if (this.state.failed && previous.fallback !== this.props.fallback) this.setState({ failed: false });
|
|
979
1222
|
}
|
|
980
1223
|
render() {
|
|
981
|
-
return this.state.failed ? /* @__PURE__ */
|
|
1224
|
+
return this.state.failed ? /* @__PURE__ */ jsx4("pre", { className: "limr-extension-error", children: this.props.fallback }) : this.props.children;
|
|
982
1225
|
}
|
|
983
1226
|
};
|
|
984
1227
|
function containsBlock(node) {
|
|
@@ -986,20 +1229,26 @@ function containsBlock(node) {
|
|
|
986
1229
|
}
|
|
987
1230
|
function renderNode(node, context, index = 0, trailing) {
|
|
988
1231
|
const { runtime } = context;
|
|
989
|
-
if (node.type === "text" && context.compact) return node.value ?? "";
|
|
1232
|
+
if (node.type === "text" && context.compact) return context.live ? /* @__PURE__ */ jsx4(StreamText, { value: node.value ?? "", animateInitial: rangeOf(node).end > context.revealFrom }, `text-${node.position?.start.offset ?? index}`) : node.value ?? "";
|
|
1233
|
+
if (node.type === "streamPending") return null;
|
|
990
1234
|
const blockElement = node === context.block.node ? context.blockElement : void 0;
|
|
991
1235
|
const key = `${node.type}-${node.position?.start.offset ?? index}-${index}`;
|
|
992
|
-
|
|
1236
|
+
let childContext = node.type === "list" ? { ...context, tightList: !node.spread } : context;
|
|
1237
|
+
if (runtime.rendererOverrides.size) childContext = { ...childContext, ancestors: [...context.ancestors ?? [], node] };
|
|
993
1238
|
const renderChildren = (nodes, options) => {
|
|
994
1239
|
let last = -1;
|
|
995
1240
|
nodes.forEach((child, i) => {
|
|
996
1241
|
if (!["definition", "footnoteDefinition", "annotationDefinition"].includes(child.type)) last = i;
|
|
997
1242
|
});
|
|
998
|
-
if (last < 0 && options?.trailing) return [/* @__PURE__ */
|
|
1243
|
+
if (last < 0 && options?.trailing) return [/* @__PURE__ */ jsx4(Fragment, { children: options.trailing }, "trailing")];
|
|
999
1244
|
return nodes.map((child, i) => renderNode(child, childContext, i, i === last ? options?.trailing : void 0));
|
|
1000
1245
|
};
|
|
1001
1246
|
const children = node.type === "table" ? [] : node.type === "listItem" && context.tightList ? (node.children ?? []).flatMap((child, index2) => child.type === "paragraph" ? renderChildren(child.children ?? []) : renderNode(child, context, index2)) : renderChildren(node.children ?? []);
|
|
1002
|
-
const
|
|
1247
|
+
const componentName = node.type === "component" ? node.name ?? "" : node.type;
|
|
1248
|
+
const rules = runtime.rendererOverrides.get(componentName);
|
|
1249
|
+
const override = rules?.slice().reverse().find((rule) => !rule.when || rule.when(node, { pending: context.block.pending, incomplete: !!node.incomplete, ancestors: context.ancestors ?? [] }));
|
|
1250
|
+
const owner = node.incomplete && !override ? runtime.configuration.get().extensions?.slice().reverse().find((extension) => extension.components?.[componentName]) : void 0;
|
|
1251
|
+
const Renderer = override?.component ?? (node.incomplete && owner?.streaming?.Loading || runtime.components[componentName]);
|
|
1003
1252
|
let element;
|
|
1004
1253
|
if (Renderer) {
|
|
1005
1254
|
const range = rangeOf(node);
|
|
@@ -1007,14 +1256,14 @@ function renderNode(node, context, index = 0, trailing) {
|
|
|
1007
1256
|
const attribute = node.attributeNodes?.[name];
|
|
1008
1257
|
if (!attribute) return String(node.attributes?.[name] ?? "");
|
|
1009
1258
|
const range2 = rangeOf(attribute);
|
|
1010
|
-
return /* @__PURE__ */
|
|
1259
|
+
return /* @__PURE__ */ jsx4(Text, { node: attribute, context, marks: context.occurrences.filter((item) => item.range.end > range2.start && item.range.end <= range2.end) });
|
|
1011
1260
|
};
|
|
1012
|
-
element = /* @__PURE__ */
|
|
1261
|
+
element = /* @__PURE__ */ jsx4(ExtensionBoundary, { fallback: runtime.document.getSnapshot().source.slice(range.start, range.end), children: /* @__PURE__ */ jsx4(Renderer, { node, children, pending: context.block.pending, incomplete: !!node.incomplete, source: runtime.document.getSnapshot().source.slice(range.start, range.end), renderChildren, renderValue: (tokens) => /* @__PURE__ */ jsx4(LiteralValue, { node, context, tokens }), renderAttribute }) }, key);
|
|
1013
1262
|
} else {
|
|
1014
1263
|
switch (node.type) {
|
|
1015
1264
|
case "text":
|
|
1016
1265
|
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1017
|
-
context.compact ? node.value ?? "" : /* @__PURE__ */
|
|
1266
|
+
context.compact ? node.value ?? "" : /* @__PURE__ */ jsx4(Text, { node, context }),
|
|
1018
1267
|
trailing
|
|
1019
1268
|
] }, key);
|
|
1020
1269
|
case "paragraph":
|
|
@@ -1033,62 +1282,62 @@ function renderNode(node, context, index = 0, trailing) {
|
|
|
1033
1282
|
trailing
|
|
1034
1283
|
] }, key);
|
|
1035
1284
|
case "strong":
|
|
1036
|
-
element = /* @__PURE__ */
|
|
1285
|
+
element = /* @__PURE__ */ jsx4("strong", { children });
|
|
1037
1286
|
break;
|
|
1038
1287
|
case "emphasis":
|
|
1039
|
-
element = /* @__PURE__ */
|
|
1288
|
+
element = /* @__PURE__ */ jsx4("em", { children });
|
|
1040
1289
|
break;
|
|
1041
1290
|
case "delete":
|
|
1042
|
-
element = /* @__PURE__ */
|
|
1291
|
+
element = /* @__PURE__ */ jsx4("del", { children });
|
|
1043
1292
|
break;
|
|
1044
1293
|
case "inlineCode":
|
|
1045
|
-
element = /* @__PURE__ */
|
|
1294
|
+
element = /* @__PURE__ */ jsx4("code", { className: "limr-inline-code", "data-limr-inline-syntax": "", "data-source-start": rangeOf(node).start, "data-source-end": rangeOf(node).end, children: /* @__PURE__ */ jsx4(LiteralValue, { node, context }) });
|
|
1046
1295
|
break;
|
|
1047
1296
|
case "code":
|
|
1048
|
-
element = /* @__PURE__ */
|
|
1297
|
+
element = /* @__PURE__ */ jsx4("pre", { children: /* @__PURE__ */ jsx4("code", { children: /* @__PURE__ */ jsx4(LiteralValue, { node, context }) }) });
|
|
1049
1298
|
break;
|
|
1050
1299
|
case "math":
|
|
1051
1300
|
case "inlineMath":
|
|
1052
|
-
element = /* @__PURE__ */
|
|
1301
|
+
element = /* @__PURE__ */ jsx4("code", { children: node.value });
|
|
1053
1302
|
break;
|
|
1054
1303
|
case "blockquote":
|
|
1055
1304
|
element = /* @__PURE__ */ jsxs2("blockquote", { className: "limr-note", children: [
|
|
1056
|
-
/* @__PURE__ */
|
|
1057
|
-
/* @__PURE__ */
|
|
1305
|
+
/* @__PURE__ */ jsx4("div", { className: "limr-card-label", "data-limr-ignore": "true", children: runtime.locale.note }),
|
|
1306
|
+
/* @__PURE__ */ jsx4("div", { className: "limr-block-content", children })
|
|
1058
1307
|
] });
|
|
1059
1308
|
break;
|
|
1060
1309
|
case "list":
|
|
1061
|
-
element = node.ordered ? /* @__PURE__ */
|
|
1310
|
+
element = node.ordered ? /* @__PURE__ */ jsx4("ol", { start: Number(node.start ?? 1), children }) : /* @__PURE__ */ jsx4("ul", { children });
|
|
1062
1311
|
break;
|
|
1063
1312
|
case "listItem":
|
|
1064
1313
|
element = /* @__PURE__ */ jsxs2("li", { className: typeof node.checked === "boolean" ? "limr-task-item" : void 0, children: [
|
|
1065
|
-
typeof node.checked === "boolean" && /* @__PURE__ */
|
|
1314
|
+
typeof node.checked === "boolean" && /* @__PURE__ */ jsx4("input", { type: "checkbox", checked: node.checked, disabled: true, "aria-label": "Task" }),
|
|
1066
1315
|
children
|
|
1067
1316
|
] });
|
|
1068
1317
|
break;
|
|
1069
1318
|
case "link":
|
|
1070
|
-
element = /* @__PURE__ */
|
|
1319
|
+
element = /* @__PURE__ */ jsx4("a", { href: safeUrl(node.url), title: node.title ? String(node.title) : void 0, children });
|
|
1071
1320
|
break;
|
|
1072
1321
|
case "image":
|
|
1073
|
-
element = /* @__PURE__ */
|
|
1322
|
+
element = /* @__PURE__ */ jsx4("img", { src: safeUrl(node.url, true), alt: String(node.alt ?? ""), title: node.title ? String(node.title) : void 0, loading: "lazy", decoding: "async" });
|
|
1074
1323
|
break;
|
|
1075
1324
|
case "linkReference":
|
|
1076
|
-
element = /* @__PURE__ */
|
|
1325
|
+
element = /* @__PURE__ */ jsx4(Reference, { node, image: false, children });
|
|
1077
1326
|
break;
|
|
1078
1327
|
case "imageReference":
|
|
1079
|
-
element = /* @__PURE__ */
|
|
1328
|
+
element = /* @__PURE__ */ jsx4(Reference, { node, image: true, children });
|
|
1080
1329
|
break;
|
|
1081
1330
|
case "thematicBreak":
|
|
1082
|
-
element = /* @__PURE__ */
|
|
1331
|
+
element = /* @__PURE__ */ jsx4("hr", {});
|
|
1083
1332
|
break;
|
|
1084
1333
|
case "break":
|
|
1085
|
-
element = /* @__PURE__ */
|
|
1334
|
+
element = /* @__PURE__ */ jsx4("br", { "data-limr-break": "", "data-source-start": rangeOf(node).start, "data-source-end": rangeOf(node).end });
|
|
1086
1335
|
break;
|
|
1087
1336
|
case "table": {
|
|
1088
1337
|
const rows = node.children ?? [], alignment = node.align;
|
|
1089
|
-
element = /* @__PURE__ */
|
|
1090
|
-
/* @__PURE__ */
|
|
1091
|
-
/* @__PURE__ */
|
|
1338
|
+
element = /* @__PURE__ */ jsx4("div", { className: "limr-table-scroll", children: /* @__PURE__ */ jsxs2("table", { children: [
|
|
1339
|
+
/* @__PURE__ */ jsx4("thead", { children: rows.slice(0, 1).map((row, i) => /* @__PURE__ */ jsx4("tr", { children: row.children?.map((cell, j) => /* @__PURE__ */ jsx4("th", { style: { textAlign: alignment?.[j] }, children: renderChildren(cell.children ?? []) }, j)) }, i)) }),
|
|
1340
|
+
/* @__PURE__ */ jsx4("tbody", { children: rows.slice(1).map((row, i) => /* @__PURE__ */ jsx4("tr", { children: row.children?.map((cell, j) => /* @__PURE__ */ jsx4("td", { style: { textAlign: alignment?.[j] }, children: renderChildren(cell.children ?? []) }, j)) }, i)) })
|
|
1092
1341
|
] }) });
|
|
1093
1342
|
break;
|
|
1094
1343
|
}
|
|
@@ -1098,19 +1347,19 @@ function renderNode(node, context, index = 0, trailing) {
|
|
|
1098
1347
|
return null;
|
|
1099
1348
|
case "footnoteReference":
|
|
1100
1349
|
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1101
|
-
/* @__PURE__ */
|
|
1350
|
+
/* @__PURE__ */ jsx4(FootnoteReference, { node }),
|
|
1102
1351
|
trailing
|
|
1103
1352
|
] }, key);
|
|
1104
1353
|
case "annotationReference": {
|
|
1105
1354
|
const Tag = node.inline ? "span" : "div";
|
|
1106
1355
|
element = /* @__PURE__ */ jsxs2(Tag, { children: [
|
|
1107
1356
|
children,
|
|
1108
|
-
/* @__PURE__ */
|
|
1357
|
+
/* @__PURE__ */ jsx4(AnnotationMarker, { occurrence: { id: `${runtime.document.id}-ref-${rangeOf(node).start}`, range: rangeOf(node), annotationIds: node.annotationIds, embedded: true } })
|
|
1109
1358
|
] });
|
|
1110
1359
|
break;
|
|
1111
1360
|
}
|
|
1112
1361
|
case "html":
|
|
1113
|
-
element = /* @__PURE__ */
|
|
1362
|
+
element = /* @__PURE__ */ jsx4("span", { className: "limr-literal", children: node.value });
|
|
1114
1363
|
break;
|
|
1115
1364
|
case "component":
|
|
1116
1365
|
element = children;
|
|
@@ -1122,27 +1371,40 @@ function renderNode(node, context, index = 0, trailing) {
|
|
|
1122
1371
|
const atomic2 = node.selection === "atomic" || ["math", "inlineMath", "image", "imageReference", "html"].includes(node.type);
|
|
1123
1372
|
const corner = atomic2 && (!node.inline && !["inlineCode", "inlineMath", "html"].includes(node.type) || ["image", "imageReference"].includes(node.type) || node.name === "img");
|
|
1124
1373
|
const after = corner ? void 0 : context.afterMarks.get(node);
|
|
1125
|
-
const withMarkers = (element2) =>
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1374
|
+
const withMarkers = (element2) => {
|
|
1375
|
+
const result = after?.length || trailing ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1376
|
+
element2,
|
|
1377
|
+
after?.map((occurrence) => /* @__PURE__ */ jsx4(AnnotationMarker, { occurrence }, occurrence.id)),
|
|
1378
|
+
trailing
|
|
1379
|
+
] }, key) : element2;
|
|
1380
|
+
return context.live && !node.inline && (node.type === "component" || ["code", "math", "mermaid", "callout", "blockquote", "table"].includes(node.type)) ? /* @__PURE__ */ jsx4(StreamEntrance, { state: node.type === "component" ? !!node.incomplete : true, children: result }, key) : result;
|
|
1381
|
+
};
|
|
1382
|
+
if (atomic2) return withMarkers(/* @__PURE__ */ jsx4(Atomic, { node, context, blockElement, inline: node.inline || ["inlineCode", "inlineMath", "image", "imageReference", "html"].includes(node.type), children: element }, key));
|
|
1131
1383
|
if (blockElement) {
|
|
1132
1384
|
const attributes = { ...blockAttributes(blockElement), ref: blockElement.ref };
|
|
1133
|
-
return withMarkers(isValidElement(element) && typeof element.type === "string" ? cloneElement(element, { ...attributes, key }) : /* @__PURE__ */
|
|
1385
|
+
return withMarkers(isValidElement(element) && typeof element.type === "string" ? cloneElement(element, { ...attributes, key }) : /* @__PURE__ */ jsx4("div", { ...attributes, children: element }, key));
|
|
1134
1386
|
}
|
|
1135
|
-
return withMarkers(isValidElement(element) ? cloneElement(element, { key }) : /* @__PURE__ */
|
|
1387
|
+
return withMarkers(isValidElement(element) ? cloneElement(element, { key }) : /* @__PURE__ */ jsx4(Fragment, { children: element }, key));
|
|
1136
1388
|
}
|
|
1137
|
-
var BlockView = memo(function BlockView2({ block, runtime, components, extensions, decorations, footnoteId }) {
|
|
1138
|
-
const
|
|
1139
|
-
|
|
1389
|
+
var BlockView = memo(function BlockView2({ block, runtime, components, extensions, rendererOverrides, decorations, footnoteId }) {
|
|
1390
|
+
const streamed = useRef4(runtime.document.getSnapshot().streaming);
|
|
1391
|
+
if (block.pending) streamed.current = true;
|
|
1392
|
+
const revealed = useRef4(block.range.start);
|
|
1393
|
+
const revealFrom = revealed.current;
|
|
1394
|
+
useIsomorphicLayoutEffect(() => {
|
|
1395
|
+
revealed.current = Math.max(revealed.current, block.range.end);
|
|
1396
|
+
}, [block.range.end]);
|
|
1397
|
+
const element = useRef4(null);
|
|
1398
|
+
const getElement = useCallback2(() => element.current, []);
|
|
1399
|
+
const typography = useStoreSelector(runtime.configuration, (config) => config.typography);
|
|
1400
|
+
const knuthPlass = useStoreSelector(runtime.configuration, (config) => config.knuthPlass);
|
|
1401
|
+
const clearBindings = useRef4(void 0);
|
|
1140
1402
|
const { occurrences } = decorations;
|
|
1141
1403
|
const highlights = useMemo(() => decorations.highlights.filter((highlight) => !highlight.occurrenceId), [decorations.highlights]);
|
|
1142
1404
|
const root = useMemo(() => footnoteId ? { ...block.node, type: "listItem" } : block.node, [block, footnoteId]);
|
|
1143
|
-
const texts = useMemo(() => compactTextNodes(root, runtime.components), [root, runtime, components, extensions]);
|
|
1144
|
-
const compact = !!texts && !occurrences.length && !highlights.length;
|
|
1145
|
-
const observe =
|
|
1405
|
+
const texts = useMemo(() => compactTextNodes(root, runtime.components, runtime.rendererOverrides), [root, runtime, components, extensions, rendererOverrides]);
|
|
1406
|
+
const compact = typography !== "knuth-plass" && !!texts && !occurrences.length && !highlights.length;
|
|
1407
|
+
const observe = useCallback2((next) => {
|
|
1146
1408
|
clearBindings.current?.();
|
|
1147
1409
|
clearBindings.current = void 0;
|
|
1148
1410
|
if (element.current) runtime.textBinders.delete(element.current);
|
|
@@ -1186,148 +1448,32 @@ var BlockView = memo(function BlockView2({ block, runtime, components, extension
|
|
|
1186
1448
|
return { marks: map, afterMarks: after };
|
|
1187
1449
|
}, [block, occurrences]);
|
|
1188
1450
|
if (!footnoteId && ["definition", "footnoteDefinition", "annotationDefinition"].includes(block.node.type)) return null;
|
|
1189
|
-
const context = { runtime, block, marks, afterMarks, highlights, occurrences, compact, blockElement: { id: block.id, range: block.range, pending: block.pending, ref: observe } };
|
|
1190
|
-
|
|
1191
|
-
return
|
|
1451
|
+
const context = { runtime, block, marks, afterMarks, highlights, occurrences, compact, live: streamed.current, revealFrom, blockElement: { id: block.id, range: block.range, pending: block.pending, ref: observe } };
|
|
1452
|
+
const content = footnoteId ? /* @__PURE__ */ jsx4("li", { id: `${runtime.document.id}-fn-${encodeURIComponent(footnoteId)}`, ...blockAttributes(context.blockElement), ref: observe, children: block.node.children?.map((child, index) => renderNode(child, { ...context, blockElement: void 0 }, index)) }) : renderNode(block.node, context);
|
|
1453
|
+
return /* @__PURE__ */ jsx4(KnuthPlassBoundary, { element: getElement, runtime, enabled: typography === "knuth-plass", pending: block.pending, options: knuthPlass, children: content });
|
|
1192
1454
|
});
|
|
1193
1455
|
function Footnotes() {
|
|
1194
1456
|
const runtime = useRuntime();
|
|
1195
1457
|
const doc = useDocumentSelector((snapshot) => snapshot);
|
|
1196
1458
|
const components = useStoreSelector(runtime.configuration, (config) => config.components);
|
|
1197
1459
|
const extensions = useStoreSelector(runtime.configuration, (config) => config.extensions);
|
|
1460
|
+
const rendererOverrides = useStoreSelector(runtime.configuration, (config) => config.rendererOverrides);
|
|
1198
1461
|
const decorations = useStoreSelector(runtime.decorations, (state) => state.byBlock);
|
|
1199
1462
|
const blocks = useMemo(() => new Map(doc.blocks.filter((block) => block.node.type === "footnoteDefinition").map((block) => [String(block.node.identifier), block])), [doc.blocks]);
|
|
1200
1463
|
if (!doc.footnoteOrder.length) return null;
|
|
1201
1464
|
return /* @__PURE__ */ jsxs2("section", { className: "limr-footnotes", "aria-label": runtime.locale.footnotes, children: [
|
|
1202
|
-
/* @__PURE__ */
|
|
1203
|
-
/* @__PURE__ */
|
|
1465
|
+
/* @__PURE__ */ jsx4("hr", {}),
|
|
1466
|
+
/* @__PURE__ */ jsx4("ol", { children: doc.footnoteOrder.map((id) => {
|
|
1204
1467
|
const node = doc.footnotes.get(id);
|
|
1205
1468
|
if (!node) return null;
|
|
1206
1469
|
const block = blocks.get(id) ?? { id: `${doc.id}-fn-${id}`, range: rangeOf(node), node, pending: false };
|
|
1207
|
-
return /* @__PURE__ */
|
|
1470
|
+
return /* @__PURE__ */ jsx4(BlockView, { block, runtime, components, extensions, rendererOverrides, footnoteId: id, decorations: decorations.get(block.id) ?? emptyDecorations }, id);
|
|
1208
1471
|
}) })
|
|
1209
1472
|
] });
|
|
1210
1473
|
}
|
|
1211
1474
|
|
|
1212
1475
|
// src/react/selection.ts
|
|
1213
|
-
import { useEffect as
|
|
1214
|
-
|
|
1215
|
-
// src/react/source-geometry.ts
|
|
1216
|
-
function flowOf(element, container) {
|
|
1217
|
-
const known = element.closest("pre,p,figcaption,li,th,td,h1,h2,h3,h4,h5,h6,.limr-choice-text,.limr-definition-title,.limr-question-title,.limr-block-content");
|
|
1218
|
-
return known && container.contains(known) ? known : element.closest("[data-limr-block]") ?? container;
|
|
1219
|
-
}
|
|
1220
|
-
function leavesIn(block, runtime) {
|
|
1221
|
-
runtime.prepareTextBindings(block);
|
|
1222
|
-
const result = [];
|
|
1223
|
-
const visit = (node, inherited) => {
|
|
1224
|
-
if (node instanceof HTMLElement) {
|
|
1225
|
-
if (node !== block && node.hasAttribute("data-limr-document") || node.hasAttribute("inert")) return;
|
|
1226
|
-
const marker = node.dataset.limrMarker;
|
|
1227
|
-
const atomic2 = node.dataset.limrAtomic;
|
|
1228
|
-
if (marker || atomic2) {
|
|
1229
|
-
const image = node.dataset.limrMedia === "image";
|
|
1230
|
-
result.push({ node, kind: marker ? "marker" : image ? "image" : atomic2 === "block" ? "block" : "inline", range: { start: Number(node.dataset.sourceStart), end: Number(node.dataset.sourceEnd) }, flow: image ? node : flowOf(node, runtime.content), offset: 0 });
|
|
1231
|
-
return;
|
|
1232
|
-
}
|
|
1233
|
-
if (node.hasAttribute("data-limr-ignore")) return;
|
|
1234
|
-
const binding = runtime.bindings.get(node);
|
|
1235
|
-
if (binding) inherited = { binding, offset: 0 };
|
|
1236
|
-
}
|
|
1237
|
-
if (node.nodeType === Node.TEXT_NODE) {
|
|
1238
|
-
const binding = runtime.bindings.get(node) ?? inherited?.binding;
|
|
1239
|
-
const offset = runtime.bindings.has(node) ? 0 : inherited?.offset ?? 0;
|
|
1240
|
-
const length = node.textContent?.length ?? 0;
|
|
1241
|
-
if (binding?.resolve && length) result.push({ node, kind: "text", range: { start: binding.resolve(offset, "start"), end: binding.resolve(offset + length, "end") }, flow: flowOf(node.parentElement, runtime.content), binding, offset });
|
|
1242
|
-
if (inherited) inherited.offset += length;
|
|
1243
|
-
return;
|
|
1244
|
-
}
|
|
1245
|
-
node.childNodes.forEach((child) => visit(child, inherited));
|
|
1246
|
-
};
|
|
1247
|
-
visit(block);
|
|
1248
|
-
return result;
|
|
1249
|
-
}
|
|
1250
|
-
function textRange(leaf, source, viewport) {
|
|
1251
|
-
const node = leaf.node, length = node.length;
|
|
1252
|
-
const resolve = leaf.binding.resolve;
|
|
1253
|
-
let lo = 0, hi = length;
|
|
1254
|
-
while (lo < hi) {
|
|
1255
|
-
const mid = lo + hi >>> 1;
|
|
1256
|
-
if (resolve(leaf.offset + mid + 1, "end") <= source.start) lo = mid + 1;
|
|
1257
|
-
else hi = mid;
|
|
1258
|
-
}
|
|
1259
|
-
let start = lo;
|
|
1260
|
-
lo = start;
|
|
1261
|
-
hi = length;
|
|
1262
|
-
while (lo < hi) {
|
|
1263
|
-
const mid = lo + hi >>> 1;
|
|
1264
|
-
if (resolve(leaf.offset + mid, "start") < source.end) lo = mid + 1;
|
|
1265
|
-
else hi = mid;
|
|
1266
|
-
}
|
|
1267
|
-
if (start === lo) return null;
|
|
1268
|
-
let end = lo;
|
|
1269
|
-
const range = document.createRange();
|
|
1270
|
-
if (viewport && end - start > 1024) {
|
|
1271
|
-
range.setStart(node, start);
|
|
1272
|
-
range.setEnd(node, end);
|
|
1273
|
-
const box = range.getBoundingClientRect();
|
|
1274
|
-
if (box.height > viewport.bottom - viewport.top + 80) {
|
|
1275
|
-
lo = start;
|
|
1276
|
-
hi = end;
|
|
1277
|
-
while (lo < hi) {
|
|
1278
|
-
const mid = lo + hi >>> 1;
|
|
1279
|
-
range.setStart(node, mid);
|
|
1280
|
-
range.setEnd(node, mid + 1);
|
|
1281
|
-
if (range.getBoundingClientRect().bottom < viewport.top) lo = mid + 1;
|
|
1282
|
-
else hi = mid;
|
|
1283
|
-
}
|
|
1284
|
-
start = lo;
|
|
1285
|
-
hi = end;
|
|
1286
|
-
while (lo < hi) {
|
|
1287
|
-
const mid = lo + hi >>> 1;
|
|
1288
|
-
range.setStart(node, mid);
|
|
1289
|
-
range.setEnd(node, mid + 1);
|
|
1290
|
-
if (range.getBoundingClientRect().top <= viewport.bottom) lo = mid + 1;
|
|
1291
|
-
else hi = mid;
|
|
1292
|
-
}
|
|
1293
|
-
end = lo;
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
if (start === end) return null;
|
|
1297
|
-
range.setStart(node, start);
|
|
1298
|
-
range.setEnd(node, end);
|
|
1299
|
-
return range;
|
|
1300
|
-
}
|
|
1301
|
-
function sourceRangeStartRect(runtime, source) {
|
|
1302
|
-
for (const block of runtime.document.getSnapshot().blocks) {
|
|
1303
|
-
if (!intersects(block.range, source)) continue;
|
|
1304
|
-
const element = runtime.blocks.get(block.id);
|
|
1305
|
-
if (!element) continue;
|
|
1306
|
-
for (const leaf of leavesIn(element, runtime)) {
|
|
1307
|
-
if (leaf.kind === "marker" || !intersects(leaf.range, source)) continue;
|
|
1308
|
-
if (leaf.kind === "text") {
|
|
1309
|
-
const range = textRange(leaf, source);
|
|
1310
|
-
if (!range) continue;
|
|
1311
|
-
const node = leaf.node, end = range.endOffset;
|
|
1312
|
-
for (let start = range.startOffset; start < end; ) {
|
|
1313
|
-
const next = Math.min(end, start + (node.data.codePointAt(start) > 65535 ? 2 : 1));
|
|
1314
|
-
range.setStart(node, start);
|
|
1315
|
-
range.setEnd(node, next);
|
|
1316
|
-
const rect = range.getBoundingClientRect();
|
|
1317
|
-
if (rect.width && rect.height) return rect;
|
|
1318
|
-
start = next;
|
|
1319
|
-
}
|
|
1320
|
-
} else {
|
|
1321
|
-
const node = leaf.node;
|
|
1322
|
-
const rect = (node.querySelector(leaf.kind === "image" ? "img" : "[data-limr-selection-surface]") ?? node).getBoundingClientRect();
|
|
1323
|
-
if (rect.width && rect.height) return rect;
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
return null;
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
// src/react/selection.ts
|
|
1476
|
+
import { useEffect as useEffect3 } from "react";
|
|
1331
1477
|
function visualSelection(runtime, native, options) {
|
|
1332
1478
|
if (![...runtime.content.querySelectorAll('[data-limr-selection-order="visual"]')].some((element) => native.intersectsNode(element))) return;
|
|
1333
1479
|
const blocks = [...runtime.blocks.values()].filter((block) => native.intersectsNode(block));
|
|
@@ -1374,7 +1520,7 @@ function visualSelection(runtime, native, options) {
|
|
|
1374
1520
|
return { ...selections[0], raw: combine("raw"), syntax: combine("syntax"), blocks: combine("blocks") };
|
|
1375
1521
|
}
|
|
1376
1522
|
function useSelectionTracking(runtime, enabled) {
|
|
1377
|
-
|
|
1523
|
+
useEffect3(() => {
|
|
1378
1524
|
const container = runtime.content;
|
|
1379
1525
|
if (!container || !enabled) return;
|
|
1380
1526
|
let frame = 0, dragging = false;
|
|
@@ -1382,6 +1528,10 @@ function useSelectionTracking(runtime, enabled) {
|
|
|
1382
1528
|
function resolve(node, offset, edge) {
|
|
1383
1529
|
let element = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement;
|
|
1384
1530
|
if (!element || element.closest("[data-limr-document]") !== container || element.closest("[data-limr-ignore]")) return null;
|
|
1531
|
+
let atom = element.closest("[data-limr-atomic]");
|
|
1532
|
+
for (let outer = atom?.parentElement?.closest("[data-limr-atomic]"); outer && container?.contains(outer); outer = atom.parentElement?.closest("[data-limr-atomic]")) atom = outer;
|
|
1533
|
+
const atomicBinding = atom && runtime.bindings.get(atom);
|
|
1534
|
+
if (atomicBinding?.atomic) return { offset: edge === "start" ? atomicBinding.range.start : atomicBinding.range.end, atomic: true, exact: true };
|
|
1385
1535
|
runtime.prepareTextBindings(element);
|
|
1386
1536
|
const native = node.nodeType === Node.TEXT_NODE ? runtime.bindings.get(node) : void 0;
|
|
1387
1537
|
if (native?.resolve) return { offset: native.resolve(offset, edge), atomic: false, exact: native.exact !== false };
|
|
@@ -1389,7 +1539,7 @@ function useSelectionTracking(runtime, enabled) {
|
|
|
1389
1539
|
const binding = runtime.bindings.get(element);
|
|
1390
1540
|
if (binding) {
|
|
1391
1541
|
if (binding.atomic) return { offset: edge === "start" ? binding.range.start : binding.range.end, atomic: true, exact: true };
|
|
1392
|
-
const range =
|
|
1542
|
+
const range = measurementRange(element.ownerDocument);
|
|
1393
1543
|
range.setStart(element, 0);
|
|
1394
1544
|
try {
|
|
1395
1545
|
range.setEnd(node, offset);
|
|
@@ -1450,12 +1600,20 @@ function useSelectionTracking(runtime, enabled) {
|
|
|
1450
1600
|
previous = { startNode: range.startContainer, start: range.startOffset, endNode: range.endContainer, end: range.endOffset, revision, settled: !dragging };
|
|
1451
1601
|
runtime.selectionRange = range.cloneRange();
|
|
1452
1602
|
runtime.highlightReference = null;
|
|
1603
|
+
const text = selection.toString();
|
|
1453
1604
|
const options = {
|
|
1454
|
-
text
|
|
1605
|
+
// An image/diagram can prohibit internal text selection while its
|
|
1606
|
+
// complete source block remains selectable and copyable.
|
|
1607
|
+
text: text || (start.atomic && end.atomic ? runtime.document.getSnapshot().source.slice(start.offset, end.offset) : ""),
|
|
1455
1608
|
settled: !dragging,
|
|
1456
1609
|
quality: !start.exact || !end.exact ? "unmapped" : start.atomic || end.atomic ? "atomic" : "exact"
|
|
1457
1610
|
};
|
|
1458
|
-
|
|
1611
|
+
let captured = visualSelection(runtime, range, options) ?? selectionFromRange(runtime.document.getSnapshot(), { start: start.offset, end: end.offset }, options);
|
|
1612
|
+
if (!dragging) {
|
|
1613
|
+
const atomicText = atomicSelectionText(runtime, captured.raw.ranges);
|
|
1614
|
+
if (atomicText !== void 0) captured = { ...captured, text: atomicText, quality: "atomic" };
|
|
1615
|
+
}
|
|
1616
|
+
runtime.updateInteraction({ activeHighlight: null, selection: captured });
|
|
1459
1617
|
}
|
|
1460
1618
|
const schedule = () => {
|
|
1461
1619
|
if (!frame) frame = requestAnimationFrame(process);
|
|
@@ -1467,11 +1625,34 @@ function useSelectionTracking(runtime, enabled) {
|
|
|
1467
1625
|
dragging = false;
|
|
1468
1626
|
schedule();
|
|
1469
1627
|
};
|
|
1628
|
+
const atomicCopyText = (event) => {
|
|
1629
|
+
const native = window.getSelection(), captured = runtime.interaction.get().selection;
|
|
1630
|
+
if (event.defaultPrevented || !native?.anchorNode || native.isCollapsed || !container.contains(native.anchorNode) || captured?.quality !== "atomic") return null;
|
|
1631
|
+
if (event.target instanceof Element && event.target.closest("input,textarea,[contenteditable],[data-limr-selection-ui]")) return null;
|
|
1632
|
+
return captured.settled ? captured.text : atomicSelectionText(runtime, captured.raw.ranges) ?? captured.text;
|
|
1633
|
+
};
|
|
1634
|
+
const copy = (event) => {
|
|
1635
|
+
const text = atomicCopyText(event);
|
|
1636
|
+
if (!text || !event.clipboardData) return;
|
|
1637
|
+
event.clipboardData.setData("text/plain", text);
|
|
1638
|
+
event.preventDefault();
|
|
1639
|
+
};
|
|
1640
|
+
const copyKey = (event) => {
|
|
1641
|
+
if (event.key.toLowerCase() !== "c" || !(event.ctrlKey || event.metaKey) || event.altKey || !navigator.clipboard?.writeText) return;
|
|
1642
|
+
if (window.getSelection()?.toString()) return;
|
|
1643
|
+
const text = atomicCopyText(event);
|
|
1644
|
+
if (!text) return;
|
|
1645
|
+
event.preventDefault();
|
|
1646
|
+
void navigator.clipboard.writeText(text).catch(() => {
|
|
1647
|
+
});
|
|
1648
|
+
};
|
|
1470
1649
|
document.addEventListener("selectionchange", schedule);
|
|
1471
1650
|
container.addEventListener("pointerdown", down);
|
|
1472
1651
|
document.addEventListener("pointerup", up);
|
|
1473
1652
|
document.addEventListener("pointercancel", up);
|
|
1474
1653
|
document.addEventListener("keyup", schedule);
|
|
1654
|
+
document.addEventListener("copy", copy);
|
|
1655
|
+
document.addEventListener("keydown", copyKey);
|
|
1475
1656
|
if (window.getSelection()?.isCollapsed === false) schedule();
|
|
1476
1657
|
return () => {
|
|
1477
1658
|
cancelAnimationFrame(frame);
|
|
@@ -1480,13 +1661,15 @@ function useSelectionTracking(runtime, enabled) {
|
|
|
1480
1661
|
document.removeEventListener("pointerup", up);
|
|
1481
1662
|
document.removeEventListener("pointercancel", up);
|
|
1482
1663
|
document.removeEventListener("keyup", schedule);
|
|
1664
|
+
document.removeEventListener("copy", copy);
|
|
1665
|
+
document.removeEventListener("keydown", copyKey);
|
|
1483
1666
|
};
|
|
1484
1667
|
}, [runtime, enabled]);
|
|
1485
1668
|
}
|
|
1486
1669
|
|
|
1487
1670
|
// src/react/selection-paint.tsx
|
|
1488
|
-
import { useEffect as
|
|
1489
|
-
import { jsx as
|
|
1671
|
+
import { useEffect as useEffect4, useRef as useRef5 } from "react";
|
|
1672
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1490
1673
|
function rectangles(leaves, source, viewport, measure) {
|
|
1491
1674
|
const raw = [];
|
|
1492
1675
|
const geometry = (leaf, rect, reference) => {
|
|
@@ -1509,7 +1692,7 @@ function rectangles(leaves, source, viewport, measure) {
|
|
|
1509
1692
|
};
|
|
1510
1693
|
const edgeRect = (leaf, edge) => {
|
|
1511
1694
|
const node = leaf.node;
|
|
1512
|
-
const range =
|
|
1695
|
+
const range = measurementRange(node.ownerDocument);
|
|
1513
1696
|
const offset = edge === "first" ? 0 : Math.max(0, node.length - 1);
|
|
1514
1697
|
range.setStart(node, offset);
|
|
1515
1698
|
range.setEnd(node, Math.min(node.length, offset + 1));
|
|
@@ -1527,7 +1710,7 @@ function rectangles(leaves, source, viewport, measure) {
|
|
|
1527
1710
|
const boxAt = (index) => {
|
|
1528
1711
|
const leaf = leaves[index];
|
|
1529
1712
|
if (leaf.kind !== "text") return leaf.node.getBoundingClientRect();
|
|
1530
|
-
const range =
|
|
1713
|
+
const range = measurementRange(leaf.node.ownerDocument);
|
|
1531
1714
|
range.selectNodeContents(leaf.node);
|
|
1532
1715
|
return range.getBoundingClientRect();
|
|
1533
1716
|
};
|
|
@@ -1557,6 +1740,13 @@ function rectangles(leaves, source, viewport, measure) {
|
|
|
1557
1740
|
raw.push({ ...item, marker: leaf.node.dataset.limrMarker });
|
|
1558
1741
|
} else if (intersects(leaf.range, source)) {
|
|
1559
1742
|
if (leaf.kind === "text") {
|
|
1743
|
+
const glue = leaf.node.parentElement?.closest(".limr-kp-glue");
|
|
1744
|
+
if (glue) {
|
|
1745
|
+
const rect = glue.getBoundingClientRect();
|
|
1746
|
+
const reference = referenceFor(index, rect);
|
|
1747
|
+
if (rect.width && reference && rect.bottom >= viewport.top && rect.top <= viewport.bottom) raw.push(geometry(leaf, rect, reference));
|
|
1748
|
+
continue;
|
|
1749
|
+
}
|
|
1560
1750
|
const range = textRange(leaf, source, viewport);
|
|
1561
1751
|
const shell = leaf.node.parentElement?.closest("[data-limr-inline-syntax]");
|
|
1562
1752
|
const edges = shell ? Array.from(shell.getClientRects()) : [];
|
|
@@ -1605,15 +1795,42 @@ function rectangles(leaves, source, viewport, measure) {
|
|
|
1605
1795
|
const gap = right.left - left.left - left.width;
|
|
1606
1796
|
if (left.flow === right.flow && Math.abs(left.top - right.top) < 0.5 && gap > 0.1 && gap < left.height * 0.6) bridges.push({ left: left.left + left.width, top: left.top, width: gap, height: left.height, flow: left.flow });
|
|
1607
1797
|
}
|
|
1608
|
-
|
|
1798
|
+
const result = [], rows = /* @__PURE__ */ new Map();
|
|
1799
|
+
for (const rect of [...aligned, ...bridges]) {
|
|
1800
|
+
if (!rect.flow.hasAttribute("data-limr-kp") || rect.atomic || rect.marker) {
|
|
1801
|
+
result.push(rect);
|
|
1802
|
+
continue;
|
|
1803
|
+
}
|
|
1804
|
+
let flow = rows.get(rect.flow);
|
|
1805
|
+
if (!flow) {
|
|
1806
|
+
flow = /* @__PURE__ */ new Map();
|
|
1807
|
+
rows.set(rect.flow, flow);
|
|
1808
|
+
}
|
|
1809
|
+
const row = flow.get(rect.top) ?? [];
|
|
1810
|
+
row.push(rect);
|
|
1811
|
+
flow.set(rect.top, row);
|
|
1812
|
+
}
|
|
1813
|
+
for (const flow of rows.values()) for (const row of flow.values()) {
|
|
1814
|
+
row.sort((a, b) => a.left - b.left);
|
|
1815
|
+
let previous;
|
|
1816
|
+
for (const rect of row) {
|
|
1817
|
+
if (previous && rect.left <= previous.left + previous.width + 0.1 && Math.abs(rect.height - previous.height) < 0.1) previous.width = Math.max(previous.width, rect.left + rect.width - previous.left);
|
|
1818
|
+
else {
|
|
1819
|
+
previous = { ...rect };
|
|
1820
|
+
result.push(previous);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
return result;
|
|
1609
1825
|
}
|
|
1610
1826
|
function SelectionPaint({ runtime, interactive = true }) {
|
|
1611
|
-
const layer =
|
|
1612
|
-
|
|
1827
|
+
const layer = useRef5(null);
|
|
1828
|
+
useEffect4(() => {
|
|
1613
1829
|
const container = runtime.content, paint = layer.current;
|
|
1614
1830
|
if (!container || !paint) return;
|
|
1615
1831
|
let frame = 0, translating = false;
|
|
1616
1832
|
let leavesCache = /* @__PURE__ */ new WeakMap();
|
|
1833
|
+
let geometryCache = /* @__PURE__ */ new WeakMap();
|
|
1617
1834
|
let metrics = /* @__PURE__ */ new WeakMap();
|
|
1618
1835
|
const fontMetrics = /* @__PURE__ */ new Map();
|
|
1619
1836
|
let blocks;
|
|
@@ -1751,17 +1968,31 @@ function SelectionPaint({ runtime, interactive = true }) {
|
|
|
1751
1968
|
};
|
|
1752
1969
|
for (let index = lo; index < blocks.length; index++) {
|
|
1753
1970
|
const block = blocks[index];
|
|
1754
|
-
|
|
1971
|
+
const blockBox = block.element.getBoundingClientRect();
|
|
1972
|
+
if (blockBox.top > viewport.bottom + 32) break;
|
|
1755
1973
|
const tasks = [...decorations.get(block.id)?.highlights ?? []];
|
|
1756
1974
|
for (const range of selections) if (intersects(range, block.range)) tasks.push({ id: "selection", range, selection: true });
|
|
1757
1975
|
if (!tasks.length) continue;
|
|
1758
1976
|
let leaves = leavesCache.get(block.element);
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1977
|
+
let cached = geometryCache.get(block.element);
|
|
1978
|
+
if (cached?.width !== blockBox.width || cached.height !== blockBox.height) cached = void 0;
|
|
1979
|
+
if (!cached && blockBox.height < (viewport.bottom - viewport.top) * 3) {
|
|
1980
|
+
cached = { width: blockBox.width, height: blockBox.height, tasks: /* @__PURE__ */ new Map() };
|
|
1981
|
+
geometryCache.set(block.element, cached);
|
|
1762
1982
|
}
|
|
1763
1983
|
for (const task of tasks) {
|
|
1764
|
-
const
|
|
1984
|
+
const saved = cached?.tasks.get(task.id);
|
|
1985
|
+
if (task.occurrenceId && !referenceActive(task.occurrenceId) && !saved) continue;
|
|
1986
|
+
if (!leaves) {
|
|
1987
|
+
leaves = leavesIn(block.element, runtime);
|
|
1988
|
+
leavesCache.set(block.element, leaves);
|
|
1989
|
+
}
|
|
1990
|
+
let local = saved && sameRange(saved.source, task.range) ? saved.rects : void 0;
|
|
1991
|
+
if (!local && cached) {
|
|
1992
|
+
local = rectangles(leaves, task.range, { ...viewport, top: -Infinity, bottom: Infinity }, measure).map((rect) => ({ ...rect, left: rect.left - blockBox.left, top: rect.top - blockBox.top }));
|
|
1993
|
+
cached.tasks.set(task.id, { source: task.range, rects: local });
|
|
1994
|
+
}
|
|
1995
|
+
const rects = local ? local.map((rect) => ({ ...rect, left: rect.left + blockBox.left, top: rect.top + blockBox.top })) : rectangles(leaves, task.range, { ...viewport, top: viewport.top - 32, bottom: viewport.bottom + 32 }, measure);
|
|
1765
1996
|
for (const rect of rects) {
|
|
1766
1997
|
const clip = clipFor(rect.flow);
|
|
1767
1998
|
const left = Math.max(rect.left, clip.left), top = Math.max(rect.top, clip.top);
|
|
@@ -1771,13 +2002,14 @@ function SelectionPaint({ runtime, interactive = true }) {
|
|
|
1771
2002
|
}
|
|
1772
2003
|
}
|
|
1773
2004
|
}
|
|
1774
|
-
paint.style.top = `${viewport.top - origin.top + scrollTop}px`;
|
|
1775
|
-
paint.style.height = `${Math.max(0, viewport.bottom - viewport.top)}px`;
|
|
1776
2005
|
const hostGeometry = /* @__PURE__ */ new Map();
|
|
1777
2006
|
for (const { rect, task } of output) if (!task.selection && !hostGeometry.has(rect.flow)) {
|
|
1778
2007
|
const host = rect.flow, box = host.getBoundingClientRect();
|
|
1779
|
-
|
|
2008
|
+
const x = host.scrollLeft - host.clientLeft, y = host.scrollTop - host.clientTop;
|
|
2009
|
+
hostGeometry.set(host, { box, x, y, top: Math.max(viewport.top, box.top) - box.top + y, positioned: getComputedStyle(host).position !== "static" });
|
|
1780
2010
|
}
|
|
2011
|
+
paint.style.top = `${viewport.top - origin.top + scrollTop}px`;
|
|
2012
|
+
paint.style.height = `${Math.max(0, viewport.bottom - viewport.top)}px`;
|
|
1781
2013
|
const counts = /* @__PURE__ */ new Map();
|
|
1782
2014
|
const nextHits = [];
|
|
1783
2015
|
output.forEach(({ rect, task }) => {
|
|
@@ -1798,8 +2030,8 @@ function SelectionPaint({ runtime, interactive = true }) {
|
|
|
1798
2030
|
layer2.style.top = `${geometry.top}px`;
|
|
1799
2031
|
layer2.style.height = `${Math.max(0, Math.min(viewport.bottom, geometry.box.bottom) - Math.max(viewport.top, geometry.box.top))}px`;
|
|
1800
2032
|
target = layer2;
|
|
1801
|
-
left += origin.left - geometry.box.left
|
|
1802
|
-
top += viewport.top - geometry.box.top
|
|
2033
|
+
left += origin.left - geometry.box.left + geometry.x;
|
|
2034
|
+
top += viewport.top - geometry.box.top + geometry.y - geometry.top;
|
|
1803
2035
|
nextHits.push({ id: task.id, rect: { left: rect.left + origin.left - scrollLeft, top: rect.top + viewport.top, width: rect.width, height: rect.height } });
|
|
1804
2036
|
}
|
|
1805
2037
|
const index = counts.get(target) ?? 0;
|
|
@@ -1828,8 +2060,11 @@ function SelectionPaint({ runtime, interactive = true }) {
|
|
|
1828
2060
|
}
|
|
1829
2061
|
if (!item.parentNode) target.append(item);
|
|
1830
2062
|
});
|
|
1831
|
-
for (const layer2 of [paint, ...highlightLayers.values()]) while (layer2.children.length > (counts.get(layer2) ?? 0)) layer2.lastChild.remove();
|
|
1832
2063
|
for (const [host, layer2] of highlightLayers) if (!counts.has(layer2)) removeLayer(host, layer2);
|
|
2064
|
+
for (const layer2 of [paint, ...highlightLayers.values()]) {
|
|
2065
|
+
const count = counts.get(layer2) ?? 0;
|
|
2066
|
+
if (layer2.children.length > count) layer2.replaceChildren(...Array.from(layer2.children).slice(0, count));
|
|
2067
|
+
}
|
|
1833
2068
|
hits = nextHits;
|
|
1834
2069
|
const active = runtime.interaction.get().activeHighlight;
|
|
1835
2070
|
if (active && !hits.some((hit) => hit.id === active)) runtime.clearSelection();
|
|
@@ -1857,10 +2092,12 @@ function SelectionPaint({ runtime, interactive = true }) {
|
|
|
1857
2092
|
};
|
|
1858
2093
|
const fontsChanged = () => {
|
|
1859
2094
|
fontMetrics.clear();
|
|
2095
|
+
geometryCache = /* @__PURE__ */ new WeakMap();
|
|
1860
2096
|
invalidate();
|
|
1861
2097
|
};
|
|
1862
2098
|
const unsubscribers = [runtime.interaction.subscribe(() => {
|
|
1863
2099
|
const state = runtime.interaction.get(), selection = state.selection;
|
|
2100
|
+
const referenceChanged = state.active !== lastAnnotation || state.hovered !== lastHoveredAnnotation;
|
|
1864
2101
|
if (state.hoveredHighlight !== lastHovered || state.activeHighlight !== lastActive || state.active !== lastAnnotation || state.hovered !== lastHoveredAnnotation) {
|
|
1865
2102
|
lastHovered = state.hoveredHighlight;
|
|
1866
2103
|
lastActive = state.activeHighlight;
|
|
@@ -1868,6 +2105,7 @@ function SelectionPaint({ runtime, interactive = true }) {
|
|
|
1868
2105
|
lastHoveredAnnotation = state.hovered;
|
|
1869
2106
|
feedback();
|
|
1870
2107
|
}
|
|
2108
|
+
if (referenceChanged) schedule();
|
|
1871
2109
|
if (selection === lastSelection) return;
|
|
1872
2110
|
lastSelection = selection;
|
|
1873
2111
|
render();
|
|
@@ -1876,8 +2114,12 @@ function SelectionPaint({ runtime, interactive = true }) {
|
|
|
1876
2114
|
if (decorations === lastDecorations) return;
|
|
1877
2115
|
lastDecorations = decorations;
|
|
1878
2116
|
leavesCache = /* @__PURE__ */ new WeakMap();
|
|
2117
|
+
geometryCache = /* @__PURE__ */ new WeakMap();
|
|
1879
2118
|
schedule();
|
|
1880
|
-
}), runtime.layout.subscribe(invalidate), runtime.documentOffset.subscribe(schedule), runtime.configuration.subscribe(
|
|
2119
|
+
}), runtime.layout.subscribe(invalidate), runtime.documentOffset.subscribe(schedule), runtime.configuration.subscribe(() => {
|
|
2120
|
+
geometryCache = /* @__PURE__ */ new WeakMap();
|
|
2121
|
+
invalidate();
|
|
2122
|
+
})];
|
|
1881
2123
|
const observer = new MutationObserver((records) => {
|
|
1882
2124
|
let changed = false;
|
|
1883
2125
|
for (const record of records) {
|
|
@@ -1885,8 +2127,13 @@ function SelectionPaint({ runtime, interactive = true }) {
|
|
|
1885
2127
|
if (!target || target === paint || paint.contains(target) || target.closest(".limr-highlight-layer")) continue;
|
|
1886
2128
|
if (record.type === "childList" && [...record.addedNodes, ...record.removedNodes].every((node) => node instanceof Element && node.classList.contains("limr-highlight-layer"))) continue;
|
|
1887
2129
|
const block = target.closest("[data-limr-block]");
|
|
1888
|
-
if (block)
|
|
1889
|
-
|
|
2130
|
+
if (block) {
|
|
2131
|
+
leavesCache.delete(block);
|
|
2132
|
+
geometryCache.delete(block);
|
|
2133
|
+
} else {
|
|
2134
|
+
blocks = void 0;
|
|
2135
|
+
geometryCache = /* @__PURE__ */ new WeakMap();
|
|
2136
|
+
}
|
|
1890
2137
|
changed = true;
|
|
1891
2138
|
}
|
|
1892
2139
|
if (changed) {
|
|
@@ -1895,7 +2142,12 @@ function SelectionPaint({ runtime, interactive = true }) {
|
|
|
1895
2142
|
}
|
|
1896
2143
|
});
|
|
1897
2144
|
observer.observe(container, { subtree: true, childList: true, characterData: true, attributes: true, attributeFilter: ["class", "style", "inert", "open", "data-limr-theme", "data-limr-justify"] });
|
|
1898
|
-
const scroll = () => {
|
|
2145
|
+
const scroll = (event) => {
|
|
2146
|
+
const target = event.target;
|
|
2147
|
+
if (target instanceof Element) {
|
|
2148
|
+
const block = target.closest("[data-limr-block]");
|
|
2149
|
+
if (block) geometryCache.delete(block);
|
|
2150
|
+
}
|
|
1899
2151
|
runtime.hoverHighlight(null);
|
|
1900
2152
|
schedule();
|
|
1901
2153
|
};
|
|
@@ -1986,15 +2238,15 @@ function SelectionPaint({ runtime, interactive = true }) {
|
|
|
1986
2238
|
clear();
|
|
1987
2239
|
};
|
|
1988
2240
|
}, [runtime, interactive]);
|
|
1989
|
-
return /* @__PURE__ */
|
|
2241
|
+
return /* @__PURE__ */ jsx5("div", { ref: layer, className: "limr-paint-layer", "data-limr-ignore": "true", "aria-hidden": "true" });
|
|
1990
2242
|
}
|
|
1991
2243
|
|
|
1992
2244
|
// src/react/Markdown.tsx
|
|
1993
|
-
import { jsx as
|
|
2245
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1994
2246
|
function Markdown({ className, style, interactive = true, followOutput = false, justify, ...props }) {
|
|
1995
2247
|
const parent = useContext(RuntimeContext);
|
|
1996
|
-
if (props.source !== void 0 || !parent) return /* @__PURE__ */
|
|
1997
|
-
return /* @__PURE__ */
|
|
2248
|
+
if (props.source !== void 0 || !parent) return /* @__PURE__ */ jsx6(DocumentProvider, { ...props, justify, children: /* @__PURE__ */ jsx6(MarkdownBody, { className, style, interactive, followOutput }) });
|
|
2249
|
+
return /* @__PURE__ */ jsx6(MarkdownBody, { className, style, interactive, followOutput, justify });
|
|
1998
2250
|
}
|
|
1999
2251
|
function MarkdownBody({ className, style, interactive, followOutput, justify }) {
|
|
2000
2252
|
const runtime = useRuntime();
|
|
@@ -2002,17 +2254,20 @@ function MarkdownBody({ className, style, interactive, followOutput, justify })
|
|
|
2002
2254
|
const appearance = useAppearance();
|
|
2003
2255
|
const theme = useStoreSelector(runtime.configuration, (config) => config.theme ?? "light");
|
|
2004
2256
|
const configuredJustify = useStoreSelector(runtime.configuration, (config) => config.justify ?? false);
|
|
2257
|
+
const typography = useStoreSelector(runtime.configuration, (config) => config.typography ?? "standard");
|
|
2258
|
+
const justified = justify ?? (typography === "justify" || configuredJustify);
|
|
2005
2259
|
const scrollRoot = useStoreSelector(runtime.configuration, (config) => config.scrollRoot);
|
|
2006
2260
|
const offset = useStoreSelector(runtime.documentOffset, (value) => value);
|
|
2007
2261
|
const components = useStoreSelector(runtime.configuration, (config) => config.components);
|
|
2008
2262
|
const extensions = useStoreSelector(runtime.configuration, (config) => config.extensions);
|
|
2263
|
+
const rendererOverrides = useStoreSelector(runtime.configuration, (config) => config.rendererOverrides);
|
|
2009
2264
|
const decorations = useStoreSelector(runtime.decorations, (state) => state.byBlock);
|
|
2010
|
-
const ref =
|
|
2011
|
-
const pinned =
|
|
2265
|
+
const ref = useRef6(null);
|
|
2266
|
+
const pinned = useRef6(true);
|
|
2012
2267
|
useIsomorphicLayoutEffect(() => ref.current ? runtime.mountContent(ref.current) : void 0, [runtime, scrollRoot]);
|
|
2013
|
-
useIsomorphicLayoutEffect(() => runtime.requestLayout(), [runtime, justify, configuredJustify]);
|
|
2268
|
+
useIsomorphicLayoutEffect(() => runtime.requestLayout(), [runtime, justify, configuredJustify, typography]);
|
|
2014
2269
|
useSelectionTracking(runtime, interactive);
|
|
2015
|
-
|
|
2270
|
+
useEffect5(() => {
|
|
2016
2271
|
if (!followOutput) return;
|
|
2017
2272
|
const root = scrollRoot ?? window;
|
|
2018
2273
|
const onScroll = () => {
|
|
@@ -2028,23 +2283,23 @@ function MarkdownBody({ className, style, interactive, followOutput, justify })
|
|
|
2028
2283
|
const frame = requestAnimationFrame(() => runtime.scrollTo(scrollRoot?.scrollHeight ?? window.document.documentElement.scrollHeight, "instant"));
|
|
2029
2284
|
return () => cancelAnimationFrame(frame);
|
|
2030
2285
|
}, [document2, runtime, followOutput, scrollRoot]);
|
|
2031
|
-
return /* @__PURE__ */ jsxs3("article", { ref, className: `limr-prose ${className ?? ""}`, style: { ...style, translate: offset ? `0 ${offset}px` : style?.translate }, "data-limr-theme": theme, "data-limr-appearance": appearance, "data-limr-document": document2.id, "data-limr-justify":
|
|
2032
|
-
document2.blocks.map((block) => /* @__PURE__ */
|
|
2033
|
-
/* @__PURE__ */
|
|
2034
|
-
/* @__PURE__ */
|
|
2286
|
+
return /* @__PURE__ */ jsxs3("article", { ref, className: `limr-prose ${className ?? ""}`, style: { ...style, translate: offset ? `0 ${offset}px` : style?.translate }, "data-limr-theme": theme, "data-limr-appearance": appearance, "data-limr-document": document2.id, "data-limr-justify": justified, "data-limr-typography": typography, children: [
|
|
2287
|
+
document2.blocks.map((block) => /* @__PURE__ */ jsx6(BlockView, { block, runtime, components, extensions, rendererOverrides, decorations: decorations.get(block.id) ?? emptyDecorations }, block.id)),
|
|
2288
|
+
/* @__PURE__ */ jsx6(Footnotes, {}),
|
|
2289
|
+
/* @__PURE__ */ jsx6(SelectionPaint, { runtime, interactive })
|
|
2035
2290
|
] });
|
|
2036
2291
|
}
|
|
2037
2292
|
|
|
2038
2293
|
// src/components/OverlayScrollArea.tsx
|
|
2039
|
-
import { useRef as
|
|
2040
|
-
import { jsx as
|
|
2294
|
+
import { useRef as useRef7 } from "react";
|
|
2295
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2041
2296
|
function OverlayScrollArea({ children, active, resetKey, label }) {
|
|
2042
|
-
const area =
|
|
2043
|
-
const content =
|
|
2044
|
-
const thumb =
|
|
2045
|
-
const track =
|
|
2046
|
-
const drag =
|
|
2047
|
-
const show =
|
|
2297
|
+
const area = useRef7(null);
|
|
2298
|
+
const content = useRef7(null);
|
|
2299
|
+
const thumb = useRef7(null);
|
|
2300
|
+
const track = useRef7(null);
|
|
2301
|
+
const drag = useRef7(null);
|
|
2302
|
+
const show = useRef7(() => {
|
|
2048
2303
|
});
|
|
2049
2304
|
useIsomorphicLayoutEffect(() => {
|
|
2050
2305
|
const element = area.current, wrapper = element.parentElement;
|
|
@@ -2117,73 +2372,73 @@ function OverlayScrollArea({ children, active, resetKey, label }) {
|
|
|
2117
2372
|
show.current();
|
|
2118
2373
|
};
|
|
2119
2374
|
return /* @__PURE__ */ jsxs4("div", { className: "limr-overlay-scroll", children: [
|
|
2120
|
-
/* @__PURE__ */
|
|
2121
|
-
/* @__PURE__ */
|
|
2375
|
+
/* @__PURE__ */ jsx7("div", { ref: area, className: "limr-overlay-content", "data-limr-card-body": "", tabIndex: 0, role: "region", "aria-label": label, children: /* @__PURE__ */ jsx7("div", { ref: content, className: "limr-overlay-scroll-inner", children }) }),
|
|
2376
|
+
/* @__PURE__ */ jsx7("div", { ref: track, className: "limr-overlay-scrollbar", "aria-hidden": "true", onPointerDown: startDrag, onPointerMove: move, onPointerUp: end, onPointerCancel: end, onLostPointerCapture: end, children: /* @__PURE__ */ jsx7("div", { ref: thumb, className: "limr-overlay-scroll-thumb" }) })
|
|
2122
2377
|
] });
|
|
2123
2378
|
}
|
|
2124
2379
|
|
|
2125
2380
|
// src/components/AnnotationCard.tsx
|
|
2126
|
-
import { Fragment as Fragment3, jsx as
|
|
2381
|
+
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2127
2382
|
function AnnotationCard({ title, bodyLabel, occurrence, expanded, pinned, canExpand, expand, collapse, close, children }) {
|
|
2128
2383
|
const locale = useLocale();
|
|
2129
2384
|
return /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
2130
2385
|
/* @__PURE__ */ jsxs5("div", { className: "limr-overlay-header", children: [
|
|
2131
|
-
/* @__PURE__ */
|
|
2386
|
+
/* @__PURE__ */ jsx8("span", { children: title }),
|
|
2132
2387
|
/* @__PURE__ */ jsxs5("div", { className: "limr-overlay-controls", children: [
|
|
2133
|
-
expanded ? /* @__PURE__ */
|
|
2134
|
-
pinned && /* @__PURE__ */
|
|
2388
|
+
expanded ? /* @__PURE__ */ jsx8("button", { type: "button", onClick: collapse, children: /* @__PURE__ */ jsx8("span", { className: "limr-underline", children: locale.collapse }) }) : canExpand && /* @__PURE__ */ jsx8("button", { type: "button", onClick: expand, children: /* @__PURE__ */ jsx8("span", { className: "limr-underline", children: locale.expand }) }),
|
|
2389
|
+
pinned && /* @__PURE__ */ jsx8("button", { type: "button", className: "limr-overlay-close", onClick: close, "aria-label": locale.close, children: "\xD7" })
|
|
2135
2390
|
] })
|
|
2136
2391
|
] }),
|
|
2137
|
-
/* @__PURE__ */
|
|
2392
|
+
/* @__PURE__ */ jsx8(OverlayScrollArea, { active: true, resetKey: occurrence.id, label: bodyLabel ?? (typeof title === "string" ? title : locale.annotations), children })
|
|
2138
2393
|
] });
|
|
2139
2394
|
}
|
|
2140
2395
|
|
|
2141
2396
|
// src/extensions/annotations.tsx
|
|
2142
|
-
import { jsx as
|
|
2143
|
-
var CitationParagraph = ({ children }) => /* @__PURE__ */
|
|
2397
|
+
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2398
|
+
var CitationParagraph = ({ children }) => /* @__PURE__ */ jsx9("p", { children: /* @__PURE__ */ jsx9("span", { className: "limr-underline", children }) });
|
|
2144
2399
|
function CitationIcon() {
|
|
2145
|
-
return /* @__PURE__ */
|
|
2400
|
+
return /* @__PURE__ */ jsx9("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", fill: "currentColor", children: /* @__PURE__ */ jsx9("path", { d: "M2.5 4.2h4.3v4.3c0 2.1-1.2 3.3-3.5 3.8l-.5-1.4c1.4-.4 2-1 2-2H2.5V4.2Zm6.7 0h4.3v4.3c0 2.1-1.2 3.3-3.5 3.8l-.5-1.4c1.4-.4 2-1 2-2H9.2V4.2Z" }) });
|
|
2146
2401
|
}
|
|
2147
2402
|
function AnnotationMarkdown({ source, className, ...props }) {
|
|
2148
2403
|
const runtime = useRuntime();
|
|
2149
2404
|
const config = useStoreSelector(runtime.configuration, (config2) => config2);
|
|
2150
|
-
return /* @__PURE__ */
|
|
2405
|
+
return /* @__PURE__ */ jsx9(Markdown, { source, extensions: config.extensions, parameters: config.parameters, components: config.components, annotationTypes: config.annotationTypes, theme: config.theme, appearance: config.appearance, locale: config.locale, interactive: false, ...props, className: `limr-annotation-markdown ${className ?? ""}` });
|
|
2151
2406
|
}
|
|
2152
2407
|
function citation(options = {}) {
|
|
2153
|
-
function
|
|
2408
|
+
function Preview2({ annotations }) {
|
|
2154
2409
|
const summary = useMemo2(() => annotations.filter((annotation) => annotation.type === (options.type ?? "citation")).map((annotation) => {
|
|
2155
2410
|
const data = annotation.data;
|
|
2156
2411
|
const source = data?.summary?.trim() || data?.description?.trim();
|
|
2157
2412
|
if (source) return fromMarkdown(source).children?.map(textContent).join(" ").replace(/\s+/g, " ").trim();
|
|
2158
2413
|
return safeUrl(data?.url) || data?.title;
|
|
2159
2414
|
}).filter(Boolean).join(" \xB7 "), [annotations]);
|
|
2160
|
-
return summary ? /* @__PURE__ */
|
|
2415
|
+
return summary ? /* @__PURE__ */ jsx9("span", { title: summary, children: summary }) : null;
|
|
2161
2416
|
}
|
|
2162
|
-
function
|
|
2417
|
+
function Card2(props) {
|
|
2163
2418
|
const locale = useLocale();
|
|
2164
|
-
return /* @__PURE__ */
|
|
2419
|
+
return /* @__PURE__ */ jsx9(AnnotationCard, { ...props, title: locale.citation ?? locale.annotations });
|
|
2165
2420
|
}
|
|
2166
|
-
function
|
|
2421
|
+
function Content3({ data }) {
|
|
2167
2422
|
const runtime = useRuntime();
|
|
2168
2423
|
const configured = useStoreSelector(runtime.configuration, () => runtime.components);
|
|
2169
2424
|
const components = useMemo2(() => ({ ...configured, paragraph: configured.paragraph ?? CitationParagraph }), [configured]);
|
|
2170
|
-
const link =
|
|
2425
|
+
const link = useRef8(null);
|
|
2171
2426
|
const url = safeUrl(data?.url);
|
|
2172
2427
|
return /* @__PURE__ */ jsxs6("div", { className: "limr-citation-content", "data-linked": !!url || void 0, onClick: (event) => {
|
|
2173
2428
|
if (url && !event.defaultPrevented && !event.target.closest('a,button,input,textarea,select,summary,[role="button"],[contenteditable="true"],[data-limr-card-interactive]') && window.getSelection()?.isCollapsed !== false) link.current?.click();
|
|
2174
2429
|
}, children: [
|
|
2175
|
-
/* @__PURE__ */
|
|
2176
|
-
(data?.description || data?.summary) && /* @__PURE__ */
|
|
2430
|
+
/* @__PURE__ */ jsx9("a", { ref: link, className: "limr-citation-title", href: url, target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsx9("span", { className: "limr-underline", children: data?.title ?? data?.url ?? "Citation" }) }),
|
|
2431
|
+
(data?.description || data?.summary) && /* @__PURE__ */ jsx9(AnnotationMarkdown, { source: data.description || data.summary, components })
|
|
2177
2432
|
] });
|
|
2178
2433
|
}
|
|
2179
2434
|
return {
|
|
2180
2435
|
name: "citation",
|
|
2181
2436
|
tags: ["citation", "ref"],
|
|
2182
2437
|
scope: "local",
|
|
2183
|
-
annotationTypes: [{ type: "citation", label: (locale) => locale.citation ?? "Citation", icon: CitationIcon, color: "#6366f1", highlight: "hover", Content, ...options, sidebar: { Preview, collapseOnContentClick: false, ...options.sidebar }, overlay: { Card, expand: false, ...options.overlay } }],
|
|
2438
|
+
annotationTypes: [{ type: "citation", label: (locale) => locale.citation ?? "Citation", icon: CitationIcon, color: "#6366f1", highlight: "hover", Content: Content3, ...options, sidebar: { Preview: Preview2, collapseOnContentClick: false, ...options.sidebar }, overlay: { Card: Card2, expand: false, ...options.overlay } }],
|
|
2184
2439
|
transform(root) {
|
|
2185
2440
|
walk(root, (node) => {
|
|
2186
|
-
if (node.type !== "component") return;
|
|
2441
|
+
if (node.type !== "component" || node.incomplete) return;
|
|
2187
2442
|
if (node.name === "citation") {
|
|
2188
2443
|
const attributes = node.attributes ?? {};
|
|
2189
2444
|
const id = String(attributes["cite-id"] ?? attributes.id ?? "");
|
|
@@ -2207,13 +2462,13 @@ function citation(options = {}) {
|
|
|
2207
2462
|
}
|
|
2208
2463
|
|
|
2209
2464
|
// src/extensions/translations.tsx
|
|
2210
|
-
import { useRef as
|
|
2465
|
+
import { useRef as useRef10, useState as useState3 } from "react";
|
|
2211
2466
|
|
|
2212
2467
|
// src/components/InlineMarker.tsx
|
|
2213
2468
|
import { forwardRef } from "react";
|
|
2214
|
-
import { jsx as
|
|
2469
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
2215
2470
|
var InlineMarker = forwardRef(function InlineMarker2({ label, color, children, className = "", style, ...props }, ref) {
|
|
2216
|
-
return /* @__PURE__ */
|
|
2471
|
+
return /* @__PURE__ */ jsx10("span", { className: "limr-mark-wrap", "data-limr-ignore": "true", children: /* @__PURE__ */ jsx10(
|
|
2217
2472
|
"button",
|
|
2218
2473
|
{
|
|
2219
2474
|
...props,
|
|
@@ -2223,18 +2478,18 @@ var InlineMarker = forwardRef(function InlineMarker2({ label, color, children, c
|
|
|
2223
2478
|
title: props.title ?? label,
|
|
2224
2479
|
className: `limr-mark limr-action-mark ${className}`,
|
|
2225
2480
|
style: { "--limr-mark-color": color, ...style },
|
|
2226
|
-
children: /* @__PURE__ */
|
|
2481
|
+
children: /* @__PURE__ */ jsx10("span", { className: "limr-mark-icon", children })
|
|
2227
2482
|
}
|
|
2228
2483
|
) });
|
|
2229
2484
|
});
|
|
2230
2485
|
|
|
2231
2486
|
// src/components/Collapse.tsx
|
|
2232
|
-
import { useRef as
|
|
2233
|
-
import { jsx as
|
|
2487
|
+
import { useRef as useRef9, useState as useState2 } from "react";
|
|
2488
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
2234
2489
|
function Collapse({ open, children, className = "", keepMounted = false }) {
|
|
2235
2490
|
const [mounted, setMounted] = useState2(open);
|
|
2236
2491
|
const [visible, setVisible] = useState2(open);
|
|
2237
|
-
const panel =
|
|
2492
|
+
const panel = useRef9(null);
|
|
2238
2493
|
useIsomorphicLayoutEffect(() => {
|
|
2239
2494
|
if (keepMounted) return;
|
|
2240
2495
|
if (open) {
|
|
@@ -2250,24 +2505,24 @@ function Collapse({ open, children, className = "", keepMounted = false }) {
|
|
|
2250
2505
|
const timer = setTimeout(() => setMounted(false), 420);
|
|
2251
2506
|
return () => clearTimeout(timer);
|
|
2252
2507
|
}, [open, keepMounted, mounted]);
|
|
2253
|
-
return /* @__PURE__ */
|
|
2508
|
+
return /* @__PURE__ */ jsx11("div", { ref: (element) => {
|
|
2254
2509
|
panel.current = element;
|
|
2255
2510
|
element?.toggleAttribute("inert", !open);
|
|
2256
|
-
}, className: `limr-collapse ${className}`, "data-open": (keepMounted ? open : visible) || void 0, "aria-hidden": !open, children: /* @__PURE__ */
|
|
2511
|
+
}, className: `limr-collapse ${className}`, "data-open": (keepMounted ? open : visible) || void 0, "aria-hidden": !open, children: /* @__PURE__ */ jsx11("div", { className: "limr-collapse-inner", children: mounted || keepMounted ? children : null }) });
|
|
2257
2512
|
}
|
|
2258
2513
|
|
|
2259
2514
|
// src/extensions/translations.tsx
|
|
2260
|
-
import { Fragment as Fragment4, jsx as
|
|
2515
|
+
import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2261
2516
|
var modes = ["origin", "translation", "both"];
|
|
2262
2517
|
var names = { origin: "\u539F\u6587", translation: "\u8BD1\u6587", both: "\u5BF9\u7167" };
|
|
2263
2518
|
function TranslationIcon({ mode }) {
|
|
2264
|
-
return /* @__PURE__ */
|
|
2265
|
-
/* @__PURE__ */
|
|
2266
|
-
/* @__PURE__ */
|
|
2267
|
-
/* @__PURE__ */
|
|
2519
|
+
return /* @__PURE__ */ jsx12("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: mode === "both" ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
2520
|
+
/* @__PURE__ */ jsx12("rect", { x: "2.5", y: "4", width: "8", height: "16", rx: "2.5" }),
|
|
2521
|
+
/* @__PURE__ */ jsx12("rect", { x: "13.5", y: "4", width: "8", height: "16", rx: "2.5" }),
|
|
2522
|
+
/* @__PURE__ */ jsx12("path", { d: "M5 9h3M5 12h3M16 9h3M16 12h3" })
|
|
2268
2523
|
] }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
2269
|
-
/* @__PURE__ */
|
|
2270
|
-
mode === "origin" ? /* @__PURE__ */
|
|
2524
|
+
/* @__PURE__ */ jsx12("rect", { x: "4.5", y: "3", width: "15", height: "18", rx: "3" }),
|
|
2525
|
+
mode === "origin" ? /* @__PURE__ */ jsx12("path", { d: "M8.5 8h7M8.5 12h7M8.5 16h4" }) : /* @__PURE__ */ jsx12("path", { d: "M8 8.5h8M12 6.5v2M14.5 8.5c-.5 4-3 6.5-6.5 8M9.5 11c1.2 2.5 3.2 4.2 6.5 5.5" })
|
|
2271
2526
|
] }) });
|
|
2272
2527
|
}
|
|
2273
2528
|
function modeOf(value, fallback) {
|
|
@@ -2291,8 +2546,8 @@ function translations(options = {}) {
|
|
|
2291
2546
|
const requested = modeOf(globalMode ?? localMode ?? node.attributes?.default, options.defaultMode ?? "origin");
|
|
2292
2547
|
const mode = !origin ? "translation" : !translation ? "origin" : requested;
|
|
2293
2548
|
const next = modes[(modes.indexOf(mode) + 1) % modes.length];
|
|
2294
|
-
const marker =
|
|
2295
|
-
const restoreFocus =
|
|
2549
|
+
const marker = useRef10(null);
|
|
2550
|
+
const restoreFocus = useRef10(false);
|
|
2296
2551
|
const locked = globalMode !== void 0 && !onGlobalChange;
|
|
2297
2552
|
useIsomorphicLayoutEffect(() => {
|
|
2298
2553
|
if (restoreFocus.current) {
|
|
@@ -2300,8 +2555,8 @@ function translations(options = {}) {
|
|
|
2300
2555
|
restoreFocus.current = false;
|
|
2301
2556
|
}
|
|
2302
2557
|
}, [mode]);
|
|
2303
|
-
if (!origin && !translation) return /* @__PURE__ */
|
|
2304
|
-
const toggle = origin && translation ? /* @__PURE__ */
|
|
2558
|
+
if (!origin && !translation) return /* @__PURE__ */ jsx12(Fragment4, { children });
|
|
2559
|
+
const toggle = origin && translation ? /* @__PURE__ */ jsx12(
|
|
2305
2560
|
InlineMarker,
|
|
2306
2561
|
{
|
|
2307
2562
|
ref: marker,
|
|
@@ -2315,12 +2570,12 @@ function translations(options = {}) {
|
|
|
2315
2570
|
if (globalMode !== void 0) onGlobalChange?.(next);
|
|
2316
2571
|
else setLocalMode(next);
|
|
2317
2572
|
},
|
|
2318
|
-
children: /* @__PURE__ */
|
|
2573
|
+
children: /* @__PURE__ */ jsx12(TranslationIcon, { mode })
|
|
2319
2574
|
}
|
|
2320
2575
|
) : void 0;
|
|
2321
2576
|
return /* @__PURE__ */ jsxs7("div", { className: "limr-translations", "data-mode": mode, children: [
|
|
2322
|
-
translation && /* @__PURE__ */
|
|
2323
|
-
origin && /* @__PURE__ */
|
|
2577
|
+
translation && /* @__PURE__ */ jsx12(Collapse, { open: mode !== "origin", keepMounted: true, className: "limr-translation-panel", children: /* @__PURE__ */ jsx12("div", { className: "limr-translation-text", "data-language": "translation", children: renderChildren(translation.children ?? [], { trailing: mode === "translation" ? toggle : void 0 }) }) }),
|
|
2578
|
+
origin && /* @__PURE__ */ jsx12(Collapse, { open: mode !== "translation", keepMounted: true, className: "limr-translation-panel", children: /* @__PURE__ */ jsx12("div", { className: "limr-translation-text", "data-language": "origin", children: renderChildren(origin.children ?? [], { trailing: mode !== "translation" ? toggle : void 0 }) }) })
|
|
2324
2579
|
] });
|
|
2325
2580
|
}
|
|
2326
2581
|
return {
|
|
@@ -2330,16 +2585,338 @@ function translations(options = {}) {
|
|
|
2330
2585
|
display: "block",
|
|
2331
2586
|
scope: "local",
|
|
2332
2587
|
parameters: { translationMode: void 0, onTranslationModeChange: void 0 },
|
|
2333
|
-
components: { translations: Translations, origin: ({ children }) => /* @__PURE__ */
|
|
2588
|
+
components: { translations: Translations, origin: ({ children }) => /* @__PURE__ */ jsx12(Fragment4, { children }), translation: ({ children }) => /* @__PURE__ */ jsx12(Fragment4, { children }) }
|
|
2334
2589
|
};
|
|
2335
2590
|
}
|
|
2336
2591
|
|
|
2337
|
-
// src/extensions/
|
|
2338
|
-
import { useState as
|
|
2592
|
+
// src/extensions/mermaid.tsx
|
|
2593
|
+
import { useEffect as useEffect6, useRef as useRef11, useState as useState4 } from "react";
|
|
2594
|
+
|
|
2595
|
+
// src/components/LoadingRing.tsx
|
|
2596
|
+
import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2597
|
+
function LoadingRing() {
|
|
2598
|
+
const locale = useLocale();
|
|
2599
|
+
return /* @__PURE__ */ jsx13("span", { className: "limr-loading", role: "status", "aria-label": locale.loading, "data-limr-ignore": "true", children: /* @__PURE__ */ jsxs8("svg", { viewBox: "0 0 32 32", "aria-hidden": "true", children: [
|
|
2600
|
+
/* @__PURE__ */ jsx13("circle", { className: "limr-loading-track", cx: "16", cy: "16", r: "12" }),
|
|
2601
|
+
/* @__PURE__ */ jsx13("g", { className: "limr-loading-orbit", children: /* @__PURE__ */ jsx13("circle", { className: "limr-loading-arc", cx: "16", cy: "16", r: "12", pathLength: "100" }) })
|
|
2602
|
+
] }) });
|
|
2603
|
+
}
|
|
2604
|
+
function BlockLoading() {
|
|
2605
|
+
return /* @__PURE__ */ jsx13("div", { className: "limr-block-loading", children: /* @__PURE__ */ jsx13(LoadingRing, {}) });
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
// src/components/ToolIcon.tsx
|
|
2609
|
+
import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2610
|
+
function ToolIcon({ name, ...props }) {
|
|
2611
|
+
return /* @__PURE__ */ jsx14("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props, children: /* @__PURE__ */ jsxs9("g", { transform: name === "highlight" ? "translate(0 -1.25)" : name === "comment" ? "translate(0 -.5)" : void 0, children: [
|
|
2612
|
+
(name === "eye" || name === "eye-off") && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2613
|
+
/* @__PURE__ */ jsx14("path", { d: "M3 12s3.3-6 9-6 9 6 9 6-3.3 6-9 6-9-6-9-6Z" }),
|
|
2614
|
+
/* @__PURE__ */ jsx14("circle", { cx: "12", cy: "12", r: "2.7" }),
|
|
2615
|
+
name === "eye-off" && /* @__PURE__ */ jsx14("path", { d: "m4 4 16 16" })
|
|
2616
|
+
] }),
|
|
2617
|
+
name === "question" && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2618
|
+
/* @__PURE__ */ jsx14("circle", { cx: "12", cy: "12", r: "8.5" }),
|
|
2619
|
+
/* @__PURE__ */ jsx14("path", { d: "M9.4 9a2.7 2.7 0 0 1 5.2 1c0 1.8-2.6 2-2.6 3.7M12 17h.01" })
|
|
2620
|
+
] }),
|
|
2621
|
+
name === "highlight" && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2622
|
+
/* @__PURE__ */ jsx14("path", { d: "m8 15 7.6-9a2 2 0 0 1 2.8-.2l.8.7a2 2 0 0 1 .2 2.8L12 18l-4-3Z" }),
|
|
2623
|
+
/* @__PURE__ */ jsx14("path", { d: "m8 15-2 3 3 1 3-1M4 21h10M14 8l4 3.5" })
|
|
2624
|
+
] }),
|
|
2625
|
+
name === "edit" && /* @__PURE__ */ jsx14(Fragment5, { children: /* @__PURE__ */ jsx14("path", { d: "m14.5 5.5 4 4M4.5 19.5l4.5-1 11-11a2.1 2.1 0 0 0 0-3 2.1 2.1 0 0 0-3 0l-11 11-1.5 4Z" }) }),
|
|
2626
|
+
name === "close" && /* @__PURE__ */ jsx14("path", { d: "m6 6 12 12M18 6 6 18" }),
|
|
2627
|
+
name === "copy" && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2628
|
+
/* @__PURE__ */ jsx14("rect", { x: "8.5", y: "8", width: "10.5", height: "12", rx: "3" }),
|
|
2629
|
+
/* @__PURE__ */ jsx14("path", { d: "M15.5 8V6.8A2.8 2.8 0 0 0 12.7 4H7A3 3 0 0 0 4 7v6a3 3 0 0 0 3 3h1.5" })
|
|
2630
|
+
] }),
|
|
2631
|
+
(name === "zoom-in" || name === "zoom-out") && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2632
|
+
/* @__PURE__ */ jsx14("circle", { cx: "10.5", cy: "10.5", r: "6.5" }),
|
|
2633
|
+
/* @__PURE__ */ jsx14("path", { d: "m15.4 15.4 4.6 4.6M7.5 10.5h6" }),
|
|
2634
|
+
name === "zoom-in" && /* @__PURE__ */ jsx14("path", { d: "M10.5 7.5v6" })
|
|
2635
|
+
] }),
|
|
2636
|
+
name === "source" && /* @__PURE__ */ jsx14(Fragment5, { children: /* @__PURE__ */ jsx14("path", { d: "m7 7-4 5 4 5m10-10 4 5-4 5m-4-13-2 16" }) }),
|
|
2637
|
+
name === "image" && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2638
|
+
/* @__PURE__ */ jsx14("rect", { x: "3.5", y: "4.5", width: "17", height: "15", rx: "3.5" }),
|
|
2639
|
+
/* @__PURE__ */ jsx14("circle", { cx: "15.5", cy: "9", r: "1.5" }),
|
|
2640
|
+
/* @__PURE__ */ jsx14("path", { d: "m4 16 4.4-4.4a1.5 1.5 0 0 1 2.2 0L17 19m-3-3 1.4-1.4a1.5 1.5 0 0 1 2.2 0L20 17" })
|
|
2641
|
+
] }),
|
|
2642
|
+
["background", "underline", "dotted", "wavy"].includes(name) && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2643
|
+
name === "background" && /* @__PURE__ */ jsx14("rect", { x: "3", y: "3", width: "18", height: "18", rx: "5", fill: "currentColor", fillOpacity: ".13", stroke: "none" }),
|
|
2644
|
+
/* @__PURE__ */ jsx14("path", { d: "m8 15 3-8a1.05 1.05 0 0 1 2 0l3 8M9.2 12h5.6" }),
|
|
2645
|
+
name === "background" && /* @__PURE__ */ jsx14("path", { d: "M7 19h10", strokeWidth: "2.5" }),
|
|
2646
|
+
name === "underline" && /* @__PURE__ */ jsx14("path", { d: "M5 20h14" }),
|
|
2647
|
+
name === "dotted" && /* @__PURE__ */ jsx14("path", { d: "M5 20h14", strokeDasharray: ".1 3.4", strokeWidth: "2.4" }),
|
|
2648
|
+
name === "wavy" && /* @__PURE__ */ jsx14("path", { d: "M4 20c1.3-2 2.7-2 4 0s2.7 2 4 0 2.7-2 4 0 2.7 2 4 0" })
|
|
2649
|
+
] }),
|
|
2650
|
+
name === "chevron" && /* @__PURE__ */ jsx14("path", { d: "m8 10 4 4 4-4" }),
|
|
2651
|
+
name === "check" && /* @__PURE__ */ jsx14("path", { d: "m5.5 12 4.2 4.2 8.8-9" }),
|
|
2652
|
+
name === "trash" && /* @__PURE__ */ jsx14(Fragment5, { children: /* @__PURE__ */ jsx14("path", { d: "M4.5 7h15M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M7 7l.7 12a2 2 0 0 0 2 2h4.6a2 2 0 0 0 2-2L17 7M10 11v6M14 11v6" }) }),
|
|
2653
|
+
name === "note" && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2654
|
+
/* @__PURE__ */ jsx14("path", { d: "M14 3H7a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V9l-6-6Z" }),
|
|
2655
|
+
/* @__PURE__ */ jsx14("path", { d: "M14 3v4a2 2 0 0 0 2 2h4M8 13h8M8 17h5" })
|
|
2656
|
+
] }),
|
|
2657
|
+
name === "comment" && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2658
|
+
/* @__PURE__ */ jsx14("path", { d: "M8 19 4 21V7a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v9a3 3 0 0 1-3 3H8Z" }),
|
|
2659
|
+
/* @__PURE__ */ jsx14("path", { d: "M8 9h8M8 13h5" })
|
|
2660
|
+
] }),
|
|
2661
|
+
name === "footnote" && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2662
|
+
/* @__PURE__ */ jsx14("path", { d: "M5 7h9M5 11h12M5 15h8M5 20h14M18 4h2v5" }),
|
|
2663
|
+
/* @__PURE__ */ jsx14("path", { d: "M17.5 9h4" })
|
|
2664
|
+
] }),
|
|
2665
|
+
name === "sparkles" && /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2666
|
+
/* @__PURE__ */ jsx14("path", { d: "m10.5 4 1.8 4.8 4.7 1.7-4.7 1.8-1.8 4.7-1.7-4.7L4 10.5l4.8-1.7L10.5 4Z" }),
|
|
2667
|
+
/* @__PURE__ */ jsx14("path", { d: "m19 15 .8 2.2L22 18l-2.2.8L19 21l-.8-2.2L16 18l2.2-.8L19 15ZM19 3v4M17 5h4" })
|
|
2668
|
+
] })
|
|
2669
|
+
] }) });
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2672
|
+
// src/extensions/mermaid.tsx
|
|
2673
|
+
import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2674
|
+
var nextId = 0;
|
|
2675
|
+
var queue = Promise.resolve();
|
|
2676
|
+
var cache2 = new ResourceCache(32);
|
|
2677
|
+
async function diagram(id, code, dark, font, signal) {
|
|
2678
|
+
let result = "";
|
|
2679
|
+
const work = queue.then(async () => {
|
|
2680
|
+
if (signal.aborted) throw signal.reason;
|
|
2681
|
+
const { default: mermaid2 } = await import("mermaid");
|
|
2682
|
+
await document.fonts.ready;
|
|
2683
|
+
if (signal.aborted) throw signal.reason;
|
|
2684
|
+
mermaid2.initialize({
|
|
2685
|
+
startOnLoad: false,
|
|
2686
|
+
securityLevel: "strict",
|
|
2687
|
+
suppressErrorRendering: true,
|
|
2688
|
+
fontFamily: font,
|
|
2689
|
+
theme: "base",
|
|
2690
|
+
themeVariables: dark ? { background: "#242321", primaryColor: "#383531", primaryTextColor: "#e2ded7", primaryBorderColor: "#7b746a", lineColor: "#a29a8e", secondaryColor: "#302e2a", tertiaryColor: "#302e2a" } : { background: "#f9f8f6", primaryColor: "#eeebe6", primaryTextColor: "#49443e", primaryBorderColor: "#b5aca0", lineColor: "#91877a", secondaryColor: "#f5f3ef", tertiaryColor: "#f5f3ef" }
|
|
2691
|
+
});
|
|
2692
|
+
const host = document.createElement("div");
|
|
2693
|
+
host.style.cssText = "position:fixed;left:-100000px;top:0;visibility:hidden;pointer-events:none";
|
|
2694
|
+
host.style.fontFamily = font;
|
|
2695
|
+
document.body.append(host);
|
|
2696
|
+
try {
|
|
2697
|
+
result = (await mermaid2.render(id, code, host)).svg;
|
|
2698
|
+
} finally {
|
|
2699
|
+
host.remove();
|
|
2700
|
+
}
|
|
2701
|
+
});
|
|
2702
|
+
queue = work.catch(() => {
|
|
2703
|
+
});
|
|
2704
|
+
await work;
|
|
2705
|
+
return result;
|
|
2706
|
+
}
|
|
2707
|
+
function MermaidNode({ node, incomplete }) {
|
|
2708
|
+
const locale = useLocale(), theme = useTheme(), runtime = useRuntime();
|
|
2709
|
+
const zh = locale.language?.startsWith("zh");
|
|
2710
|
+
const [id] = useState4(() => `limr-mermaid-${++nextId}`);
|
|
2711
|
+
const [systemDark, setSystemDark] = useState4(false);
|
|
2712
|
+
const [result, setResult] = useState4();
|
|
2713
|
+
const [sourceView, setSourceView] = useState4(false), [scale, setScale] = useState4(1), [attempt, setAttempt] = useState4(0);
|
|
2714
|
+
const ref = useRef11(null), content = useRef11(null);
|
|
2715
|
+
const drag = useRef11(null);
|
|
2716
|
+
const suppressClick = useRef11(false);
|
|
2717
|
+
const code = node.value ?? "";
|
|
2718
|
+
const dark = theme === "dark" || theme === "auto" && systemDark;
|
|
2719
|
+
const key = JSON.stringify([id, code, dark, attempt]);
|
|
2720
|
+
const current = result?.key === key ? result : void 0;
|
|
2721
|
+
useEffect6(() => {
|
|
2722
|
+
if (theme !== "auto") return;
|
|
2723
|
+
const media = matchMedia("(prefers-color-scheme: dark)");
|
|
2724
|
+
const update = () => setSystemDark(media.matches);
|
|
2725
|
+
update();
|
|
2726
|
+
media.addEventListener("change", update);
|
|
2727
|
+
return () => media.removeEventListener("change", update);
|
|
2728
|
+
}, [theme]);
|
|
2729
|
+
useEffect6(() => {
|
|
2730
|
+
if (incomplete) return;
|
|
2731
|
+
let disposed = false;
|
|
2732
|
+
const font = ref.current ? getComputedStyle(ref.current).fontFamily : "sans-serif";
|
|
2733
|
+
const request = cache2.acquire(`${key}:${font}`, (signal) => diagram(id, code, dark, font, signal));
|
|
2734
|
+
request.promise.then((svg) => {
|
|
2735
|
+
if (!disposed) setResult({ key, svg });
|
|
2736
|
+
}, () => {
|
|
2737
|
+
if (!disposed) setResult({ key, error: true });
|
|
2738
|
+
});
|
|
2739
|
+
return () => {
|
|
2740
|
+
disposed = true;
|
|
2741
|
+
request.release();
|
|
2742
|
+
};
|
|
2743
|
+
}, [key, incomplete]);
|
|
2744
|
+
useStreamEntrance(content, !!current?.svg, current?.svg);
|
|
2745
|
+
const loading2 = incomplete || !current;
|
|
2746
|
+
const source = sourceView || current?.error;
|
|
2747
|
+
useEffect6(() => {
|
|
2748
|
+
const viewport = content.current;
|
|
2749
|
+
if (!viewport || source) return;
|
|
2750
|
+
const wheel = (event) => {
|
|
2751
|
+
if (!event.shiftKey || event.ctrlKey || event.metaKey || !event.deltaY || viewport.scrollWidth <= viewport.clientWidth) return;
|
|
2752
|
+
const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? viewport.clientWidth : 1;
|
|
2753
|
+
viewport.scrollLeft += (event.deltaX || event.deltaY) * unit;
|
|
2754
|
+
event.preventDefault();
|
|
2755
|
+
};
|
|
2756
|
+
viewport.addEventListener("wheel", wheel, { passive: false });
|
|
2757
|
+
return () => viewport.removeEventListener("wheel", wheel);
|
|
2758
|
+
}, [loading2, source]);
|
|
2759
|
+
const select = () => {
|
|
2760
|
+
const canvas = content.current?.firstElementChild;
|
|
2761
|
+
if (!canvas) return;
|
|
2762
|
+
const range = document.createRange();
|
|
2763
|
+
range.selectNodeContents(canvas);
|
|
2764
|
+
const selection = canvas.ownerDocument.getSelection();
|
|
2765
|
+
selection?.removeAllRanges();
|
|
2766
|
+
selection?.addRange(range);
|
|
2767
|
+
};
|
|
2768
|
+
const label = sourceView ? zh ? "\u663E\u793A\u56FE\u50CF" : "Show diagram" : zh ? "\u663E\u793A\u6E90\u4EE3\u7801" : "Show source";
|
|
2769
|
+
return /* @__PURE__ */ jsxs10("div", { className: "limr-math-block limr-mermaid-block", ref, "data-mermaid-state": loading2 ? "loading" : current?.error ? "error" : "ready", children: [
|
|
2770
|
+
/* @__PURE__ */ jsxs10("div", { className: "limr-math-display limr-mermaid-display", children: [
|
|
2771
|
+
loading2 && /* @__PURE__ */ jsx15("div", { className: "limr-mermaid-loading", children: /* @__PURE__ */ jsx15(LoadingRing, {}) }),
|
|
2772
|
+
!loading2 && /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
2773
|
+
current?.error && /* @__PURE__ */ jsxs10("div", { className: "limr-mermaid-error", "data-limr-ignore": "true", role: "status", children: [
|
|
2774
|
+
zh ? "\u56FE\u8868\u6682\u65F6\u65E0\u6CD5\u7ED8\u5236" : "Unable to render diagram",
|
|
2775
|
+
" ",
|
|
2776
|
+
/* @__PURE__ */ jsx15("button", { type: "button", onClick: () => setAttempt((value) => value + 1), children: locale.retry })
|
|
2777
|
+
] }),
|
|
2778
|
+
/* @__PURE__ */ jsx15("pre", { className: "limr-mermaid-source", hidden: !source, children: /* @__PURE__ */ jsx15("code", { children: code }) }),
|
|
2779
|
+
/* @__PURE__ */ jsx15(
|
|
2780
|
+
"div",
|
|
2781
|
+
{
|
|
2782
|
+
className: "limr-mermaid-viewport",
|
|
2783
|
+
hidden: !!source,
|
|
2784
|
+
ref: content,
|
|
2785
|
+
tabIndex: 0,
|
|
2786
|
+
role: "region",
|
|
2787
|
+
"aria-label": zh ? "\u56FE\u8868\u89C6\u53E3" : "Diagram viewport",
|
|
2788
|
+
"aria-description": zh ? "\u62D6\u52A8\u5E73\u79FB\uFF1B\u65B9\u5411\u952E\u6216\u6EDA\u8F6E\u79FB\u52A8\uFF0CShift \u52A0\u6EDA\u8F6E\u6A2A\u5411\u79FB\u52A8\uFF1B\u5355\u51FB\u6216\u6309 Enter \u6574\u5757\u9009\u62E9\u3002" : "Drag to pan; use arrow keys or the wheel to scroll, Shift+wheel to scroll horizontally; click or press Enter to select the block.",
|
|
2789
|
+
onDragStart: (event) => event.preventDefault(),
|
|
2790
|
+
onPointerDown: (event) => {
|
|
2791
|
+
suppressClick.current = false;
|
|
2792
|
+
if (event.button !== 0 || event.pointerType === "touch") return;
|
|
2793
|
+
const viewport = event.currentTarget;
|
|
2794
|
+
const bounds = viewport.getBoundingClientRect();
|
|
2795
|
+
if (event.clientX >= bounds.left + viewport.clientLeft + viewport.clientWidth || event.clientY >= bounds.top + viewport.clientTop + viewport.clientHeight) return;
|
|
2796
|
+
event.preventDefault();
|
|
2797
|
+
viewport.focus({ preventScroll: true });
|
|
2798
|
+
drag.current = { id: event.pointerId, x: event.clientX, y: event.clientY, left: viewport.scrollLeft, top: viewport.scrollTop, moved: false };
|
|
2799
|
+
viewport.setPointerCapture(event.pointerId);
|
|
2800
|
+
},
|
|
2801
|
+
onPointerMove: (event) => {
|
|
2802
|
+
const gesture = drag.current;
|
|
2803
|
+
if (!gesture || gesture.id !== event.pointerId) return;
|
|
2804
|
+
const x = event.clientX - gesture.x, y = event.clientY - gesture.y;
|
|
2805
|
+
if (!gesture.moved && Math.hypot(x, y) <= 4) return;
|
|
2806
|
+
if (!gesture.moved) {
|
|
2807
|
+
gesture.moved = true;
|
|
2808
|
+
runtime.clearSelection();
|
|
2809
|
+
event.currentTarget.dataset.dragging = "true";
|
|
2810
|
+
}
|
|
2811
|
+
event.currentTarget.scrollTo(gesture.left - x, gesture.top - y);
|
|
2812
|
+
},
|
|
2813
|
+
onPointerUp: (event) => {
|
|
2814
|
+
if (drag.current?.id !== event.pointerId) return;
|
|
2815
|
+
suppressClick.current = drag.current.moved;
|
|
2816
|
+
drag.current = null;
|
|
2817
|
+
delete event.currentTarget.dataset.dragging;
|
|
2818
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
2819
|
+
},
|
|
2820
|
+
onLostPointerCapture: (event) => {
|
|
2821
|
+
drag.current = null;
|
|
2822
|
+
delete event.currentTarget.dataset.dragging;
|
|
2823
|
+
},
|
|
2824
|
+
onClick: (event) => {
|
|
2825
|
+
if (!event.defaultPrevented && !suppressClick.current && !event.ctrlKey && !event.metaKey && !event.shiftKey && !event.altKey) select();
|
|
2826
|
+
},
|
|
2827
|
+
onKeyDown: (event) => {
|
|
2828
|
+
if (event.altKey || event.ctrlKey || event.metaKey) return;
|
|
2829
|
+
const viewport = event.currentTarget;
|
|
2830
|
+
const moves = { ArrowLeft: [-48, 0], ArrowRight: [48, 0], ArrowUp: [0, -48], ArrowDown: [0, 48], PageUp: [0, -viewport.clientHeight * 0.9], PageDown: [0, viewport.clientHeight * 0.9] };
|
|
2831
|
+
if (moves[event.key]) viewport.scrollBy(...moves[event.key]);
|
|
2832
|
+
else if (event.key === "Home") viewport.scrollTo(0, 0);
|
|
2833
|
+
else if (event.key === "End") viewport.scrollTo(viewport.scrollWidth, viewport.scrollHeight);
|
|
2834
|
+
else if (event.key === "Enter") select();
|
|
2835
|
+
else return;
|
|
2836
|
+
event.preventDefault();
|
|
2837
|
+
},
|
|
2838
|
+
children: /* @__PURE__ */ jsx15("div", { className: "limr-mermaid-canvas", style: { width: `${scale * 100}%` }, role: "img", "aria-label": zh ? "Mermaid \u56FE\u8868" : "Mermaid diagram", dangerouslySetInnerHTML: { __html: current?.svg ?? "" } })
|
|
2839
|
+
}
|
|
2840
|
+
)
|
|
2841
|
+
] })
|
|
2842
|
+
] }),
|
|
2843
|
+
/* @__PURE__ */ jsxs10("div", { className: "limr-block-tools", "data-limr-ignore": "true", role: "group", "aria-label": zh ? "\u56FE\u8868\u5DE5\u5177" : "Diagram tools", children: [
|
|
2844
|
+
/* @__PURE__ */ jsx15(CopyButton, { value: code, label: zh ? "\u590D\u5236 Mermaid \u6E90\u4EE3\u7801" : "Copy Mermaid source" }),
|
|
2845
|
+
/* @__PURE__ */ jsx15("button", { type: "button", disabled: loading2 || !!source || scale >= 3, title: zh ? "\u653E\u5927" : "Zoom in", "aria-label": zh ? "\u653E\u5927" : "Zoom in", onClick: () => setScale((value) => Math.min(3, +(value + 0.25).toFixed(2))), children: /* @__PURE__ */ jsx15(ToolIcon, { name: "zoom-in" }) }),
|
|
2846
|
+
/* @__PURE__ */ jsx15("button", { type: "button", disabled: loading2 || !!source || scale <= 0.5, title: zh ? "\u7F29\u5C0F" : "Zoom out", "aria-label": zh ? "\u7F29\u5C0F" : "Zoom out", onClick: () => setScale((value) => Math.max(0.5, +(value - 0.25).toFixed(2))), children: /* @__PURE__ */ jsx15(ToolIcon, { name: "zoom-out" }) }),
|
|
2847
|
+
/* @__PURE__ */ jsx15("button", { type: "button", disabled: loading2 || current?.error, title: label, "aria-label": label, "aria-pressed": sourceView, onClick: () => setSourceView((value) => !value), children: /* @__PURE__ */ jsx15(ToolIcon, { name: sourceView ? "image" : "source" }) })
|
|
2848
|
+
] })
|
|
2849
|
+
] });
|
|
2850
|
+
}
|
|
2851
|
+
function mermaid() {
|
|
2852
|
+
return {
|
|
2853
|
+
name: "mermaid",
|
|
2854
|
+
directives: ["mermaid"],
|
|
2855
|
+
literal: true,
|
|
2856
|
+
scope: "local",
|
|
2857
|
+
components: { mermaid: MermaidNode },
|
|
2858
|
+
transform(root, context) {
|
|
2859
|
+
literalDirective(root, context.source, "mermaid");
|
|
2860
|
+
walk(root, (node) => {
|
|
2861
|
+
if (node.type === "code" && String(node.lang).toLowerCase() === "mermaid") node.type = "mermaid";
|
|
2862
|
+
if (node.type === "mermaid") node.selection = "atomic";
|
|
2863
|
+
});
|
|
2864
|
+
}
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
// src/extensions/callout.tsx
|
|
2869
|
+
import { useState as useState5 } from "react";
|
|
2870
|
+
|
|
2871
|
+
// src/extensions/inline-source.ts
|
|
2872
|
+
function point(source, offset, base) {
|
|
2873
|
+
const between = source.slice(base.offset, offset), breaks = [...between.matchAll(/\r\n|\r|\n/g)], last = breaks.at(-1);
|
|
2874
|
+
return { offset, line: base.line + breaks.length, column: last ? between.length - last.index - last[0].length + 1 : base.column + between.length };
|
|
2875
|
+
}
|
|
2876
|
+
function sliceInline(node, from, until, source) {
|
|
2877
|
+
if (!node.position) return;
|
|
2878
|
+
const range = rangeOf(node);
|
|
2879
|
+
if (range.end <= from || range.start >= until) return;
|
|
2880
|
+
if (range.start >= from && range.end <= until) return node;
|
|
2881
|
+
let start = Math.max(range.start, from), end = Math.min(range.end, until);
|
|
2882
|
+
const result = { ...node };
|
|
2883
|
+
if (node.type === "text") {
|
|
2884
|
+
const value = (node.value ?? "").replace(/\r\n?/g, "\n"), mapped = mapText(source, value, range);
|
|
2885
|
+
const first = mapped.ends.findIndex((offset) => offset > start);
|
|
2886
|
+
let last = mapped.starts.findIndex((offset) => offset >= end);
|
|
2887
|
+
if (first < 0) return;
|
|
2888
|
+
if (last < 0) last = mapped.starts.length;
|
|
2889
|
+
if (last <= first) return;
|
|
2890
|
+
result.value = value.slice(first, last);
|
|
2891
|
+
start = mapped.starts[first];
|
|
2892
|
+
end = mapped.ends[last - 1];
|
|
2893
|
+
}
|
|
2894
|
+
if (node.children) result.children = sliceChildren(node.children, start, end, source);
|
|
2895
|
+
result.position = { start: point(source, start, node.position.start), end: point(source, end, node.position.start) };
|
|
2896
|
+
return result;
|
|
2897
|
+
}
|
|
2898
|
+
function sliceChildren(children, from, until, source) {
|
|
2899
|
+
return children.flatMap((child) => {
|
|
2900
|
+
const value = sliceInline(child, from, until, source);
|
|
2901
|
+
return value ? [value] : [];
|
|
2902
|
+
});
|
|
2903
|
+
}
|
|
2904
|
+
function textTokens(children, expression, source) {
|
|
2905
|
+
return children.flatMap((node) => {
|
|
2906
|
+
if (node.type !== "text" || !node.value || !node.position) return [];
|
|
2907
|
+
const matches = [...node.value.matchAll(expression)];
|
|
2908
|
+
if (!matches.length) return [];
|
|
2909
|
+
const map = mapText(source, node.value, rangeOf(node));
|
|
2910
|
+
return matches.flatMap((match) => {
|
|
2911
|
+
const start = map.starts[match.index], end = map.ends[match.index + match[0].length - 1];
|
|
2912
|
+
return source.slice(start, end) === match[0] ? [{ start, end }] : [];
|
|
2913
|
+
});
|
|
2914
|
+
});
|
|
2915
|
+
}
|
|
2339
2916
|
|
|
2340
2917
|
// src/extensions/define.ts
|
|
2341
|
-
function defineBlock({ name, component, tags = [name], directives = [name], selection = "content" }) {
|
|
2342
|
-
return { name, tags, directives, selection, display: "block", scope: "local", components: Object.fromEntries([.../* @__PURE__ */ new Set([...tags, ...directives])].map((tag) => [tag, component])) };
|
|
2918
|
+
function defineBlock({ name, component, tags = [name], directives = [name], selection = "content", streaming }) {
|
|
2919
|
+
return { name, tags, directives, selection, streaming, display: "block", scope: "local", components: Object.fromEntries([.../* @__PURE__ */ new Set([...tags, ...directives])].map((tag) => [tag, component])) };
|
|
2343
2920
|
}
|
|
2344
2921
|
function defineAnnotation(type) {
|
|
2345
2922
|
return { name: `annotation:${type.type}`, annotationTypes: [type], scope: "local" };
|
|
@@ -2348,43 +2925,293 @@ function defineExtension(extension) {
|
|
|
2348
2925
|
return extension;
|
|
2349
2926
|
}
|
|
2350
2927
|
|
|
2928
|
+
// src/extensions/callout.tsx
|
|
2929
|
+
import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2930
|
+
var types = {
|
|
2931
|
+
note: { color: "#6488b5", icon: "edit" },
|
|
2932
|
+
abstract: { color: "#4b9ba0", icon: "note" },
|
|
2933
|
+
info: { color: "#6488b5", icon: "note" },
|
|
2934
|
+
todo: { color: "#6488b5", icon: "check" },
|
|
2935
|
+
tip: { color: "#4b9b8d", icon: "sparkles" },
|
|
2936
|
+
success: { color: "#659664", icon: "check" },
|
|
2937
|
+
question: { color: "#b38b4e", icon: "question" },
|
|
2938
|
+
warning: { color: "#bc8850", icon: "question" },
|
|
2939
|
+
failure: { color: "#be6967", icon: "close" },
|
|
2940
|
+
danger: { color: "#be6967", icon: "close" },
|
|
2941
|
+
bug: { color: "#be6967", icon: "note" },
|
|
2942
|
+
example: { color: "#9580b4", icon: "note" },
|
|
2943
|
+
quote: { color: "#928b80", icon: "comment" }
|
|
2944
|
+
};
|
|
2945
|
+
var aliases2 = { summary: "abstract", tldr: "abstract", hint: "tip", important: "tip", check: "success", done: "success", help: "question", faq: "question", caution: "warning", attention: "warning", fail: "failure", missing: "failure", error: "danger", cite: "quote" };
|
|
2946
|
+
function calloutType(value) {
|
|
2947
|
+
const name = value.toLowerCase();
|
|
2948
|
+
return aliases2[name] ?? (Object.hasOwn(types, name) ? name : "note");
|
|
2949
|
+
}
|
|
2950
|
+
function Callout({ node, renderChildren, renderAttribute }) {
|
|
2951
|
+
const zh = useLocale().language?.startsWith("zh");
|
|
2952
|
+
const name = String(node.attributes?.type ?? "note").toLowerCase(), type = calloutType(name), style = types[type];
|
|
2953
|
+
const title = node.children?.find((child) => child.type === "calloutTitle");
|
|
2954
|
+
const body = node.children?.filter((child) => child.type !== "calloutTitle") ?? [];
|
|
2955
|
+
const fold = node.attributes?.fold;
|
|
2956
|
+
const [expanded, setExpanded] = useState5(fold !== "-" && fold !== "closed");
|
|
2957
|
+
const content = /* @__PURE__ */ jsx16("div", { className: "limr-block-content", children: renderChildren(body) });
|
|
2958
|
+
const label = /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
2959
|
+
/* @__PURE__ */ jsx16(ToolIcon, { name: style.icon, "data-limr-ignore": "true" }),
|
|
2960
|
+
/* @__PURE__ */ jsx16("span", { children: title ? renderChildren(title.children ?? []) : node.attributes?.title ? renderAttribute("title") : /* @__PURE__ */ jsx16("span", { "data-limr-ignore": "true", children: name.charAt(0).toUpperCase() + name.slice(1) }) })
|
|
2961
|
+
] });
|
|
2962
|
+
return /* @__PURE__ */ jsxs11("aside", { className: "limr-note limr-callout", "data-callout": name, "data-callout-type": type, style: { "--limr-callout-color": style.color }, children: [
|
|
2963
|
+
/* @__PURE__ */ jsxs11("div", { className: "limr-card-label limr-callout-title", children: [
|
|
2964
|
+
label,
|
|
2965
|
+
fold && /* @__PURE__ */ jsx16("button", { type: "button", className: "limr-callout-toggle", "aria-label": expanded ? zh ? "\u6536\u8D77\u63D0\u793A\u5757" : "Collapse callout" : zh ? "\u5C55\u5F00\u63D0\u793A\u5757" : "Expand callout", "aria-expanded": expanded, onClick: () => setExpanded((value) => !value), "data-limr-ignore": "true", children: /* @__PURE__ */ jsx16(ToolIcon, { name: "chevron" }) })
|
|
2966
|
+
] }),
|
|
2967
|
+
fold ? /* @__PURE__ */ jsx16(Collapse, { open: expanded, keepMounted: true, children: content }) : content
|
|
2968
|
+
] });
|
|
2969
|
+
}
|
|
2970
|
+
function callout(options = {}) {
|
|
2971
|
+
return {
|
|
2972
|
+
...defineBlock({ name: "callout", component: options.component ?? Callout, streaming: options.component ? void 0 : { Loading: BlockLoading } }),
|
|
2973
|
+
transform(root, context) {
|
|
2974
|
+
walk(root, (node) => {
|
|
2975
|
+
if (node.type !== "blockquote") return;
|
|
2976
|
+
const first = node.children?.[0];
|
|
2977
|
+
if (first?.type !== "paragraph" || !first.position) return;
|
|
2978
|
+
const from = first.position.start.offset, end = first.position.end.offset;
|
|
2979
|
+
const raw = context.source.slice(from, end);
|
|
2980
|
+
const header = /^\[!([\w-]+)\]([+-])?[ \t]*/.exec(raw);
|
|
2981
|
+
if (!header) {
|
|
2982
|
+
if (context.streaming && /^\[![\w-]*$/.test(raw)) {
|
|
2983
|
+
node.type = "callout";
|
|
2984
|
+
node.incomplete = true;
|
|
2985
|
+
node.children = [];
|
|
2986
|
+
}
|
|
2987
|
+
return;
|
|
2988
|
+
}
|
|
2989
|
+
node.type = "callout";
|
|
2990
|
+
node.attributes = { type: header[1].toLowerCase(), ...header[2] ? { fold: header[2] } : {} };
|
|
2991
|
+
const newline = /\r\n|\r|\n/.exec(raw), titleEnd = newline ? from + newline.index : end;
|
|
2992
|
+
const bodyStart = newline ? titleEnd + newline[0].length : end;
|
|
2993
|
+
const title = sliceInline(first, from + header[0].length, titleEnd, context.source);
|
|
2994
|
+
const body = sliceInline(first, bodyStart, end, context.source);
|
|
2995
|
+
node.children = [...title?.children?.length ? [{ ...title, type: "calloutTitle" }] : [], ...body?.children?.length ? [body] : [], ...node.children.slice(1)];
|
|
2996
|
+
});
|
|
2997
|
+
}
|
|
2998
|
+
};
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
// src/extensions/inline-highlights.tsx
|
|
3002
|
+
import { Fragment as Fragment8, jsx as jsx17 } from "react/jsx-runtime";
|
|
3003
|
+
var Content = ({ children }) => /* @__PURE__ */ jsx17(Fragment8, { children });
|
|
3004
|
+
function inlineHighlights(options = {}) {
|
|
3005
|
+
const decorate = (node, range) => {
|
|
3006
|
+
node.type = "embeddedHighlight";
|
|
3007
|
+
node.highlightRange = range;
|
|
3008
|
+
node.annotation = {
|
|
3009
|
+
id: `inline-highlight:${rangeOf(node).start}`,
|
|
3010
|
+
type: "highlight",
|
|
3011
|
+
range,
|
|
3012
|
+
data: { color: options.color ?? "var(--limr-inline-highlight, #6B9BD2)", style: "background", readOnly: true }
|
|
3013
|
+
};
|
|
3014
|
+
};
|
|
3015
|
+
return {
|
|
3016
|
+
name: "inline-highlights",
|
|
3017
|
+
tags: ["highlight"],
|
|
3018
|
+
scope: "local",
|
|
3019
|
+
components: { embeddedHighlight: options.component ?? Content },
|
|
3020
|
+
transform(root, { source, streaming }) {
|
|
3021
|
+
const visit = (node) => {
|
|
3022
|
+
if (!node.children || ["code", "inlineCode", "math", "inlineMath", "html", "footnoteDefinition", "annotationDefinition"].includes(node.type)) return;
|
|
3023
|
+
node.children.forEach(visit);
|
|
3024
|
+
if (node.type === "component" && node.name === "highlight") {
|
|
3025
|
+
const first = node.children[0], last = node.children.at(-1);
|
|
3026
|
+
if (first && last) decorate(node, { start: rangeOf(first).start, end: rangeOf(last).end });
|
|
3027
|
+
return;
|
|
3028
|
+
}
|
|
3029
|
+
const tokens = textTokens(node.children, /(?<!=)==(?!=)/g, source);
|
|
3030
|
+
if (!node.position) return;
|
|
3031
|
+
if (!tokens.length) {
|
|
3032
|
+
const last = node.children.at(-1), end = rangeOf(node).end;
|
|
3033
|
+
if (streaming && end === source.length && last?.type === "text" && source.endsWith("=") && source[end - 2] !== "\\") node.children = sliceChildren(node.children, rangeOf(node).start, end - 1, source);
|
|
3034
|
+
return;
|
|
3035
|
+
}
|
|
3036
|
+
const children = [];
|
|
3037
|
+
let from = rangeOf(node).start;
|
|
3038
|
+
for (let index = 0; index < tokens.length; index += 2) {
|
|
3039
|
+
const open = tokens[index], close = tokens[index + 1];
|
|
3040
|
+
if (!close && (!streaming || rangeOf(node).end < source.trimEnd().length)) break;
|
|
3041
|
+
let end = close?.start ?? rangeOf(node).end;
|
|
3042
|
+
if (!close && source[end - 1] === "=" && source[end - 2] !== "=" && source[end - 2] !== "\\") end--;
|
|
3043
|
+
const body = sliceChildren(node.children, open.end, end, source);
|
|
3044
|
+
if (!body.length && close) continue;
|
|
3045
|
+
children.push(...sliceChildren(node.children, from, open.start, source));
|
|
3046
|
+
const highlight = {
|
|
3047
|
+
type: "embeddedHighlight",
|
|
3048
|
+
inline: true,
|
|
3049
|
+
children: body,
|
|
3050
|
+
incomplete: close ? void 0 : true,
|
|
3051
|
+
position: { start: point(source, open.start, node.position.start), end: point(source, close?.end ?? rangeOf(node).end, node.position.start) }
|
|
3052
|
+
};
|
|
3053
|
+
if (body.length) decorate(highlight, { start: open.end, end });
|
|
3054
|
+
children.push(highlight);
|
|
3055
|
+
from = close?.end ?? rangeOf(node).end;
|
|
3056
|
+
}
|
|
3057
|
+
children.push(...sliceChildren(node.children, from, rangeOf(node).end, source));
|
|
3058
|
+
node.children = children;
|
|
3059
|
+
};
|
|
3060
|
+
visit(root);
|
|
3061
|
+
}
|
|
3062
|
+
};
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
// src/extensions/footnotes.tsx
|
|
3066
|
+
import { useMemo as useMemo3 } from "react";
|
|
3067
|
+
import { fromMarkdown as fromMarkdown2 } from "mdast-util-from-markdown";
|
|
3068
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
3069
|
+
var idFor = (identifier2) => `footnote:${String(identifier2).trim().replace(/\s+/g, " ").toLowerCase()}`;
|
|
3070
|
+
function Icon() {
|
|
3071
|
+
return /* @__PURE__ */ jsx18(ToolIcon, { name: "comment" });
|
|
3072
|
+
}
|
|
3073
|
+
function Content2({ data }) {
|
|
3074
|
+
return /* @__PURE__ */ jsx18(AnnotationMarkdown, { source: data?.body ?? "" });
|
|
3075
|
+
}
|
|
3076
|
+
function Card(props) {
|
|
3077
|
+
return /* @__PURE__ */ jsx18(AnnotationCard, { ...props, title: useLocale().footnotes });
|
|
3078
|
+
}
|
|
3079
|
+
function Preview({ data }) {
|
|
3080
|
+
const summary = useMemo3(() => textContent(fromMarkdown2(data?.body ?? "")).replace(/\s+/g, " ").trim(), [data?.body]);
|
|
3081
|
+
return summary ? /* @__PURE__ */ jsx18("span", { title: summary, children: summary }) : null;
|
|
3082
|
+
}
|
|
3083
|
+
function footnotes(options = {}) {
|
|
3084
|
+
const type = options.type ?? "footnote";
|
|
3085
|
+
const definition2 = (id, body) => ({ id, type, data: { body } });
|
|
3086
|
+
return {
|
|
3087
|
+
name: "footnotes",
|
|
3088
|
+
tags: ["footnote", "footnote-ref"],
|
|
3089
|
+
scope: "local",
|
|
3090
|
+
annotationTypes: [{
|
|
3091
|
+
type,
|
|
3092
|
+
label: (locale) => locale.footnotes,
|
|
3093
|
+
icon: Icon,
|
|
3094
|
+
color: "#6B9BD2",
|
|
3095
|
+
highlight: "hover",
|
|
3096
|
+
Content: Content2,
|
|
3097
|
+
...options,
|
|
3098
|
+
sidebar: { Preview, collapseOnContentClick: false, ...options.sidebar },
|
|
3099
|
+
overlay: { Card, expand: false, ...options.overlay }
|
|
3100
|
+
}],
|
|
3101
|
+
transform(root, { source, streaming }) {
|
|
3102
|
+
const visit = (node) => {
|
|
3103
|
+
if (node.type === "footnoteDefinition") {
|
|
3104
|
+
const range = rangeOf(node), raw = source.slice(range.start, range.end);
|
|
3105
|
+
const body = raw.replace(/^\[\^[^\]]+\]:[ \t]*/, "").replace(/(\r\n|\r|\n)(?: {4}|\t)/g, "$1");
|
|
3106
|
+
node.annotation = definition2(idFor(node.identifier), body);
|
|
3107
|
+
return;
|
|
3108
|
+
}
|
|
3109
|
+
if (node.type === "footnoteReference") {
|
|
3110
|
+
node.type = "annotationReference";
|
|
3111
|
+
node.inline = true;
|
|
3112
|
+
node.annotationIds = [idFor(node.identifier)];
|
|
3113
|
+
return;
|
|
3114
|
+
}
|
|
3115
|
+
if (node.type === "component" && ["footnote", "footnote-ref"].includes(node.name ?? "")) {
|
|
3116
|
+
if (node.incomplete) {
|
|
3117
|
+
node.children = [];
|
|
3118
|
+
return;
|
|
3119
|
+
}
|
|
3120
|
+
const id = idFor(node.attributes?.id ?? "");
|
|
3121
|
+
if (node.name === "footnote") {
|
|
3122
|
+
const first = node.children?.[0], last = node.children?.at(-1);
|
|
3123
|
+
node.type = "annotationDefinition";
|
|
3124
|
+
node.annotation = definition2(id, first && last ? source.slice(rangeOf(first).start, rangeOf(last).end) : String(node.attributes?.body ?? ""));
|
|
3125
|
+
return;
|
|
3126
|
+
}
|
|
3127
|
+
node.type = "annotationReference";
|
|
3128
|
+
node.annotationIds = [id];
|
|
3129
|
+
return;
|
|
3130
|
+
}
|
|
3131
|
+
if (!node.children || ["code", "inlineCode", "math", "inlineMath", "html", "annotationDefinition"].includes(node.type)) return;
|
|
3132
|
+
node.children.forEach(visit);
|
|
3133
|
+
const opens = textTokens(node.children, /\^\[/g, source);
|
|
3134
|
+
if (opens.length && node.position) {
|
|
3135
|
+
const children = [], range = rangeOf(node);
|
|
3136
|
+
let from = range.start;
|
|
3137
|
+
for (const open of opens) {
|
|
3138
|
+
if (open.start < from) continue;
|
|
3139
|
+
let depth = 1, at = open.end;
|
|
3140
|
+
const protectedNodes = node.children.filter((child) => child.type !== "text").map(rangeOf);
|
|
3141
|
+
for (; at < range.end && depth; at++) {
|
|
3142
|
+
const protectedNode = protectedNodes.find((child) => child.start <= at && child.end > at);
|
|
3143
|
+
if (protectedNode) {
|
|
3144
|
+
at = protectedNode.end - 1;
|
|
3145
|
+
continue;
|
|
3146
|
+
}
|
|
3147
|
+
if (source[at] === "\\") {
|
|
3148
|
+
at++;
|
|
3149
|
+
continue;
|
|
3150
|
+
}
|
|
3151
|
+
if (source[at] === "[") depth++;
|
|
3152
|
+
else if (source[at] === "]") depth--;
|
|
3153
|
+
}
|
|
3154
|
+
if (depth) {
|
|
3155
|
+
if (streaming && range.end >= source.trimEnd().length) {
|
|
3156
|
+
children.push(...sliceChildren(node.children, from, open.start, source));
|
|
3157
|
+
from = range.end;
|
|
3158
|
+
break;
|
|
3159
|
+
}
|
|
3160
|
+
continue;
|
|
3161
|
+
}
|
|
3162
|
+
const id = `inline-footnote:${open.start}`;
|
|
3163
|
+
children.push(...sliceChildren(node.children, from, open.start, source), {
|
|
3164
|
+
type: "annotationReference",
|
|
3165
|
+
inline: true,
|
|
3166
|
+
annotationIds: [id],
|
|
3167
|
+
annotation: definition2(id, source.slice(open.end, at - 1)),
|
|
3168
|
+
position: { start: point(source, open.start, node.position.start), end: point(source, at, node.position.start) }
|
|
3169
|
+
});
|
|
3170
|
+
from = at;
|
|
3171
|
+
}
|
|
3172
|
+
children.push(...sliceChildren(node.children, from, range.end, source));
|
|
3173
|
+
node.children = children;
|
|
3174
|
+
}
|
|
3175
|
+
node.children.forEach((child, index) => {
|
|
3176
|
+
const previous = node.children[index - 1];
|
|
3177
|
+
if (child.type === "annotationReference" && previous?.type === "embeddedHighlight" && rangeOf(previous).end === rangeOf(child).start) child.referenceRange = previous.highlightRange;
|
|
3178
|
+
});
|
|
3179
|
+
};
|
|
3180
|
+
visit(root);
|
|
3181
|
+
}
|
|
3182
|
+
};
|
|
3183
|
+
}
|
|
3184
|
+
|
|
3185
|
+
// src/extensions/blocks.tsx
|
|
3186
|
+
import { useState as useState8 } from "react";
|
|
3187
|
+
|
|
2351
3188
|
// src/components/Disclosure.tsx
|
|
2352
|
-
import {
|
|
2353
|
-
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3189
|
+
import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2354
3190
|
function Disclosure({ title, open, onChange, children }) {
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
if (open) {
|
|
2358
|
-
setPresent(true);
|
|
2359
|
-
return;
|
|
2360
|
-
}
|
|
2361
|
-
const timer = setTimeout(() => setPresent(false), 420);
|
|
2362
|
-
return () => clearTimeout(timer);
|
|
2363
|
-
}, [open]);
|
|
2364
|
-
return /* @__PURE__ */ jsxs8("details", { className: "limr-disclosure", open: present || open, "data-expanded": open || void 0, children: [
|
|
2365
|
-
/* @__PURE__ */ jsxs8("summary", { "aria-expanded": open, onClick: (event) => {
|
|
3191
|
+
return /* @__PURE__ */ jsxs12("details", { className: "limr-disclosure", open: true, "data-expanded": open || void 0, children: [
|
|
3192
|
+
/* @__PURE__ */ jsxs12("summary", { "aria-expanded": open, onClick: (event) => {
|
|
2366
3193
|
event.preventDefault();
|
|
2367
3194
|
onChange(!open);
|
|
2368
3195
|
}, "data-limr-ignore": "true", children: [
|
|
2369
|
-
/* @__PURE__ */
|
|
2370
|
-
/* @__PURE__ */
|
|
3196
|
+
/* @__PURE__ */ jsx19("span", { className: "limr-underline", children: title }),
|
|
3197
|
+
/* @__PURE__ */ jsx19("svg", { viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx19("path", { d: "m6 8 4 4 4-4" }) })
|
|
2371
3198
|
] }),
|
|
2372
|
-
/* @__PURE__ */
|
|
3199
|
+
/* @__PURE__ */ jsx19(Collapse, { open, keepMounted: true, children: /* @__PURE__ */ jsx19("div", { className: "limr-question-detail", children }) })
|
|
2373
3200
|
] });
|
|
2374
3201
|
}
|
|
2375
3202
|
|
|
2376
3203
|
// src/components/DiamondCheck.tsx
|
|
2377
|
-
import { jsx as
|
|
3204
|
+
import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2378
3205
|
function DiamondCheck({ checked }) {
|
|
2379
|
-
return /* @__PURE__ */
|
|
2380
|
-
/* @__PURE__ */
|
|
2381
|
-
/* @__PURE__ */
|
|
3206
|
+
return /* @__PURE__ */ jsxs13("svg", { className: "limr-choice-diamond", width: "14", height: "14", viewBox: "0 0 18 18", fill: "none", "aria-hidden": "true", "data-limr-ignore": "true", "data-checked": checked || void 0, children: [
|
|
3207
|
+
/* @__PURE__ */ jsx20("path", { className: "limr-diamond-outline", d: "M9 1.5L16.5 9L9 16.5L1.5 9Z", fill: "none" }),
|
|
3208
|
+
/* @__PURE__ */ jsx20("path", { className: "limr-diamond-fill", d: "M9 5L13 9L9 13L5 9Z", fill: "currentColor" })
|
|
2382
3209
|
] });
|
|
2383
3210
|
}
|
|
2384
3211
|
|
|
2385
3212
|
// src/extensions/video.tsx
|
|
2386
|
-
import { useEffect as
|
|
2387
|
-
import { jsx as
|
|
3213
|
+
import { useEffect as useEffect7, useRef as useRef12, useState as useState6 } from "react";
|
|
3214
|
+
import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2388
3215
|
function resolveVideo(source, provider = "auto") {
|
|
2389
3216
|
const safe = safeUrl(source);
|
|
2390
3217
|
if (!safe) return;
|
|
@@ -2432,21 +3259,21 @@ function video(options = {}) {
|
|
|
2432
3259
|
function Video({ node, source: markdown, renderAttribute }) {
|
|
2433
3260
|
const runtime = useRuntime();
|
|
2434
3261
|
const scrollRoot = useStoreSelector(runtime.configuration, (config) => config.scrollRoot);
|
|
2435
|
-
const element =
|
|
2436
|
-
const [visible, setVisible] =
|
|
2437
|
-
const [playing, setPlaying] =
|
|
2438
|
-
const [failed, setFailed] =
|
|
3262
|
+
const element = useRef12(null);
|
|
3263
|
+
const [visible, setVisible] = useState6(false);
|
|
3264
|
+
const [playing, setPlaying] = useState6(false);
|
|
3265
|
+
const [failed, setFailed] = useState6(false);
|
|
2439
3266
|
const provider = String(node.attributes?.provider ?? "auto");
|
|
2440
3267
|
const source = String(node.attributes?.url ?? node.attributes?.src ?? "");
|
|
2441
3268
|
const requested = node.attributes?.loading ?? options.loading ?? "visible";
|
|
2442
3269
|
const loading2 = requested === "click" || requested === "eager" ? requested : "visible";
|
|
2443
3270
|
const resolved = options.resolveUrl?.(provider, source);
|
|
2444
3271
|
const media = resolved && safeUrl(resolved) ? { url: safeUrl(resolved), native: provider === "native" } : resolveVideo(source, provider);
|
|
2445
|
-
|
|
3272
|
+
useEffect7(() => {
|
|
2446
3273
|
setFailed(false);
|
|
2447
3274
|
setPlaying(false);
|
|
2448
3275
|
}, [source, provider]);
|
|
2449
|
-
|
|
3276
|
+
useEffect7(() => {
|
|
2450
3277
|
if (visible || loading2 !== "visible" || !element.current) return;
|
|
2451
3278
|
if (typeof IntersectionObserver === "undefined") {
|
|
2452
3279
|
setVisible(true);
|
|
@@ -2464,20 +3291,20 @@ function video(options = {}) {
|
|
|
2464
3291
|
const enabled = loading2 === "eager" || loading2 === "visible" && visible || playing;
|
|
2465
3292
|
const title = String(node.attributes?.title ?? `${provider === "auto" ? "Video" : provider} video`);
|
|
2466
3293
|
const original = safeUrl(source);
|
|
2467
|
-
return /* @__PURE__ */
|
|
2468
|
-
/* @__PURE__ */
|
|
2469
|
-
/* @__PURE__ */
|
|
2470
|
-
original && /* @__PURE__ */
|
|
2471
|
-
] }) : enabled ? media.native ? /* @__PURE__ */
|
|
2472
|
-
node.attributes?.title && /* @__PURE__ */
|
|
2473
|
-
/* @__PURE__ */
|
|
3294
|
+
return /* @__PURE__ */ jsxs14("div", { ref: element, className: "limr-video", "data-limr-selection-surface": "", "data-loading": loading2, children: [
|
|
3295
|
+
/* @__PURE__ */ jsx21("div", { className: "limr-video-frame", children: !media || failed ? /* @__PURE__ */ jsxs14("div", { className: "limr-video-error", children: [
|
|
3296
|
+
/* @__PURE__ */ jsx21("span", { children: runtime.locale.unavailable }),
|
|
3297
|
+
original && /* @__PURE__ */ jsx21("a", { href: original, target: "_blank", rel: "noopener noreferrer", children: source })
|
|
3298
|
+
] }) : enabled ? media.native ? /* @__PURE__ */ jsx21("video", { controls: true, playsInline: true, preload: "metadata", src: media.url, "aria-label": title, onError: () => setFailed(true) }) : /* @__PURE__ */ jsx21("iframe", { src: media.url, title, allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share", allowFullScreen: true, referrerPolicy: "strict-origin-when-cross-origin", onError: () => setFailed(true) }) : /* @__PURE__ */ jsx21("button", { type: "button", className: "limr-video-play", onClick: () => setPlaying(true), "aria-label": runtime.locale.play, children: /* @__PURE__ */ jsx21("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("path", { d: "m8 5 11 7-11 7Z", fill: "currentColor" }) }) }) }),
|
|
3299
|
+
node.attributes?.title && /* @__PURE__ */ jsx21("div", { className: "limr-video-title", children: renderAttribute("title") }),
|
|
3300
|
+
/* @__PURE__ */ jsx21(CopyButton, { className: "limr-video-copy", variant: "glass", value: markdown })
|
|
2474
3301
|
] });
|
|
2475
3302
|
}
|
|
2476
|
-
return defineBlock({ name: "video", tags: ["video", "md-video"], component: options.component ?? Video, selection: "atomic" });
|
|
3303
|
+
return defineBlock({ name: "video", streaming: options.component ? void 0 : { Loading: BlockLoading }, tags: ["video", "md-video"], component: options.component ?? Video, selection: "atomic" });
|
|
2477
3304
|
}
|
|
2478
3305
|
|
|
2479
3306
|
// src/extensions/figures.tsx
|
|
2480
|
-
import { createContext, useContext as useContext2, useEffect as
|
|
3307
|
+
import { createContext, useContext as useContext2, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef13, useState as useState7 } from "react";
|
|
2481
3308
|
|
|
2482
3309
|
// src/extensions/figure-layout.ts
|
|
2483
3310
|
var defaultFigureLimits = { minWidth: 220, maxWidth: 560, minHeight: 120, maxHeight: 480 };
|
|
@@ -2519,7 +3346,7 @@ function figureLimits(attributes = {}, defaults2 = defaultFigureLimits) {
|
|
|
2519
3346
|
}
|
|
2520
3347
|
|
|
2521
3348
|
// src/extensions/figures.tsx
|
|
2522
|
-
import { jsx as
|
|
3349
|
+
import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2523
3350
|
var FigureContext = createContext(defaultFigureLimits);
|
|
2524
3351
|
var captionNode = (node) => node.name === "figcaption" || node.name === "caption";
|
|
2525
3352
|
var flatten = (nodes) => nodes.flatMap((node) => node.type === "paragraph" && node.children?.some((child) => child.name === "figure" || captionNode(child)) ? node.children : [node]);
|
|
@@ -2536,14 +3363,14 @@ function figures(options = {}) {
|
|
|
2536
3363
|
const panels = nodes.filter((child) => child.name === "figure");
|
|
2537
3364
|
const captions = nodes.filter(captionNode);
|
|
2538
3365
|
const body = nodes.filter((child) => !captionNode(child));
|
|
2539
|
-
const limits =
|
|
2540
|
-
const grid =
|
|
2541
|
-
const [columns, setColumns] =
|
|
3366
|
+
const limits = useMemo4(() => figureLimits(node.attributes, defaults2), [node.attributes]);
|
|
3367
|
+
const grid = useRef13(null);
|
|
3368
|
+
const [columns, setColumns] = useState7(1);
|
|
2542
3369
|
const gap = Math.min(100, dimension(node.attributes?.gap, options.gap ?? 16));
|
|
2543
3370
|
const rows = dimension(node.attributes?.rows, options.rows ?? 0);
|
|
2544
3371
|
const requested = dimension(node.attributes?.columns ?? node.attributes?.cols, options.columns ?? 0) || (rows > 0 ? Math.ceil(panels.length / rows) : void 0);
|
|
2545
3372
|
const responsive = String(node.attributes?.responsive ?? options.responsive ?? true) !== "false";
|
|
2546
|
-
|
|
3373
|
+
useEffect8(() => {
|
|
2547
3374
|
const element = grid.current;
|
|
2548
3375
|
if (!element) return;
|
|
2549
3376
|
const measure = () => {
|
|
@@ -2566,22 +3393,22 @@ function figures(options = {}) {
|
|
|
2566
3393
|
element.removeEventListener("error", measure, true);
|
|
2567
3394
|
};
|
|
2568
3395
|
}, [node, limits, gap, requested, responsive]);
|
|
2569
|
-
return /* @__PURE__ */
|
|
2570
|
-
/* @__PURE__ */
|
|
2571
|
-
/* @__PURE__ */
|
|
2572
|
-
captions.length ? renderChildren(captions) : node.attributes?.caption ? /* @__PURE__ */
|
|
3396
|
+
return /* @__PURE__ */ jsxs15("figure", { id: identifier(node), className: "limr-figures", "data-limr-selection-order": "visual", "data-columns": columns, "data-responsive": responsive, children: [
|
|
3397
|
+
/* @__PURE__ */ jsx22(CopyButton, { value: source, label: locale.copyFigures, variant: "glass", className: "limr-figures-copy" }),
|
|
3398
|
+
/* @__PURE__ */ jsx22(FigureContext.Provider, { value: limits, children: /* @__PURE__ */ jsx22("div", { ref: grid, className: "limr-figures-grid", style: { gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`, gridTemplateRows: rows ? `repeat(${Math.max(1, Math.min(24, Math.floor(rows)))}, auto auto)` : void 0, gap }, children: renderChildren(body) }) }),
|
|
3399
|
+
captions.length ? renderChildren(captions) : node.attributes?.caption ? /* @__PURE__ */ jsx22("figcaption", { children: renderAttribute("caption") }) : null
|
|
2573
3400
|
] });
|
|
2574
3401
|
}
|
|
2575
3402
|
function Figure({ node, renderChildren, renderAttribute }) {
|
|
2576
3403
|
const locale = useLocale();
|
|
2577
3404
|
const inherited = useContext2(FigureContext);
|
|
2578
3405
|
const limits = figureLimits(node.attributes, inherited === defaultFigureLimits ? defaults2 : inherited);
|
|
2579
|
-
const media =
|
|
2580
|
-
const [ratio, setRatio] =
|
|
3406
|
+
const media = useRef13(null);
|
|
3407
|
+
const [ratio, setRatio] = useState7(ratioOf(node.attributes?.width, node.attributes?.height));
|
|
2581
3408
|
const nodes = flatten(node.children ?? []);
|
|
2582
3409
|
const captions = nodes.filter(captionNode);
|
|
2583
3410
|
const body = nodes.filter((child) => !captionNode(child));
|
|
2584
|
-
|
|
3411
|
+
useEffect8(() => {
|
|
2585
3412
|
const element = media.current;
|
|
2586
3413
|
if (!element) return;
|
|
2587
3414
|
const measure = () => {
|
|
@@ -2593,23 +3420,24 @@ function figures(options = {}) {
|
|
|
2593
3420
|
return () => element.removeEventListener("load", measure, true);
|
|
2594
3421
|
}, [node]);
|
|
2595
3422
|
const maximum = figureWidths({ ratio, limits }).maximum;
|
|
2596
|
-
return /* @__PURE__ */
|
|
3423
|
+
return /* @__PURE__ */ jsxs15("figure", { id: identifier(node), className: "limr-figure", "data-limr-selection-order": "visual", style: {
|
|
2597
3424
|
"--limr-figure-width": Number.isFinite(maximum) ? `${maximum}px` : "100%",
|
|
2598
3425
|
"--limr-figure-min-height": `${Math.min(limits.minHeight, limits.maxHeight)}px`,
|
|
2599
3426
|
"--limr-figure-max-height": Number.isFinite(limits.maxHeight) ? `${limits.maxHeight}px` : "none"
|
|
2600
3427
|
}, children: [
|
|
2601
|
-
/* @__PURE__ */
|
|
2602
|
-
/* @__PURE__ */
|
|
3428
|
+
/* @__PURE__ */ jsx22("div", { ref: media, className: "limr-figure-media", children: renderChildren(body) }),
|
|
3429
|
+
/* @__PURE__ */ jsx22(CopyButton, { onCopy: async () => {
|
|
2603
3430
|
const url = media.current?.querySelector("img")?.getAttribute("src");
|
|
2604
3431
|
if (!url) throw new Error("Image URL unavailable");
|
|
2605
3432
|
await navigator.clipboard.writeText(url);
|
|
2606
3433
|
}, label: locale.copyImage, variant: "glass", className: "limr-figure-copy" }),
|
|
2607
|
-
captions.length ? renderChildren(captions) : node.attributes?.caption ? /* @__PURE__ */
|
|
3434
|
+
captions.length ? renderChildren(captions) : node.attributes?.caption ? /* @__PURE__ */ jsx22("figcaption", { children: renderAttribute("caption") }) : null
|
|
2608
3435
|
] });
|
|
2609
3436
|
}
|
|
2610
|
-
const Caption = ({ children }) => /* @__PURE__ */
|
|
3437
|
+
const Caption = ({ children }) => /* @__PURE__ */ jsx22("figcaption", { children });
|
|
2611
3438
|
return {
|
|
2612
3439
|
name: "figures",
|
|
3440
|
+
streaming: { Loading: BlockLoading },
|
|
2613
3441
|
tags: ["figures", "figure", "figcaption", "caption", "img"],
|
|
2614
3442
|
directives: ["figures", "figure", "figcaption"],
|
|
2615
3443
|
scope: "local",
|
|
@@ -2619,7 +3447,7 @@ function figures(options = {}) {
|
|
|
2619
3447
|
figure: Figure,
|
|
2620
3448
|
figcaption: Caption,
|
|
2621
3449
|
caption: Caption,
|
|
2622
|
-
img: ({ node }) => /* @__PURE__ */
|
|
3450
|
+
img: ({ node }) => /* @__PURE__ */ jsx22("img", { src: safeUrl(node.attributes?.src, true), alt: String(node.attributes?.alt ?? ""), loading: "lazy", decoding: "async" })
|
|
2623
3451
|
},
|
|
2624
3452
|
transform(root) {
|
|
2625
3453
|
const visit = (node) => {
|
|
@@ -2639,7 +3467,7 @@ function figures(options = {}) {
|
|
|
2639
3467
|
}
|
|
2640
3468
|
|
|
2641
3469
|
// src/extensions/blocks.tsx
|
|
2642
|
-
import { Fragment as
|
|
3470
|
+
import { Fragment as Fragment9, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2643
3471
|
function parts(node, name) {
|
|
2644
3472
|
const result = [];
|
|
2645
3473
|
walk(node, (child) => {
|
|
@@ -2647,25 +3475,25 @@ function parts(node, name) {
|
|
|
2647
3475
|
});
|
|
2648
3476
|
return result;
|
|
2649
3477
|
}
|
|
2650
|
-
var PassThrough = ({ children }) => /* @__PURE__ */
|
|
3478
|
+
var PassThrough = ({ children }) => /* @__PURE__ */ jsx23(Fragment9, { children });
|
|
2651
3479
|
function definition(options = {}) {
|
|
2652
3480
|
function Definition({ node, children, renderChildren, renderAttribute }) {
|
|
2653
3481
|
const runtime = useRuntime();
|
|
2654
3482
|
const title = parts(node, "title")[0];
|
|
2655
3483
|
const content = parts(node, "content")[0];
|
|
2656
|
-
return /* @__PURE__ */
|
|
2657
|
-
/* @__PURE__ */
|
|
2658
|
-
(title || node.attributes?.title) && /* @__PURE__ */
|
|
2659
|
-
/* @__PURE__ */
|
|
3484
|
+
return /* @__PURE__ */ jsxs16("aside", { className: "limr-definition", children: [
|
|
3485
|
+
/* @__PURE__ */ jsx23("div", { className: "limr-card-label", "data-limr-ignore": "true", children: runtime.locale.definition }),
|
|
3486
|
+
(title || node.attributes?.title) && /* @__PURE__ */ jsx23("div", { className: "limr-definition-title", children: title ? renderChildren(title.children ?? []) : renderAttribute("title") }),
|
|
3487
|
+
/* @__PURE__ */ jsx23("div", { className: "limr-block-content", children: content ? renderChildren(content.children ?? []) : children })
|
|
2660
3488
|
] });
|
|
2661
3489
|
}
|
|
2662
|
-
return { ...defineBlock({ name: "definition", component: options.component ?? Definition }), tags: ["definition", "title", "content"], components: { definition: options.component ?? Definition, title: PassThrough, content: PassThrough } };
|
|
3490
|
+
return { ...defineBlock({ name: "definition", streaming: options.component ? void 0 : { Loading: BlockLoading }, component: options.component ?? Definition }), tags: ["definition", "title", "content"], components: { definition: options.component ?? Definition, title: PassThrough, content: PassThrough } };
|
|
2663
3491
|
}
|
|
2664
3492
|
function question(options = {}) {
|
|
2665
3493
|
function Question({ node, children, renderChildren, renderAttribute }) {
|
|
2666
3494
|
const runtime = useRuntime();
|
|
2667
|
-
const [showHint, setHint] =
|
|
2668
|
-
const [selected, setSelected] =
|
|
3495
|
+
const [showHint, setHint] = useState8(false), [showAnswer, setAnswer] = useState8(false);
|
|
3496
|
+
const [selected, setSelected] = useState8([]), [checked, setChecked] = useState8(false);
|
|
2669
3497
|
const content = parts(node, "question-content")[0];
|
|
2670
3498
|
const hint = parts(node, "question-hint")[0];
|
|
2671
3499
|
const answer = parts(node, "question-answer")[0];
|
|
@@ -2679,22 +3507,22 @@ function question(options = {}) {
|
|
|
2679
3507
|
} catch {
|
|
2680
3508
|
}
|
|
2681
3509
|
const success = correct.length === selected.length && correct.every((index) => selected.includes(index));
|
|
2682
|
-
return /* @__PURE__ */
|
|
2683
|
-
/* @__PURE__ */
|
|
2684
|
-
node.attributes?.title && /* @__PURE__ */
|
|
2685
|
-
/* @__PURE__ */
|
|
2686
|
-
selections.length > 0 && /* @__PURE__ */
|
|
2687
|
-
/* @__PURE__ */
|
|
2688
|
-
selections.map((selection, index) => /* @__PURE__ */
|
|
2689
|
-
/* @__PURE__ */
|
|
3510
|
+
return /* @__PURE__ */ jsxs16("section", { className: "limr-question", children: [
|
|
3511
|
+
/* @__PURE__ */ jsx23("div", { className: "limr-card-label", "data-limr-ignore": "true", children: runtime.locale.question }),
|
|
3512
|
+
node.attributes?.title && /* @__PURE__ */ jsx23("div", { className: "limr-question-title", children: renderAttribute("title") }),
|
|
3513
|
+
/* @__PURE__ */ jsx23("div", { className: "limr-block-content", children: content ? renderChildren(content.children ?? []) : !selections.length && !hint && !answer ? children : null }),
|
|
3514
|
+
selections.length > 0 && /* @__PURE__ */ jsxs16("fieldset", { className: "limr-question-options", children: [
|
|
3515
|
+
/* @__PURE__ */ jsx23("legend", { className: "limr-sr-only", children: String(node.attributes?.title ?? runtime.locale.question) }),
|
|
3516
|
+
selections.map((selection, index) => /* @__PURE__ */ jsxs16("label", { "data-selected": selected.includes(index) || void 0, "data-result": checked ? correct.includes(index) ? "correct" : selected.includes(index) ? "incorrect" : void 0 : void 0, children: [
|
|
3517
|
+
/* @__PURE__ */ jsx23("input", { type: multi ? "checkbox" : "radio", name: `${runtime.document.id}-question-${rangeOf(node).start}`, checked: selected.includes(index), disabled: checked, onChange: () => {
|
|
2690
3518
|
setSelected(multi ? selected.includes(index) ? selected.filter((item) => item !== index) : [...selected, index] : [index]);
|
|
2691
3519
|
} }),
|
|
2692
|
-
/* @__PURE__ */
|
|
2693
|
-
/* @__PURE__ */
|
|
3520
|
+
/* @__PURE__ */ jsx23(DiamondCheck, { checked: selected.includes(index) || checked && correct.includes(index) }),
|
|
3521
|
+
/* @__PURE__ */ jsx23("span", { className: "limr-choice-text", children: renderChildren(selection.children ?? []) })
|
|
2694
3522
|
] }, index))
|
|
2695
3523
|
] }),
|
|
2696
|
-
selections.length > 0 && correct.length > 0 && /* @__PURE__ */
|
|
2697
|
-
/* @__PURE__ */
|
|
3524
|
+
selections.length > 0 && correct.length > 0 && /* @__PURE__ */ jsxs16("div", { className: "limr-question-actions", "data-limr-ignore": "true", children: [
|
|
3525
|
+
/* @__PURE__ */ jsx23("button", { type: "button", "data-checked": checked || void 0, disabled: !checked && !selected.length, onClick: () => {
|
|
2698
3526
|
if (checked) {
|
|
2699
3527
|
setChecked(false);
|
|
2700
3528
|
setSelected([]);
|
|
@@ -2703,53 +3531,53 @@ function question(options = {}) {
|
|
|
2703
3531
|
setChecked(true);
|
|
2704
3532
|
setAnswer(true);
|
|
2705
3533
|
}
|
|
2706
|
-
}, children: /* @__PURE__ */
|
|
2707
|
-
/* @__PURE__ */
|
|
3534
|
+
}, children: /* @__PURE__ */ jsx23("span", { className: "limr-button-label", children: checked ? runtime.locale.retry : runtime.locale.submit }, checked ? "retry" : "submit") }),
|
|
3535
|
+
/* @__PURE__ */ jsx23(Collapse, { open: checked, children: /* @__PURE__ */ jsx23("span", { role: "status", className: `limr-question-result ${success ? "limr-success" : "limr-error"}`, children: success ? runtime.locale.correct : runtime.locale.incorrect }) })
|
|
2708
3536
|
] }),
|
|
2709
|
-
hint && /* @__PURE__ */
|
|
2710
|
-
answer && /* @__PURE__ */
|
|
3537
|
+
hint && /* @__PURE__ */ jsx23(Disclosure, { title: runtime.locale.hint, open: showHint, onChange: setHint, children: renderChildren(hint.children ?? []) }),
|
|
3538
|
+
answer && /* @__PURE__ */ jsx23(Disclosure, { title: runtime.locale.answer, open: showAnswer, onChange: setAnswer, children: renderChildren(answer.children ?? []) })
|
|
2711
3539
|
] });
|
|
2712
3540
|
}
|
|
2713
3541
|
const names2 = ["question-content", "question-hint", "question-answer", "question-sel-grp", "question-sel"];
|
|
2714
|
-
return { ...defineBlock({ name: "question", component: options.component ?? Question }), tags: ["question", ...names2], components: { question: options.component ?? Question, ...Object.fromEntries(names2.map((name) => [name, PassThrough])) } };
|
|
3542
|
+
return { ...defineBlock({ name: "question", streaming: options.component ? void 0 : { Loading: BlockLoading }, component: options.component ?? Question }), tags: ["question", ...names2], components: { question: options.component ?? Question, ...Object.fromEntries(names2.map((name) => [name, PassThrough])) } };
|
|
2715
3543
|
}
|
|
2716
3544
|
function extras(options = {}) {
|
|
2717
|
-
const Extra = ({ node, children, renderAttribute }) => /* @__PURE__ */
|
|
2718
|
-
/* @__PURE__ */
|
|
2719
|
-
/* @__PURE__ */
|
|
2720
|
-
node.attributes?.desc && /* @__PURE__ */
|
|
3545
|
+
const Extra = ({ node, children, renderAttribute }) => /* @__PURE__ */ jsxs16("div", { className: "limr-extra", children: [
|
|
3546
|
+
/* @__PURE__ */ jsxs16("a", { className: "limr-extra-link", href: safeUrl(node.attributes?.url), target: "_blank", rel: "noreferrer", children: [
|
|
3547
|
+
/* @__PURE__ */ jsx23("span", { className: "limr-underline", children: renderAttribute(node.attributes?.title ? "title" : "url") }),
|
|
3548
|
+
node.attributes?.desc && /* @__PURE__ */ jsx23("p", { children: /* @__PURE__ */ jsx23("span", { className: "limr-underline", children: renderAttribute("desc") }) })
|
|
2721
3549
|
] }),
|
|
2722
3550
|
children
|
|
2723
3551
|
] });
|
|
2724
3552
|
const Extras = ({ children }) => {
|
|
2725
3553
|
const runtime = useRuntime();
|
|
2726
|
-
return /* @__PURE__ */
|
|
2727
|
-
/* @__PURE__ */
|
|
3554
|
+
return /* @__PURE__ */ jsxs16("aside", { className: "limr-extras", children: [
|
|
3555
|
+
/* @__PURE__ */ jsx23("div", { className: "limr-card-label", "data-limr-ignore": "true", children: runtime.locale.extra }),
|
|
2728
3556
|
children
|
|
2729
3557
|
] });
|
|
2730
3558
|
};
|
|
2731
|
-
return { ...defineBlock({ name: "extras", component: options.component ?? Extras }), tags: ["extras", "extra"], components: { extras: options.component ?? Extras, extra: Extra } };
|
|
3559
|
+
return { ...defineBlock({ name: "extras", streaming: options.component ? void 0 : { Loading: BlockLoading }, component: options.component ?? Extras }), tags: ["extras", "extra"], components: { extras: options.component ?? Extras, extra: Extra } };
|
|
2732
3560
|
}
|
|
2733
3561
|
|
|
2734
3562
|
// src/extensions/standard.ts
|
|
2735
3563
|
function standard() {
|
|
2736
|
-
return [gfm(), math(), codeHighlight(), definition(), question(), extras(), video(), figures(), citation(), translations()];
|
|
3564
|
+
return [gfm(), math(), codeHighlight(), mermaid(), callout(), definition(), question(), extras(), video(), figures(), citation(), translations(), inlineHighlights(), footnotes()];
|
|
2737
3565
|
}
|
|
2738
3566
|
|
|
2739
3567
|
// src/react/context.tsx
|
|
2740
|
-
import { jsx as
|
|
3568
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
2741
3569
|
var defaults;
|
|
2742
3570
|
var RuntimeContext = createContext2(null);
|
|
2743
|
-
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect :
|
|
3571
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect9;
|
|
2744
3572
|
function DocumentProvider({ children, source = "", streaming = false, documentId, ...options }) {
|
|
2745
3573
|
const generatedId = useId();
|
|
2746
|
-
const extensions =
|
|
3574
|
+
const extensions = useMemo5(() => {
|
|
2747
3575
|
const base = options.extensions ?? (defaults ??= standard());
|
|
2748
3576
|
return options.plugins?.length ? [...base, ...options.plugins] : base;
|
|
2749
3577
|
}, [options.extensions, options.plugins]);
|
|
2750
3578
|
const config = { ...options, extensions };
|
|
2751
|
-
const [runtime] =
|
|
2752
|
-
const previous =
|
|
3579
|
+
const [runtime] = useState9(() => new ReaderRuntime(documentId ?? `limr-${generatedId.replace(/[^a-z\d_-]/gi, "")}`, source, streaming, config));
|
|
3580
|
+
const previous = useRef14({ source, streaming, config });
|
|
2753
3581
|
useIsomorphicLayoutEffect(() => {
|
|
2754
3582
|
const old = previous.current;
|
|
2755
3583
|
const changed = Object.keys({ ...old.config, ...config }).some((key) => old.config[key] !== config[key]);
|
|
@@ -2757,11 +3585,11 @@ function DocumentProvider({ children, source = "", streaming = false, documentId
|
|
|
2757
3585
|
if (old.source !== source || old.streaming !== streaming) runtime.document.update(source, { streaming });
|
|
2758
3586
|
previous.current = { source, streaming, config };
|
|
2759
3587
|
});
|
|
2760
|
-
|
|
3588
|
+
useEffect9(() => {
|
|
2761
3589
|
runtime.start();
|
|
2762
3590
|
return () => runtime.dispose();
|
|
2763
3591
|
}, [runtime]);
|
|
2764
|
-
return /* @__PURE__ */
|
|
3592
|
+
return /* @__PURE__ */ jsx24(RuntimeContext.Provider, { value: runtime, children });
|
|
2765
3593
|
}
|
|
2766
3594
|
function useRuntime() {
|
|
2767
3595
|
const runtime = useContext3(RuntimeContext);
|
|
@@ -2780,14 +3608,14 @@ function useRendererParameter(name) {
|
|
|
2780
3608
|
});
|
|
2781
3609
|
}
|
|
2782
3610
|
function useStoreSelector(store, select) {
|
|
2783
|
-
const selectRef =
|
|
3611
|
+
const selectRef = useRef14(select);
|
|
2784
3612
|
selectRef.current = select;
|
|
2785
|
-
const
|
|
2786
|
-
const get =
|
|
3613
|
+
const cache3 = useRef14(void 0);
|
|
3614
|
+
const get = useCallback3(() => {
|
|
2787
3615
|
const state = store.get();
|
|
2788
|
-
if (
|
|
3616
|
+
if (cache3.current && cache3.current.state === state && cache3.current.select === selectRef.current) return cache3.current.value;
|
|
2789
3617
|
const value = selectRef.current(state);
|
|
2790
|
-
|
|
3618
|
+
cache3.current = { state, select: selectRef.current, value };
|
|
2791
3619
|
return value;
|
|
2792
3620
|
}, [store]);
|
|
2793
3621
|
return useSyncExternalStore(store.subscribe, get, get);
|
|
@@ -2798,7 +3626,7 @@ function useDocument() {
|
|
|
2798
3626
|
}
|
|
2799
3627
|
function useDocumentSelector(select) {
|
|
2800
3628
|
const runtime = useRuntime();
|
|
2801
|
-
const store =
|
|
3629
|
+
const store = useMemo5(() => ({ subscribe: runtime.document.subscribe, get: runtime.document.getSnapshot }), [runtime]);
|
|
2802
3630
|
return useStoreSelector(store, select);
|
|
2803
3631
|
}
|
|
2804
3632
|
function useSelection() {
|
|
@@ -2820,7 +3648,7 @@ function useAnnotation(id) {
|
|
|
2820
3648
|
}
|
|
2821
3649
|
function useAnnotations() {
|
|
2822
3650
|
const state = useStoreSelector(useRuntime().decorations, (state2) => state2);
|
|
2823
|
-
return
|
|
3651
|
+
return useMemo5(() => ({ annotations: state.annotations, occurrences: state.occurrences }), [state.annotations, state.occurrences]);
|
|
2824
3652
|
}
|
|
2825
3653
|
function useAnnotationState() {
|
|
2826
3654
|
const runtime = useRuntime();
|
|
@@ -2837,7 +3665,7 @@ function useAnchor(id) {
|
|
|
2837
3665
|
}
|
|
2838
3666
|
function useLiMR() {
|
|
2839
3667
|
const runtime = useRuntime();
|
|
2840
|
-
return
|
|
3668
|
+
return useMemo5(() => ({
|
|
2841
3669
|
...runtime.commands,
|
|
2842
3670
|
document: runtime.document,
|
|
2843
3671
|
get signal() {
|
|
@@ -2851,14 +3679,14 @@ function useLiMR() {
|
|
|
2851
3679
|
}
|
|
2852
3680
|
|
|
2853
3681
|
// src/components/CopyButton.tsx
|
|
2854
|
-
import { jsx as
|
|
3682
|
+
import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2855
3683
|
function CopyButton({ value = "", onCopy, label, variant = "plain", className = "" }) {
|
|
2856
3684
|
const locale = useLocale();
|
|
2857
|
-
const [status, setStatus] =
|
|
2858
|
-
const timer =
|
|
2859
|
-
const mounted =
|
|
3685
|
+
const [status, setStatus] = useState10("idle");
|
|
3686
|
+
const timer = useRef15(void 0);
|
|
3687
|
+
const mounted = useRef15(true);
|
|
2860
3688
|
const title = status === "copied" ? locale.copied : status === "error" ? locale.copyFailed : label ?? locale.copy;
|
|
2861
|
-
|
|
3689
|
+
useEffect10(() => {
|
|
2862
3690
|
mounted.current = true;
|
|
2863
3691
|
return () => {
|
|
2864
3692
|
mounted.current = false;
|
|
@@ -2878,7 +3706,7 @@ function CopyButton({ value = "", onCopy, label, variant = "plain", className =
|
|
|
2878
3706
|
clearTimeout(timer.current);
|
|
2879
3707
|
timer.current = setTimeout(() => setStatus("idle"), 2200);
|
|
2880
3708
|
};
|
|
2881
|
-
return /* @__PURE__ */
|
|
3709
|
+
return /* @__PURE__ */ jsxs17(
|
|
2882
3710
|
"button",
|
|
2883
3711
|
{
|
|
2884
3712
|
type: "button",
|
|
@@ -2890,21 +3718,21 @@ function CopyButton({ value = "", onCopy, label, variant = "plain", className =
|
|
|
2890
3718
|
title,
|
|
2891
3719
|
onClick: copy,
|
|
2892
3720
|
children: [
|
|
2893
|
-
/* @__PURE__ */
|
|
2894
|
-
/* @__PURE__ */
|
|
2895
|
-
/* @__PURE__ */
|
|
2896
|
-
/* @__PURE__ */
|
|
3721
|
+
/* @__PURE__ */ jsxs17("svg", { className: "limr-copy-glyph", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
3722
|
+
/* @__PURE__ */ jsxs17("g", { className: "limr-copy-sheets", children: [
|
|
3723
|
+
/* @__PURE__ */ jsx25("rect", { x: "8.5", y: "8", width: "10.5", height: "12", rx: "3" }),
|
|
3724
|
+
/* @__PURE__ */ jsx25("path", { d: "M15.5 8V6.8A2.8 2.8 0 0 0 12.7 4H7A3 3 0 0 0 4 7v6a3 3 0 0 0 3 3h1.5" })
|
|
2897
3725
|
] }),
|
|
2898
|
-
/* @__PURE__ */
|
|
3726
|
+
/* @__PURE__ */ jsx25("path", { className: "limr-copy-check", d: "m5.5 12 4.2 4.2 8.8-9", pathLength: "1" })
|
|
2899
3727
|
] }),
|
|
2900
|
-
/* @__PURE__ */
|
|
3728
|
+
/* @__PURE__ */ jsx25("span", { className: status === "error" ? "limr-copy-error" : "limr-sr-only", role: "status", children: status === "copied" ? locale.copied : status === "error" ? locale.copyFailed : "" })
|
|
2901
3729
|
]
|
|
2902
3730
|
}
|
|
2903
3731
|
);
|
|
2904
3732
|
}
|
|
2905
3733
|
|
|
2906
3734
|
// src/extensions/math.tsx
|
|
2907
|
-
import { jsx as
|
|
3735
|
+
import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2908
3736
|
var loaded;
|
|
2909
3737
|
var loading;
|
|
2910
3738
|
var load = () => loading ??= import("./math-renderer-L6DOH4RX.js").then((module) => {
|
|
@@ -2918,74 +3746,21 @@ async function preloadMath() {
|
|
|
2918
3746
|
function math(options = {}) {
|
|
2919
3747
|
function MathNode({ node }) {
|
|
2920
3748
|
const display = node.type === "math";
|
|
2921
|
-
const fallback = /* @__PURE__ */
|
|
3749
|
+
const fallback = /* @__PURE__ */ jsx26("code", { className: "limr-math-source", children: node.value });
|
|
2922
3750
|
const Renderer = loaded ?? MathContent;
|
|
2923
|
-
const content = /* @__PURE__ */
|
|
2924
|
-
return display ? /* @__PURE__ */
|
|
3751
|
+
const content = /* @__PURE__ */ jsx26(Suspense, { fallback, children: /* @__PURE__ */ jsx26(Renderer, { value: node.value ?? "", display, options }) });
|
|
3752
|
+
return display ? /* @__PURE__ */ jsxs18("div", { className: "limr-math-block", children: [
|
|
2925
3753
|
content,
|
|
2926
|
-
/* @__PURE__ */
|
|
3754
|
+
/* @__PURE__ */ jsx26(CopyButton, { className: "limr-math-copy", variant: "glass", label: "Copy LaTeX", value: `$$
|
|
2927
3755
|
${node.value ?? ""}
|
|
2928
3756
|
$$` })
|
|
2929
3757
|
] }) : content;
|
|
2930
3758
|
}
|
|
2931
|
-
return { name: "math", micromark: [syntax2()], mdast: [mathFromMarkdown()], scope: "local", components: { math: MathNode, inlineMath: MathNode } };
|
|
2932
|
-
}
|
|
2933
|
-
|
|
2934
|
-
// src/components/ToolIcon.tsx
|
|
2935
|
-
import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2936
|
-
function ToolIcon({ name, ...props }) {
|
|
2937
|
-
return /* @__PURE__ */ jsx19("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props, children: /* @__PURE__ */ jsxs15("g", { transform: name === "highlight" ? "translate(0 -1.25)" : name === "comment" ? "translate(0 -.5)" : void 0, children: [
|
|
2938
|
-
(name === "eye" || name === "eye-off") && /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
2939
|
-
/* @__PURE__ */ jsx19("path", { d: "M3 12s3.3-6 9-6 9 6 9 6-3.3 6-9 6-9-6-9-6Z" }),
|
|
2940
|
-
/* @__PURE__ */ jsx19("circle", { cx: "12", cy: "12", r: "2.7" }),
|
|
2941
|
-
name === "eye-off" && /* @__PURE__ */ jsx19("path", { d: "m4 4 16 16" })
|
|
2942
|
-
] }),
|
|
2943
|
-
name === "question" && /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
2944
|
-
/* @__PURE__ */ jsx19("circle", { cx: "12", cy: "12", r: "8.5" }),
|
|
2945
|
-
/* @__PURE__ */ jsx19("path", { d: "M9.4 9a2.7 2.7 0 0 1 5.2 1c0 1.8-2.6 2-2.6 3.7M12 17h.01" })
|
|
2946
|
-
] }),
|
|
2947
|
-
name === "highlight" && /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
2948
|
-
/* @__PURE__ */ jsx19("path", { d: "m8 15 7.6-9a2 2 0 0 1 2.8-.2l.8.7a2 2 0 0 1 .2 2.8L12 18l-4-3Z" }),
|
|
2949
|
-
/* @__PURE__ */ jsx19("path", { d: "m8 15-2 3 3 1 3-1M4 21h10M14 8l4 3.5" })
|
|
2950
|
-
] }),
|
|
2951
|
-
name === "edit" && /* @__PURE__ */ jsx19(Fragment6, { children: /* @__PURE__ */ jsx19("path", { d: "m14.5 5.5 4 4M4.5 19.5l4.5-1 11-11a2.1 2.1 0 0 0 0-3 2.1 2.1 0 0 0-3 0l-11 11-1.5 4Z" }) }),
|
|
2952
|
-
name === "close" && /* @__PURE__ */ jsx19("path", { d: "m6 6 12 12M18 6 6 18" }),
|
|
2953
|
-
name === "copy" && /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
2954
|
-
/* @__PURE__ */ jsx19("rect", { x: "8.5", y: "8", width: "10.5", height: "12", rx: "3" }),
|
|
2955
|
-
/* @__PURE__ */ jsx19("path", { d: "M15.5 8V6.8A2.8 2.8 0 0 0 12.7 4H7A3 3 0 0 0 4 7v6a3 3 0 0 0 3 3h1.5" })
|
|
2956
|
-
] }),
|
|
2957
|
-
["background", "underline", "dotted", "wavy"].includes(name) && /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
2958
|
-
name === "background" && /* @__PURE__ */ jsx19("rect", { x: "3", y: "3", width: "18", height: "18", rx: "5", fill: "currentColor", fillOpacity: ".13", stroke: "none" }),
|
|
2959
|
-
/* @__PURE__ */ jsx19("path", { d: "m8 15 3-8a1.05 1.05 0 0 1 2 0l3 8M9.2 12h5.6" }),
|
|
2960
|
-
name === "background" && /* @__PURE__ */ jsx19("path", { d: "M7 19h10", strokeWidth: "2.5" }),
|
|
2961
|
-
name === "underline" && /* @__PURE__ */ jsx19("path", { d: "M5 20h14" }),
|
|
2962
|
-
name === "dotted" && /* @__PURE__ */ jsx19("path", { d: "M5 20h14", strokeDasharray: ".1 3.4", strokeWidth: "2.4" }),
|
|
2963
|
-
name === "wavy" && /* @__PURE__ */ jsx19("path", { d: "M4 20c1.3-2 2.7-2 4 0s2.7 2 4 0 2.7-2 4 0 2.7 2 4 0" })
|
|
2964
|
-
] }),
|
|
2965
|
-
name === "chevron" && /* @__PURE__ */ jsx19("path", { d: "m8 10 4 4 4-4" }),
|
|
2966
|
-
name === "check" && /* @__PURE__ */ jsx19("path", { d: "m5.5 12 4.2 4.2 8.8-9" }),
|
|
2967
|
-
name === "trash" && /* @__PURE__ */ jsx19(Fragment6, { children: /* @__PURE__ */ jsx19("path", { d: "M4.5 7h15M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M7 7l.7 12a2 2 0 0 0 2 2h4.6a2 2 0 0 0 2-2L17 7M10 11v6M14 11v6" }) }),
|
|
2968
|
-
name === "note" && /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
2969
|
-
/* @__PURE__ */ jsx19("path", { d: "M14 3H7a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V9l-6-6Z" }),
|
|
2970
|
-
/* @__PURE__ */ jsx19("path", { d: "M14 3v4a2 2 0 0 0 2 2h4M8 13h8M8 17h5" })
|
|
2971
|
-
] }),
|
|
2972
|
-
name === "comment" && /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
2973
|
-
/* @__PURE__ */ jsx19("path", { d: "M8 19 4 21V7a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v9a3 3 0 0 1-3 3H8Z" }),
|
|
2974
|
-
/* @__PURE__ */ jsx19("path", { d: "M8 9h8M8 13h5" })
|
|
2975
|
-
] }),
|
|
2976
|
-
name === "footnote" && /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
2977
|
-
/* @__PURE__ */ jsx19("path", { d: "M5 7h9M5 11h12M5 15h8M5 20h14M18 4h2v5" }),
|
|
2978
|
-
/* @__PURE__ */ jsx19("path", { d: "M17.5 9h4" })
|
|
2979
|
-
] }),
|
|
2980
|
-
name === "sparkles" && /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
2981
|
-
/* @__PURE__ */ jsx19("path", { d: "m10.5 4 1.8 4.8 4.7 1.7-4.7 1.8-1.8 4.7-1.7-4.7L4 10.5l4.8-1.7L10.5 4Z" }),
|
|
2982
|
-
/* @__PURE__ */ jsx19("path", { d: "m19 15 .8 2.2L22 18l-2.2.8L19 21l-.8-2.2L16 18l2.2-.8L19 15ZM19 3v4M17 5h4" })
|
|
2983
|
-
] })
|
|
2984
|
-
] }) });
|
|
3759
|
+
return { name: "math", directives: ["math"], literal: true, micromark: [syntax2()], mdast: [mathFromMarkdown()], scope: "local", components: { math: MathNode, inlineMath: MathNode }, transform: (root, context) => literalDirective(root, context.source, "math") };
|
|
2985
3760
|
}
|
|
2986
3761
|
|
|
2987
3762
|
// src/extensions/selection-actions.tsx
|
|
2988
|
-
import { jsx as
|
|
3763
|
+
import { jsx as jsx27, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2989
3764
|
var highlightColors = [
|
|
2990
3765
|
{ color: "#E57373", label: "Rose", labelZh: "\u73AB\u7470" },
|
|
2991
3766
|
{ color: "#F2C744", label: "Gold", labelZh: "\u6696\u9EC4" },
|
|
@@ -2999,9 +3774,9 @@ function copyText(options = {}) {
|
|
|
2999
3774
|
return {
|
|
3000
3775
|
id: `copy-${options.format ?? "text"}`,
|
|
3001
3776
|
label: options.label ?? ((context) => context.locale.copy),
|
|
3002
|
-
icon: /* @__PURE__ */
|
|
3777
|
+
icon: /* @__PURE__ */ jsx27(ToolIcon, { name: "copy" }),
|
|
3003
3778
|
successLabel: (context) => context.locale.copied,
|
|
3004
|
-
successIcon: /* @__PURE__ */
|
|
3779
|
+
successIcon: /* @__PURE__ */ jsx27(ToolIcon, { name: "check" }),
|
|
3005
3780
|
run: async ({ selection }) => {
|
|
3006
3781
|
const format = options.format ?? "text";
|
|
3007
3782
|
await navigator.clipboard.writeText(format === "text" ? selection.text : selection[format].sourceText);
|
|
@@ -3023,17 +3798,17 @@ function HighlightSettings({ context, options }) {
|
|
|
3023
3798
|
context.setHighlightAppearance(appearance);
|
|
3024
3799
|
if (highlight) void context.run((current) => current.updateAnnotation(highlight.id, { data: appearance }));
|
|
3025
3800
|
};
|
|
3026
|
-
return /* @__PURE__ */
|
|
3027
|
-
/* @__PURE__ */
|
|
3028
|
-
/* @__PURE__ */
|
|
3029
|
-
/* @__PURE__ */
|
|
3030
|
-
/* @__PURE__ */
|
|
3031
|
-
/* @__PURE__ */
|
|
3801
|
+
return /* @__PURE__ */ jsxs19("div", { className: "limr-highlight-settings", children: [
|
|
3802
|
+
/* @__PURE__ */ jsxs19("fieldset", { disabled: context.busy, children: [
|
|
3803
|
+
/* @__PURE__ */ jsx27("legend", { children: locale.highlightStyle }),
|
|
3804
|
+
/* @__PURE__ */ jsx27("div", { className: "limr-highlight-styles", children: styles.map(([value, label]) => /* @__PURE__ */ jsxs19("button", { type: "button", "aria-pressed": style === value, onClick: () => change(color, value), children: [
|
|
3805
|
+
/* @__PURE__ */ jsx27(ToolIcon, { name: value }),
|
|
3806
|
+
/* @__PURE__ */ jsx27("span", { className: "limr-highlight-style-label", children: /* @__PURE__ */ jsx27("span", { className: "limr-underline", children: label }) })
|
|
3032
3807
|
] }, value)) })
|
|
3033
3808
|
] }),
|
|
3034
|
-
/* @__PURE__ */
|
|
3035
|
-
/* @__PURE__ */
|
|
3036
|
-
/* @__PURE__ */
|
|
3809
|
+
/* @__PURE__ */ jsxs19("fieldset", { disabled: context.busy, children: [
|
|
3810
|
+
/* @__PURE__ */ jsx27("legend", { children: locale.highlightColor }),
|
|
3811
|
+
/* @__PURE__ */ jsx27("div", { className: "limr-highlight-colors", children: (options.colors ?? highlightColors).map((item) => /* @__PURE__ */ jsx27("button", { type: "button", className: "limr-color-swatch", "aria-label": locale.highlight === "\u9AD8\u4EAE" ? item.labelZh ?? item.label : item.label, title: locale.highlight === "\u9AD8\u4EAE" ? item.labelZh ?? item.label : item.label, "aria-pressed": color.toLowerCase() === item.color.toLowerCase(), style: { "--swatch": item.color }, onClick: () => change(item.color, style), children: /* @__PURE__ */ jsx27(ToolIcon, { name: "check" }) }, item.color)) })
|
|
3037
3812
|
] })
|
|
3038
3813
|
] });
|
|
3039
3814
|
}
|
|
@@ -3041,17 +3816,17 @@ function highlightPalette(options = {}) {
|
|
|
3041
3816
|
return {
|
|
3042
3817
|
id: "highlight-palette",
|
|
3043
3818
|
label: (context) => context.locale.editHighlight,
|
|
3044
|
-
icon: /* @__PURE__ */
|
|
3819
|
+
icon: /* @__PURE__ */ jsx27(ToolIcon, { name: "background" }),
|
|
3045
3820
|
placement: "start",
|
|
3046
|
-
render: (context) => /* @__PURE__ */
|
|
3047
|
-
renderExpanded: (context) => /* @__PURE__ */
|
|
3821
|
+
render: (context) => /* @__PURE__ */ jsx27("button", { type: "button", className: "limr-toolbar-swatch", "aria-label": context.locale.editHighlight, "aria-expanded": context.expanded, disabled: context.busy, onClick: () => context.expanded ? context.collapse() : context.expand(), style: { "--swatch": context.highlightAppearance.color ?? defaultHighlight.color } }),
|
|
3822
|
+
renderExpanded: (context) => /* @__PURE__ */ jsx27(HighlightSettings, { context, options })
|
|
3048
3823
|
};
|
|
3049
3824
|
}
|
|
3050
3825
|
function highlightSelection() {
|
|
3051
3826
|
return {
|
|
3052
3827
|
id: "highlight",
|
|
3053
3828
|
label: (context) => !context.highlight ? context.locale.addHighlight : context.highlight.data?.hidden ? context.locale.showHighlight : context.locale.hideHighlight,
|
|
3054
|
-
icon: (context) => /* @__PURE__ */
|
|
3829
|
+
icon: (context) => /* @__PURE__ */ jsx27(ToolIcon, { name: !context.highlight ? "highlight" : context.highlight.data?.hidden ? "eye" : "eye-off" }),
|
|
3055
3830
|
visible: (context) => !context.highlight || context.annotations.some((annotation) => annotation.type !== "highlight"),
|
|
3056
3831
|
run: (context) => {
|
|
3057
3832
|
if (context.highlight) context.updateAnnotation(context.highlight.id, { data: { ...context.highlight.data, hidden: !context.highlight.data?.hidden } });
|
|
@@ -3066,7 +3841,7 @@ function deleteAnnotations() {
|
|
|
3066
3841
|
return {
|
|
3067
3842
|
id: "delete-annotations",
|
|
3068
3843
|
label: (context) => context.locale.deleteAnnotations,
|
|
3069
|
-
icon: /* @__PURE__ */
|
|
3844
|
+
icon: /* @__PURE__ */ jsx27(ToolIcon, { name: "trash" }),
|
|
3070
3845
|
placement: "end",
|
|
3071
3846
|
tone: "danger",
|
|
3072
3847
|
visible: (context) => context.annotations.length > 0,
|
|
@@ -3086,7 +3861,6 @@ export {
|
|
|
3086
3861
|
preloadMath,
|
|
3087
3862
|
math,
|
|
3088
3863
|
codeHighlight,
|
|
3089
|
-
sourceRangeStartRect,
|
|
3090
3864
|
Markdown,
|
|
3091
3865
|
OverlayScrollArea,
|
|
3092
3866
|
AnnotationCard,
|
|
@@ -3095,9 +3869,15 @@ export {
|
|
|
3095
3869
|
InlineMarker,
|
|
3096
3870
|
Collapse,
|
|
3097
3871
|
translations,
|
|
3872
|
+
ToolIcon,
|
|
3873
|
+
mermaid,
|
|
3098
3874
|
defineBlock,
|
|
3099
3875
|
defineAnnotation,
|
|
3100
3876
|
defineExtension,
|
|
3877
|
+
calloutType,
|
|
3878
|
+
callout,
|
|
3879
|
+
inlineHighlights,
|
|
3880
|
+
footnotes,
|
|
3101
3881
|
video,
|
|
3102
3882
|
figures,
|
|
3103
3883
|
definition,
|
|
@@ -3120,11 +3900,10 @@ export {
|
|
|
3120
3900
|
useAnnotationState,
|
|
3121
3901
|
useAnchor,
|
|
3122
3902
|
useLiMR,
|
|
3123
|
-
ToolIcon,
|
|
3124
3903
|
highlightColors,
|
|
3125
3904
|
copyText,
|
|
3126
3905
|
highlightPalette,
|
|
3127
3906
|
highlightSelection,
|
|
3128
3907
|
deleteAnnotations
|
|
3129
3908
|
};
|
|
3130
|
-
//# sourceMappingURL=chunk-
|
|
3909
|
+
//# sourceMappingURL=chunk-SUAAUGAX.js.map
|