tiptap-markdown-react 0.8.6 → 0.8.7
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 +5 -2
- package/dist/components/EditorToolbar.d.ts +32 -2
- package/dist/icons/index.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +171 -54
- package/dist/index.js.map +1 -1
- package/dist/insertMarkdown.d.ts +3 -0
- package/dist/insertMarkdown.test.d.ts +1 -0
- package/dist/labels.d.ts +9 -0
- package/dist/style.css +70 -51
- package/package.json +1 -1
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** —
|
|
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
|
|
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;
|
package/dist/icons/index.d.ts
CHANGED
|
@@ -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,10 @@ 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
|
+
importDocumentCancel: "Cancel",
|
|
583
|
+
importDocumentFailed: "Import failed",
|
|
575
584
|
blockquote: "Blockquote",
|
|
576
585
|
bulletList: "Bullet list",
|
|
577
586
|
orderedList: "Ordered list",
|
|
@@ -980,46 +989,84 @@ function MarkdownPreview({
|
|
|
980
989
|
}
|
|
981
990
|
function insertMarkdown(editor, markdown, sources = []) {
|
|
982
991
|
const prepared = enrichMarkdownCitations(markdown, sources);
|
|
983
|
-
|
|
992
|
+
if (!prepared) return;
|
|
993
|
+
if (tryInsertMarkdown(editor, prepared)) return;
|
|
994
|
+
for (const block of splitTopLevelBlocks(prepared)) {
|
|
995
|
+
if (tryInsertMarkdown(editor, block)) continue;
|
|
996
|
+
insertPlainParagraph(editor, stripToPlainText(block));
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
function tryInsertMarkdown(editor, markdown) {
|
|
1000
|
+
try {
|
|
1001
|
+
return editor.chain().focus().insertContent(markdown, { contentType: "markdown" }).run();
|
|
1002
|
+
} catch {
|
|
1003
|
+
return false;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
function insertPlainParagraph(editor, text) {
|
|
1007
|
+
if (!text) return;
|
|
1008
|
+
editor.chain().focus().insertContent({
|
|
1009
|
+
type: "paragraph",
|
|
1010
|
+
content: [{ type: "text", text }]
|
|
1011
|
+
}).run();
|
|
1012
|
+
}
|
|
1013
|
+
function splitTopLevelBlocks(markdown) {
|
|
1014
|
+
const out = [];
|
|
1015
|
+
for (const [i2, part] of markdown.split(/(```[\s\S]*?```)/).entries()) {
|
|
1016
|
+
if (!part) continue;
|
|
1017
|
+
if (i2 % 2 === 1) {
|
|
1018
|
+
out.push(part);
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
for (const block of part.split(/\n{2,}/)) {
|
|
1022
|
+
if (block.trim()) out.push(block);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return out;
|
|
984
1026
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
const
|
|
989
|
-
const
|
|
990
|
-
const
|
|
991
|
-
const
|
|
992
|
-
const
|
|
993
|
-
const
|
|
994
|
-
const
|
|
995
|
-
const
|
|
996
|
-
const
|
|
997
|
-
const
|
|
998
|
-
const
|
|
999
|
-
const
|
|
1000
|
-
const
|
|
1001
|
-
const
|
|
1002
|
-
const
|
|
1003
|
-
const
|
|
1004
|
-
const
|
|
1005
|
-
const
|
|
1006
|
-
const
|
|
1007
|
-
const
|
|
1008
|
-
const
|
|
1009
|
-
const
|
|
1010
|
-
const
|
|
1011
|
-
const
|
|
1012
|
-
const
|
|
1013
|
-
const
|
|
1014
|
-
const
|
|
1015
|
-
const
|
|
1016
|
-
const
|
|
1017
|
-
const
|
|
1027
|
+
function stripToPlainText(markdown) {
|
|
1028
|
+
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();
|
|
1029
|
+
}
|
|
1030
|
+
const toolbar = "_toolbar_1ybhg_2";
|
|
1031
|
+
const inner = "_inner_1ybhg_15";
|
|
1032
|
+
const btn = "_btn_1ybhg_27";
|
|
1033
|
+
const btnActive = "_btnActive_1ybhg_50";
|
|
1034
|
+
const importCancel = "_importCancel_1ybhg_66";
|
|
1035
|
+
const tableBubble = "_tableBubble_1ybhg_85";
|
|
1036
|
+
const txtIcon = "_txtIcon_1ybhg_97";
|
|
1037
|
+
const colorIcon = "_colorIcon_1ybhg_105";
|
|
1038
|
+
const colorIconGlyph = "_colorIconGlyph_1ybhg_113";
|
|
1039
|
+
const colorIconBar = "_colorIconBar_1ybhg_119";
|
|
1040
|
+
const scriptTrigger = "_scriptTrigger_1ybhg_126";
|
|
1041
|
+
const scriptTriggerGlyph = "_scriptTriggerGlyph_1ybhg_146";
|
|
1042
|
+
const divider = "_divider_1ybhg_154";
|
|
1043
|
+
const styleTrigger = "_styleTrigger_1ybhg_163";
|
|
1044
|
+
const styleTriggerLabel = "_styleTriggerLabel_1ybhg_192";
|
|
1045
|
+
const styleTriggerCaret = "_styleTriggerCaret_1ybhg_200";
|
|
1046
|
+
const styleItem = "_styleItem_1ybhg_206";
|
|
1047
|
+
const styleIcon = "_styleIcon_1ybhg_212";
|
|
1048
|
+
const scriptGlyph = "_scriptGlyph_1ybhg_222";
|
|
1049
|
+
const menu = "_menu_1ybhg_234";
|
|
1050
|
+
const menuItem = "_menuItem_1ybhg_245";
|
|
1051
|
+
const menuItemSelected = "_menuItemSelected_1ybhg_271";
|
|
1052
|
+
const popoverContent$1 = "_popoverContent_1ybhg_285";
|
|
1053
|
+
const mathLayer = "_mathLayer_1ybhg_289";
|
|
1054
|
+
const mathStack = "_mathStack_1ybhg_294";
|
|
1055
|
+
const mathStackBlock = "_mathStackBlock_1ybhg_301";
|
|
1056
|
+
const mathHint = "_mathHint_1ybhg_306";
|
|
1057
|
+
const mathHintBlock = "_mathHintBlock_1ybhg_318";
|
|
1058
|
+
const mathHintIcon = "_mathHintIcon_1ybhg_324";
|
|
1059
|
+
const mathField = "_mathField_1ybhg_355";
|
|
1060
|
+
const mathFieldBlock = "_mathFieldBlock_1ybhg_367";
|
|
1061
|
+
const mathInput = "_mathInput_1ybhg_374";
|
|
1062
|
+
const mathDone = "_mathDone_1ybhg_392";
|
|
1063
|
+
const mathDoneKbd = "_mathDoneKbd_1ybhg_417";
|
|
1018
1064
|
const styles$3 = {
|
|
1019
1065
|
toolbar,
|
|
1020
1066
|
inner,
|
|
1021
1067
|
btn,
|
|
1022
1068
|
btnActive,
|
|
1069
|
+
importCancel,
|
|
1023
1070
|
tableBubble,
|
|
1024
1071
|
txtIcon,
|
|
1025
1072
|
colorIcon,
|
|
@@ -1356,6 +1403,7 @@ function ToolbarButton({
|
|
|
1356
1403
|
title,
|
|
1357
1404
|
active: active2,
|
|
1358
1405
|
disabled,
|
|
1406
|
+
busy,
|
|
1359
1407
|
onClick,
|
|
1360
1408
|
children
|
|
1361
1409
|
}) {
|
|
@@ -1366,6 +1414,7 @@ function ToolbarButton({
|
|
|
1366
1414
|
title,
|
|
1367
1415
|
"aria-label": title,
|
|
1368
1416
|
"aria-pressed": active2,
|
|
1417
|
+
"aria-busy": busy,
|
|
1369
1418
|
disabled,
|
|
1370
1419
|
className: `${styles$3.btn} ${active2 ? styles$3.btnActive : ""}`,
|
|
1371
1420
|
onMouseDown: (e) => e.preventDefault(),
|
|
@@ -1471,10 +1520,15 @@ function ColorPopover({
|
|
|
1471
1520
|
}
|
|
1472
1521
|
const HEADING_LEVELS = [1, 2, 3, 4, 5, 6];
|
|
1473
1522
|
const FONT_SIZES = ["12px", "14px", "16px", "18px", "20px", "24px", "30px"];
|
|
1523
|
+
const MD_FILE_RE = /\.(md|markdown)$/i;
|
|
1524
|
+
const MD_ACCEPT = ".md,.markdown,text/markdown";
|
|
1474
1525
|
function EditorToolbar({
|
|
1475
1526
|
editor,
|
|
1476
1527
|
onImageUpload,
|
|
1477
1528
|
onError,
|
|
1529
|
+
onImportDocument,
|
|
1530
|
+
importAccept,
|
|
1531
|
+
showImport = true,
|
|
1478
1532
|
labels,
|
|
1479
1533
|
extraToolbarItems,
|
|
1480
1534
|
className
|
|
@@ -1586,20 +1640,61 @@ function EditorToolbar({
|
|
|
1586
1640
|
onError == null ? void 0 : onError(err, "image");
|
|
1587
1641
|
}
|
|
1588
1642
|
};
|
|
1589
|
-
const
|
|
1590
|
-
const
|
|
1643
|
+
const importInputRef = useRef(null);
|
|
1644
|
+
const [importing, setImporting] = useState(
|
|
1645
|
+
null
|
|
1646
|
+
);
|
|
1647
|
+
const importAbortRef = useRef(null);
|
|
1648
|
+
useEffect(() => () => {
|
|
1649
|
+
var _a;
|
|
1650
|
+
return (_a = importAbortRef.current) == null ? void 0 : _a.abort();
|
|
1651
|
+
}, []);
|
|
1652
|
+
const handleImportChange = async (e) => {
|
|
1591
1653
|
var _a;
|
|
1592
1654
|
const file = (_a = e.target.files) == null ? void 0 : _a[0];
|
|
1593
1655
|
e.target.value = "";
|
|
1594
1656
|
if (!file) return;
|
|
1657
|
+
if (MD_FILE_RE.test(file.name)) {
|
|
1658
|
+
try {
|
|
1659
|
+
insertMarkdown(editor, await file.text());
|
|
1660
|
+
} catch (err) {
|
|
1661
|
+
console.error("markdown import failed:", err);
|
|
1662
|
+
onError == null ? void 0 : onError(err, "markdown");
|
|
1663
|
+
}
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
if (!onImportDocument) {
|
|
1667
|
+
onError == null ? void 0 : onError(new Error(`unsupported file: ${file.name}`), "import");
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
const ctrl = new AbortController();
|
|
1671
|
+
importAbortRef.current = ctrl;
|
|
1672
|
+
setImporting({ phase: "upload" });
|
|
1595
1673
|
try {
|
|
1596
|
-
const
|
|
1597
|
-
|
|
1674
|
+
const raw = await onImportDocument(file, {
|
|
1675
|
+
signal: ctrl.signal,
|
|
1676
|
+
onProgress: (p) => {
|
|
1677
|
+
if (!ctrl.signal.aborted) setImporting(p);
|
|
1678
|
+
}
|
|
1679
|
+
});
|
|
1680
|
+
const md = typeof raw === "string" ? raw : raw.markdown;
|
|
1681
|
+
const sources = typeof raw === "string" ? [] : raw.sources ?? [];
|
|
1682
|
+
insertMarkdown(editor, md, sources);
|
|
1598
1683
|
} catch (err) {
|
|
1599
|
-
|
|
1600
|
-
|
|
1684
|
+
if (!ctrl.signal.aborted) {
|
|
1685
|
+
console.error("document import failed:", err);
|
|
1686
|
+
onError == null ? void 0 : onError(err, "import");
|
|
1687
|
+
}
|
|
1688
|
+
} finally {
|
|
1689
|
+
if (importAbortRef.current === ctrl) importAbortRef.current = null;
|
|
1690
|
+
setImporting(null);
|
|
1601
1691
|
}
|
|
1602
1692
|
};
|
|
1693
|
+
const importTitle = (() => {
|
|
1694
|
+
if (!importing) return t.importDocument;
|
|
1695
|
+
const pct = importing.phase === "upload" && importing.ratio != null ? ` ${Math.round(importing.ratio * 100)}%` : "";
|
|
1696
|
+
return `${t.importDocumentBusy}${pct}`;
|
|
1697
|
+
})();
|
|
1603
1698
|
const applyTextColor = (color) => {
|
|
1604
1699
|
if (color) chain().setColor(color).run();
|
|
1605
1700
|
else chain().unsetColor().run();
|
|
@@ -1951,6 +2046,34 @@ function EditorToolbar({
|
|
|
1951
2046
|
}
|
|
1952
2047
|
)
|
|
1953
2048
|
] }) : null,
|
|
2049
|
+
showImport ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
2050
|
+
/* @__PURE__ */ jsx(
|
|
2051
|
+
ToolbarButton,
|
|
2052
|
+
{
|
|
2053
|
+
title: importTitle,
|
|
2054
|
+
disabled: !!importing,
|
|
2055
|
+
busy: !!importing,
|
|
2056
|
+
onClick: () => {
|
|
2057
|
+
var _a;
|
|
2058
|
+
return (_a = importInputRef.current) == null ? void 0 : _a.click();
|
|
2059
|
+
},
|
|
2060
|
+
children: /* @__PURE__ */ jsx(ImportIcon, {})
|
|
2061
|
+
}
|
|
2062
|
+
),
|
|
2063
|
+
importing ? /* @__PURE__ */ jsx(
|
|
2064
|
+
"button",
|
|
2065
|
+
{
|
|
2066
|
+
type: "button",
|
|
2067
|
+
className: styles$3.importCancel,
|
|
2068
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
2069
|
+
onClick: () => {
|
|
2070
|
+
var _a;
|
|
2071
|
+
return (_a = importAbortRef.current) == null ? void 0 : _a.abort();
|
|
2072
|
+
},
|
|
2073
|
+
children: t.importDocumentCancel
|
|
2074
|
+
}
|
|
2075
|
+
) : null
|
|
2076
|
+
] }) : null,
|
|
1954
2077
|
/* @__PURE__ */ jsx(
|
|
1955
2078
|
ToolbarButton,
|
|
1956
2079
|
{
|
|
@@ -2033,13 +2156,6 @@ function EditorToolbar({
|
|
|
2033
2156
|
] })
|
|
2034
2157
|
}
|
|
2035
2158
|
),
|
|
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
2159
|
extraToolbarItems == null ? void 0 : extraToolbarItems.map((item2) => /* @__PURE__ */ jsx(
|
|
2044
2160
|
MenuItem,
|
|
2045
2161
|
{
|
|
@@ -2058,16 +2174,16 @@ function EditorToolbar({
|
|
|
2058
2174
|
] })
|
|
2059
2175
|
}
|
|
2060
2176
|
),
|
|
2061
|
-
/* @__PURE__ */ jsx(
|
|
2177
|
+
showImport ? /* @__PURE__ */ jsx(
|
|
2062
2178
|
"input",
|
|
2063
2179
|
{
|
|
2064
|
-
ref:
|
|
2180
|
+
ref: importInputRef,
|
|
2065
2181
|
type: "file",
|
|
2066
|
-
accept:
|
|
2182
|
+
accept: onImportDocument && importAccept ? `${MD_ACCEPT},${importAccept}` : MD_ACCEPT,
|
|
2067
2183
|
hidden: true,
|
|
2068
|
-
onChange:
|
|
2184
|
+
onChange: handleImportChange
|
|
2069
2185
|
}
|
|
2070
|
-
),
|
|
2186
|
+
) : null,
|
|
2071
2187
|
mathEdit ? /* @__PURE__ */ jsx(
|
|
2072
2188
|
MathEditorPopover,
|
|
2073
2189
|
{
|
|
@@ -2481,6 +2597,7 @@ export {
|
|
|
2481
2597
|
CommentPopover,
|
|
2482
2598
|
EditorToolbar,
|
|
2483
2599
|
ImageIcon,
|
|
2600
|
+
ImportIcon,
|
|
2484
2601
|
ItalicIcon,
|
|
2485
2602
|
LinkIcon,
|
|
2486
2603
|
ListChecksIcon,
|