tiptap-markdown-react 0.8.6 → 0.8.8

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.md CHANGED
@@ -222,7 +222,7 @@ Three ways to get markdown into the editor, all built in:
222
222
 
223
223
  - **Paste markdown text** — plain-text paste is heuristically detected (headings, lists, links, fences, tables…) and parsed into rich content. Rich-text (HTML) paste is untouched; Shift+paste always inserts plain text; pasting inside a code block is never converted. Opt out with `markdownPaste={false}`.
224
224
  - **Drop / paste `.md` files** — drag a `.md` / `.markdown` file into the editor (inserted at drop point) or paste a copied file (inserted at cursor). Opt out with `markdownFileDrop={false}`.
225
- - **Toolbar import** — "Import Markdown" in the toolbar's More menu opens a file picker and inserts the parsed file at the cursor (label: `labels.importMarkdown`).
225
+ - **Toolbar import** — the main-bar **Import** button opens a file picker and inserts the parsed file at the cursor (label: `labels.importDocument`). `.md` / `.markdown` is read in-package; any other file is handed to `onImportDocument`, so hosts decide which formats to accept (`importAccept`) and how to convert them. Without that callback the picker stays `.md`-only.
226
226
 
227
227
  The underlying extensions `MarkdownPaste` / `MarkdownFileDrop` (and the `looksLikeMarkdown` heuristic) are exported for custom pipelines.
228
228
 
