@rtdui/editor
Version:
React rich text editor based on tiptap
226 lines (224 loc) • 10.2 kB
JavaScript
'use client';
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
const require_uploadImageWithResizable = require('./tiptap_extensions/extension-image-upload/uploadImageWithResizable.cjs');
const require_markdownPaste = require('./tiptap_extensions/extension-markdown-paste/markdownPaste.cjs');
const require_math_katex_inline = require('./tiptap_extensions/extension-math/math-katex-inline.cjs');
const require_math_katex_block = require('./tiptap_extensions/extension-math/math-katex-block.cjs');
const require_code_block_shiki = require('./tiptap_extensions/extension-code-block-shiki/code-block-shiki.cjs');
require('./tiptap.cjs');
const require_Toolbar = require('./toolbar/Toolbar.cjs');
require('./toolbar/index.cjs');
let react = require("react");
let clsx = require("clsx");
clsx = require_runtime.__toESM(clsx);
let _tiptap_react = require("@tiptap/react");
let _tiptap_react_menus = require("@tiptap/react/menus");
let _tabler_icons_react = require("@tabler/icons-react");
let react_jsx_runtime = require("react/jsx-runtime");
let _tiptap_starter_kit = require("@tiptap/starter-kit");
let _tiptap_extension_table = require("@tiptap/extension-table");
let _tiptap_extension_list = require("@tiptap/extension-list");
let _tiptap_extension_superscript = require("@tiptap/extension-superscript");
let _tiptap_extension_subscript = require("@tiptap/extension-subscript");
let _tiptap_extension_highlight = require("@tiptap/extension-highlight");
let _tiptap_extensions = require("@tiptap/extensions");
let _tiptap_extension_text_align = require("@tiptap/extension-text-align");
let _tiptap_extension_text_style = require("@tiptap/extension-text-style");
//#region packages/editor/src/RichTextEditor/RichTextEditor.tsx
function RichTextEditor(props) {
const { ref, slots, editable = true, placeholder = "输入内容或者从剪贴板粘贴, 复制粘贴支持Markdown", limit, uploadImageUrl, imageResizable = true, className, ...other } = props;
const editorOptions = {
extensions: [
_tiptap_starter_kit.StarterKit.configure({
codeBlock: false,
link: { openOnClick: !editable }
}),
_tiptap_extension_table.TableKit.configure({
table: { resizable: true },
tableCell: { HTMLAttributes: { class: "not-prose" } },
tableHeader: { HTMLAttributes: { class: "not-prose" } }
}),
_tiptap_extension_list.TaskItem.configure({ nested: true }),
_tiptap_extension_list.TaskList,
_tiptap_extension_superscript.Superscript,
_tiptap_extension_subscript.Subscript,
_tiptap_extension_highlight.Highlight,
_tiptap_extensions.Placeholder.configure({ placeholder }),
_tiptap_extension_text_align.TextAlign.configure({ types: [
"heading",
"paragraph",
"tableHeader",
"tableCell"
] }),
_tiptap_extension_text_style.TextStyleKit,
require_code_block_shiki.CodeBlockShiki,
require_uploadImageWithResizable.UploadImageWithResizable.configure({
resizable: imageResizable,
inline: true,
url: uploadImageUrl,
method: "post"
}),
require_markdownPaste.MarkdownPaste,
require_math_katex_inline.MathKatexInline,
require_math_katex_block.MathKatexBlock
],
editable
};
if (limit) editorOptions.extensions?.push(_tiptap_extensions.CharacterCount.configure({ limit }));
const editor = (0, _tiptap_react.useEditor)(editorOptions);
const { charactersCount, wordsCount } = (0, _tiptap_react.useEditorState)({
editor,
selector: (context) => ({
charactersCount: context.editor?.storage?.characterCount?.characters(),
wordsCount: context.editor?.storage?.characterCount?.words()
})
});
(0, react.useImperativeHandle)(ref, () => ({
getJSON: () => {
if (editor) return editor.getJSON();
return null;
},
setContent: (jsonOrHtml) => {
if (editor) editor.commands.setContent(jsonOrHtml);
}
}));
if (!editor) return null;
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
...other,
className: (0, clsx.default)(className),
children: [
editable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Toolbar.Toolbar, {
editor,
className: (0, clsx.default)("editor-content", slots?.toolbar)
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tiptap_react_menus.FloatingMenu, {
editor,
shouldShow: ({ editor }) => editor.isActive("tableCell") || editor.isActive("tableHeader"),
options: { autoPlacement: { allowedPlacements: ["top-start", "top-end"] } },
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
className: "join",
children: [
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "插入表格",
onClick: () => editor.chain().focus().insertTable({
rows: 3,
cols: 3,
withHeaderRow: true
}).run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconTable, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "左侧插入列",
onClick: () => editor.chain().focus().addColumnBefore().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconColumnInsertLeft, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "右侧插入列",
onClick: () => editor.chain().focus().addColumnAfter().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconColumnInsertRight, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "删除列",
onClick: () => editor.chain().focus().deleteColumn().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconContainerOff, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "上方插入行",
onClick: () => editor.chain().focus().addRowBefore().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconRowInsertTop, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "下方插入行",
onClick: () => editor.chain().focus().addRowAfter().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconRowInsertBottom, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "删除行",
onClick: () => editor.chain().focus().deleteRow().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconContainerOff, {
className: "rotate-90",
stroke: 1
})
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "删除表格",
onClick: () => editor.chain().focus().deleteTable().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconTableOff, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "合并单元格",
onClick: () => editor.chain().focus().mergeCells().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconViewportNarrow, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "拆分单元格",
onClick: () => editor.chain().focus().splitCell().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconArrowBarBoth, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "合并或拆分",
onClick: () => editor.chain().focus().mergeOrSplit().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconSquareToggle, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "首列切换",
onClick: () => editor.chain().focus().toggleHeaderColumn().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconBoxAlignLeft, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "首行切换",
onClick: () => editor.chain().focus().toggleHeaderRow().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconBoxAlignTop, { stroke: 1 })
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
type: "button",
className: "join-item btn btn-sm px-1",
title: "单元格切换行头样式",
onClick: () => editor.chain().focus().toggleHeaderCell().run(),
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tabler_icons_react.IconBoxAlignTopLeft, { stroke: 1 })
})
]
})
})] }),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_tiptap_react.EditorContent, {
editor,
className: (0, clsx.default)("editor-content prose max-w-none! overflow-y-auto", slots?.content)
}),
limit && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
className: "character-count text-xs flex flex-row-reverse px-1.5",
children: [
charactersCount,
" / ",
limit
]
})
]
});
}
//#endregion
exports.RichTextEditor = RichTextEditor;