rte-react 0.1.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/README.md +78 -0
- package/dist/editor-XH5ZEVLH.css +288 -0
- package/dist/index.d.mts +30 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +604 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +567 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +64 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
RichEditor: () => RichEditor_default
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
|
|
37
|
+
// src/components/RichEditor.tsx
|
|
38
|
+
var import_react4 = require("@tiptap/react");
|
|
39
|
+
|
|
40
|
+
// src/hooks/useEditor.ts
|
|
41
|
+
var import_react = require("react");
|
|
42
|
+
var import_react2 = require("@tiptap/react");
|
|
43
|
+
var import_starter_kit = __toESM(require("@tiptap/starter-kit"));
|
|
44
|
+
var import_extension_underline = __toESM(require("@tiptap/extension-underline"));
|
|
45
|
+
var import_extension_text_style2 = __toESM(require("@tiptap/extension-text-style"));
|
|
46
|
+
var import_extension_link = __toESM(require("@tiptap/extension-link"));
|
|
47
|
+
var import_extension_image = __toESM(require("@tiptap/extension-image"));
|
|
48
|
+
var import_extension_table = __toESM(require("@tiptap/extension-table"));
|
|
49
|
+
var import_extension_table_row = __toESM(require("@tiptap/extension-table-row"));
|
|
50
|
+
var import_extension_table_cell = __toESM(require("@tiptap/extension-table-cell"));
|
|
51
|
+
var import_extension_table_header = __toESM(require("@tiptap/extension-table-header"));
|
|
52
|
+
var import_extension_placeholder = __toESM(require("@tiptap/extension-placeholder"));
|
|
53
|
+
|
|
54
|
+
// src/extensions/FontSize.ts
|
|
55
|
+
var import_core = require("@tiptap/core");
|
|
56
|
+
var import_extension_text_style = require("@tiptap/extension-text-style");
|
|
57
|
+
var FontSize = import_core.Extension.create({
|
|
58
|
+
name: "fontSize",
|
|
59
|
+
addOptions() {
|
|
60
|
+
return {
|
|
61
|
+
types: ["textStyle"]
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
addGlobalAttributes() {
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
types: this.options.types,
|
|
68
|
+
attributes: {
|
|
69
|
+
fontSize: {
|
|
70
|
+
default: null,
|
|
71
|
+
parseHTML: (element) => element.style.fontSize || null,
|
|
72
|
+
renderHTML: (attributes) => {
|
|
73
|
+
if (!attributes.fontSize) return {};
|
|
74
|
+
return { style: `font-size: ${attributes.fontSize}` };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
];
|
|
80
|
+
},
|
|
81
|
+
addCommands() {
|
|
82
|
+
return {
|
|
83
|
+
setFontSize: (fontSize) => ({ chain }) => {
|
|
84
|
+
return chain().setMark("textStyle", { fontSize }).run();
|
|
85
|
+
},
|
|
86
|
+
unsetFontSize: () => ({ chain }) => {
|
|
87
|
+
return chain().setMark("textStyle", { fontSize: null }).removeEmptyTextStyle().run();
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
var FontSize_default = FontSize;
|
|
93
|
+
|
|
94
|
+
// src/hooks/useEditor.ts
|
|
95
|
+
var useEditor = ({
|
|
96
|
+
value = "",
|
|
97
|
+
onChange,
|
|
98
|
+
placeholder = "Start typing...",
|
|
99
|
+
editable = true
|
|
100
|
+
}) => {
|
|
101
|
+
const editor = (0, import_react2.useEditor)({
|
|
102
|
+
extensions: [
|
|
103
|
+
import_starter_kit.default,
|
|
104
|
+
import_extension_underline.default,
|
|
105
|
+
import_extension_text_style2.default,
|
|
106
|
+
FontSize_default,
|
|
107
|
+
import_extension_link.default.configure({ openOnClick: false }),
|
|
108
|
+
import_extension_image.default,
|
|
109
|
+
import_extension_table.default.configure({ resizable: true }),
|
|
110
|
+
import_extension_table_row.default,
|
|
111
|
+
import_extension_table_cell.default,
|
|
112
|
+
import_extension_table_header.default,
|
|
113
|
+
import_extension_placeholder.default.configure({ placeholder })
|
|
114
|
+
],
|
|
115
|
+
content: value,
|
|
116
|
+
editable,
|
|
117
|
+
onUpdate({ editor: editor2 }) {
|
|
118
|
+
onChange == null ? void 0 : onChange(editor2.getHTML());
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
(0, import_react.useEffect)(() => {
|
|
122
|
+
if (editor && value !== editor.getHTML()) {
|
|
123
|
+
editor.commands.setContent(value, false);
|
|
124
|
+
}
|
|
125
|
+
}, [value, editor]);
|
|
126
|
+
(0, import_react.useEffect)(() => {
|
|
127
|
+
if (editor) {
|
|
128
|
+
editor.setEditable(editable != null ? editable : true);
|
|
129
|
+
}
|
|
130
|
+
}, [editable, editor]);
|
|
131
|
+
return editor;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// src/components/Toolbar.tsx
|
|
135
|
+
var import_react3 = require("react");
|
|
136
|
+
|
|
137
|
+
// src/components/toolbar/ToolbarButton.tsx
|
|
138
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
139
|
+
var ToolbarButton = ({
|
|
140
|
+
onClick,
|
|
141
|
+
isActive = false,
|
|
142
|
+
disabled = false,
|
|
143
|
+
title,
|
|
144
|
+
children
|
|
145
|
+
}) => {
|
|
146
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
147
|
+
"button",
|
|
148
|
+
{
|
|
149
|
+
type: "button",
|
|
150
|
+
onMouseDown: (e) => {
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
onClick();
|
|
153
|
+
},
|
|
154
|
+
disabled,
|
|
155
|
+
title,
|
|
156
|
+
"aria-label": title,
|
|
157
|
+
"aria-pressed": isActive,
|
|
158
|
+
className: [
|
|
159
|
+
"rre-toolbar-btn",
|
|
160
|
+
isActive ? "rre-toolbar-btn--active" : "",
|
|
161
|
+
disabled ? "rre-toolbar-btn--disabled" : ""
|
|
162
|
+
].filter(Boolean).join(" "),
|
|
163
|
+
children
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
var ToolbarButton_default = ToolbarButton;
|
|
168
|
+
|
|
169
|
+
// src/components/toolbar/tools.ts
|
|
170
|
+
var toolDefinitions = [
|
|
171
|
+
{ name: "bold", title: "Bold", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/><path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/></svg>' },
|
|
172
|
+
{ name: "italic", title: "Italic", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg>' },
|
|
173
|
+
{ name: "underline", title: "Underline", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3"/><line x1="4" y1="21" x2="20" y2="21"/></svg>' },
|
|
174
|
+
{ name: "strikethrough", title: "Strikethrough", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M17.3 4.9c-2.3-.6-4.4-1-6.2-.9-2.7 0-5.3.7-5.3 3.6 0 1.5 1.8 3.3 6.5 3.9h.1"/><path d="M21.8 12H2.2"/><path d="M6.7 19.1c2.3.6 4.4 1 6.2.9 2.7 0 5.3-.7 5.3-3.6 0-1.5-1.8-3.3-6.5-3.9H11"/></svg>' },
|
|
175
|
+
{ name: "heading1", title: "Heading 1", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="m17 12 3-2v8"/></svg>' },
|
|
176
|
+
{ name: "heading2", title: "Heading 2", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1"/></svg>' },
|
|
177
|
+
{ name: "heading3", title: "Heading 3", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2"/><path d="M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2"/></svg>' },
|
|
178
|
+
{ name: "heading4", title: "Heading 4", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="M17 10v4h4"/><path d="M21 10v8"/></svg>' },
|
|
179
|
+
{ name: "heading5", title: "Heading 5", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="M17 10h3"/><path d="M17 14h2a2 2 0 0 1 0 4h-2v-4z"/><path d="M17 10v4"/></svg>' },
|
|
180
|
+
{ name: "heading6", title: "Heading 6", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><circle cx="19" cy="16" r="2"/><path d="M20 10c-2 2-3 3.5-3 6"/></svg>' },
|
|
181
|
+
{ name: "bulletList", title: "Bullet List", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>' },
|
|
182
|
+
{ name: "orderedList", title: "Ordered List", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/></svg>' },
|
|
183
|
+
{ name: "blockquote", title: "Blockquote", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z"/><path d="M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z"/></svg>' },
|
|
184
|
+
{ name: "codeBlock", title: "Code Block", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>' },
|
|
185
|
+
{ name: "link", title: "Link", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>' },
|
|
186
|
+
{ name: "image", title: "Image", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>' },
|
|
187
|
+
{ name: "table", title: "Table", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="15" y1="3" x2="15" y2="21"/></svg>' },
|
|
188
|
+
{ name: "undo", title: "Undo", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13"/></svg>' },
|
|
189
|
+
{ name: "redo", title: "Redo", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M21 7v6h-6"/><path d="M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13"/></svg>' }
|
|
190
|
+
];
|
|
191
|
+
var getToolDefinition = (name) => toolDefinitions.find((t) => t.name === name);
|
|
192
|
+
|
|
193
|
+
// src/components/Toolbar.tsx
|
|
194
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
195
|
+
var FONT_SIZES = ["12", "14", "16", "18", "20", "24", "28", "32", "36", "48"];
|
|
196
|
+
var MAX_IMAGE_SIZE = 10 * 1024 * 1024;
|
|
197
|
+
var Toolbar = ({ editor, toolbar, className }) => {
|
|
198
|
+
var _a;
|
|
199
|
+
const [popup, setPopup] = (0, import_react3.useState)(null);
|
|
200
|
+
const [linkUrl, setLinkUrl] = (0, import_react3.useState)("");
|
|
201
|
+
const [linkText, setLinkText] = (0, import_react3.useState)("");
|
|
202
|
+
const [tableRows, setTableRows] = (0, import_react3.useState)("3");
|
|
203
|
+
const [tableCols, setTableCols] = (0, import_react3.useState)("3");
|
|
204
|
+
const popupRef = (0, import_react3.useRef)(null);
|
|
205
|
+
const imageInputRef = (0, import_react3.useRef)(null);
|
|
206
|
+
const hasSelection = !editor.state.selection.empty;
|
|
207
|
+
const currentFontSize = ((_a = editor.getAttributes("textStyle").fontSize) == null ? void 0 : _a.replace("px", "")) || "16";
|
|
208
|
+
(0, import_react3.useEffect)(() => {
|
|
209
|
+
const handleClickOutside = (e) => {
|
|
210
|
+
if (popupRef.current && !popupRef.current.contains(e.target)) {
|
|
211
|
+
setPopup(null);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
if (popup) document.addEventListener("mousedown", handleClickOutside);
|
|
215
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
216
|
+
}, [popup]);
|
|
217
|
+
const handleFontSize = (size) => {
|
|
218
|
+
editor.chain().focus().setFontSize(`${size}px`).run();
|
|
219
|
+
};
|
|
220
|
+
const handleLinkOpen = () => {
|
|
221
|
+
setLinkUrl(editor.getAttributes("link").href || "");
|
|
222
|
+
setLinkText("");
|
|
223
|
+
setPopup(popup === "link" ? null : "link");
|
|
224
|
+
};
|
|
225
|
+
const handleLinkSave = () => {
|
|
226
|
+
if (!linkUrl) return;
|
|
227
|
+
if (hasSelection) {
|
|
228
|
+
editor.chain().focus().setLink({ href: linkUrl }).run();
|
|
229
|
+
} else {
|
|
230
|
+
if (!linkText) return;
|
|
231
|
+
editor.chain().focus().insertContent(`<a href="${linkUrl}">${linkText}</a>`).run();
|
|
232
|
+
}
|
|
233
|
+
setLinkUrl("");
|
|
234
|
+
setLinkText("");
|
|
235
|
+
setPopup(null);
|
|
236
|
+
};
|
|
237
|
+
const handleLinkKeyDown = (e) => {
|
|
238
|
+
if (e.key === "Enter") handleLinkSave();
|
|
239
|
+
if (e.key === "Escape") setPopup(null);
|
|
240
|
+
};
|
|
241
|
+
const handleImageClick = () => {
|
|
242
|
+
var _a2;
|
|
243
|
+
(_a2 = imageInputRef.current) == null ? void 0 : _a2.click();
|
|
244
|
+
};
|
|
245
|
+
const handleImageChange = (e) => {
|
|
246
|
+
var _a2;
|
|
247
|
+
const file = (_a2 = e.target.files) == null ? void 0 : _a2[0];
|
|
248
|
+
if (!file) return;
|
|
249
|
+
if (file.size > MAX_IMAGE_SIZE) {
|
|
250
|
+
alert("Image is too large. Maximum size is 10MB.");
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const reader = new FileReader();
|
|
254
|
+
reader.onload = () => {
|
|
255
|
+
const base64 = reader.result;
|
|
256
|
+
editor.chain().focus().setImage({ src: base64 }).run();
|
|
257
|
+
};
|
|
258
|
+
reader.readAsDataURL(file);
|
|
259
|
+
e.target.value = "";
|
|
260
|
+
};
|
|
261
|
+
const handleTableOpen = () => {
|
|
262
|
+
setPopup(popup === "table" ? null : "table");
|
|
263
|
+
};
|
|
264
|
+
const handleTableInsert = () => {
|
|
265
|
+
const rows = Math.min(10, Math.max(1, parseInt(tableRows) || 3));
|
|
266
|
+
const cols = Math.min(10, Math.max(1, parseInt(tableCols) || 3));
|
|
267
|
+
editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run();
|
|
268
|
+
setPopup(null);
|
|
269
|
+
};
|
|
270
|
+
const handleTableKeyDown = (e) => {
|
|
271
|
+
if (e.key === "Enter") handleTableInsert();
|
|
272
|
+
if (e.key === "Escape") setPopup(null);
|
|
273
|
+
};
|
|
274
|
+
const handleTool = (tool) => {
|
|
275
|
+
switch (tool) {
|
|
276
|
+
case "bold":
|
|
277
|
+
editor.chain().focus().toggleBold().run();
|
|
278
|
+
break;
|
|
279
|
+
case "italic":
|
|
280
|
+
editor.chain().focus().toggleItalic().run();
|
|
281
|
+
break;
|
|
282
|
+
case "underline":
|
|
283
|
+
editor.chain().focus().toggleUnderline().run();
|
|
284
|
+
break;
|
|
285
|
+
case "strikethrough":
|
|
286
|
+
editor.chain().focus().toggleStrike().run();
|
|
287
|
+
break;
|
|
288
|
+
case "heading1":
|
|
289
|
+
editor.chain().focus().toggleHeading({ level: 1 }).run();
|
|
290
|
+
break;
|
|
291
|
+
case "heading2":
|
|
292
|
+
editor.chain().focus().toggleHeading({ level: 2 }).run();
|
|
293
|
+
break;
|
|
294
|
+
case "heading3":
|
|
295
|
+
editor.chain().focus().toggleHeading({ level: 3 }).run();
|
|
296
|
+
break;
|
|
297
|
+
case "heading4":
|
|
298
|
+
editor.chain().focus().toggleHeading({ level: 4 }).run();
|
|
299
|
+
break;
|
|
300
|
+
case "heading5":
|
|
301
|
+
editor.chain().focus().toggleHeading({ level: 5 }).run();
|
|
302
|
+
break;
|
|
303
|
+
case "heading6":
|
|
304
|
+
editor.chain().focus().toggleHeading({ level: 6 }).run();
|
|
305
|
+
break;
|
|
306
|
+
case "bulletList":
|
|
307
|
+
editor.chain().focus().toggleBulletList().run();
|
|
308
|
+
break;
|
|
309
|
+
case "orderedList":
|
|
310
|
+
editor.chain().focus().toggleOrderedList().run();
|
|
311
|
+
break;
|
|
312
|
+
case "blockquote":
|
|
313
|
+
editor.chain().focus().toggleBlockquote().run();
|
|
314
|
+
break;
|
|
315
|
+
case "codeBlock":
|
|
316
|
+
editor.chain().focus().toggleCodeBlock().run();
|
|
317
|
+
break;
|
|
318
|
+
case "undo":
|
|
319
|
+
editor.chain().focus().undo().run();
|
|
320
|
+
break;
|
|
321
|
+
case "redo":
|
|
322
|
+
editor.chain().focus().redo().run();
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
const isActive = (tool) => {
|
|
327
|
+
switch (tool) {
|
|
328
|
+
case "bold":
|
|
329
|
+
return editor.isActive("bold");
|
|
330
|
+
case "italic":
|
|
331
|
+
return editor.isActive("italic");
|
|
332
|
+
case "underline":
|
|
333
|
+
return editor.isActive("underline");
|
|
334
|
+
case "strikethrough":
|
|
335
|
+
return editor.isActive("strike");
|
|
336
|
+
case "heading1":
|
|
337
|
+
return editor.isActive("heading", { level: 1 });
|
|
338
|
+
case "heading2":
|
|
339
|
+
return editor.isActive("heading", { level: 2 });
|
|
340
|
+
case "heading3":
|
|
341
|
+
return editor.isActive("heading", { level: 3 });
|
|
342
|
+
case "heading4":
|
|
343
|
+
return editor.isActive("heading", { level: 4 });
|
|
344
|
+
case "heading5":
|
|
345
|
+
return editor.isActive("heading", { level: 5 });
|
|
346
|
+
case "heading6":
|
|
347
|
+
return editor.isActive("heading", { level: 6 });
|
|
348
|
+
case "bulletList":
|
|
349
|
+
return editor.isActive("bulletList");
|
|
350
|
+
case "orderedList":
|
|
351
|
+
return editor.isActive("orderedList");
|
|
352
|
+
case "blockquote":
|
|
353
|
+
return editor.isActive("blockquote");
|
|
354
|
+
case "codeBlock":
|
|
355
|
+
return editor.isActive("codeBlock");
|
|
356
|
+
case "link":
|
|
357
|
+
return editor.isActive("link");
|
|
358
|
+
default:
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
const isDisabled = (tool) => {
|
|
363
|
+
if (tool === "undo") return !editor.can().undo();
|
|
364
|
+
if (tool === "redo") return !editor.can().redo();
|
|
365
|
+
return false;
|
|
366
|
+
};
|
|
367
|
+
const renderPopup = (tool) => {
|
|
368
|
+
if (tool === "link" && popup === "link") {
|
|
369
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "rre-popup", ref: popupRef, children: [
|
|
370
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
371
|
+
"input",
|
|
372
|
+
{
|
|
373
|
+
className: "rre-popup-input",
|
|
374
|
+
type: "url",
|
|
375
|
+
placeholder: "https://example.com",
|
|
376
|
+
value: linkUrl,
|
|
377
|
+
onChange: (e) => setLinkUrl(e.target.value),
|
|
378
|
+
onKeyDown: handleLinkKeyDown,
|
|
379
|
+
autoFocus: true
|
|
380
|
+
}
|
|
381
|
+
),
|
|
382
|
+
!hasSelection && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
383
|
+
"input",
|
|
384
|
+
{
|
|
385
|
+
className: "rre-popup-input",
|
|
386
|
+
type: "text",
|
|
387
|
+
placeholder: "Display text",
|
|
388
|
+
value: linkText,
|
|
389
|
+
onChange: (e) => setLinkText(e.target.value),
|
|
390
|
+
onKeyDown: handleLinkKeyDown
|
|
391
|
+
}
|
|
392
|
+
),
|
|
393
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
394
|
+
"button",
|
|
395
|
+
{
|
|
396
|
+
className: "rre-popup-btn",
|
|
397
|
+
onMouseDown: (e) => {
|
|
398
|
+
e.preventDefault();
|
|
399
|
+
handleLinkSave();
|
|
400
|
+
},
|
|
401
|
+
children: "Save"
|
|
402
|
+
}
|
|
403
|
+
)
|
|
404
|
+
] });
|
|
405
|
+
}
|
|
406
|
+
if (tool === "table" && popup === "table") {
|
|
407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "rre-popup rre-popup--table", ref: popupRef, children: [
|
|
408
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
409
|
+
"input",
|
|
410
|
+
{
|
|
411
|
+
className: "rre-popup-input rre-popup-input--num",
|
|
412
|
+
type: "number",
|
|
413
|
+
min: "1",
|
|
414
|
+
max: "10",
|
|
415
|
+
value: tableRows,
|
|
416
|
+
onChange: (e) => setTableRows(e.target.value),
|
|
417
|
+
onKeyDown: handleTableKeyDown,
|
|
418
|
+
autoFocus: true
|
|
419
|
+
}
|
|
420
|
+
),
|
|
421
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "rre-popup-x", children: "\xD7" }),
|
|
422
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
423
|
+
"input",
|
|
424
|
+
{
|
|
425
|
+
className: "rre-popup-input rre-popup-input--num",
|
|
426
|
+
type: "number",
|
|
427
|
+
min: "1",
|
|
428
|
+
max: "10",
|
|
429
|
+
value: tableCols,
|
|
430
|
+
onChange: (e) => setTableCols(e.target.value),
|
|
431
|
+
onKeyDown: handleTableKeyDown
|
|
432
|
+
}
|
|
433
|
+
),
|
|
434
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
435
|
+
"button",
|
|
436
|
+
{
|
|
437
|
+
className: "rre-popup-btn",
|
|
438
|
+
onMouseDown: (e) => {
|
|
439
|
+
e.preventDefault();
|
|
440
|
+
handleTableInsert();
|
|
441
|
+
},
|
|
442
|
+
children: "Insert"
|
|
443
|
+
}
|
|
444
|
+
)
|
|
445
|
+
] });
|
|
446
|
+
}
|
|
447
|
+
return null;
|
|
448
|
+
};
|
|
449
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: ["rre-toolbar", className].filter(Boolean).join(" "), role: "toolbar", children: [
|
|
450
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
451
|
+
"input",
|
|
452
|
+
{
|
|
453
|
+
ref: imageInputRef,
|
|
454
|
+
type: "file",
|
|
455
|
+
accept: "image/*",
|
|
456
|
+
style: { display: "none" },
|
|
457
|
+
onChange: handleImageChange
|
|
458
|
+
}
|
|
459
|
+
),
|
|
460
|
+
toolbar.map((tool, i) => {
|
|
461
|
+
if (tool === "divider") {
|
|
462
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "rre-toolbar-divider", "aria-hidden": "true" }, `divider-${i}`);
|
|
463
|
+
}
|
|
464
|
+
if (tool === "fontSize") {
|
|
465
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
466
|
+
"select",
|
|
467
|
+
{
|
|
468
|
+
className: "rre-fontsize-select",
|
|
469
|
+
value: currentFontSize,
|
|
470
|
+
onChange: (e) => handleFontSize(e.target.value),
|
|
471
|
+
title: "Font size",
|
|
472
|
+
children: FONT_SIZES.map((size) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("option", { value: size, children: [
|
|
473
|
+
size,
|
|
474
|
+
"px"
|
|
475
|
+
] }, size))
|
|
476
|
+
},
|
|
477
|
+
"fontSize"
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
if (tool === "link") {
|
|
481
|
+
const def2 = getToolDefinition(tool);
|
|
482
|
+
if (!def2) return null;
|
|
483
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "rre-toolbar-popup-wrapper", onMouseDown: (e) => e.stopPropagation(), children: [
|
|
484
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
485
|
+
ToolbarButton_default,
|
|
486
|
+
{
|
|
487
|
+
onClick: handleLinkOpen,
|
|
488
|
+
isActive: editor.isActive("link") || popup === "link",
|
|
489
|
+
title: def2.title,
|
|
490
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "rre-icon", dangerouslySetInnerHTML: { __html: def2.icon } })
|
|
491
|
+
}
|
|
492
|
+
),
|
|
493
|
+
renderPopup("link")
|
|
494
|
+
] }, "link");
|
|
495
|
+
}
|
|
496
|
+
if (tool === "image") {
|
|
497
|
+
const def2 = getToolDefinition(tool);
|
|
498
|
+
if (!def2) return null;
|
|
499
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
500
|
+
ToolbarButton_default,
|
|
501
|
+
{
|
|
502
|
+
onClick: handleImageClick,
|
|
503
|
+
title: def2.title,
|
|
504
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "rre-icon", dangerouslySetInnerHTML: { __html: def2.icon } })
|
|
505
|
+
},
|
|
506
|
+
"image"
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
if (tool === "table") {
|
|
510
|
+
const def2 = getToolDefinition(tool);
|
|
511
|
+
if (!def2) return null;
|
|
512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "rre-toolbar-popup-wrapper", onMouseDown: (e) => e.stopPropagation(), children: [
|
|
513
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
514
|
+
ToolbarButton_default,
|
|
515
|
+
{
|
|
516
|
+
onClick: handleTableOpen,
|
|
517
|
+
isActive: popup === "table",
|
|
518
|
+
title: def2.title,
|
|
519
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "rre-icon", dangerouslySetInnerHTML: { __html: def2.icon } })
|
|
520
|
+
}
|
|
521
|
+
),
|
|
522
|
+
renderPopup("table")
|
|
523
|
+
] }, "table");
|
|
524
|
+
}
|
|
525
|
+
const def = getToolDefinition(tool);
|
|
526
|
+
if (!def) return null;
|
|
527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
528
|
+
ToolbarButton_default,
|
|
529
|
+
{
|
|
530
|
+
onClick: () => handleTool(tool),
|
|
531
|
+
isActive: isActive(tool),
|
|
532
|
+
disabled: isDisabled(tool),
|
|
533
|
+
title: def.title,
|
|
534
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "rre-icon", dangerouslySetInnerHTML: { __html: def.icon } })
|
|
535
|
+
},
|
|
536
|
+
tool
|
|
537
|
+
);
|
|
538
|
+
})
|
|
539
|
+
] });
|
|
540
|
+
};
|
|
541
|
+
var Toolbar_default = Toolbar;
|
|
542
|
+
|
|
543
|
+
// src/components/RichEditor.tsx
|
|
544
|
+
var import_editor = require("./editor-XH5ZEVLH.css");
|
|
545
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
546
|
+
var DEFAULT_TOOLBAR = [
|
|
547
|
+
"bold",
|
|
548
|
+
"italic",
|
|
549
|
+
"underline",
|
|
550
|
+
"strikethrough",
|
|
551
|
+
"divider",
|
|
552
|
+
"heading1",
|
|
553
|
+
"heading2",
|
|
554
|
+
"heading3",
|
|
555
|
+
"divider",
|
|
556
|
+
"bulletList",
|
|
557
|
+
"orderedList",
|
|
558
|
+
"blockquote",
|
|
559
|
+
"codeBlock",
|
|
560
|
+
"divider",
|
|
561
|
+
"link",
|
|
562
|
+
"image",
|
|
563
|
+
"table",
|
|
564
|
+
"divider",
|
|
565
|
+
"undo",
|
|
566
|
+
"redo"
|
|
567
|
+
];
|
|
568
|
+
var RichEditor = ({
|
|
569
|
+
value = "",
|
|
570
|
+
onChange,
|
|
571
|
+
toolbar = DEFAULT_TOOLBAR,
|
|
572
|
+
placeholder = "Start typing...",
|
|
573
|
+
editable = true,
|
|
574
|
+
className,
|
|
575
|
+
style,
|
|
576
|
+
toolbarClassName,
|
|
577
|
+
contentClassName
|
|
578
|
+
}) => {
|
|
579
|
+
const editor = useEditor({ value, onChange, placeholder, editable, toolbar });
|
|
580
|
+
if (!editor) return null;
|
|
581
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
582
|
+
"div",
|
|
583
|
+
{
|
|
584
|
+
className: ["rre-editor", className].filter(Boolean).join(" "),
|
|
585
|
+
style,
|
|
586
|
+
children: [
|
|
587
|
+
editable && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Toolbar_default, { editor, toolbar, className: toolbarClassName }),
|
|
588
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
589
|
+
import_react4.EditorContent,
|
|
590
|
+
{
|
|
591
|
+
editor,
|
|
592
|
+
className: ["rre-content", contentClassName].filter(Boolean).join(" ")
|
|
593
|
+
}
|
|
594
|
+
)
|
|
595
|
+
]
|
|
596
|
+
}
|
|
597
|
+
);
|
|
598
|
+
};
|
|
599
|
+
var RichEditor_default = RichEditor;
|
|
600
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
601
|
+
0 && (module.exports = {
|
|
602
|
+
RichEditor
|
|
603
|
+
});
|
|
604
|
+
//# sourceMappingURL=index.js.map
|