@@ -232,7 +232,10 @@ The underlying extensions `MarkdownPaste` / `MarkdownFileDrop` (and the `looksLi
232
232
  | --- | --- | --- |
233
233
  | `editor` | `Editor` | The instance from `onEditorReady`. |
234
234
  | `onImageUpload` | `(file: File) => Promise<string>` | Upload handler returning a URL. Omit to hide the image button. |
235
- | `onError` | `(err: unknown) => void` | Side-effect error callback (e.g. failed upload). |
235
+ | `onError` | `(err, source?: 'image' \| 'markdown' \| 'import') => void` | Side-effect error callback (e.g. failed upload). |
236
+ | `onImportDocument` | `(file, ctx) => Promise<ImportDocumentResult \| string>` | Converts a non-Markdown file to Markdown. `ctx.signal` aborts on cancel/unmount; `ctx.onProgress` reports upload/convert progress back. Omit and Import only takes `.md`. |
237
+ | `importAccept` | `string` | Extra `accept` for the Import picker, e.g. `.docx,.csv,.pdf`. The package never validates extensions itself. |
238
+ | `showImport` | `boolean` | Show the Import button (default `true`). |
236
239
  | `labels` | `Partial<ToolbarLabels>` | i18n labels. |
237
240
  | `extraToolbarItems` | `ExtraToolbarItem[]` | Custom items appended to the "More" menu. |
238
241
  | `labels.inlineMath` / `blockMath` | `string` | More-menu equation items. |
@@ -1,6 +1,23 @@
1
1
  import { Editor } from '@tiptap/react';
2
2
  import { ReactNode } from 'react';
3
3
  import { ToolbarLabels } from '../labels';
4
+ import { SourceRef } from '../citationUtils';
5
+ /** `onImportDocument` 的成功返回。给字符串等价于 `{ markdown }`。 */
6
+ export interface ImportDocumentResult {
7
+ markdown: string;
8
+ sources?: SourceRef[];
9
+ }
10
+ /** 导入进度。宿主自行决定怎么展示(包只据此禁用按钮)。 */
11
+ export interface ImportDocumentProgress {
12
+ /** 0–1。通常只有上传阶段可测;转换阶段可省略。 */
13
+ ratio?: number;
14
+ phase: 'upload' | 'convert';
15
+ }
16
+ export interface ImportDocumentContext {
17
+ /** 用户点取消或组件卸载时 abort,宿主据此中断请求。 */
18
+ signal: AbortSignal;
19
+ onProgress?: (p: ImportDocumentProgress) => void;
20
+ }
4
21
  /** More 菜单里注入的自定义项(宿主用它扩展工具栏,如「导入项目报告」)。 */
5
22
  export interface ExtraToolbarItem {
6
23
  key: string;
@@ -22,7 +39,20 @@ export interface EditorToolbarProps {
22
39
  * 副作用错误回调(图片上传 / Markdown 导入失败),供宿主弹自己的提示。
23
40
  * `source` 区分来源,避免一律显示「图片上传失败」。
24
41
  */
25
- onError?: (err: unknown, source?: 'image' | 'markdown') => void;
42
+ onError?: (err: unknown, source?: 'image' | 'markdown' | 'import') => void;
43
+ /**
44
+ * 非 Markdown 文件的转换:收到文件,返回可插入的 Markdown。未提供则导入只吃 .md。
45
+ * 包内不校验扩展名——格式白名单由宿主的 `importAccept` 与本回调自己负责。
46
+ * 抛错转交 onError(..., 'import');`AbortError` 视为用户取消,不报错。
47
+ */
48
+ onImportDocument?: (file: File, ctx: ImportDocumentContext) => Promise<ImportDocumentResult | string>;
49
+ /**
50
+ * 追加到导入 input 的 accept(默认已含 `.md,.markdown,text/markdown`)。
51
+ * 例:`.doc,.docx,.csv,.pdf`。仅在传了 `onImportDocument` 时生效。
52
+ */
53
+ importAccept?: string;
54
+ /** 是否显示导入按钮,默认 `true`。卡片等场景可关掉。 */
55
+ showImport?: boolean;
26
56
  labels?: Partial<ToolbarLabels>;
27
57
  /** 追加到 More 菜单末尾的自定义项。 */
28
58
  extraToolbarItems?: ExtraToolbarItem[];
@@ -32,4 +62,4 @@ export interface EditorToolbarProps {
32
62
  * 顶部操作栏(antd-free,Radix Popover 菜单 + 内联 SVG 图标)。位置由父级控制,
33
63
  * 这里只渲染按钮 + 反映 editor 激活态。不含业务耦合,扩展项经 extraToolbarItems 注入。
34
64
  */
35
- export declare function EditorToolbar({ editor, onImageUpload, onError, labels, extraToolbarItems, className, }: EditorToolbarProps): import("react").JSX.Element;
65
+ export declare function EditorToolbar({ editor, onImageUpload, onError, onImportDocument, importAccept, showImport, labels, extraToolbarItems, className, }: EditorToolbarProps): import("react").JSX.Element;
@@ -17,6 +17,7 @@ export declare const StrikethroughIcon: (p: IconProps) => import("react").JSX.El
17
17
  export declare const CodeIcon: (p: IconProps) => import("react").JSX.Element;
18
18
  export declare const LinkIcon: (p: IconProps) => import("react").JSX.Element;
19
19
  export declare const ImageIcon: (p: IconProps) => import("react").JSX.Element;
20
+ export declare const ImportIcon: (p: IconProps) => import("react").JSX.Element;
20
21
  export declare const ListUnorderedIcon: (p: IconProps) => import("react").JSX.Element;
21
22
  export declare const ListOrderedIcon: (p: IconProps) => import("react").JSX.Element;
22
23
  export declare const ListChecksIcon: (p: IconProps) => import("react").JSX.Element;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { MarkdownWysiwygEditor, type MarkdownWysiwygEditorHandle, type MarkdownWysiwygEditorProps, } from './components/MarkdownWysiwygEditor';
2
2
  export { MarkdownPreview, type MarkdownPreviewProps, } from './components/MarkdownPreview';
3
- export { EditorToolbar, type EditorToolbarProps, type ExtraToolbarItem, } from './components/EditorToolbar';
3
+ export { EditorToolbar, type EditorToolbarProps, type ExtraToolbarItem, type ImportDocumentContext, type ImportDocumentProgress, type ImportDocumentResult, } from './components/EditorToolbar';
4
4
  export { ColorPalette, type ColorPaletteProps } from './components/ColorPalette';
5
5
  export { TocPanel, type TocPanelProps } from './components/TocPanel';
6
6
  export { CodeBlockView } from './components/CodeBlockView';
package/dist/index.js CHANGED
@@ -327,10 +327,10 @@ function nextComment(editor, dir = "next") {
327
327
  focusComment(editor, target);
328
328
  return target;
329
329
  }
330
- const MD_FILE_RE = /\.(md|markdown)$/i;
330
+ const MD_FILE_RE$1 = /\.(md|markdown)$/i;
331
331
  const MD_MIME_TYPES = ["text/markdown", "text/x-markdown", ""];
332
332
  async function insertMarkdownFiles(editor, files, pos) {
333
- const mdFiles = files.filter((f) => MD_FILE_RE.test(f.name));
333
+ const mdFiles = files.filter((f) => MD_FILE_RE$1.test(f.name));
334
334
  if (mdFiles.length === 0) return;
335
335
  const markdown = editor.markdown;
336
336
  if (!markdown) return;
@@ -461,6 +461,11 @@ const ImageIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
461
461
  /* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "2" }),
462
462
  /* @__PURE__ */ jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
463
463
  ] });
464
+ const ImportIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
465
+ /* @__PURE__ */ jsx("path", { d: "M12 3v12" }),
466
+ /* @__PURE__ */ jsx("path", { d: "m8 11 4 4 4-4" }),
467
+ /* @__PURE__ */ jsx("path", { d: "M8 5H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-4" })
468
+ ] });
464
469
  const ListUnorderedIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
465
470
  /* @__PURE__ */ jsx("line", { x1: "8", x2: "21", y1: "6", y2: "6" }),
466
471
  /* @__PURE__ */ jsx("line", { x1: "8", x2: "21", y1: "12", y2: "12" }),
@@ -572,6 +577,12 @@ const defaultToolbarLabels = {
572
577
  image: "Image",
573
578
  imageUploadFailed: "Image upload failed",
574
579
  importMarkdownFailed: "Markdown import failed",
580
+ importDocument: "Import",
581
+ importDocumentBusy: "Importing…",
582
+ importDocumentUploading: (percent) => `Uploading ${percent}%`,
583
+ importDocumentConverting: "Converting…",
584
+ importDocumentCancel: "Cancel",
585
+ importDocumentFailed: "Import failed",
575
586
  blockquote: "Blockquote",
576
587
  bulletList: "Bullet list",
577
588
  orderedList: "Ordered list",
@@ -980,46 +991,84 @@ function MarkdownPreview({
980
991
  }
981
992
  function insertMarkdown(editor, markdown, sources = []) {
982
993
  const prepared = enrichMarkdownCitations(markdown, sources);
983
- editor.chain().focus().insertContent(prepared, { contentType: "markdown" }).run();
994
+ if (!prepared) return;
995
+ if (tryInsertMarkdown(editor, prepared)) return;
996
+ for (const block of splitTopLevelBlocks(prepared)) {
997
+ if (tryInsertMarkdown(editor, block)) continue;
998
+ insertPlainParagraph(editor, stripToPlainText(block));
999
+ }
1000
+ }
1001
+ function tryInsertMarkdown(editor, markdown) {
1002
+ try {
1003
+ return editor.chain().focus().insertContent(markdown, { contentType: "markdown" }).run();
1004
+ } catch {
1005
+ return false;
1006
+ }
1007
+ }
1008
+ function insertPlainParagraph(editor, text) {
1009
+ if (!text) return;
1010
+ editor.chain().focus().insertContent({
1011
+ type: "paragraph",
1012
+ content: [{ type: "text", text }]
1013
+ }).run();
1014
+ }
1015
+ function splitTopLevelBlocks(markdown) {
1016
+ const out = [];
1017
+ for (const [i2, part] of markdown.split(/(```[\s\S]*?```)/).entries()) {
1018
+ if (!part) continue;
1019
+ if (i2 % 2 === 1) {
1020
+ out.push(part);
1021
+ continue;
1022
+ }
1023
+ for (const block of part.split(/\n{2,}/)) {
1024
+ if (block.trim()) out.push(block);
1025
+ }
1026
+ }
1027
+ return out;
984
1028
  }
985
- const toolbar = "_toolbar_16b09_2";
986
- const inner = "_inner_16b09_15";
987
- const btn = "_btn_16b09_27";
988
- const btnActive = "_btnActive_16b09_50";
989
- const tableBubble = "_tableBubble_16b09_66";
990
- const txtIcon = "_txtIcon_16b09_78";
991
- const colorIcon = "_colorIcon_16b09_86";
992
- const colorIconGlyph = "_colorIconGlyph_16b09_94";
993
- const colorIconBar = "_colorIconBar_16b09_100";
994
- const scriptTrigger = "_scriptTrigger_16b09_107";
995
- const scriptTriggerGlyph = "_scriptTriggerGlyph_16b09_127";
996
- const divider = "_divider_16b09_135";
997
- const styleTrigger = "_styleTrigger_16b09_144";
998
- const styleTriggerLabel = "_styleTriggerLabel_16b09_173";
999
- const styleTriggerCaret = "_styleTriggerCaret_16b09_181";
1000
- const styleItem = "_styleItem_16b09_187";
1001
- const styleIcon = "_styleIcon_16b09_193";
1002
- const scriptGlyph = "_scriptGlyph_16b09_203";
1003
- const menu = "_menu_16b09_215";
1004
- const menuItem = "_menuItem_16b09_226";
1005
- const menuItemSelected = "_menuItemSelected_16b09_252";
1006
- const popoverContent$1 = "_popoverContent_16b09_266";
1007
- const mathLayer = "_mathLayer_16b09_270";
1008
- const mathStack = "_mathStack_16b09_275";
1009
- const mathStackBlock = "_mathStackBlock_16b09_282";
1010
- const mathHint = "_mathHint_16b09_287";
1011
- const mathHintBlock = "_mathHintBlock_16b09_299";
1012
- const mathHintIcon = "_mathHintIcon_16b09_305";
1013
- const mathField = "_mathField_16b09_336";
1014
- const mathFieldBlock = "_mathFieldBlock_16b09_348";
1015
- const mathInput = "_mathInput_16b09_355";
1016
- const mathDone = "_mathDone_16b09_373";
1017
- const mathDoneKbd = "_mathDoneKbd_16b09_398";
1029
+ function stripToPlainText(markdown) {
1030
+ return markdown.replace(/!\[[^\]]*\]\([^)]+\)/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/^#{1,6}\s+/gm, "").replace(/^[ \t]*[-*+]\s+/gm, "").replace(/^[ \t]*\d+\.\s+/gm, "").replace(/[*_~`]+/g, "").replace(/<[^>]+>/g, "").replace(/\|/g, " ").replace(/\s+/g, " ").trim();
1031
+ }
1032
+ const toolbar = "_toolbar_1ybhg_2";
1033
+ const inner = "_inner_1ybhg_15";
1034
+ const btn = "_btn_1ybhg_27";
1035
+ const btnActive = "_btnActive_1ybhg_50";
1036
+ const importCancel = "_importCancel_1ybhg_66";
1037
+ const tableBubble = "_tableBubble_1ybhg_85";
1038
+ const txtIcon = "_txtIcon_1ybhg_97";
1039
+ const colorIcon = "_colorIcon_1ybhg_105";
1040
+ const colorIconGlyph = "_colorIconGlyph_1ybhg_113";
1041
+ const colorIconBar = "_colorIconBar_1ybhg_119";
1042
+ const scriptTrigger = "_scriptTrigger_1ybhg_126";
1043
+ const scriptTriggerGlyph = "_scriptTriggerGlyph_1ybhg_146";
1044
+ const divider = "_divider_1ybhg_154";
1045
+ const styleTrigger = "_styleTrigger_1ybhg_163";
1046
+ const styleTriggerLabel = "_styleTriggerLabel_1ybhg_192";
1047
+ const styleTriggerCaret = "_styleTriggerCaret_1ybhg_200";
1048
+ const styleItem = "_styleItem_1ybhg_206";
1049
+ const styleIcon = "_styleIcon_1ybhg_212";
1050
+ const scriptGlyph = "_scriptGlyph_1ybhg_222";
1051
+ const menu = "_menu_1ybhg_234";
1052
+ const menuItem = "_menuItem_1ybhg_245";
1053
+ const menuItemSelected = "_menuItemSelected_1ybhg_271";
1054
+ const popoverContent$1 = "_popoverContent_1ybhg_285";
1055
+ const mathLayer = "_mathLayer_1ybhg_289";
1056
+ const mathStack = "_mathStack_1ybhg_294";
1057
+ const mathStackBlock = "_mathStackBlock_1ybhg_301";
1058
+ const mathHint = "_mathHint_1ybhg_306";
1059
+ const mathHintBlock = "_mathHintBlock_1ybhg_318";
1060
+ const mathHintIcon = "_mathHintIcon_1ybhg_324";
1061
+ const mathField = "_mathField_1ybhg_355";
1062
+ const mathFieldBlock = "_mathFieldBlock_1ybhg_367";
1063
+ const mathInput = "_mathInput_1ybhg_374";
1064
+ const mathDone = "_mathDone_1ybhg_392";
1065
+ const mathDoneKbd = "_mathDoneKbd_1ybhg_417";
1018
1066
  const styles$3 = {
1019
1067
  toolbar,
1020
1068
  inner,
1021
1069
  btn,
1022
1070
  btnActive,
1071
+ importCancel,
1023
1072
  tableBubble,
1024
1073
  txtIcon,
1025
1074
  colorIcon,
@@ -1356,6 +1405,7 @@ function ToolbarButton({
1356
1405
  title,
1357
1406
  active: active2,
1358
1407
  disabled,
1408
+ busy,
1359
1409
  onClick,
1360
1410
  children
1361
1411
  }) {
@@ -1366,6 +1416,7 @@ function ToolbarButton({
1366
1416
  title,
1367
1417
  "aria-label": title,
1368
1418
  "aria-pressed": active2,
1419
+ "aria-busy": busy,
1369
1420
  disabled,
1370
1421
  className: `${styles$3.btn} ${active2 ? styles$3.btnActive : ""}`,
1371
1422
  onMouseDown: (e) => e.preventDefault(),
@@ -1471,10 +1522,15 @@ function ColorPopover({
1471
1522
  }
1472
1523
  const HEADING_LEVELS = [1, 2, 3, 4, 5, 6];
1473
1524
  const FONT_SIZES = ["12px", "14px", "16px", "18px", "20px", "24px", "30px"];
1525
+ const MD_FILE_RE = /\.(md|markdown)$/i;
1526
+ const MD_ACCEPT = ".md,.markdown,text/markdown";
1474
1527
  function EditorToolbar({
1475
1528
  editor,
1476
1529
  onImageUpload,
1477
1530
  onError,
1531
+ onImportDocument,
1532
+ importAccept,
1533
+ showImport = true,
1478
1534
  labels,
1479
1535
  extraToolbarItems,
1480
1536
  className
@@ -1586,20 +1642,62 @@ function EditorToolbar({
1586
1642
  onError == null ? void 0 : onError(err, "image");
1587
1643
  }
1588
1644
  };
1589
- const mdFileInputRef = useRef(null);
1590
- const handleMdFileChange = async (e) => {
1645
+ const importInputRef = useRef(null);
1646
+ const [importing, setImporting] = useState(
1647
+ null
1648
+ );
1649
+ const importAbortRef = useRef(null);
1650
+ useEffect(() => () => {
1651
+ var _a;
1652
+ return (_a = importAbortRef.current) == null ? void 0 : _a.abort();
1653
+ }, []);
1654
+ const handleImportChange = async (e) => {
1591
1655
  var _a;
1592
1656
  const file = (_a = e.target.files) == null ? void 0 : _a[0];
1593
1657
  e.target.value = "";
1594
1658
  if (!file) return;
1659
+ if (MD_FILE_RE.test(file.name)) {
1660
+ try {
1661
+ insertMarkdown(editor, await file.text());
1662
+ } catch (err) {
1663
+ console.error("markdown import failed:", err);
1664
+ onError == null ? void 0 : onError(err, "markdown");
1665
+ }
1666
+ return;
1667
+ }
1668
+ if (!onImportDocument) {
1669
+ onError == null ? void 0 : onError(new Error(`unsupported file: ${file.name}`), "import");
1670
+ return;
1671
+ }
1672
+ const ctrl = new AbortController();
1673
+ importAbortRef.current = ctrl;
1674
+ setImporting({ phase: "upload" });
1595
1675
  try {
1596
- const text = await file.text();
1597
- insertMarkdown(editor, text);
1676
+ const raw = await onImportDocument(file, {
1677
+ signal: ctrl.signal,
1678
+ onProgress: (p) => {
1679
+ if (!ctrl.signal.aborted) setImporting(p);
1680
+ }
1681
+ });
1682
+ const md = typeof raw === "string" ? raw : raw.markdown;
1683
+ const sources = typeof raw === "string" ? [] : raw.sources ?? [];
1684
+ insertMarkdown(editor, md, sources);
1598
1685
  } catch (err) {
1599
- console.error("markdown import failed:", err);
1600
- onError == null ? void 0 : onError(err, "markdown");
1686
+ if (!ctrl.signal.aborted) {
1687
+ console.error("document import failed:", err);
1688
+ onError == null ? void 0 : onError(err, "import");
1689
+ }
1690
+ } finally {
1691
+ if (importAbortRef.current === ctrl) importAbortRef.current = null;
1692
+ setImporting(null);
1601
1693
  }
1602
1694
  };
1695
+ const importTitle = (() => {
1696
+ if (!importing) return t.importDocument;
1697
+ if (importing.phase === "convert") return t.importDocumentConverting;
1698
+ const pct = Math.round((importing.ratio ?? 0) * 100);
1699
+ return t.importDocumentUploading(pct);
1700
+ })();
1603
1701
  const applyTextColor = (color) => {
1604
1702
  if (color) chain().setColor(color).run();
1605
1703
  else chain().unsetColor().run();
@@ -1951,6 +2049,34 @@ function EditorToolbar({
1951
2049
  }
1952
2050
  )
1953
2051
  ] }) : null,
2052
+ showImport ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
2053
+ /* @__PURE__ */ jsx(
2054
+ ToolbarButton,
2055
+ {
2056
+ title: importTitle,
2057
+ disabled: !!importing,
2058
+ busy: !!importing,
2059
+ onClick: () => {
2060
+ var _a;
2061
+ return (_a = importInputRef.current) == null ? void 0 : _a.click();
2062
+ },
2063
+ children: /* @__PURE__ */ jsx(ImportIcon, {})
2064
+ }
2065
+ ),
2066
+ importing ? /* @__PURE__ */ jsx(
2067
+ "button",
2068
+ {
2069
+ type: "button",
2070
+ className: styles$3.importCancel,
2071
+ onMouseDown: (e) => e.preventDefault(),
2072
+ onClick: () => {
2073
+ var _a;
2074
+ return (_a = importAbortRef.current) == null ? void 0 : _a.abort();
2075
+ },
2076
+ children: t.importDocumentCancel
2077
+ }
2078
+ ) : null
2079
+ ] }) : null,
1954
2080
  /* @__PURE__ */ jsx(
1955
2081
  ToolbarButton,
1956
2082
  {
@@ -2033,13 +2159,6 @@ function EditorToolbar({
2033
2159
  ] })
2034
2160
  }
2035
2161
  ),
2036
- /* @__PURE__ */ jsx(MenuItem, { onSelect: () => {
2037
- var _a;
2038
- return (_a = mdFileInputRef.current) == null ? void 0 : _a.click();
2039
- }, children: /* @__PURE__ */ jsxs("span", { className: styles$3.styleItem, children: [
2040
- /* @__PURE__ */ jsx("span", { className: styles$3.styleIcon, children: "M↓" }),
2041
- t.importMarkdown
2042
- ] }) }),
2043
2162
  extraToolbarItems == null ? void 0 : extraToolbarItems.map((item2) => /* @__PURE__ */ jsx(
2044
2163
  MenuItem,
2045
2164
  {
@@ -2058,16 +2177,16 @@ function EditorToolbar({
2058
2177
  ] })
2059
2178
  }
2060
2179
  ),
2061
- /* @__PURE__ */ jsx(
2180
+ showImport ? /* @__PURE__ */ jsx(
2062
2181
  "input",
2063
2182
  {
2064
- ref: mdFileInputRef,
2183
+ ref: importInputRef,
2065
2184
  type: "file",
2066
- accept: ".md,.markdown,text/markdown",
2185
+ accept: onImportDocument && importAccept ? `${MD_ACCEPT},${importAccept}` : MD_ACCEPT,
2067
2186
  hidden: true,
2068
- onChange: handleMdFileChange
2187
+ onChange: handleImportChange
2069
2188
  }
2070
- ),
2189
+ ) : null,
2071
2190
  mathEdit ? /* @__PURE__ */ jsx(
2072
2191
  MathEditorPopover,
2073
2192
  {
@@ -2481,6 +2600,7 @@ export {
2481
2600
  CommentPopover,
2482
2601
  EditorToolbar,
2483
2602
  ImageIcon,
2603
+ ImportIcon,
2484
2604
  ItalicIcon,
2485
2605
  LinkIcon,
2486
2606
  ListChecksIcon,