tiptap-markdown-react 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,19 +1,75 @@
1
1
  "use client";
2
2
  import { Markdown } from "@tiptap/markdown";
3
- import { jsxs, jsx, Fragment } from "react/jsx-runtime";
3
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
4
4
  import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
5
5
  import Image from "@tiptap/extension-image";
6
6
  import { TableOfContents } from "@tiptap/extension-table-of-contents";
7
- import { NodeViewWrapper, NodeViewContent, useEditor, EditorContent, ReactNodeViewRenderer, useEditorState } from "@tiptap/react";
8
- import { forwardRef, useEffect, useImperativeHandle, useState, useRef, useCallback, useContext, createContext } from "react";
9
- import { s as styles$4, b as baseExtensions, l as lowlight, m as makeTocGetId, p as pureCodeBlock, a as pureImage } from "./extractToc-C7e1DuVc.js";
10
- import { R, e } from "./extractToc-C7e1DuVc.js";
7
+ import { NodeViewWrapper, ReactNodeViewRenderer, NodeViewContent, useEditor, EditorContent, useEditorState } from "@tiptap/react";
8
+ import { forwardRef, useEffect, useImperativeHandle, useMemo, useState, useRef, useCallback, useContext, createContext } from "react";
9
+ import { C as CitationRef, e as enrichMarkdownCitations, s as styles$4, b as baseExtensions, l as lowlight, m as makeTocGetId, p as pureCodeBlock, a as pureImage, R as ReportContent } from "./extractToc-DW6HOiGt.js";
10
+ import { c, d } from "./extractToc-DW6HOiGt.js";
11
11
  import { Extension } from "@tiptap/core";
12
12
  import { FileHandlePlugin } from "@tiptap/extension-file-handler";
13
13
  import { PluginKey, Plugin } from "@tiptap/pm/state";
14
14
  import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
15
15
  import * as Popover from "@radix-ui/react-popover";
16
16
  import { createPortal } from "react-dom";
17
+ function CitationRefView({ node, extension }) {
18
+ const index = String(node.attrs.index ?? "");
19
+ const url = node.attrs.url || null;
20
+ const title = node.attrs.title || "";
21
+ const renderCitation = extension.options.renderCitation;
22
+ const pill = /* @__PURE__ */ jsx(
23
+ "span",
24
+ {
25
+ className: "citation-ref",
26
+ "data-index": index,
27
+ ...url ? { "data-url": url } : {},
28
+ ...title ? { "data-title": title } : {},
29
+ children: !renderCitation && url ? /* @__PURE__ */ jsx(
30
+ "a",
31
+ {
32
+ href: url,
33
+ title,
34
+ target: "_blank",
35
+ rel: "noopener noreferrer",
36
+ children: index
37
+ }
38
+ ) : index
39
+ }
40
+ );
41
+ const content = renderCitation ? renderCitation({
42
+ index,
43
+ attrs: { index, url, title: title || null },
44
+ defaultDom: pill
45
+ }) : pill;
46
+ return /* @__PURE__ */ jsx(
47
+ NodeViewWrapper,
48
+ {
49
+ as: "span",
50
+ "data-citation-ref": "",
51
+ style: { display: "inline" },
52
+ children: content
53
+ }
54
+ );
55
+ }
56
+ function createCitationRef(options = {}) {
57
+ return CitationRef.extend({
58
+ addOptions() {
59
+ var _a;
60
+ return {
61
+ HTMLAttributes: {},
62
+ ...(_a = this.parent) == null ? void 0 : _a.call(this),
63
+ renderCitation: options.renderCitation
64
+ };
65
+ },
66
+ addNodeView() {
67
+ return ReactNodeViewRenderer(CitationRefView);
68
+ }
69
+ }).configure({
70
+ renderCitation: options.renderCitation
71
+ });
72
+ }
17
73
  const MD_FILE_RE = /\.(md|markdown)$/i;
18
74
  const MD_MIME_TYPES = ["text/markdown", "text/x-markdown", ""];
19
75
  async function insertMarkdownFiles(editor, files, pos) {
@@ -454,6 +510,8 @@ const ImageWithConfirmDelete = Image.extend({
454
510
  });
455
511
  const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
456
512
  initialMarkdown = "",
513
+ sources,
514
+ renderCitation,
457
515
  placeholder,
458
516
  onEditorReady,
459
517
  onTocChange,
@@ -463,11 +521,16 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
463
521
  codeBlockLabels,
464
522
  className
465
523
  }, ref) {
524
+ const preparedInitial = enrichMarkdownCitations(
525
+ initialMarkdown,
526
+ sources ?? []
527
+ );
466
528
  const editor = useEditor({
467
529
  extensions: [
468
530
  ...baseExtensions,
469
531
  CodeBlock.configure({ lowlight, codeBlockLabels }),
470
532
  ImageWithConfirmDelete.configure({ inline: false }),
533
+ createCitationRef({ renderCitation }),
471
534
  Markdown,
472
535
  TableOfContents.configure({
473
536
  getId: makeTocGetId(),
@@ -481,7 +544,7 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
481
544
  ...markdownFileDrop ? [MarkdownFileDrop] : [],
482
545
  ...extraExtensions ?? []
483
546
  ],
484
- content: initialMarkdown,
547
+ content: preparedInitial,
485
548
  contentType: "markdown",
486
549
  // Next.js SSR:服务端不立即渲染,避免 hydration 不一致
487
550
  immediatelyRender: false,
@@ -523,23 +586,43 @@ const MarkdownWysiwygEditor = forwardRef(function MarkdownWysiwygEditor2({
523
586
  }
524
587
  );
525
588
  });
526
- function MarkdownPreview({ markdown, className }) {
527
- const editor = useEditor({
528
- extensions: [...baseExtensions, pureCodeBlock, pureImage, Markdown],
529
- content: markdown,
530
- contentType: "markdown",
531
- editable: false,
532
- immediatelyRender: false,
533
- // 关键:内部 ProseMirror DOM 挂与编辑器一字不差的 editorContent class,
534
- // 所有内容样式都作用在该选择器下,预览才能与编辑/插入后逐像素一致。
535
- editorProps: {
536
- attributes: { class: styles$4.editorContent }
537
- }
538
- });
589
+ function MarkdownPreview({
590
+ markdown,
591
+ sources,
592
+ renderCitation,
593
+ className
594
+ }) {
595
+ const prepared = useMemo(
596
+ () => enrichMarkdownCitations(markdown, sources ?? []),
597
+ [markdown, sources]
598
+ );
599
+ const extensions = useMemo(
600
+ () => [
601
+ ...baseExtensions,
602
+ pureCodeBlock,
603
+ pureImage,
604
+ createCitationRef({ renderCitation }),
605
+ Markdown
606
+ ],
607
+ [renderCitation]
608
+ );
609
+ const editor = useEditor(
610
+ {
611
+ extensions,
612
+ content: prepared,
613
+ contentType: "markdown",
614
+ editable: false,
615
+ immediatelyRender: false,
616
+ editorProps: {
617
+ attributes: { class: styles$4.editorContent }
618
+ }
619
+ },
620
+ [extensions]
621
+ );
539
622
  useEffect(() => {
540
623
  if (!editor) return;
541
- editor.commands.setContent(markdown, { contentType: "markdown" });
542
- }, [editor, markdown]);
624
+ editor.commands.setContent(prepared, { contentType: "markdown" });
625
+ }, [editor, prepared]);
543
626
  return /* @__PURE__ */ jsx(
544
627
  EditorContent,
545
628
  {
@@ -548,8 +631,9 @@ function MarkdownPreview({ markdown, className }) {
548
631
  }
549
632
  );
550
633
  }
551
- function insertMarkdown(editor, markdown) {
552
- editor.chain().focus().insertContent(markdown, { contentType: "markdown" }).run();
634
+ function insertMarkdown(editor, markdown, sources = []) {
635
+ const prepared = enrichMarkdownCitations(markdown, sources);
636
+ editor.chain().focus().insertContent(prepared, { contentType: "markdown" }).run();
553
637
  }
554
638
  const toolbar = "_toolbar_i2emf_2";
555
639
  const inner = "_inner_i2emf_15";
@@ -635,7 +719,7 @@ function ColorPalette({ value, onPick, labels }) {
635
719
  {
636
720
  type: "button",
637
721
  className: styles$1.noneRow,
638
- onMouseDown: (e2) => e2.preventDefault(),
722
+ onMouseDown: (e) => e.preventDefault(),
639
723
  onClick: () => onPick(null),
640
724
  children: [
641
725
  /* @__PURE__ */ jsx("span", { className: styles$1.noneIcon, "aria-hidden": true }),
@@ -643,32 +727,32 @@ function ColorPalette({ value, onPick, labels }) {
643
727
  ]
644
728
  }
645
729
  ),
646
- /* @__PURE__ */ jsx("div", { className: styles$1.grid, children: PALETTE.flat().map((c) => /* @__PURE__ */ jsx(
730
+ /* @__PURE__ */ jsx("div", { className: styles$1.grid, children: PALETTE.flat().map((c2) => /* @__PURE__ */ jsx(
647
731
  "button",
648
732
  {
649
733
  type: "button",
650
- className: `${styles$1.swatch} ${current === c.toLowerCase() ? styles$1.swatchActive : ""}`,
651
- style: { background: c },
652
- title: c,
653
- "aria-label": c,
654
- onMouseDown: (e2) => e2.preventDefault(),
655
- onClick: () => onPick(c)
734
+ className: `${styles$1.swatch} ${current === c2.toLowerCase() ? styles$1.swatchActive : ""}`,
735
+ style: { background: c2 },
736
+ title: c2,
737
+ "aria-label": c2,
738
+ onMouseDown: (e) => e.preventDefault(),
739
+ onClick: () => onPick(c2)
656
740
  },
657
- c
741
+ c2
658
742
  )) }),
659
743
  /* @__PURE__ */ jsx("div", { className: styles$1.themeLabel, children: t.theme }),
660
- /* @__PURE__ */ jsx("div", { className: styles$1.themeRow, children: THEME_COLORS.map((c) => /* @__PURE__ */ jsx(
744
+ /* @__PURE__ */ jsx("div", { className: styles$1.themeRow, children: THEME_COLORS.map((c2) => /* @__PURE__ */ jsx(
661
745
  "button",
662
746
  {
663
747
  type: "button",
664
- className: `${styles$1.swatch} ${current === c.toLowerCase() ? styles$1.swatchActive : ""}`,
665
- style: { background: c },
666
- title: c,
667
- "aria-label": c,
668
- onMouseDown: (e2) => e2.preventDefault(),
669
- onClick: () => onPick(c)
748
+ className: `${styles$1.swatch} ${current === c2.toLowerCase() ? styles$1.swatchActive : ""}`,
749
+ style: { background: c2 },
750
+ title: c2,
751
+ "aria-label": c2,
752
+ onMouseDown: (e) => e.preventDefault(),
753
+ onClick: () => onPick(c2)
670
754
  },
671
- c
755
+ c2
672
756
  )) })
673
757
  ] });
674
758
  }
@@ -688,7 +772,7 @@ function ToolbarButton({
688
772
  "aria-pressed": active2,
689
773
  disabled,
690
774
  className: `${styles$2.btn} ${active2 ? styles$2.btnActive : ""}`,
691
- onMouseDown: (e2) => e2.preventDefault(),
775
+ onMouseDown: (e) => e.preventDefault(),
692
776
  onClick,
693
777
  children
694
778
  }
@@ -713,8 +797,8 @@ function MenuPopover({
713
797
  className: styles$2.menu,
714
798
  sideOffset: 4,
715
799
  align: "start",
716
- onOpenAutoFocus: (e2) => e2.preventDefault(),
717
- onCloseAutoFocus: (e2) => e2.preventDefault(),
800
+ onOpenAutoFocus: (e) => e.preventDefault(),
801
+ onCloseAutoFocus: (e) => e.preventDefault(),
718
802
  children: /* @__PURE__ */ jsx(MenuCloseCtx.Provider, { value: close, children })
719
803
  }
720
804
  ) })
@@ -733,7 +817,7 @@ function MenuItem({
733
817
  type: "button",
734
818
  disabled,
735
819
  className: `${styles$2.menuItem} ${selected ? styles$2.menuItemSelected : ""}`,
736
- onMouseDown: (e2) => e2.preventDefault(),
820
+ onMouseDown: (e) => e.preventDefault(),
737
821
  onClick: () => {
738
822
  onSelect();
739
823
  close();
@@ -759,7 +843,7 @@ function ColorPopover({
759
843
  className: styles$2.btn,
760
844
  title,
761
845
  "aria-label": title,
762
- onMouseDown: (e2) => e2.preventDefault(),
846
+ onMouseDown: (e) => e.preventDefault(),
763
847
  children: /* @__PURE__ */ jsxs("span", { className: styles$2.colorIcon, children: [
764
848
  /* @__PURE__ */ jsx("span", { className: styles$2.colorIconGlyph, children: glyph }),
765
849
  /* @__PURE__ */ jsx("span", { className: styles$2.colorIconBar, style: { background: bar } })
@@ -772,14 +856,14 @@ function ColorPopover({
772
856
  className: styles$2.popoverContent,
773
857
  sideOffset: 4,
774
858
  align: "start",
775
- onOpenAutoFocus: (e2) => e2.preventDefault(),
776
- onCloseAutoFocus: (e2) => e2.preventDefault(),
859
+ onOpenAutoFocus: (e) => e.preventDefault(),
860
+ onCloseAutoFocus: (e) => e.preventDefault(),
777
861
  children: /* @__PURE__ */ jsx(
778
862
  ColorPalette,
779
863
  {
780
864
  value,
781
- onPick: (c) => {
782
- onPick(c);
865
+ onPick: (c2) => {
866
+ onPick(c2);
783
867
  setOpen(false);
784
868
  },
785
869
  labels: paletteLabels
@@ -802,30 +886,30 @@ function EditorToolbar({
802
886
  const t = { ...defaultToolbarLabels, ...labels };
803
887
  const state = useEditorState({
804
888
  editor,
805
- selector: ({ editor: e2 }) => ({
806
- bold: e2.isActive("bold"),
807
- italic: e2.isActive("italic"),
808
- underline: e2.isActive("underline"),
809
- strike: e2.isActive("strike"),
810
- code: e2.isActive("code"),
811
- link: e2.isActive("link"),
812
- taskList: e2.isActive("taskList"),
889
+ selector: ({ editor: e }) => ({
890
+ bold: e.isActive("bold"),
891
+ italic: e.isActive("italic"),
892
+ underline: e.isActive("underline"),
893
+ strike: e.isActive("strike"),
894
+ code: e.isActive("code"),
895
+ link: e.isActive("link"),
896
+ taskList: e.isActive("taskList"),
813
897
  headingLevel: [1, 2, 3, 4, 5, 6].find(
814
- (lv) => e2.isActive("heading", { level: lv })
898
+ (lv) => e.isActive("heading", { level: lv })
815
899
  ),
816
- fontSize: e2.getAttributes("textStyle").fontSize || void 0,
817
- isParagraph: e2.isActive("paragraph"),
818
- bulletList: e2.isActive("bulletList"),
819
- orderedList: e2.isActive("orderedList"),
820
- blockquote: e2.isActive("blockquote"),
821
- textColor: e2.getAttributes("textStyle").color || void 0,
822
- highlightColor: e2.getAttributes("highlight").color || void 0,
823
- superscript: e2.isActive("superscript"),
824
- subscript: e2.isActive("subscript"),
825
- inTable: e2.isActive("table"),
826
- inTableHeader: e2.isActive("tableHeader"),
827
- canUndo: e2.can().undo(),
828
- canRedo: e2.can().redo()
900
+ fontSize: e.getAttributes("textStyle").fontSize || void 0,
901
+ isParagraph: e.isActive("paragraph"),
902
+ bulletList: e.isActive("bulletList"),
903
+ orderedList: e.isActive("orderedList"),
904
+ blockquote: e.isActive("blockquote"),
905
+ textColor: e.getAttributes("textStyle").color || void 0,
906
+ highlightColor: e.getAttributes("highlight").color || void 0,
907
+ superscript: e.isActive("superscript"),
908
+ subscript: e.isActive("subscript"),
909
+ inTable: e.isActive("table"),
910
+ inTableHeader: e.isActive("tableHeader"),
911
+ canUndo: e.can().undo(),
912
+ canRedo: e.can().redo()
829
913
  })
830
914
  });
831
915
  const [editorFocused, setEditorFocused] = useState(() => editor.isFocused);
@@ -847,32 +931,32 @@ function EditorToolbar({
847
931
  const closeTableMenu = useCallback(() => setTableMenu(null), []);
848
932
  useEffect(() => {
849
933
  const dom = editor.view.dom;
850
- const onContextMenu = (e2) => {
934
+ const onContextMenu = (e) => {
851
935
  const coords = editor.view.posAtCoords({
852
- left: e2.clientX,
853
- top: e2.clientY
936
+ left: e.clientX,
937
+ top: e.clientY
854
938
  });
855
939
  if (!coords) return;
856
940
  const $pos = editor.state.doc.resolve(coords.pos);
857
941
  let inTable = false;
858
- for (let d = $pos.depth; d > 0; d--) {
859
- if ($pos.node(d).type.name === "table") {
942
+ for (let d2 = $pos.depth; d2 > 0; d2--) {
943
+ if ($pos.node(d2).type.name === "table") {
860
944
  inTable = true;
861
945
  break;
862
946
  }
863
947
  }
864
948
  if (!inTable) return;
865
- e2.preventDefault();
949
+ e.preventDefault();
866
950
  editor.chain().focus().setTextSelection(coords.pos).run();
867
- setTableMenu({ x: e2.clientX, y: e2.clientY });
951
+ setTableMenu({ x: e.clientX, y: e.clientY });
868
952
  };
869
953
  dom.addEventListener("contextmenu", onContextMenu);
870
954
  return () => dom.removeEventListener("contextmenu", onContextMenu);
871
955
  }, [editor]);
872
956
  useEffect(() => {
873
957
  if (!tableMenu) return;
874
- const onKey = (e2) => {
875
- if (e2.key === "Escape") closeTableMenu();
958
+ const onKey = (e) => {
959
+ if (e.key === "Escape") closeTableMenu();
876
960
  };
877
961
  document.addEventListener("mousedown", closeTableMenu);
878
962
  document.addEventListener("keydown", onKey, true);
@@ -892,10 +976,10 @@ function EditorToolbar({
892
976
  var _a;
893
977
  return (_a = fileInputRef.current) == null ? void 0 : _a.click();
894
978
  };
895
- const handleImageChange = async (e2) => {
979
+ const handleImageChange = async (e) => {
896
980
  var _a;
897
- const file = (_a = e2.target.files) == null ? void 0 : _a[0];
898
- e2.target.value = "";
981
+ const file = (_a = e.target.files) == null ? void 0 : _a[0];
982
+ e.target.value = "";
899
983
  if (!file || !onImageUpload) return;
900
984
  try {
901
985
  const url = await onImageUpload(file);
@@ -907,10 +991,10 @@ function EditorToolbar({
907
991
  }
908
992
  };
909
993
  const mdFileInputRef = useRef(null);
910
- const handleMdFileChange = async (e2) => {
994
+ const handleMdFileChange = async (e) => {
911
995
  var _a;
912
- const file = (_a = e2.target.files) == null ? void 0 : _a[0];
913
- e2.target.value = "";
996
+ const file = (_a = e.target.files) == null ? void 0 : _a[0];
997
+ e.target.value = "";
914
998
  if (!file) return;
915
999
  try {
916
1000
  const text = await file.text();
@@ -981,7 +1065,7 @@ function EditorToolbar({
981
1065
  type: "button",
982
1066
  className: styles$2.styleTrigger,
983
1067
  title: t.style,
984
- onMouseDown: (e2) => e2.preventDefault(),
1068
+ onMouseDown: (e) => e.preventDefault(),
985
1069
  children: [
986
1070
  /* @__PURE__ */ jsx("span", { className: styles$2.styleTriggerLabel, children: t.style }),
987
1071
  /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$2.styleTriggerCaret })
@@ -1026,7 +1110,7 @@ function EditorToolbar({
1026
1110
  title: t.fontSize,
1027
1111
  "aria-label": t.fontSize,
1028
1112
  disabled: !canEditFontSize,
1029
- onMouseDown: (e2) => e2.preventDefault(),
1113
+ onMouseDown: (e) => e.preventDefault(),
1030
1114
  children: [
1031
1115
  /* @__PURE__ */ jsx("span", { className: styles$2.styleTriggerLabel, children: state.fontSize || t.fontSize }),
1032
1116
  /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$2.styleTriggerCaret })
@@ -1138,7 +1222,7 @@ function EditorToolbar({
1138
1222
  className: `${styles$2.scriptTrigger} ${scriptActive !== "normal" ? styles$2.btnActive : ""}`,
1139
1223
  title: t.scriptMenu,
1140
1224
  "aria-label": t.scriptMenu,
1141
- onMouseDown: (e2) => e2.preventDefault(),
1225
+ onMouseDown: (e) => e.preventDefault(),
1142
1226
  children: [
1143
1227
  /* @__PURE__ */ jsx("span", { className: styles$2.scriptTriggerGlyph, children: "A" }),
1144
1228
  /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$2.styleTriggerCaret })
@@ -1250,7 +1334,7 @@ function EditorToolbar({
1250
1334
  type: "button",
1251
1335
  className: styles$2.styleTrigger,
1252
1336
  title: t.more,
1253
- onMouseDown: (e2) => e2.preventDefault(),
1337
+ onMouseDown: (e) => e.preventDefault(),
1254
1338
  children: [
1255
1339
  /* @__PURE__ */ jsx("span", { className: styles$2.styleTriggerLabel, children: t.more }),
1256
1340
  /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12, className: styles$2.styleTriggerCaret })
@@ -1318,8 +1402,8 @@ function EditorToolbar({
1318
1402
  {
1319
1403
  className: styles$2.tableBubble,
1320
1404
  style: { position: "fixed", left: tableMenu.x, top: tableMenu.y },
1321
- onMouseDown: (e2) => e2.stopPropagation(),
1322
- onContextMenu: (e2) => e2.preventDefault(),
1405
+ onMouseDown: (e) => e.stopPropagation(),
1406
+ onContextMenu: (e) => e.preventDefault(),
1323
1407
  children: [
1324
1408
  /* @__PURE__ */ jsx(
1325
1409
  ToolbarButton,
@@ -1464,8 +1548,8 @@ function TocPanel({ items, activeId, onItemClick, labels }) {
1464
1548
  style: { paddingLeft: `${(item2.level - minLevel) * 12 + 12}px` },
1465
1549
  "aria-current": item2.id === activeId ? "true" : void 0,
1466
1550
  "aria-disabled": item2.locked ? "true" : void 0,
1467
- onClick: (e2) => {
1468
- e2.preventDefault();
1551
+ onClick: (e) => {
1552
+ e.preventDefault();
1469
1553
  handleClick(item2);
1470
1554
  },
1471
1555
  children: [
@@ -1538,10 +1622,125 @@ function TocPanel({ items, activeId, onItemClick, labels }) {
1538
1622
  list2
1539
1623
  ] });
1540
1624
  }
1625
+ function findCitationRefElement(target, root) {
1626
+ if (!(target instanceof Element)) return null;
1627
+ const el = target.closest(".citation-ref");
1628
+ if (!(el instanceof HTMLElement)) return null;
1629
+ if (!root.contains(el)) return null;
1630
+ return el;
1631
+ }
1632
+ function readCitationAttrs(el) {
1633
+ var _a;
1634
+ return {
1635
+ index: el.getAttribute("data-index") || ((_a = el.textContent) == null ? void 0 : _a.trim()) || "",
1636
+ url: el.getAttribute("data-url"),
1637
+ title: el.getAttribute("data-title")
1638
+ };
1639
+ }
1640
+ function CitationInteractive({
1641
+ containerRef,
1642
+ renderCitation,
1643
+ trigger = "click"
1644
+ }) {
1645
+ const [active2, setActive] = useState(null);
1646
+ useEffect(() => {
1647
+ const root = containerRef.current;
1648
+ if (!root) return;
1649
+ const activate = (el, e) => {
1650
+ e == null ? void 0 : e.preventDefault();
1651
+ e == null ? void 0 : e.stopPropagation();
1652
+ const attrs = readCitationAttrs(el);
1653
+ setActive({ index: attrs.index, attrs, anchorEl: el });
1654
+ };
1655
+ const onClick = (e) => {
1656
+ const el = findCitationRefElement(e.target, root);
1657
+ if (el) {
1658
+ activate(el, e);
1659
+ return;
1660
+ }
1661
+ setActive(null);
1662
+ };
1663
+ const onMouseOver = (e) => {
1664
+ const el = findCitationRefElement(e.target, root);
1665
+ if (el) activate(el, e);
1666
+ };
1667
+ const onMouseLeave = () => setActive(null);
1668
+ const onKeyDown = (e) => {
1669
+ if (e.key === "Escape") setActive(null);
1670
+ };
1671
+ if (trigger === "hover") {
1672
+ root.addEventListener("mouseover", onMouseOver);
1673
+ root.addEventListener("mouseleave", onMouseLeave);
1674
+ } else {
1675
+ root.addEventListener("click", onClick);
1676
+ }
1677
+ document.addEventListener("keydown", onKeyDown);
1678
+ return () => {
1679
+ root.removeEventListener("mouseover", onMouseOver);
1680
+ root.removeEventListener("mouseleave", onMouseLeave);
1681
+ root.removeEventListener("click", onClick);
1682
+ document.removeEventListener("keydown", onKeyDown);
1683
+ };
1684
+ }, [containerRef, trigger]);
1685
+ if (!active2) return null;
1686
+ return /* @__PURE__ */ jsx(Fragment, { children: renderCitation({
1687
+ index: active2.index,
1688
+ attrs: active2.attrs,
1689
+ anchorEl: active2.anchorEl,
1690
+ close: () => setActive(null)
1691
+ }) });
1692
+ }
1693
+ function ReportContentInteractive({
1694
+ renderCitation,
1695
+ trigger,
1696
+ className,
1697
+ html,
1698
+ ...rest
1699
+ }) {
1700
+ const ref = useRef(null);
1701
+ return /* @__PURE__ */ jsxs("div", { ref, className, children: [
1702
+ /* @__PURE__ */ jsx(ReportContent, { html, ...rest }),
1703
+ /* @__PURE__ */ jsx(
1704
+ CitationInteractive,
1705
+ {
1706
+ containerRef: ref,
1707
+ renderCitation,
1708
+ trigger
1709
+ }
1710
+ )
1711
+ ] });
1712
+ }
1713
+ function easeOutCubic(t) {
1714
+ return 1 - (1 - t) * (1 - t) * (1 - t);
1715
+ }
1716
+ function scrollToTocHeading(headingId, scrollContainer, options) {
1717
+ const el = scrollContainer.querySelector(
1718
+ `[data-toc-id="${CSS.escape(headingId)}"]`
1719
+ );
1720
+ if (!el) return;
1721
+ const startTop = scrollContainer.scrollTop;
1722
+ const rootRect = scrollContainer.getBoundingClientRect();
1723
+ const elRect = el.getBoundingClientRect();
1724
+ const targetTop = startTop + (elRect.top - rootRect.top);
1725
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
1726
+ scrollContainer.scrollTop = targetTop;
1727
+ return;
1728
+ }
1729
+ const duration = (options == null ? void 0 : options.duration) ?? 400;
1730
+ const start = performance.now();
1731
+ const animate = () => {
1732
+ const t = Math.min((performance.now() - start) / duration, 1);
1733
+ scrollContainer.scrollTop = startTop + (targetTop - startTop) * easeOutCubic(t);
1734
+ if (t < 1) requestAnimationFrame(animate);
1735
+ };
1736
+ requestAnimationFrame(animate);
1737
+ }
1541
1738
  export {
1542
1739
  BoldIcon,
1543
1740
  CheckIcon,
1544
1741
  ChevronDownIcon,
1742
+ CitationInteractive,
1743
+ CitationRef,
1545
1744
  CodeBlockView,
1546
1745
  CodeIcon,
1547
1746
  ColorPalette,
@@ -1562,7 +1761,8 @@ export {
1562
1761
  MarkdownWysiwygEditor,
1563
1762
  MenuIcon,
1564
1763
  RedoIcon,
1565
- R as ReportContent,
1764
+ ReportContent,
1765
+ ReportContentInteractive,
1566
1766
  RowAfterIcon,
1567
1767
  RowBeforeIcon,
1568
1768
  RowDeleteIcon,
@@ -1571,18 +1771,24 @@ export {
1571
1771
  TrashIcon,
1572
1772
  UnderlineIcon,
1573
1773
  UndoIcon,
1774
+ c as applyCitationSources,
1574
1775
  baseExtensions,
1776
+ createCitationRef,
1575
1777
  defaultCodeBlockLabels,
1576
1778
  defaultColorPaletteLabels,
1577
1779
  defaultTocLabels,
1578
1780
  defaultToolbarLabels,
1579
- e as extractToc,
1781
+ enrichMarkdownCitations,
1782
+ d as extractToc,
1783
+ findCitationRefElement,
1580
1784
  insertMarkdown,
1581
1785
  looksLikeMarkdown,
1582
1786
  lowlight,
1583
1787
  makeTocGetId,
1584
1788
  pureCodeBlock,
1585
1789
  pureImage,
1790
+ readCitationAttrs,
1791
+ scrollToTocHeading,
1586
1792
  useIsMobile
1587
1793
  };
1588
1794
  //# sourceMappingURL=index.js.map